Fixes #8596 Introduce mutually exclusive tags and glossary terms (#8597)

This commit is contained in:
Suresh Srinivas 2022-11-10 16:47:21 -08:00 committed by GitHub
parent d4b2621e9d
commit 86c3ae30f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 95 additions and 152 deletions

View File

@ -1,3 +1,6 @@
--
-- Upgrade changes for 0.13
--
CREATE TABLE IF NOT EXISTS web_analytic_event (
id VARCHAR(36) GENERATED ALWAYS AS (json ->> '$.id') NOT NULL,
name VARCHAR(256) GENERATED ALWAYS AS (json ->> '$.name') NOT NULL,
@ -53,6 +56,21 @@ UPDATE pipeline_service_entity
SET json = JSON_REMOVE(json ,'$.connection.config.hostPort', '$.connection.config.numberOfStatus')
WHERE serviceType = 'Dagster';
-- Remove categoryType
UPDATE tag_category
SET json = JSON_REMOVE(json ,'$.categoryType');
-- Set mutuallyExclusive flag
UPDATE tag_category
SET json = JSON_INSERT(json ,'$.mutuallyExclusive', 'false');
UPDATE tag_category
SET json = JSON_INSERT(json ,'$.mutuallyExclusive', 'true')
WHERE name in ('PersonalData', 'PII', 'Tier');
UPDATE tag
SET json = JSON_INSERT(json ,'$.mutuallyExclusive', 'false');
CREATE TABLE IF NOT EXISTS kpi_entity (
id VARCHAR(36) GENERATED ALWAYS AS (json ->> '$.id') STORED NOT NULL,
name VARCHAR(256) GENERATED ALWAYS AS (json ->> '$.name') NOT NULL,

View File

@ -1,3 +1,6 @@
--
-- Upgrade changes for 0.13
--
CREATE TABLE IF NOT EXISTS web_analytic_event (
id VARCHAR(36) GENERATED ALWAYS AS (json ->> 'id') STORED NOT NULL,
name VARCHAR(256) GENERATED ALWAYS AS (json ->> 'name') STORED NOT NULL,
@ -51,13 +54,28 @@ WHERE fullyQualifiedName in ('PersonalData.Personal', 'PersonalData.SpecialCateg
'Tier.Tier1', 'Tier.Tier2', 'Tier.Tier3', 'Tier.Tier4', 'Tier.Tier5');
UPDATE pipeline_service_entity
SET json = jsonb_set(json::jsonb,'{connection,config}',json::jsonb #>'{connection,config}' || jsonb_build_object('configSource',jsonb_build_object('hostPort',json #>'{connection,config,hostPort}')), true)
SET json = JSONB_SET(json::jsonb,'{connection,config}',json::jsonb #>'{connection,config}' || jsonb_build_object('configSource',jsonb_build_object('hostPort',json #>'{connection,config,hostPort}')), true)
where servicetype = 'Dagster';
UPDATE pipeline_service_entity
SET json = json::jsonb #- '{connection,config,hostPort}' #- '{connection,config,numberOfStatus}'
where servicetype = 'Dagster';
-- Remove categoryType
UPDATE tag_category
SET json = json::jsonb #- '{categoryType}';
-- set mutuallyExclusive flag
UPDATE tag_category
SET json = jsonb_set(json, '{mutuallyExclusive}', 'false'::jsonb, true);
UPDATE tag_category
SET json = jsonb_set(json, '{mutuallyExclusive}', 'true'::jsonb, true)
WHERE name in ('PersonalData', 'PII', 'Tier');
UPDATE tag
SET json = jsonb_set(json, '{mutuallyExclusive}', 'false'::jsonb, true);
CREATE TABLE IF NOT EXISTS kpi_entity (
id VARCHAR(36) GENERATED ALWAYS AS (json ->> 'id') STORED NOT NULL,
name VARCHAR(256) GENERATED ALWAYS AS (json ->> 'name') STORED NOT NULL,

View File

@ -194,7 +194,6 @@ class TableauSource(DashboardServiceSource):
category_name=CreateTagCategoryRequest(
name=TABLEAU_TAG_CATEGORY,
description="Tags associates with tableau entities",
categoryType="Descriptive",
),
category_details=CreateTagRequest(name=tag, description="Tableau Tag"),
)

View File

@ -159,7 +159,6 @@ class BigquerySource(CommonDbSourceService):
category_name=CreateTagCategoryRequest(
name=self.service_connection.tagCategoryName,
description="",
categoryType="Classification",
),
category_details=CreateTagRequest(
name=tag.display_name, description="Bigquery Policy Tag"

View File

@ -407,7 +407,6 @@ class DatabaseServiceSource(
category_name=CreateTagCategoryRequest(
name="DBTTags",
description="",
categoryType="Classification",
),
category_details=CreateTagRequest(
name=tag_label.tagFQN.__root__.split(".")[1],

View File

@ -308,7 +308,6 @@ class SnowflakeSource(CommonDbSourceService):
category_name=CreateTagCategoryRequest(
name=row[0],
description="SNOWFLAKE TAG NAME",
categoryType="Descriptive",
),
category_details=CreateTagRequest(
name=row[1], description="SNOWFLAKE TAG VALUE"

View File

@ -251,7 +251,6 @@ class AmundsenSource(Source[Entity]):
category_name=CreateTagCategoryRequest(
name=AMUNDSEN_TAG_CATEGORY,
description="Tags associates with amundsen entities",
categoryType="Descriptive",
),
category_details=CreateTagRequest(
name=tag, description="Amundsen Table Tag"
@ -351,7 +350,6 @@ class AmundsenSource(Source[Entity]):
category_name=CreateTagCategoryRequest(
name=AMUNDSEN_TAG_CATEGORY,
description="Tags associates with amundsen entities",
categoryType="Descriptive",
),
category_details=CreateTagRequest(
name=AMUNDSEN_TABLE_TAG, description="Amundsen Table Tag"
@ -362,7 +360,6 @@ class AmundsenSource(Source[Entity]):
category_name=CreateTagCategoryRequest(
name=AMUNDSEN_TAG_CATEGORY,
description="Tags associates with amundsen entities",
categoryType="Descriptive",
),
category_details=CreateTagRequest(
name=table["cluster"], description="Amundsen Cluster Tag"

View File

@ -172,7 +172,6 @@ class DagsterSource(PipelineServiceSource):
category_name=CreateTagCategoryRequest(
name="DagsterTags",
description="Tags associated with dagster",
categoryType="Descriptive",
),
category_details=CreateTagRequest(
name=self.context.repository_name, description="Dagster Tag"

View File

@ -42,7 +42,7 @@ class OMetaTagMixinPost(TestCase):
"""Test POST category Mixin method"""
tag_category = CreateTagCategoryRequest(
categoryType="Descriptive", description="test tag", name=CATEGORY_NAME
description="test tag", name=CATEGORY_NAME
)
self.metadata.create_tag_category(tag_category)
@ -144,7 +144,7 @@ class OMetaTagMixinPut(TestCase):
rand_name = random.getrandbits(64)
updated_tag_category = CreateTagCategoryRequest(
categoryType="Descriptive", description="test tag", name=f"{rand_name}"
description="test tag", name=f"{rand_name}"
)
self.metadata.create_or_update_tag_category(CATEGORY_NAME, updated_tag_category)

View File

@ -12,7 +12,6 @@ slug: /main-concepts/metadata-standard/schemas/api/tags/createtagcategory
- **`name`**: Refer to *../../entity/tags/tagCategory.json#/definitions/tagName*.
- **`displayName`** *(string)*: Display Name that identifies this tag category.
- **`description`**: Description of the tag category. Refer to *../../type/basic.json#/definitions/markdown*.
- **`categoryType`**: Refer to *../../entity/tags/tagCategory.json#/definitions/tagCategoryType*.
Documentation file automatically generated at 2022-07-14 10:51:34.749986.

View File

@ -17,7 +17,6 @@ slug: /main-concepts/metadata-standard/schemas/entity/tags/tagcategory
- **`version`**: Metadata version of the entity. Refer to *../../type/entityHistory.json#/definitions/entityVersion*.
- **`updatedAt`**: Last update time corresponding to the new version of the entity in Unix epoch time milliseconds. Refer to *../../type/basic.json#/definitions/timestamp*.
- **`updatedBy`** *(string)*: User who made the update.
- **`categoryType`**: Refer to *#/definitions/tagCategoryType*.
- **`href`**: Link to the resource corresponding to the tag category. Refer to *../../type/basic.json#/definitions/href*.
- **`usageCount`** *(integer)*: Count of how many times the tags from this tag category are used.
- **`children`** *(array)*: Tags under this category.
@ -27,7 +26,6 @@ slug: /main-concepts/metadata-standard/schemas/entity/tags/tagcategory
## Definitions
- **`tagName`** *(string)*: Name of the tag.
- **`tagCategoryType`** *(string)*: Type of tag category. Must be one of: `['Descriptive', 'Classification']`.
- **`tag`**: Cannot contain additional properties.
- **`id`**: Unique identifier of this entity instance. Refer to *../../type/basic.json#/definitions/uuid*.
- **`name`**: Name of the tag. Refer to *#/definitions/tagName*.

View File

@ -135,7 +135,8 @@ public class TagCategoryRepository extends EntityRepository<TagCategory> {
@Override
public void entitySpecificUpdate() throws IOException {
// TODO handle name change
recordChange("categoryType", original.getCategoryType(), updated.getCategoryType());
// TODO mutuallyExclusive from false to true?
recordChange("mutuallyExclusive", original.getMutuallyExclusive(), updated.getMutuallyExclusive());
updateName(original, updated);
}

View File

@ -144,6 +144,9 @@ public class TagRepository extends EntityRepository<Tag> {
@Override
public void entitySpecificUpdate() throws IOException {
// TODO mutuallyExclusive from false to true?
recordChange("mutuallyExclusive", original.getMutuallyExclusive(), updated.getMutuallyExclusive());
// TODO check the below
updateName(original, updated);
}

View File

@ -551,7 +551,7 @@ public class TagResource {
.withId(UUID.randomUUID())
.withName(create.getName())
.withFullyQualifiedName(create.getName())
.withCategoryType(create.getCategoryType())
.withMutuallyExclusive(create.getMutuallyExclusive())
.withDescription(create.getDescription())
.withUpdatedBy(securityContext.getUserPrincipal().getName())
.withUpdatedAt(System.currentTimeMillis());
@ -564,6 +564,7 @@ public class TagResource {
.withFullyQualifiedName(FullyQualifiedName.add(parentFQN, create.getName()))
.withDescription(create.getDescription())
.withUpdatedBy(securityContext.getUserPrincipal().getName())
.withUpdatedAt(System.currentTimeMillis());
.withUpdatedAt(System.currentTimeMillis())
.withMutuallyExclusive(create.getMutuallyExclusive());
}
}

View File

@ -55,9 +55,6 @@
"href": {
"type": "text"
},
"categoryType": {
"type": "text"
},
"deleted": {
"type": "text"
},

View File

@ -1,8 +1,8 @@
{
"name": "PersonalData",
"categoryType": "Classification",
"description": "Tags related classifying **Personal data** as defined by **GDPR.**<br/><br/>_Note to Legal - This tag category is provided as a starting point. Please review and update the tags based on your company policy. Also, add a reference to your GDPR policy document in this description._",
"provider": "system",
"mutuallyExclusive": "true",
"children": [
{
"name": "Personal",

View File

@ -1,8 +1,8 @@
{
"name": "PII",
"categoryType": "Classification",
"description": "Personally Identifiable Information information that, when used alone or with other relevant data, can identify an individual.<br/><br/>_Note to Legal - This tag category is provided as a starting point. Please review and update the tags based on your company policy. Also, add a reference to your PII policy document in this description._",
"provider": "system",
"mutuallyExclusive": "true",
"children": [
{
"name": "None",

View File

@ -1,8 +1,8 @@
{
"name": "Tier",
"categoryType": "Descriptive",
"description": "Tags related to tiering of the data. Tiers capture the business importance of data. When a data asset is tagged with `Tier` tag, all the upstream data assets used for producing it will also be labeled with the same tag. This will help upstream data asset owners to understand the critical purposes their data is being used.",
"provider": "system",
"mutuallyExclusive": "true",
"children": [
{
"name": "Tier1",

View File

@ -45,7 +45,6 @@ import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.TestMethodOrder;
import org.openmetadata.schema.api.tags.CreateTag;
import org.openmetadata.schema.api.tags.CreateTagCategory;
import org.openmetadata.schema.api.tags.CreateTagCategory.TagCategoryType;
import org.openmetadata.schema.entity.tags.Tag;
import org.openmetadata.schema.type.TagCategory;
import org.openmetadata.schema.type.TagLabel;
@ -80,11 +79,7 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
EntityResourceTest.TIER1_TAG_LABEL = getTagLabel(FullyQualifiedName.add("Tier", "Tier1"));
EntityResourceTest.TIER2_TAG_LABEL = getTagLabel(FullyQualifiedName.add("Tier", "Tier2"));
CreateTagCategory create =
new CreateTagCategory()
.withName("User")
.withDescription("description")
.withCategoryType(TagCategoryType.Descriptive);
CreateTagCategory create = new CreateTagCategory().withName("User").withDescription("description");
USER_TAG_CATEGORY = tagResourceTest.createAndCheckCategory(create, ADMIN_AUTH_HEADERS);
List<String> associatedTags = new ArrayList<>();
@ -156,10 +151,7 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
void post_alreadyExistingTagCategory_4xx() {
// POST .../tags/{allReadyExistingCategory} returns 4xx
CreateTagCategory create =
new CreateTagCategory()
.withName(USER_TAG_CATEGORY.getName())
.withDescription("description")
.withCategoryType(TagCategoryType.Descriptive);
new CreateTagCategory().withName(USER_TAG_CATEGORY.getName()).withDescription("description");
assertResponse(() -> createAndCheckCategory(create, ADMIN_AUTH_HEADERS), CONFLICT, "Entity already exists");
}
@ -167,11 +159,7 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
void post_delete_validTagCategory_as_admin_201(TestInfo test) throws HttpResponseException {
// POST .../tags/{newCategory} returns 201
String categoryName = test.getDisplayName().substring(0, 20); // Form a unique category name based on the test name
CreateTagCategory create =
new CreateTagCategory()
.withName(categoryName)
.withDescription("description")
.withCategoryType(TagCategoryType.Descriptive);
CreateTagCategory create = new CreateTagCategory().withName(categoryName).withDescription("description");
TagCategory category = createAndCheckCategory(create, ADMIN_AUTH_HEADERS);
assertEquals(0, category.getChildren().size());
@ -198,11 +186,7 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
void post_delete_validTags_as_admin_201(TestInfo test) throws HttpResponseException {
// Create tag category
String categoryName = test.getDisplayName().substring(0, 20);
CreateTagCategory create =
new CreateTagCategory()
.withName(categoryName)
.withDescription("description")
.withCategoryType(TagCategoryType.Descriptive);
CreateTagCategory create = new CreateTagCategory().withName(categoryName).withDescription("description");
TagCategory category = createAndCheckCategory(create, ADMIN_AUTH_HEADERS);
assertEquals(0, category.getChildren().size());
@ -272,21 +256,12 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
String categoryName = test.getDisplayName().substring(0, 10); // Form a unique category name based on the test name
// Missing description
CreateTagCategory create =
new CreateTagCategory()
.withName(categoryName)
.withDescription(null)
.withCategoryType(TagCategoryType.Descriptive);
CreateTagCategory create = new CreateTagCategory().withName(categoryName).withDescription(null);
assertResponseContains(
() -> createAndCheckCategory(create, ADMIN_AUTH_HEADERS), BAD_REQUEST, "description must not be null");
// Missing category
create.withDescription("description").withCategoryType(null);
assertResponseContains(
() -> createAndCheckCategory(create, ADMIN_AUTH_HEADERS), BAD_REQUEST, "categoryType must not be null");
// Long name
create.withName(TestUtils.LONG_ENTITY_NAME).withCategoryType(TagCategoryType.Descriptive);
create.withName(TestUtils.LONG_ENTITY_NAME);
assertResponseContains(
() -> createAndCheckCategory(create, ADMIN_AUTH_HEADERS), BAD_REQUEST, "name size must be between 2 and 64");
}
@ -354,31 +329,11 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
entityNotFound(Entity.TAG, FullyQualifiedName.build(USER_TAG_CATEGORY.getName(), nonExistent)));
}
@Test
void put_tagCategory_200(TestInfo test) {
// Update an existing tag category
String newCategoryName = test.getDisplayName().substring(0, 10);
CreateTagCategory create =
new CreateTagCategory()
.withName(newCategoryName)
.withDescription("updatedDescription")
.withCategoryType(TagCategoryType.Descriptive);
updateCategory(USER_TAG_CATEGORY.getName(), create, ADMIN_AUTH_HEADERS);
// Revert tag category back
create.withName(USER_TAG_CATEGORY.getName()).withCategoryType(TagCategoryType.Classification);
updateCategory(newCategoryName, create, ADMIN_AUTH_HEADERS);
}
@Test
void put_tagCategoryInvalidRequest_400(TestInfo test) {
// Primary tag with missing description
String newCategoryName = test.getDisplayName().substring(0, 10);
CreateTagCategory create =
new CreateTagCategory()
.withName(newCategoryName)
.withDescription(null)
.withCategoryType(TagCategoryType.Descriptive);
CreateTagCategory create = new CreateTagCategory().withName(newCategoryName).withDescription(null);
assertResponseContains(
() -> updateCategory(USER_TAG_CATEGORY.getName(), create, ADMIN_AUTH_HEADERS),
BAD_REQUEST,
@ -448,12 +403,11 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
String updatedBy = getPrincipalName(authHeaders);
WebTarget target = getResource("tags");
TagCategory tagCategory = TestUtils.post(target, create, TagCategory.class, authHeaders);
TagCategory category =
validate(tagCategory, create.getCategoryType(), create.getName(), create.getDescription(), updatedBy);
TagCategory category = validate(tagCategory, create.getName(), create.getDescription(), updatedBy);
assertEquals(0.1, category.getVersion());
TagCategory getCategory = getCategory(create.getName(), authHeaders);
validate(getCategory, create.getCategoryType(), create.getName(), create.getDescription(), updatedBy);
validate(getCategory, create.getName(), create.getDescription(), updatedBy);
return category;
}
@ -504,11 +458,11 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
// Ensure PUT returns the updated tag category
TagCategory tagCategory = TestUtils.put(target, update, TagCategory.class, Status.OK, authHeaders);
validate(tagCategory, update.getCategoryType(), update.getName(), update.getDescription(), updatedBy);
validate(tagCategory, update.getName(), update.getDescription(), updatedBy);
// Ensure GET returns the updated tag category
TagCategory getCategory = getCategory(update.getName(), authHeaders);
validate(getCategory, update.getCategoryType(), update.getName(), update.getDescription(), updatedBy);
validate(getCategory, update.getName(), update.getDescription(), updatedBy);
}
private void updatePrimaryTag(String category, String primaryTag, CreateTag update, Map<String, String> authHeaders)
@ -587,14 +541,9 @@ public class TagResourceTest extends OpenMetadataApplicationTest {
}
private TagCategory validate(
TagCategory actual,
TagCategoryType expectedCategoryType,
String expectedName,
String expectedDescription,
String expectedUpdatedBy) {
TagCategory actual, String expectedName, String expectedDescription, String expectedUpdatedBy) {
validate(actual);
assertEquals(expectedName, actual.getName());
assertEquals(expectedCategoryType, actual.getCategoryType());
assertEquals(expectedDescription, actual.getDescription());
assertEquals(expectedUpdatedBy, actual.getUpdatedBy());
return actual;

View File

@ -25,6 +25,11 @@
"items": {
"type": "string"
}
},
"mutuallyExclusive" : {
"description" : "Tags under this category are mutually exclusive. When mutually exclusive is `true` the tags from this category are used to **classify** an entity. An entity can only be in one class - example, it can only be either `tier1` or `tier2` and not both. When mutually exclusive is `false`, the tags from this category are used to **categorize** an entity. An entity can be in multiple categories simultaneously - example a customer can be `newCustomer` and `atRisk` simultaneously. ** Note when a tag category is marked mutually exclusive, all the tag groups under it are also mutually exclusive.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["name", "description"],

View File

@ -19,10 +19,12 @@
"description": "Description of the tag category",
"$ref": "../../type/basic.json#/definitions/markdown"
},
"categoryType": {
"$ref": "../../entity/tags/tagCategory.json#/definitions/tagCategoryType"
"mutuallyExclusive" : {
"description" : "Tags under this category are mutually exclusive. When mutually exclusive is `true` the tags from this category are used to **classify** an entity. An entity can only be in one class - example, it can only be either `tier1` or `tier2` and not both. When mutually exclusive is `false`, the tags from this category are used to **categorize** an entity. An entity can be in multiple categories simultaneously - example a customer can be `newCustomer` and `atRisk` simultaneously. ** Note when a tag category is marked mutually exclusive, all the tag groups under it are also mutually exclusive.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["name", "description", "categoryType"],
"required": ["name", "description"],
"additionalProperties": false
}

View File

@ -18,7 +18,7 @@
"$ref": "../../type/basic.json#/definitions/uuid"
},
"name": {
"description": "Preferred name for the glossary term.",
"description": "Name of the glossary",
"type": "string",
"$ref": "#/definitions/name"
},
@ -88,6 +88,11 @@
"disabled" : {
"description": "System glossary can't be deleted. Use this flag to disable them.",
"type": "boolean"
},
"mutuallyExclusive" : {
"description" : "Glossary terms under this glossary are mutually exclusive. When mutually exclusive is `true` only one term can be used to label an entity. When mutually exclusive is `false`, multiple terms from this group can be used to label an entity. When Glossary is mutually exclusive, all the glossary term groups under it are also mutually exclusive.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["id", "name", "description"],

View File

@ -134,6 +134,11 @@
"disabled" : {
"description": "System glossary can't be deleted. Use this flag to disable them.",
"type": "boolean"
},
"mutuallyExclusive" : {
"description" : "Glossary terms under this group mutually exclusive. When mutually exclusive is `true` only one term can be used to label an entity from this group. When mutually exclusive is `false`, multiple terms from this group can be used to label an entity. When a group is mutually exclusive, all the glossary term groups under it are also mutually exclusive.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["id", "name", "description", "glossary"],

View File

@ -13,21 +13,6 @@
"minLength": 2,
"maxLength": 64
},
"tagCategoryType": {
"description": "Type of tag category.",
"type": "string",
"enum": ["Descriptive", "Classification"],
"javaEnums": [
{
"name": "Descriptive",
"description": "Tag category used for describing an entity. Example - column is of of type User.Address."
},
{
"name": "Classification",
"description": "Tag category used for classifying an entity. Example - column is of of type PII.sensitive."
}
]
},
"tag": {
"javaType": "org.openmetadata.schema.entity.tags.Tag",
"javaInterfaces": ["org.openmetadata.schema.EntityInterface"],
@ -99,6 +84,11 @@
"disabled" : {
"description": "System tags can't be deleted. Use this flag to disable them.",
"type": "boolean"
},
"mutuallyExclusive" : {
"description" : "Children tags under this group are mutually exclusive. When mutually exclusive is `true` the tags from this group are used to **classify** an entity. An entity can only be in one class - example, it can only be either `tier1` or `tier2` and not both. When mutually exclusive is `false`, the tags from this group are used to **categorize** an entity. An entity can be in multiple categories simultaneously - example a customer can be `newCustomer` and `atRisk` simultaneously.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["name", "description"],
@ -137,9 +127,6 @@
"description": "User who made the update.",
"type": "string"
},
"categoryType": {
"$ref": "#/definitions/tagCategoryType"
},
"href": {
"description": "Link to the resource corresponding to the tag category.",
"$ref": "../../type/basic.json#/definitions/href"
@ -170,8 +157,13 @@
"disabled" : {
"description": "System tag categories can't be deleted. Use this flag to disable them.",
"type": "boolean"
},
"mutuallyExclusive" : {
"description" : "Tags under this category are mutually exclusive. When mutually exclusive is `true` the tags from this category are used to **classify** an entity. An entity can only be in one class - example, it can only be either `tier1` or `tier2` and not both. When mutually exclusive is `false`, the tags from this category are used to **categorize** an entity. An entity can be in multiple categories simultaneously - example a customer can be `newCustomer` and `atRisk` simultaneously. ** Note when a tag category is marked mutually exclusive, all the tag groups under it are also mutually exclusive.",
"type" : "boolean",
"default" : "false"
}
},
"required": ["name", "description", "categoryType"],
"required": ["name", "description"],
"additionalProperties": false
}

View File

@ -131,7 +131,6 @@ const mockTagList = [
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
@ -147,7 +146,6 @@ const mockTagList = [
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',

View File

@ -122,7 +122,6 @@ const mockTagList = [
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
@ -138,7 +137,6 @@ const mockTagList = [
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',

View File

@ -23,7 +23,6 @@ const mockTierData = {
version: 0.1,
updatedAt: 1665646906357,
updatedBy: 'admin',
categoryType: 'Descriptive',
href: 'http://localhost:8585/api/v1/tags/Tier',
children: [
{

View File

@ -127,7 +127,6 @@ const mockTagList = [
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
@ -143,7 +142,6 @@ const mockTagList = [
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',

View File

@ -5,7 +5,6 @@ import Form from './Form';
const mockFunction = jest.fn();
const mockInitialData = {
categoryType: 'Descriptive',
description: '',
name: '',
};
@ -27,10 +26,8 @@ describe('Test TagsPage form component', () => {
}
);
const categoryType = await findByTestId(container, 'category-type');
const name = await findByTestId(container, 'name');
expect(categoryType).toBeInTheDocument();
expect(name).toBeInTheDocument();
expect(
await findByText(container, /MarkdownWithPreview component/i)

View File

@ -24,7 +24,6 @@ import { CreateTagCategory } from '../../generated/api/tags/createTagCategory';
import { errorMsg } from '../../utils/CommonUtils';
type CustomTagCategory = {
categoryType: string;
description: CreateTagCategory['description'];
name: CreateTagCategory['name'];
};
@ -42,7 +41,6 @@ const Form: React.FC<FormProp> = forwardRef(
const [data, setData] = useState<CustomTagCategory>({
name: initialData.name,
description: initialData.description,
categoryType: initialData.categoryType,
});
const isMounting = useRef<boolean>(true);
@ -83,25 +81,6 @@ const Form: React.FC<FormProp> = forwardRef(
<div className="tw-w-full tw-flex ">
<div className="tw-flex tw-w-full">
<div className="tw-w-full">
{initialData.categoryType && (
<div className="tw-mb-4">
<label className="tw-form-label required-field">
Select Category Type
</label>
<select
required
className="tw-text-sm tw-appearance-none tw-border tw-border-main
tw-rounded tw-w-full tw-py-2 tw-px-3 tw-text-grey-body tw-leading-tight
focus:tw-outline-none focus:tw-border-focus hover:tw-border-hover tw-h-10 tw-bg-white"
data-testid="category-type"
name="categoryType"
value={data.categoryType}
onChange={onChangeHadler}>
<option value="Descriptive">Descriptive </option>
<option value="Classification">Classification</option>
</select>
</div>
)}
<div className="tw-mb-4">
<label className="tw-form-label required-field">Name</label>
<input

View File

@ -53,7 +53,6 @@ jest.mock('react-router-dom', () => ({
const mockTagsCategory = [
{
categoryType: 'Classification',
id: 'test',
children: [
{
@ -78,7 +77,6 @@ const mockTagsCategory = [
usageCount: 3,
},
{
categoryType: 'Classification',
id: 'test2',
children: [],
description: 'description',
@ -96,7 +94,6 @@ const mockCategory = [
version: 0.1,
updatedAt: 1649665563400,
updatedBy: 'admin',
categoryType: 'Classification',
href: 'http://localhost:8585/api/v1/tags/PersonalData',
usageCount: 0,
children: [
@ -139,7 +136,6 @@ const mockCategory = [
version: 0.1,
updatedAt: 1649665563410,
updatedBy: 'admin',
categoryType: 'Classification',
href: 'http://localhost:8585/api/v1/tags/PII',
usageCount: 0,
children: [

View File

@ -46,10 +46,7 @@ import {
import { TIER_CATEGORY } from '../../constants/constants';
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
import { delimiterRegex } from '../../constants/regex.constants';
import {
CreateTagCategory,
TagCategoryType,
} from '../../generated/api/tags/createTagCategory';
import { CreateTagCategory } from '../../generated/api/tags/createTagCategory';
import { Operation } from '../../generated/entity/policies/accessControl/rule';
import { TagCategory, TagClass } from '../../generated/entity/tags/tagCategory';
import { EntityReference } from '../../generated/type/entityReference';
@ -334,7 +331,6 @@ const TagsPage = () => {
const response = await updateTagCategory(currentCategory?.name ?? '', {
name: currentCategory?.name ?? '',
description: updatedHTML,
categoryType: currentCategory?.categoryType,
});
if (response) {
await fetchCurrentCategory(currentCategory?.name as string, true);
@ -722,7 +718,6 @@ const TagsPage = () => {
initialData={{
name: '',
description: '',
categoryType: TagCategoryType.Descriptive,
}}
isSaveButtonDisabled={!isEmpty(errorDataCategory)}
onCancel={() => setIsAddingCategory(false)}
@ -743,7 +738,6 @@ const TagsPage = () => {
initialData={{
name: '',
description: '',
categoryType: '',
}}
isSaveButtonDisabled={!isEmpty(errorDataTag)}
onCancel={() => setIsAddingTag(false)}

View File

@ -22,7 +22,6 @@ export type Tag = {
export type TagsCategory = {
name: string;
description: string;
categoryType?: string;
children?: Array<Tag>;
href?: string;
usageCount?: number;