Skip to content

Commit

Permalink
fix(tags): Filter system tags from the tags list (apache#26701)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vitor-Avila authored and sfirke committed Mar 22, 2024
1 parent 1a96793 commit ae9b147
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 3 deletions.
20 changes: 19 additions & 1 deletion superset-frontend/src/pages/Tags/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ function TagList(props: TagListProps) {
const { addDangerToast, addSuccessToast, user } = props;
const { userId } = user;

const initialFilters = useMemo(
() => [
{
id: 'type',
operator: 'custom_tag',
value: true,
},
],
[],
);

const {
state: {
loading,
Expand All @@ -70,7 +81,14 @@ function TagList(props: TagListProps) {
fetchData,
toggleBulkSelect,
refreshData,
} = useListViewResource<Tag>('tag', t('tag'), addDangerToast);
} = useListViewResource<Tag>(
'tag',
t('tag'),
addDangerToast,
undefined,
undefined,
initialFilters,
);

const [showTagModal, setShowTagModal] = useState<boolean>(false);
const [tagToEdit, setTagToEdit] = useState<Tag | null>(null);
Expand Down
2 changes: 1 addition & 1 deletion superset/commands/dashboard/importers/v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def import_chart(


def import_dashboard(
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
# pylint: disable=too-many-locals,too-many-statements
dashboard_to_import: Dashboard,
dataset_id_mapping: Optional[dict[int, int]] = None,
import_time: Optional[int] = None,
Expand Down
3 changes: 3 additions & 0 deletions superset/tags/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from superset.daos.tag import TagDAO
from superset.exceptions import MissingUserContextException
from superset.extensions import event_logger
from superset.tags.filters import UserCreatedTagTypeFilter
from superset.tags.models import ObjectType, Tag
from superset.tags.schemas import (
delete_tags_schema,
Expand Down Expand Up @@ -119,6 +120,8 @@ class TagRestApi(BaseSupersetModelRestApi):
}
allowed_rel_fields = {"created_by", "changed_by"}

search_filters = {"type": [UserCreatedTagTypeFilter]}

add_model_schema = TagPostSchema()
edit_model_schema = TagPutSchema()
tag_get_response_schema = TagGetResponseSchema()
Expand Down
39 changes: 39 additions & 0 deletions superset/tags/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from flask_babel import lazy_gettext as _
from sqlalchemy.orm import Query

from superset.tags.models import Tag, TagType
from superset.views.base import BaseFilter


class UserCreatedTagTypeFilter(BaseFilter): # pylint: disable=too-few-public-methods
"""
Filter for tag type.
When set to True, only user-created tags are returned.
When set to False, only system tags are returned.
"""

name = _("Is custom tag")
arg_name = "custom_tag"

def apply(self, query: Query, value: bool) -> Query:
if value:
return query.filter(Tag.type == TagType.custom)
if value is False:
return query.filter(Tag.type != TagType.custom)
return query
1 change: 0 additions & 1 deletion superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# specific language governing permissions and limitations
# under the License.
# pylint: disable=invalid-name
# pylint: disable=too-many-lines
from __future__ import annotations

import contextlib
Expand Down
46 changes: 46 additions & 0 deletions tests/integration_tests/tags/api_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# isort:skip_file
"""Unit tests for Superset"""
import json
import prison
from datetime import datetime

from flask import g
Expand All @@ -30,6 +31,7 @@
from superset.models.sql_lab import SavedQuery
from superset.tags.models import user_favorite_tag_table
from unittest.mock import patch
from urllib import parse


import tests.integration_tests.test_app
Expand Down Expand Up @@ -175,6 +177,50 @@ def test_get_list_tag(self):
# check expected columns
assert data["list_columns"] == TAGS_LIST_COLUMNS

def test_get_list_tag_filtered(self):
"""
Query API: Test get list query applying filters for
type == "custom" and type != "custom"
"""
tags = [
{"name": "Test custom Tag", "type": "custom"},
{"name": "type:dashboard", "type": "type"},
{"name": "owner:1", "type": "owner"},
{"name": "Another Tag", "type": "custom"},
{"name": "favorited_by:1", "type": "favorited_by"},
]

for tag in tags:
self.insert_tag(
name=tag["name"],
tag_type=tag["type"],
)
self.login(username="admin")

# Only user-created tags
query = {
"filters": [
{
"col": "type",
"opr": "custom_tag",
"value": True,
}
],
}
uri = f"api/v1/tag/?{parse.urlencode({'q': prison.dumps(query)})}"
rv = self.client.get(uri)
self.assertEqual(rv.status_code, 200)
data = json.loads(rv.data.decode("utf-8"))
assert data["count"] == 2

# Only system tags
query["filters"][0]["value"] = False
uri = f"api/v1/tag/?{parse.urlencode({'q': prison.dumps(query)})}"
rv = self.client.get(uri)
self.assertEqual(rv.status_code, 200)
data = json.loads(rv.data.decode("utf-8"))
assert data["count"] == 3

# test add tagged objects
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
Expand Down

0 comments on commit ae9b147

Please sign in to comment.