mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-08 08:31:37 +00:00
Assets improvements part 2 (#14255)
* fix: make filters consistent * disable if no selection * fix: hide notification * fix: failed status data * localization * fix notification loading * remove close icon here * fix: cypress * update error alert design * fix alert styling * fix: minor issues * fix: redirect link of data product * fix: minor suggestion prompt * complete user flow * fix: glossary cypress * update alert view * fix tags manipulation * fix: domain reload fixes Co-Authored-By: Ashish Gupta <ashish@getcollate.io> * fix: minor loading issue on delete * fix: add admin check for activity feed Co-Authored-By: Ashish Gupta <ashish@getcollate.io> * fix: minor css fixes * fix: localisation * fix: minor issue * miner cypress fix * add mlmodelservice as mlmodel parent * fix: added null checks --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io> Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com> Co-authored-by: 07Himank <himank07mehta@gmail.com>
This commit is contained in:
parent
a76308bf77
commit
a215f03a28
@ -273,7 +273,8 @@ public class SearchRepository {
|
|||||||
if (changeDescription != null) {
|
if (changeDescription != null) {
|
||||||
Pair<String, Map<String, Object>> updates = getInheritedFieldChanges(changeDescription);
|
Pair<String, Map<String, Object>> updates = getInheritedFieldChanges(changeDescription);
|
||||||
Pair<String, String> parentMatch;
|
Pair<String, String> parentMatch;
|
||||||
if (updates.getValue().get("type").toString().equalsIgnoreCase("domain")
|
if (!updates.getValue().isEmpty()
|
||||||
|
&& updates.getValue().get("type").toString().equalsIgnoreCase("domain")
|
||||||
&& (entityType.equalsIgnoreCase(Entity.DATABASE_SERVICE)
|
&& (entityType.equalsIgnoreCase(Entity.DATABASE_SERVICE)
|
||||||
|| entityType.equalsIgnoreCase(Entity.DASHBOARD_SERVICE)
|
|| entityType.equalsIgnoreCase(Entity.DASHBOARD_SERVICE)
|
||||||
|| entityType.equalsIgnoreCase(Entity.MESSAGING_SERVICE)
|
|| entityType.equalsIgnoreCase(Entity.MESSAGING_SERVICE)
|
||||||
|
@ -207,7 +207,7 @@
|
|||||||
"indexName": "mlmodel_service_search_index",
|
"indexName": "mlmodel_service_search_index",
|
||||||
"indexMappingFile": "/elasticsearch/%s/mlmodel_service_index_mapping.json",
|
"indexMappingFile": "/elasticsearch/%s/mlmodel_service_index_mapping.json",
|
||||||
"alias": "mlModelService",
|
"alias": "mlModelService",
|
||||||
"parentAliases": ["all"]
|
"parentAliases": ["all","mlModelService"]
|
||||||
},
|
},
|
||||||
"testCaseResolutionStatus": {
|
"testCaseResolutionStatus": {
|
||||||
"indexName": "test_case_resolution_status_search_index",
|
"indexName": "test_case_resolution_status_search_index",
|
||||||
|
@ -307,6 +307,7 @@ export const NEW_GLOSSARY = {
|
|||||||
reviewer: 'Aaron Johnson',
|
reviewer: 'Aaron Johnson',
|
||||||
addReviewer: true,
|
addReviewer: true,
|
||||||
tag: 'PersonalData.Personal',
|
tag: 'PersonalData.Personal',
|
||||||
|
isMutually: true,
|
||||||
};
|
};
|
||||||
export const NEW_GLOSSARY_1 = {
|
export const NEW_GLOSSARY_1 = {
|
||||||
name: 'Cypress Product%Glossary',
|
name: 'Cypress Product%Glossary',
|
||||||
|
@ -116,7 +116,11 @@ const createGlossary = (glossaryData) => {
|
|||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.type(glossaryData.description);
|
.type(glossaryData.description);
|
||||||
|
|
||||||
cy.get('[data-testid="mutually-exclusive-button"]').scrollIntoView().click();
|
if (glossaryData.isMutually) {
|
||||||
|
cy.get('[data-testid="mutually-exclusive-button"]')
|
||||||
|
.scrollIntoView()
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
|
||||||
if (glossaryData.tag) {
|
if (glossaryData.tag) {
|
||||||
// Add tag
|
// Add tag
|
||||||
@ -311,10 +315,12 @@ const removeAssetsFromGlossaryTerm = (glossaryTerm, glossary) => {
|
|||||||
cy.get('[data-testid="delete-button"]').click();
|
cy.get('[data-testid="delete-button"]').click();
|
||||||
cy.get("[data-testid='save-button']").click();
|
cy.get("[data-testid='save-button']").click();
|
||||||
|
|
||||||
interceptURL('GET', '/api/v1/search/query*', 'assetTab');
|
cy.get('[data-testid="overview"]').click();
|
||||||
|
cy.get('[data-testid="assets"]').click();
|
||||||
|
|
||||||
// go assets tab
|
// go assets tab
|
||||||
goToAssetsTab(glossaryTerm.name, glossaryTerm.fullyQualifiedName, true);
|
verifyResponseStatusCode('@searchAssets', 200);
|
||||||
verifyResponseStatusCode('@assetTab', 200);
|
|
||||||
checkAssetsCount(glossaryTerm.assets.length - (index + 1));
|
checkAssetsCount(glossaryTerm.assets.length - (index + 1));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -719,7 +725,7 @@ describe('Glossary page should work properly', () => {
|
|||||||
|
|
||||||
const ProductTerms = Object.values(NEW_GLOSSARY_1_TERMS);
|
const ProductTerms = Object.values(NEW_GLOSSARY_1_TERMS);
|
||||||
ProductTerms.forEach((term) =>
|
ProductTerms.forEach((term) =>
|
||||||
createGlossaryTerm(term, NEW_GLOSSARY_1, 'Approved')
|
createGlossaryTerm(term, NEW_GLOSSARY_1, 'Approved', false)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ describe('Postgres Ingestion', () => {
|
|||||||
|
|
||||||
cy.get('#root\\/filterCondition')
|
cy.get('#root\\/filterCondition')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.type(`s.query like '%${tableName}%'`);
|
.type(`s.query like '%%${tableName}%%'`);
|
||||||
cy.get('[data-testid="submit-btn"]')
|
cy.get('[data-testid="submit-btn"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
|
@ -40,6 +40,7 @@ import {
|
|||||||
ThreadTaskStatus,
|
ThreadTaskStatus,
|
||||||
ThreadType,
|
ThreadType,
|
||||||
} from '../../../generated/entity/feed/thread';
|
} from '../../../generated/entity/feed/thread';
|
||||||
|
import { useAuth } from '../../../hooks/authHooks';
|
||||||
import { useElementInView } from '../../../hooks/useElementInView';
|
import { useElementInView } from '../../../hooks/useElementInView';
|
||||||
import { getAllFeeds, getFeedCount } from '../../../rest/feedsAPI';
|
import { getAllFeeds, getFeedCount } from '../../../rest/feedsAPI';
|
||||||
import { getCountBadge, getEntityDetailLink } from '../../../utils/CommonUtils';
|
import { getCountBadge, getEntityDetailLink } from '../../../utils/CommonUtils';
|
||||||
@ -81,6 +82,7 @@ export const ActivityFeedTab = ({
|
|||||||
});
|
});
|
||||||
const { subTab: activeTab = ActivityFeedTabs.ALL } =
|
const { subTab: activeTab = ActivityFeedTabs.ALL } =
|
||||||
useParams<{ subTab: ActivityFeedTabs }>();
|
useParams<{ subTab: ActivityFeedTabs }>();
|
||||||
|
const { isAdminUser } = useAuth();
|
||||||
const [taskFilter, setTaskFilter] = useState<TaskFilter>('open');
|
const [taskFilter, setTaskFilter] = useState<TaskFilter>('open');
|
||||||
const [allCount, setAllCount] = useState(0);
|
const [allCount, setAllCount] = useState(0);
|
||||||
const [tasksCount, setTasksCount] = useState(0);
|
const [tasksCount, setTasksCount] = useState(0);
|
||||||
@ -162,7 +164,7 @@ export const ActivityFeedTab = ({
|
|||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
ThreadType.Task,
|
ThreadType.Task,
|
||||||
FeedFilter.OWNER,
|
isAdminUser ? undefined : FeedFilter.OWNER,
|
||||||
undefined,
|
undefined,
|
||||||
userId
|
userId
|
||||||
).then((res) => {
|
).then((res) => {
|
||||||
@ -178,7 +180,7 @@ export const ActivityFeedTab = ({
|
|||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
ThreadType.Conversation,
|
ThreadType.Conversation,
|
||||||
FeedFilter.OWNER,
|
isAdminUser ? undefined : FeedFilter.OWNER,
|
||||||
undefined,
|
undefined,
|
||||||
userId
|
userId
|
||||||
).then((res) => {
|
).then((res) => {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
@ -239,7 +240,7 @@ const Suggestions = ({
|
|||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.length === 0 && !isTourOpen) {
|
if (options.length === 0 && !isTourOpen && !isEmpty(searchText)) {
|
||||||
return (
|
return (
|
||||||
<Typography.Text>
|
<Typography.Text>
|
||||||
<Transi18next
|
<Transi18next
|
||||||
|
@ -1,188 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2023 Collate.
|
|
||||||
* Licensed 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.
|
|
||||||
*/
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
|
||||||
import { Button, Divider, Dropdown, Menu, Typography } from 'antd';
|
|
||||||
import { isEmpty } from 'lodash';
|
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
|
||||||
import {
|
|
||||||
QueryFieldInterface,
|
|
||||||
QueryFieldValueInterface,
|
|
||||||
} from '../../pages/ExplorePage/ExplorePage.interface';
|
|
||||||
import { getAssetsPageQuickFilters } from '../../utils/AdvancedSearchUtils';
|
|
||||||
import { getSelectedValuesFromQuickFilter } from '../../utils/Explore.utils';
|
|
||||||
import { ExploreQuickFilterField } from '../Explore/ExplorePage.interface';
|
|
||||||
import ExploreQuickFilters from '../Explore/ExploreQuickFilters';
|
|
||||||
import { AssetFiltersProps } from './AssetFilters.interface';
|
|
||||||
|
|
||||||
const AssetFilters = ({
|
|
||||||
filterData,
|
|
||||||
type,
|
|
||||||
aggregations,
|
|
||||||
onQuickFilterChange,
|
|
||||||
quickFilterQuery,
|
|
||||||
}: AssetFiltersProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [filters, setFilters] = useState<ExploreQuickFilterField[]>([]);
|
|
||||||
const [selectedFilter, setSelectedFilter] = useState<string[]>([]);
|
|
||||||
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
|
||||||
ExploreQuickFilterField[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleMenuClick = ({ key }: { key: string }) => {
|
|
||||||
setSelectedFilter((prevSelected) => [...prevSelected, key]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const menu = useMemo(
|
|
||||||
() => (
|
|
||||||
<Menu selectedKeys={selectedFilter} onClick={handleMenuClick}>
|
|
||||||
{filters.map((filter) => (
|
|
||||||
<Menu.Item key={filter.key}>{filter.label}</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
),
|
|
||||||
[selectedFilter, filters]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleQuickFiltersChange = (data: ExploreQuickFilterField[]) => {
|
|
||||||
const must: QueryFieldInterface[] = [];
|
|
||||||
data.forEach((filter) => {
|
|
||||||
if (!isEmpty(filter.value)) {
|
|
||||||
const should: QueryFieldValueInterface[] = [];
|
|
||||||
if (filter.value) {
|
|
||||||
filter.value.forEach((filterValue) => {
|
|
||||||
const term: Record<string, string> = {};
|
|
||||||
term[filter.key] = filterValue.key;
|
|
||||||
should.push({ term });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
must.push({
|
|
||||||
bool: { should },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const quickFilterQuery = isEmpty(must)
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
query: { bool: { must } },
|
|
||||||
};
|
|
||||||
|
|
||||||
onQuickFilterChange?.(quickFilterQuery);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQuickFiltersValueSelect = useCallback(
|
|
||||||
(field: ExploreQuickFilterField) => {
|
|
||||||
setSelectedQuickFilters((pre) => {
|
|
||||||
const data = pre.map((preField) => {
|
|
||||||
if (preField.key === field.key) {
|
|
||||||
return field;
|
|
||||||
} else {
|
|
||||||
return preField;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
handleQuickFiltersChange(data);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[setSelectedQuickFilters]
|
|
||||||
);
|
|
||||||
|
|
||||||
const clearFilters = useCallback(() => {
|
|
||||||
setSelectedQuickFilters((pre) => {
|
|
||||||
const data = pre.map((preField) => {
|
|
||||||
return { ...preField, value: [] };
|
|
||||||
});
|
|
||||||
|
|
||||||
handleQuickFiltersChange(data);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}, [handleQuickFiltersChange, setSelectedQuickFilters]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (filterData?.length === 0) {
|
|
||||||
const dropdownItems = getAssetsPageQuickFilters(type);
|
|
||||||
|
|
||||||
setFilters(
|
|
||||||
dropdownItems.map((item) => ({
|
|
||||||
...item,
|
|
||||||
value: getSelectedValuesFromQuickFilter(item, dropdownItems),
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setFilters(filterData ?? []);
|
|
||||||
}
|
|
||||||
}, [filterData, type]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const updatedQuickFilters = filters
|
|
||||||
.filter((filter) => selectedFilter.includes(filter.key))
|
|
||||||
.map((selectedFilterItem) => {
|
|
||||||
const originalFilterItem = selectedQuickFilters?.find(
|
|
||||||
(filter) => filter.key === selectedFilterItem.key
|
|
||||||
);
|
|
||||||
|
|
||||||
return originalFilterItem || selectedFilterItem;
|
|
||||||
});
|
|
||||||
|
|
||||||
const newItems = updatedQuickFilters.filter(
|
|
||||||
(item) =>
|
|
||||||
!selectedQuickFilters.some(
|
|
||||||
(existingItem) => item.key === existingItem.key
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (newItems.length > 0) {
|
|
||||||
setSelectedQuickFilters((prevSelected) => [...prevSelected, ...newItems]);
|
|
||||||
}
|
|
||||||
}, [selectedFilter, selectedQuickFilters, filters]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Dropdown overlay={menu} trigger={['click']}>
|
|
||||||
<Button icon={<PlusOutlined />} size="small" type="primary" />
|
|
||||||
</Dropdown>
|
|
||||||
{selectedQuickFilters.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Divider className="m-x-md h-6" type="vertical" />
|
|
||||||
<div className="d-flex justify-between flex-1">
|
|
||||||
<ExploreQuickFilters
|
|
||||||
aggregations={aggregations}
|
|
||||||
fields={selectedQuickFilters}
|
|
||||||
index={SearchIndex.ALL}
|
|
||||||
onFieldValueSelect={(data) =>
|
|
||||||
handleQuickFiltersValueSelect?.(data)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{quickFilterQuery && (
|
|
||||||
<Typography.Text
|
|
||||||
className="text-primary self-center cursor-pointer"
|
|
||||||
onClick={clearFilters}>
|
|
||||||
{t('label.clear-entity', {
|
|
||||||
entity: '',
|
|
||||||
})}
|
|
||||||
</Typography.Text>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AssetFilters;
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2023 Collate.
|
|
||||||
* Licensed 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.
|
|
||||||
*/
|
|
||||||
import { Aggregations } from '../../interface/search.interface';
|
|
||||||
import { QueryFilterInterface } from '../../pages/ExplorePage/ExplorePage.interface';
|
|
||||||
import { ExploreQuickFilterField } from '../Explore/ExplorePage.interface';
|
|
||||||
import { AssetsOfEntity } from '../Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
|
||||||
|
|
||||||
export interface AssetFiltersProps {
|
|
||||||
filterData?: ExploreQuickFilterField[];
|
|
||||||
defaultFilter?: string[];
|
|
||||||
aggregations?: Aggregations;
|
|
||||||
onQuickFilterChange?: (query?: QueryFilterInterface) => void;
|
|
||||||
type: AssetsOfEntity;
|
|
||||||
quickFilterQuery?: QueryFilterInterface;
|
|
||||||
}
|
|
@ -10,9 +10,27 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { Button, Checkbox, List, Modal, Space, Typography } from 'antd';
|
import {
|
||||||
|
CheckOutlined,
|
||||||
|
CloseOutlined,
|
||||||
|
ExclamationCircleOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Divider,
|
||||||
|
Dropdown,
|
||||||
|
List,
|
||||||
|
Modal,
|
||||||
|
Space,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import { ItemType } from 'antd/lib/menu/hooks/useItems';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import { EntityDetailUnion } from 'Models';
|
import { EntityDetailUnion } from 'Models';
|
||||||
import VirtualList from 'rc-virtual-list';
|
import VirtualList from 'rc-virtual-list';
|
||||||
import {
|
import {
|
||||||
@ -20,10 +38,11 @@ import {
|
|||||||
UIEventHandler,
|
UIEventHandler,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PAGE_SIZE_MEDIUM } from '../../../constants/constants';
|
import { ERROR_COLOR, PAGE_SIZE_MEDIUM } from '../../../constants/constants';
|
||||||
import { SearchIndex } from '../../../enums/search.enum';
|
import { SearchIndex } from '../../../enums/search.enum';
|
||||||
import { GlossaryTerm } from '../../../generated/entity/data/glossaryTerm';
|
import { GlossaryTerm } from '../../../generated/entity/data/glossaryTerm';
|
||||||
import { DataProduct } from '../../../generated/entity/domains/dataProduct';
|
import { DataProduct } from '../../../generated/entity/domains/dataProduct';
|
||||||
@ -33,7 +52,11 @@ import {
|
|||||||
Status,
|
Status,
|
||||||
} from '../../../generated/type/bulkOperationResult';
|
} from '../../../generated/type/bulkOperationResult';
|
||||||
import { Aggregations } from '../../../interface/search.interface';
|
import { Aggregations } from '../../../interface/search.interface';
|
||||||
import { QueryFilterInterface } from '../../../pages/ExplorePage/ExplorePage.interface';
|
import {
|
||||||
|
QueryFieldInterface,
|
||||||
|
QueryFieldValueInterface,
|
||||||
|
QueryFilterInterface,
|
||||||
|
} from '../../../pages/ExplorePage/ExplorePage.interface';
|
||||||
import {
|
import {
|
||||||
addAssetsToDataProduct,
|
addAssetsToDataProduct,
|
||||||
getDataProductByName,
|
getDataProductByName,
|
||||||
@ -53,11 +76,11 @@ import {
|
|||||||
import { getCombinedQueryFilterObject } from '../../../utils/ExplorePage/ExplorePageUtils';
|
import { getCombinedQueryFilterObject } from '../../../utils/ExplorePage/ExplorePageUtils';
|
||||||
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
||||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||||
import AssetFilters from '../../AssetFilters/AssetFilters.component';
|
|
||||||
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||||
import Searchbar from '../../common/SearchBarComponent/SearchBar.component';
|
import Searchbar from '../../common/SearchBarComponent/SearchBar.component';
|
||||||
import TableDataCardV2 from '../../common/TableDataCardV2/TableDataCardV2';
|
import TableDataCardV2 from '../../common/TableDataCardV2/TableDataCardV2';
|
||||||
import { ExploreQuickFilterField } from '../../Explore/ExplorePage.interface';
|
import { ExploreQuickFilterField } from '../../Explore/ExplorePage.interface';
|
||||||
|
import ExploreQuickFilters from '../../Explore/ExploreQuickFilters';
|
||||||
import { AssetsOfEntity } from '../../Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
import { AssetsOfEntity } from '../../Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
||||||
import Loader from '../../Loader/Loader';
|
import Loader from '../../Loader/Loader';
|
||||||
import { SearchedDataProps } from '../../SearchedData/SearchedData.interface';
|
import { SearchedDataProps } from '../../SearchedData/SearchedData.interface';
|
||||||
@ -103,6 +126,20 @@ export const AssetSelectionModal = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
const [selectedFilter, setSelectedFilter] = useState<string[]>([]);
|
||||||
|
const [filters, setFilters] = useState<ExploreQuickFilterField[]>([]);
|
||||||
|
|
||||||
|
const handleMenuClick = ({ key }: { key: string }) => {
|
||||||
|
setSelectedFilter((prevSelected) => [...prevSelected, key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterMenu: ItemType[] = useMemo(() => {
|
||||||
|
return filters.map((filter) => ({
|
||||||
|
key: filter.key,
|
||||||
|
label: filter.label,
|
||||||
|
onClick: handleMenuClick,
|
||||||
|
}));
|
||||||
|
}, [filters]);
|
||||||
|
|
||||||
const fetchEntities = useCallback(
|
const fetchEntities = useCallback(
|
||||||
async ({
|
async ({
|
||||||
@ -153,10 +190,14 @@ export const AssetSelectionModal = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const dropdownItems = getAssetsPageQuickFilters(type);
|
const dropdownItems = getAssetsPageQuickFilters(type);
|
||||||
|
|
||||||
setSelectedQuickFilters(
|
setFilters(
|
||||||
dropdownItems.map((item) => ({
|
dropdownItems.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
value: getSelectedValuesFromQuickFilter(item, dropdownItems),
|
value: getSelectedValuesFromQuickFilter(
|
||||||
|
item,
|
||||||
|
dropdownItems,
|
||||||
|
undefined // pass in state variable
|
||||||
|
),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}, [type]);
|
}, [type]);
|
||||||
@ -213,6 +254,7 @@ export const AssetSelectionModal = ({
|
|||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
try {
|
try {
|
||||||
setIsSaveLoading(true);
|
setIsSaveLoading(true);
|
||||||
|
setFailedStatus(undefined);
|
||||||
if (!activeEntity) {
|
if (!activeEntity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -283,6 +325,29 @@ export const AssetSelectionModal = ({
|
|||||||
mergeFilters();
|
mergeFilters();
|
||||||
}, [quickFilterQuery, queryFilter]);
|
}, [quickFilterQuery, queryFilter]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updatedQuickFilters = filters
|
||||||
|
.filter((filter) => selectedFilter.includes(filter.key))
|
||||||
|
.map((selectedFilterItem) => {
|
||||||
|
const originalFilterItem = selectedQuickFilters?.find(
|
||||||
|
(filter) => filter.key === selectedFilterItem.key
|
||||||
|
);
|
||||||
|
|
||||||
|
return originalFilterItem || selectedFilterItem;
|
||||||
|
});
|
||||||
|
|
||||||
|
const newItems = updatedQuickFilters.filter(
|
||||||
|
(item) =>
|
||||||
|
!selectedQuickFilters.some(
|
||||||
|
(existingItem) => item.key === existingItem.key
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newItems.length > 0) {
|
||||||
|
setSelectedQuickFilters((prevSelected) => [...prevSelected, ...newItems]);
|
||||||
|
}
|
||||||
|
}, [selectedFilter, selectedQuickFilters, filters]);
|
||||||
|
|
||||||
const onScroll: UIEventHandler<HTMLElement> = useCallback(
|
const onScroll: UIEventHandler<HTMLElement> = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
const scrollHeight =
|
const scrollHeight =
|
||||||
@ -353,6 +418,66 @@ export const AssetSelectionModal = ({
|
|||||||
[failedStatus]
|
[failedStatus]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleQuickFiltersChange = (data: ExploreQuickFilterField[]) => {
|
||||||
|
const must: QueryFieldInterface[] = [];
|
||||||
|
data.forEach((filter) => {
|
||||||
|
if (!isEmpty(filter.value)) {
|
||||||
|
const should: QueryFieldValueInterface[] = [];
|
||||||
|
if (filter.value) {
|
||||||
|
filter.value.forEach((filterValue) => {
|
||||||
|
const term: Record<string, string> = {};
|
||||||
|
term[filter.key] = filterValue.key;
|
||||||
|
should.push({ term });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
must.push({
|
||||||
|
bool: { should },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const quickFilterQuery = isEmpty(must)
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
query: { bool: { must } },
|
||||||
|
};
|
||||||
|
|
||||||
|
setQuickFilterQuery(quickFilterQuery);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQuickFiltersValueSelect = useCallback(
|
||||||
|
(field: ExploreQuickFilterField) => {
|
||||||
|
setSelectedQuickFilters((pre) => {
|
||||||
|
const data = pre.map((preField) => {
|
||||||
|
if (preField.key === field.key) {
|
||||||
|
return field;
|
||||||
|
} else {
|
||||||
|
return preField;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
handleQuickFiltersChange(data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setSelectedQuickFilters]
|
||||||
|
);
|
||||||
|
|
||||||
|
const clearFilters = useCallback(() => {
|
||||||
|
setQuickFilterQuery(undefined);
|
||||||
|
setSelectedQuickFilters((pre) => {
|
||||||
|
const data = pre.map((preField) => {
|
||||||
|
return { ...preField, value: [] };
|
||||||
|
});
|
||||||
|
|
||||||
|
handleQuickFiltersChange(data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}, [setQuickFilterQuery, handleQuickFiltersChange, setSelectedQuickFilters]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
@ -362,12 +487,23 @@ export const AssetSelectionModal = ({
|
|||||||
data-testid="asset-selection-modal"
|
data-testid="asset-selection-modal"
|
||||||
footer={
|
footer={
|
||||||
<div className="d-flex justify-between">
|
<div className="d-flex justify-between">
|
||||||
<div>
|
<div className="d-flex items-center gap-2">
|
||||||
{selectedItems && selectedItems.size > 1 && (
|
{selectedItems && selectedItems.size >= 1 && (
|
||||||
<Typography.Text>
|
<Typography.Text className="gap-2">
|
||||||
|
<CheckOutlined className="text-success m-r-xs" />
|
||||||
{selectedItems.size} {t('label.selected-lowercase')}
|
{selectedItems.size} {t('label.selected-lowercase')}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
)}
|
)}
|
||||||
|
{failedStatus?.failedRequest &&
|
||||||
|
failedStatus.failedRequest.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Divider className="m-x-xss" type="vertical" />
|
||||||
|
<Typography.Text type="danger">
|
||||||
|
<CloseOutlined className="m-r-xs" />
|
||||||
|
{failedStatus.failedRequest.length} {t('label.error')}
|
||||||
|
</Typography.Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -376,7 +512,7 @@ export const AssetSelectionModal = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
data-testid="save-btn"
|
data-testid="save-btn"
|
||||||
disabled={isLoading}
|
disabled={!selectedItems?.size || isLoading}
|
||||||
loading={isSaveLoading}
|
loading={isSaveLoading}
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={onSaveAction}>
|
onClick={onSaveAction}>
|
||||||
@ -391,26 +527,74 @@ export const AssetSelectionModal = ({
|
|||||||
width={675}
|
width={675}
|
||||||
onCancel={onCancel}>
|
onCancel={onCancel}>
|
||||||
<Space className="w-full h-full" direction="vertical" size={16}>
|
<Space className="w-full h-full" direction="vertical" size={16}>
|
||||||
<Searchbar
|
<div className="d-flex items-center gap-3">
|
||||||
removeMargin
|
<Dropdown
|
||||||
showClearSearch
|
menu={{
|
||||||
placeholder={t('label.search-entity', {
|
items: filterMenu,
|
||||||
entity: t('label.asset-plural'),
|
selectedKeys: selectedFilter,
|
||||||
})}
|
}}
|
||||||
searchValue={search}
|
trigger={['click']}>
|
||||||
onSearch={setSearch}
|
<Button icon={<PlusOutlined />} size="small" type="primary" />
|
||||||
/>
|
</Dropdown>
|
||||||
|
<div className="flex-1">
|
||||||
<div className="d-flex items-center">
|
<Searchbar
|
||||||
<AssetFilters
|
removeMargin
|
||||||
aggregations={aggregations}
|
showClearSearch
|
||||||
filterData={selectedQuickFilters}
|
placeholder={t('label.search-entity', {
|
||||||
quickFilterQuery={quickFilterQuery}
|
entity: t('label.asset-plural'),
|
||||||
type={type}
|
})}
|
||||||
onQuickFilterChange={(data) => setQuickFilterQuery(data)}
|
searchValue={search}
|
||||||
/>
|
onSearch={setSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{selectedQuickFilters && selectedQuickFilters.length > 0 && (
|
||||||
|
<div className="d-flex items-center">
|
||||||
|
<div className="d-flex justify-between flex-1">
|
||||||
|
<ExploreQuickFilters
|
||||||
|
aggregations={aggregations}
|
||||||
|
fields={selectedQuickFilters}
|
||||||
|
index={SearchIndex.ALL}
|
||||||
|
showDeleted={false}
|
||||||
|
onFieldValueSelect={handleQuickFiltersValueSelect}
|
||||||
|
/>
|
||||||
|
{quickFilterQuery && (
|
||||||
|
<Typography.Text
|
||||||
|
className="p-r-xss text-primary self-center cursor-pointer"
|
||||||
|
onClick={clearFilters}>
|
||||||
|
{t('label.clear-entity', {
|
||||||
|
entity: '',
|
||||||
|
})}
|
||||||
|
</Typography.Text>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{failedStatus?.failedRequest && failedStatus.failedRequest.length > 0 && (
|
||||||
|
<Alert
|
||||||
|
closable
|
||||||
|
className="w-full"
|
||||||
|
description={
|
||||||
|
<Typography.Text className="text-grey-muted">
|
||||||
|
{t('message.validation-error-assets')}
|
||||||
|
</Typography.Text>
|
||||||
|
}
|
||||||
|
message={
|
||||||
|
<div className="d-flex items-center gap-3">
|
||||||
|
<ExclamationCircleOutlined
|
||||||
|
style={{ color: ERROR_COLOR, fontSize: '24px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="font-semibold text-sm">
|
||||||
|
{t('label.validation-error-plural')}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
type="error"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{items.length > 0 && (
|
{items.length > 0 && (
|
||||||
<div className="border p-xs">
|
<div className="border p-xs">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -435,7 +619,8 @@ export const AssetSelectionModal = ({
|
|||||||
<div
|
<div
|
||||||
className={classNames({
|
className={classNames({
|
||||||
'm-y-sm border-danger rounded-4': isError,
|
'm-y-sm border-danger rounded-4': isError,
|
||||||
})}>
|
})}
|
||||||
|
key={item.id}>
|
||||||
<TableDataCardV2
|
<TableDataCardV2
|
||||||
openEntityInNewPage
|
openEntityInNewPage
|
||||||
showCheckboxes
|
showCheckboxes
|
||||||
@ -449,11 +634,19 @@ export const AssetSelectionModal = ({
|
|||||||
source={{ ...item, tags: [] }}
|
source={{ ...item, tags: [] }}
|
||||||
/>
|
/>
|
||||||
{isError && (
|
{isError && (
|
||||||
<div className="p-x-sm p-b-sm">
|
<>
|
||||||
<Typography.Text type="danger">
|
<div className="p-x-sm">
|
||||||
{errorMessage}
|
<Divider className="m-t-0 m-y-sm " />
|
||||||
</Typography.Text>
|
</div>
|
||||||
</div>
|
<div className="d-flex gap-3 p-x-sm p-b-sm">
|
||||||
|
<ExclamationCircleOutlined
|
||||||
|
style={{ color: ERROR_COLOR, fontSize: '24px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="break-all">
|
||||||
|
{errorMessage}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
@import url('../../../styles/variables.less');
|
@import url('../../../styles/variables.less');
|
||||||
|
|
||||||
.asset-selection-model-card.table-data-card-container {
|
.asset-selection-model-card.table-data-card-container {
|
||||||
box-shadow: none;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
.asset-selection-model-card.table-data-card-container:hover {
|
.asset-selection-model-card.table-data-card-container:hover {
|
||||||
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.13);
|
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.13);
|
||||||
|
@ -14,6 +14,7 @@ import { Col, Row, Space, Tag, Typography } from 'antd';
|
|||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import { ReactComponent as EditIcon } from '../../assets/svg/edit-new.svg';
|
import { ReactComponent as EditIcon } from '../../assets/svg/edit-new.svg';
|
||||||
import { ReactComponent as DataProductIcon } from '../../assets/svg/ic-data-product.svg';
|
import { ReactComponent as DataProductIcon } from '../../assets/svg/ic-data-product.svg';
|
||||||
import DataProductSelectForm from '../../components/DataProductSelectForm/DataProductsSelectForm';
|
import DataProductSelectForm from '../../components/DataProductSelectForm/DataProductsSelectForm';
|
||||||
@ -27,6 +28,8 @@ import { DataProduct } from '../../generated/entity/domains/dataProduct';
|
|||||||
import { EntityReference } from '../../generated/entity/type';
|
import { EntityReference } from '../../generated/entity/type';
|
||||||
import { fetchDataProductsElasticSearch } from '../../rest/dataProductAPI';
|
import { fetchDataProductsElasticSearch } from '../../rest/dataProductAPI';
|
||||||
import { getEntityName } from '../../utils/EntityUtils';
|
import { getEntityName } from '../../utils/EntityUtils';
|
||||||
|
import { getDataProductsDetailsPath } from '../../utils/RouterUtils';
|
||||||
|
import { getEncodedFqn } from '../../utils/StringsUtils';
|
||||||
|
|
||||||
interface DataProductsContainerProps {
|
interface DataProductsContainerProps {
|
||||||
showHeader?: boolean;
|
showHeader?: boolean;
|
||||||
@ -44,6 +47,7 @@ const DataProductsContainer = ({
|
|||||||
onSave,
|
onSave,
|
||||||
}: DataProductsContainerProps) => {
|
}: DataProductsContainerProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const history = useHistory();
|
||||||
const [isEditMode, setIsEditMode] = useState(false);
|
const [isEditMode, setIsEditMode] = useState(false);
|
||||||
|
|
||||||
const handleAddClick = () => {
|
const handleAddClick = () => {
|
||||||
@ -70,6 +74,10 @@ const DataProductsContainer = ({
|
|||||||
[activeDomain]
|
[activeDomain]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const redirectLink = useCallback((fqn) => {
|
||||||
|
history.push(getDataProductsDetailsPath(getEncodedFqn(fqn)));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleSave = async (dataProducts: DataProduct[]) => {
|
const handleSave = async (dataProducts: DataProduct[]) => {
|
||||||
await onSave?.(dataProducts);
|
await onSave?.(dataProducts);
|
||||||
setIsEditMode(false);
|
setIsEditMode(false);
|
||||||
@ -107,7 +115,8 @@ const DataProductsContainer = ({
|
|||||||
return (
|
return (
|
||||||
<Tag
|
<Tag
|
||||||
className="tag-chip tag-chip-content"
|
className="tag-chip tag-chip-content"
|
||||||
key={`dp-tags-${product.fullyQualifiedName}`}>
|
key={`dp-tags-${product.fullyQualifiedName}`}
|
||||||
|
onClick={() => redirectLink(product.fullyQualifiedName)}>
|
||||||
<div className="d-flex w-full">
|
<div className="d-flex w-full">
|
||||||
<div className="d-flex items-center p-x-xs w-full gap-1">
|
<div className="d-flex items-center p-x-xs w-full gap-1">
|
||||||
<DataProductIcon
|
<DataProductIcon
|
||||||
|
@ -83,6 +83,7 @@ import {
|
|||||||
} from '../../../utils/RouterUtils';
|
} from '../../../utils/RouterUtils';
|
||||||
import {
|
import {
|
||||||
escapeESReservedCharacters,
|
escapeESReservedCharacters,
|
||||||
|
getDecodedFqn,
|
||||||
getEncodedFqn,
|
getEncodedFqn,
|
||||||
} from '../../../utils/StringsUtils';
|
} from '../../../utils/StringsUtils';
|
||||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||||
@ -111,7 +112,7 @@ const DomainDetailsPage = ({
|
|||||||
tab: activeTab,
|
tab: activeTab,
|
||||||
version,
|
version,
|
||||||
} = useParams<{ fqn: string; tab: string; version: string }>();
|
} = useParams<{ fqn: string; tab: string; version: string }>();
|
||||||
const domainFqn = fqn ? decodeURIComponent(fqn) : '';
|
const domainFqn = fqn ? getDecodedFqn(fqn) : '';
|
||||||
const assetTabRef = useRef<AssetsTabRef>(null);
|
const assetTabRef = useRef<AssetsTabRef>(null);
|
||||||
const dataProductsTabRef = useRef<DataProductsTabRef>(null);
|
const dataProductsTabRef = useRef<DataProductsTabRef>(null);
|
||||||
const [domainPermission, setDomainPermission] = useState<OperationPermission>(
|
const [domainPermission, setDomainPermission] = useState<OperationPermission>(
|
||||||
@ -512,7 +513,7 @@ const DomainDetailsPage = ({
|
|||||||
fetchDomainPermission();
|
fetchDomainPermission();
|
||||||
fetchDomainAssets();
|
fetchDomainAssets();
|
||||||
fetchDataProducts();
|
fetchDataProducts();
|
||||||
}, [fqn]);
|
}, [domain.fullyQualifiedName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -173,11 +173,15 @@ const ExploreSearchCard: React.FC<ExploreSearchCardProps> = forwardRef<
|
|||||||
<Row gutter={[8, 8]}>
|
<Row gutter={[8, 8]}>
|
||||||
{showCheckboxes && (
|
{showCheckboxes && (
|
||||||
<Col flex="25px">
|
<Col flex="25px">
|
||||||
<Checkbox
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
checked={checked}
|
<Checkbox
|
||||||
className="assets-checkbox"
|
checked={checked}
|
||||||
onChange={(e) => onCheckboxChange?.(e.target.checked)}
|
className="assets-checkbox"
|
||||||
/>
|
onChange={(e) => {
|
||||||
|
onCheckboxChange?.(e.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
{!hideBreadcrumbs && (
|
{!hideBreadcrumbs && (
|
||||||
|
@ -36,7 +36,10 @@ import { getCountBadge, getFeedCounts } from '../../../utils/CommonUtils';
|
|||||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||||
import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
|
import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
|
||||||
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
|
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
|
||||||
import { escapeESReservedCharacters } from '../../../utils/StringsUtils';
|
import {
|
||||||
|
escapeESReservedCharacters,
|
||||||
|
getEncodedFqn,
|
||||||
|
} from '../../../utils/StringsUtils';
|
||||||
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
||||||
import { AssetSelectionModal } from '../../Assets/AssetsSelectionModal/AssetSelectionModal';
|
import { AssetSelectionModal } from '../../Assets/AssetsSelectionModal/AssetSelectionModal';
|
||||||
import { CustomPropertyTable } from '../../common/CustomPropertyTable/CustomPropertyTable';
|
import { CustomPropertyTable } from '../../common/CustomPropertyTable/CustomPropertyTable';
|
||||||
@ -258,13 +261,14 @@ const GlossaryTermsV1 = ({
|
|||||||
const fetchGlossaryTermAssets = async () => {
|
const fetchGlossaryTermAssets = async () => {
|
||||||
if (glossaryTerm) {
|
if (glossaryTerm) {
|
||||||
try {
|
try {
|
||||||
|
const encodedFqn = getEncodedFqn(
|
||||||
|
escapeESReservedCharacters(glossaryTerm.fullyQualifiedName)
|
||||||
|
);
|
||||||
const res = await searchData(
|
const res = await searchData(
|
||||||
'',
|
'',
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
`(tags.tagFQN:"${escapeESReservedCharacters(
|
`(tags.tagFQN:"${encodedFqn}")`,
|
||||||
glossaryTerm.fullyQualifiedName
|
|
||||||
)}")`,
|
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
SearchIndex.ALL
|
SearchIndex.ALL
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
|
Affix,
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Col,
|
Col,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Menu,
|
|
||||||
MenuProps,
|
MenuProps,
|
||||||
notification,
|
notification,
|
||||||
Row,
|
Row,
|
||||||
@ -136,6 +136,7 @@ const AssetsTabs = forwardRef(
|
|||||||
const [itemCount, setItemCount] = useState<Record<EntityType, number>>(
|
const [itemCount, setItemCount] = useState<Record<EntityType, number>>(
|
||||||
{} as Record<EntityType, number>
|
{} as Record<EntityType, number>
|
||||||
);
|
);
|
||||||
|
const [assetRemoving, setAssetRemoving] = useState(false);
|
||||||
|
|
||||||
const [activeFilter, _] = useState<SearchIndex[]>([]);
|
const [activeFilter, _] = useState<SearchIndex[]>([]);
|
||||||
const { fqn } = useParams<{ fqn: string }>();
|
const { fqn } = useParams<{ fqn: string }>();
|
||||||
@ -173,8 +174,9 @@ const AssetsTabs = forwardRef(
|
|||||||
Domain | DataProduct | GlossaryTerm
|
Domain | DataProduct | GlossaryTerm
|
||||||
>();
|
>();
|
||||||
|
|
||||||
const [selectedItems, setSelectedItems] =
|
const [selectedItems, setSelectedItems] = useState<
|
||||||
useState<Map<string, EntityDetailUnion>>();
|
Map<string, EntityDetailUnion>
|
||||||
|
>(new Map());
|
||||||
const [aggregations, setAggregations] = useState<Aggregations>();
|
const [aggregations, setAggregations] = useState<Aggregations>();
|
||||||
const [selectedFilter, setSelectedFilter] = useState<string[]>([]); // Contains menu selection
|
const [selectedFilter, setSelectedFilter] = useState<string[]>([]); // Contains menu selection
|
||||||
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
||||||
@ -193,16 +195,13 @@ const AssetsTabs = forwardRef(
|
|||||||
setSelectedFilter((prevSelected) => [...prevSelected, key]);
|
setSelectedFilter((prevSelected) => [...prevSelected, key]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterMenu = useMemo(
|
const filterMenu: ItemType[] = useMemo(() => {
|
||||||
() => (
|
return filters.map((filter) => ({
|
||||||
<Menu selectedKeys={selectedFilter} onClick={handleMenuClick}>
|
key: filter.key,
|
||||||
{filters.map((filter) => (
|
label: filter.label,
|
||||||
<Menu.Item key={filter.key}>{filter.label}</Menu.Item>
|
onClick: handleMenuClick,
|
||||||
))}
|
}));
|
||||||
</Menu>
|
}, [filters]);
|
||||||
),
|
|
||||||
[selectedFilter, filters]
|
|
||||||
);
|
|
||||||
|
|
||||||
const queryParam = useMemo(() => {
|
const queryParam = useMemo(() => {
|
||||||
const encodedFqn = getEncodedFqn(escapeESReservedCharacters(entityFqn));
|
const encodedFqn = getEncodedFqn(escapeESReservedCharacters(entityFqn));
|
||||||
@ -425,6 +424,7 @@ const AssetsTabs = forwardRef(
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
onAssetClick?.(undefined);
|
onAssetClick?.(undefined);
|
||||||
|
hideNotification();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -434,15 +434,6 @@ const AssetsTabs = forwardRef(
|
|||||||
}
|
}
|
||||||
}, [entityFqn]);
|
}, [entityFqn]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selectedItems) {
|
|
||||||
hideNotification();
|
|
||||||
if (selectedItems.size > 1) {
|
|
||||||
openNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [selectedItems]);
|
|
||||||
|
|
||||||
const assetErrorPlaceHolder = useMemo(() => {
|
const assetErrorPlaceHolder = useMemo(() => {
|
||||||
if (!isEmpty(activeFilter)) {
|
if (!isEmpty(activeFilter)) {
|
||||||
return (
|
return (
|
||||||
@ -713,6 +704,8 @@ const AssetsTabs = forwardRef(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAssetRemoving(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entities = [...(assetsData?.values() ?? [])].map((item) => {
|
const entities = [...(assetsData?.values() ?? [])].map((item) => {
|
||||||
return getEntityReferenceFromEntity(
|
return getEntityReferenceFromEntity(
|
||||||
@ -760,6 +753,7 @@ const AssetsTabs = forwardRef(
|
|||||||
} finally {
|
} finally {
|
||||||
setShowDeleteModal(false);
|
setShowDeleteModal(false);
|
||||||
onRemoveAsset?.();
|
onRemoveAsset?.();
|
||||||
|
setAssetRemoving(false);
|
||||||
hideNotification();
|
hideNotification();
|
||||||
setSelectedItems(new Map()); // Reset selected items
|
setSelectedItems(new Map()); // Reset selected items
|
||||||
}
|
}
|
||||||
@ -784,31 +778,6 @@ const AssetsTabs = forwardRef(
|
|||||||
setSelectedQuickFilters,
|
setSelectedQuickFilters,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const openNotification = () => {
|
|
||||||
notification.warning({
|
|
||||||
key: 'asset-tab-notification-key',
|
|
||||||
message: (
|
|
||||||
<div className="d-flex items-center justify-between">
|
|
||||||
{selectedItems && selectedItems.size > 1 && (
|
|
||||||
<Typography.Text className="text-white">
|
|
||||||
{selectedItems.size} {t('label.items-selected-lowercase')}
|
|
||||||
</Typography.Text>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
data-testid="delete-all-button"
|
|
||||||
type="primary"
|
|
||||||
onClick={deleteSelectedItems}>
|
|
||||||
{t('label.delete')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
placement: 'bottom',
|
|
||||||
className: 'asset-tab-delete-notification',
|
|
||||||
duration: 0,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAssets({
|
fetchAssets({
|
||||||
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
||||||
@ -861,7 +830,7 @@ const AssetsTabs = forwardRef(
|
|||||||
refreshAssets() {
|
refreshAssets() {
|
||||||
fetchAssets({
|
fetchAssets({
|
||||||
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
||||||
page: currentPage,
|
page: 1,
|
||||||
});
|
});
|
||||||
fetchCountsByEntity();
|
fetchCountsByEntity();
|
||||||
},
|
},
|
||||||
@ -885,12 +854,18 @@ const AssetsTabs = forwardRef(
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('assets-tab-container p-md')}
|
className={classNames('assets-tab-container p-md')}
|
||||||
data-testid="table-container">
|
data-testid="table-container"
|
||||||
|
id="asset-tab">
|
||||||
{assetCount > 0 && (
|
{assetCount > 0 && (
|
||||||
<Row className="filters-row gap-2 p-l-lg">
|
<Row className="filters-row gap-2 p-l-lg">
|
||||||
<Col span={18}>
|
<Col span={18}>
|
||||||
<div className="d-flex items-center gap-3">
|
<div className="d-flex items-center gap-3">
|
||||||
<Dropdown overlay={filterMenu} trigger={['click']}>
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: filterMenu,
|
||||||
|
selectedKeys: selectedFilter,
|
||||||
|
}}
|
||||||
|
trigger={['click']}>
|
||||||
<Button icon={<PlusOutlined />} size="small" type="primary" />
|
<Button icon={<PlusOutlined />} size="small" type="primary" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
@ -952,10 +927,36 @@ const AssetsTabs = forwardRef(
|
|||||||
header={t('label.remove-entity', {
|
header={t('label.remove-entity', {
|
||||||
entity: getEntityName(assetToDelete) + '?',
|
entity: getEntityName(assetToDelete) + '?',
|
||||||
})}
|
})}
|
||||||
|
isLoading={assetRemoving}
|
||||||
visible={showDeleteModal}
|
visible={showDeleteModal}
|
||||||
onCancel={() => setShowDeleteModal(false)}
|
onCancel={() => setShowDeleteModal(false)}
|
||||||
onConfirm={() => onAssetRemove(assetToDelete ? [assetToDelete] : [])}
|
onConfirm={() => onAssetRemove(assetToDelete ? [assetToDelete] : [])}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{selectedItems.size > 1 && (
|
||||||
|
<Affix
|
||||||
|
className={classNames('asset-tab-delete-notification', {
|
||||||
|
visible: selectedItems.size > 1,
|
||||||
|
})}
|
||||||
|
offsetBottom={20}
|
||||||
|
target={() =>
|
||||||
|
document.getElementById('asset-tab') || document.body
|
||||||
|
}>
|
||||||
|
<div className="d-flex items-center justify-between">
|
||||||
|
<Typography.Text className="text-white">
|
||||||
|
{selectedItems.size} {t('label.items-selected-lowercase')}
|
||||||
|
</Typography.Text>
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
data-testid="delete-all-button"
|
||||||
|
loading={assetRemoving}
|
||||||
|
type="primary"
|
||||||
|
onClick={deleteSelectedItems}>
|
||||||
|
{t('label.delete')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Affix>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -83,10 +83,6 @@ const GlossaryOverviewTab = ({
|
|||||||
}
|
}
|
||||||
}, [selectedData, isVersionView]);
|
}, [selectedData, isVersionView]);
|
||||||
|
|
||||||
const handleTagsUpdate = async (updatedTags: TagLabel[]) => {
|
|
||||||
setTagsUpdating(updatedTags);
|
|
||||||
};
|
|
||||||
|
|
||||||
const tags = useMemo(
|
const tags = useMemo(
|
||||||
() =>
|
() =>
|
||||||
isVersionView
|
isVersionView
|
||||||
@ -98,14 +94,16 @@ const GlossaryOverviewTab = ({
|
|||||||
[isVersionView, selectedData]
|
[isVersionView, selectedData]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleTagsUpdate = async (updatedTags: TagLabel[]) => {
|
||||||
|
setTagsUpdating(updatedTags);
|
||||||
|
};
|
||||||
|
|
||||||
const handleGlossaryTagUpdateValidationConfirm = async () => {
|
const handleGlossaryTagUpdateValidationConfirm = async () => {
|
||||||
if (selectedData) {
|
if (selectedData) {
|
||||||
await onUpdate({
|
await onUpdate({
|
||||||
...selectedData,
|
...selectedData,
|
||||||
tags: tagsUpdatating,
|
tags: tagsUpdatating,
|
||||||
});
|
});
|
||||||
|
|
||||||
setTagsUpdating(undefined);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,20 +81,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.asset-tab-delete-notification {
|
.asset-tab-delete-notification {
|
||||||
background-color: @text-color !important;
|
&.visible {
|
||||||
box-shadow: none !important;
|
.ant-affix {
|
||||||
.ant-notification-notice-icon {
|
bottom: 10px !important;
|
||||||
display: none;
|
}
|
||||||
}
|
}
|
||||||
.ant-notification-notice-close {
|
|
||||||
color: @white !important;
|
.ant-affix {
|
||||||
left: 24px;
|
border-radius: 10px;
|
||||||
top: 22px;
|
background: #292929;
|
||||||
width: 20px;
|
height: 64px !important;
|
||||||
}
|
width: 350px !important;
|
||||||
.ant-notification-notice-message {
|
bottom: -64px !important;
|
||||||
padding-right: 0 !important;
|
left: 40%;
|
||||||
margin-left: 20px !important;
|
transform: translateX(-60%);
|
||||||
font-size: 14px !important;
|
transition: bottom ease-in 0.5s;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,3 +19,11 @@ export interface GlossaryUpdateConfirmationModalProps {
|
|||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
updatedTags: TagLabel[];
|
updatedTags: TagLabel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum UpdateState {
|
||||||
|
INITIAL,
|
||||||
|
VALIDATING,
|
||||||
|
FAILED,
|
||||||
|
UPDATATING,
|
||||||
|
SUCESS,
|
||||||
|
}
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import Icon from '@ant-design/icons';
|
import Icon from '@ant-design/icons';
|
||||||
import { Button, Modal, Space, Typography } from 'antd';
|
import { Alert, Button, Modal, Progress, Space, Typography } from 'antd';
|
||||||
import { isEmpty } from 'lodash';
|
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
@ -31,7 +30,10 @@ import {
|
|||||||
getEntityName,
|
getEntityName,
|
||||||
} from '../../../utils/EntityUtils';
|
} from '../../../utils/EntityUtils';
|
||||||
import Table from '../../common/Table/Table';
|
import Table from '../../common/Table/Table';
|
||||||
import { GlossaryUpdateConfirmationModalProps } from './GlossaryUpdateConfirmationModal.interface';
|
import {
|
||||||
|
GlossaryUpdateConfirmationModalProps,
|
||||||
|
UpdateState,
|
||||||
|
} from './GlossaryUpdateConfirmationModal.interface';
|
||||||
|
|
||||||
export const GlossaryUpdateConfirmationModal = ({
|
export const GlossaryUpdateConfirmationModal = ({
|
||||||
glossaryTerm,
|
glossaryTerm,
|
||||||
@ -41,13 +43,12 @@ export const GlossaryUpdateConfirmationModal = ({
|
|||||||
}: GlossaryUpdateConfirmationModalProps) => {
|
}: GlossaryUpdateConfirmationModalProps) => {
|
||||||
const [failedStatus, setFailedStatus] = useState<BulkOperationResult>();
|
const [failedStatus, setFailedStatus] = useState<BulkOperationResult>();
|
||||||
const [tagError, setTagError] = useState<{ code: number; message: string }>();
|
const [tagError, setTagError] = useState<{ code: number; message: string }>();
|
||||||
const [tagAdditionConfirmation, setTagAdditionConfirmation] = useState(false);
|
const [updateState, setUpdateState] = useState(UpdateState.INITIAL);
|
||||||
const [validating, setValidating] = useState(false);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleUpdateConfirmation = async () => {
|
const handleUpdateConfirmation = async () => {
|
||||||
setTagAdditionConfirmation(true);
|
setUpdateState(UpdateState.VALIDATING);
|
||||||
setValidating(true);
|
|
||||||
try {
|
try {
|
||||||
// dryRun validations so that we can list failures if any
|
// dryRun validations so that we can list failures if any
|
||||||
const res = await validateTagAddtionToGlossary(
|
const res = await validateTagAddtionToGlossary(
|
||||||
@ -55,16 +56,24 @@ export const GlossaryUpdateConfirmationModal = ({
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status && res.status === Status.Success) {
|
if (res.status === Status.Success) {
|
||||||
await onValidationSuccess();
|
setUpdateState(UpdateState.UPDATATING);
|
||||||
|
try {
|
||||||
|
await onValidationSuccess();
|
||||||
|
setUpdateState(UpdateState.SUCESS);
|
||||||
|
} catch (err) {
|
||||||
|
// Error
|
||||||
|
} finally {
|
||||||
|
setTimeout(onCancel, 500);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
setUpdateState(UpdateState.FAILED);
|
||||||
setFailedStatus(res);
|
setFailedStatus(res);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// error
|
// error
|
||||||
setTagError(err.response?.data);
|
setTagError(err.response?.data);
|
||||||
} finally {
|
setUpdateState(UpdateState.FAILED);
|
||||||
setValidating(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,81 +105,139 @@ export const GlossaryUpdateConfirmationModal = ({
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const progress =
|
||||||
|
updateState === UpdateState.VALIDATING
|
||||||
|
? 10
|
||||||
|
: updateState === UpdateState.UPDATATING
|
||||||
|
? 60
|
||||||
|
: 100;
|
||||||
|
|
||||||
|
const data = useMemo(() => {
|
||||||
|
const footer = (
|
||||||
|
<div className="d-flex justify-between">
|
||||||
|
<Typography.Text type="secondary">
|
||||||
|
{failedStatus?.numberOfRowsFailed &&
|
||||||
|
`${failedStatus.numberOfRowsFailed} ${t('label.failed')}`}
|
||||||
|
</Typography.Text>
|
||||||
|
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const progressBar = (
|
||||||
|
<div className="text-center">
|
||||||
|
<Progress percent={progress} status="normal" type="circle" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (updateState) {
|
||||||
|
case UpdateState.INITIAL:
|
||||||
|
return {
|
||||||
|
footer: null,
|
||||||
|
content: (
|
||||||
|
<div className="d-flex items-center flex-column gap-2">
|
||||||
|
<Icon
|
||||||
|
className="m-b-lg"
|
||||||
|
component={ExclamationIcon}
|
||||||
|
style={{ fontSize: '60px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Title level={5}>
|
||||||
|
{t('message.tag-update-confirmation')}
|
||||||
|
</Typography.Title>
|
||||||
|
<Typography.Text className="text-center">
|
||||||
|
{t('message.glossary-tag-update-description')}{' '}
|
||||||
|
<span className="font-medium">
|
||||||
|
{getEntityName(glossaryTerm)}
|
||||||
|
</span>
|
||||||
|
</Typography.Text>
|
||||||
|
<div className="m-t-lg">
|
||||||
|
<Space size={8}>
|
||||||
|
<Button onClick={onCancel}>
|
||||||
|
{t('label.no-comma-cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button type="primary" onClick={handleUpdateConfirmation}>
|
||||||
|
{t('label.yes-comma-confirm')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case UpdateState.VALIDATING:
|
||||||
|
return {
|
||||||
|
content: progressBar,
|
||||||
|
footer: footer,
|
||||||
|
};
|
||||||
|
case UpdateState.FAILED:
|
||||||
|
return {
|
||||||
|
content: (
|
||||||
|
<div className="d-flex flex-column gap-2">
|
||||||
|
{failedStatus && (
|
||||||
|
<>
|
||||||
|
<Table
|
||||||
|
bordered
|
||||||
|
columns={tagsColumn}
|
||||||
|
dataSource={failedStatus?.failedRequest ?? []}
|
||||||
|
pagination={{
|
||||||
|
pageSize: 5,
|
||||||
|
showSizeChanger: true,
|
||||||
|
}}
|
||||||
|
rowKey={(record) => record.request?.id}
|
||||||
|
/>
|
||||||
|
<Alert
|
||||||
|
className="m-t-sm"
|
||||||
|
message={t('message.glossary-tag-assignement-help-message')}
|
||||||
|
type="warning"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{tagError?.code === ClientErrors.BAD_REQUEST && (
|
||||||
|
<Alert message={tagError.message} type="warning" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
footer: (
|
||||||
|
<div className="d-flex justify-between">
|
||||||
|
<Typography.Text type="secondary">
|
||||||
|
{failedStatus?.numberOfRowsFailed &&
|
||||||
|
`${failedStatus.numberOfRowsFailed} ${t('label.failed')}`}
|
||||||
|
</Typography.Text>
|
||||||
|
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case UpdateState.UPDATATING:
|
||||||
|
return {
|
||||||
|
content: progressBar,
|
||||||
|
footer: <Button onClick={onCancel}>{t('label.cancel')}</Button>,
|
||||||
|
};
|
||||||
|
case UpdateState.SUCESS:
|
||||||
|
return {
|
||||||
|
content: progressBar,
|
||||||
|
footer: <Button onClick={onCancel}>{t('label.cancel')}</Button>,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [updateState, failedStatus]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
centered
|
centered
|
||||||
open
|
open
|
||||||
closable={false}
|
closable={false}
|
||||||
closeIcon={null}
|
closeIcon={null}
|
||||||
footer={
|
footer={data.footer}
|
||||||
tagAdditionConfirmation && (
|
|
||||||
<div className="d-flex justify-between">
|
|
||||||
<Typography.Text type="secondary">
|
|
||||||
{failedStatus?.numberOfRowsFailed &&
|
|
||||||
`${failedStatus.numberOfRowsFailed} ${t('label.failed')}`}
|
|
||||||
</Typography.Text>
|
|
||||||
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
title={
|
title={
|
||||||
tagAdditionConfirmation
|
[
|
||||||
|
UpdateState.VALIDATING,
|
||||||
|
UpdateState.FAILED,
|
||||||
|
UpdateState.UPDATATING,
|
||||||
|
UpdateState.SUCESS,
|
||||||
|
].includes(updateState)
|
||||||
? t('message.glossary-tag-update-modal-title')
|
? t('message.glossary-tag-update-modal-title')
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
width={tagAdditionConfirmation ? 750 : undefined}
|
width={updateState === UpdateState.FAILED ? 750 : undefined}
|
||||||
onCancel={onCancel}>
|
onCancel={onCancel}>
|
||||||
{tagAdditionConfirmation || validating ? (
|
{data.content}
|
||||||
<div className="d-flex flex-column gap-2">
|
|
||||||
{!isEmpty(failedStatus?.failedRequest) && !validating && (
|
|
||||||
<>
|
|
||||||
<Table
|
|
||||||
bordered
|
|
||||||
columns={tagsColumn}
|
|
||||||
dataSource={failedStatus?.failedRequest}
|
|
||||||
loading={validating}
|
|
||||||
pagination={{
|
|
||||||
pageSize: 5,
|
|
||||||
showSizeChanger: true,
|
|
||||||
}}
|
|
||||||
rowKey={(record) => record.request.id}
|
|
||||||
/>
|
|
||||||
<Typography.Text italic className="m-t-sm" type="secondary">
|
|
||||||
{t('message.glossary-tag-assignement-help-message')}
|
|
||||||
</Typography.Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{tagError?.code === ClientErrors.BAD_REQUEST && (
|
|
||||||
<Typography.Text type="danger">{tagError.message}</Typography.Text>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="d-flex items-center flex-column gap-2">
|
|
||||||
<Icon
|
|
||||||
className="m-b-lg"
|
|
||||||
component={ExclamationIcon}
|
|
||||||
style={{ fontSize: '60px' }}
|
|
||||||
/>
|
|
||||||
<Typography.Title level={5}>
|
|
||||||
{t('message.tag-update-confirmation')}
|
|
||||||
</Typography.Title>
|
|
||||||
<Typography.Text className="text-center">
|
|
||||||
{t('message.glossary-tag-update-description')}{' '}
|
|
||||||
<span className="font-medium">{getEntityName(glossaryTerm)}</span>
|
|
||||||
</Typography.Text>
|
|
||||||
<div className="m-t-lg">
|
|
||||||
<Space size={8}>
|
|
||||||
<Button onClick={onCancel}>{t('label.no-comma-cancel')}</Button>
|
|
||||||
<Button
|
|
||||||
loading={validating}
|
|
||||||
type="primary"
|
|
||||||
onClick={handleUpdateConfirmation}>
|
|
||||||
{t('label.yes-comma-confirm')}
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import { Col, Form, Row, Space, Tooltip, Typography } from 'antd';
|
import { Col, Form, Row, Space, Tooltip, Typography } from 'antd';
|
||||||
import { DefaultOptionType } from 'antd/lib/select';
|
import { DefaultOptionType } from 'antd/lib/select';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty, isEqual } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -104,7 +104,7 @@ const TagsContainerV2 = ({
|
|||||||
const handleSave = async (data: DefaultOptionType | DefaultOptionType[]) => {
|
const handleSave = async (data: DefaultOptionType | DefaultOptionType[]) => {
|
||||||
const updatedTags = (data as DefaultOptionType[]).map((tag) => {
|
const updatedTags = (data as DefaultOptionType[]).map((tag) => {
|
||||||
let tagData: EntityTags = {
|
let tagData: EntityTags = {
|
||||||
tagFQN: tag.value,
|
tagFQN: typeof tag === 'string' ? tag : tag.value,
|
||||||
source: tagType,
|
source: tagType,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,13 +115,16 @@ const TagsContainerV2 = ({
|
|||||||
displayName: tag.data?.displayName,
|
displayName: tag.data?.displayName,
|
||||||
description: tag.data?.description,
|
description: tag.data?.description,
|
||||||
style: tag.data?.style,
|
style: tag.data?.style,
|
||||||
|
labelType: tag.data?.labelType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return tagData;
|
return tagData;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onSelectionChange) {
|
const newTags = updatedTags.map((t) => t.tagFQN);
|
||||||
|
|
||||||
|
if (onSelectionChange && !isEqual(selectedTagsInternal, newTags)) {
|
||||||
await onSelectionChange([
|
await onSelectionChange([
|
||||||
...updatedTags,
|
...updatedTags,
|
||||||
...((isGlossaryType
|
...((isGlossaryType
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
export const PRIMERY_COLOR = '#0968da';
|
export const PRIMERY_COLOR = '#0968da';
|
||||||
export const SECONDARY_COLOR = '#B02AAC';
|
export const SECONDARY_COLOR = '#B02AAC';
|
||||||
export const INFO_COLOR = '#2196f3';
|
export const INFO_COLOR = '#2196f3';
|
||||||
|
export const ERROR_COLOR = '#ff4c3b';
|
||||||
export const LITE_GRAY_COLOR = '#DBE0EB';
|
export const LITE_GRAY_COLOR = '#DBE0EB';
|
||||||
export const TEXT_BODY_COLOR = '#37352F';
|
export const TEXT_BODY_COLOR = '#37352F';
|
||||||
export const TEXT_GREY_MUTED = '#757575';
|
export const TEXT_GREY_MUTED = '#757575';
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "{{entity}}-Dienst",
|
"entity-service": "{{entity}}-Dienst",
|
||||||
"entity-type-plural": "{{entity}}-Typen",
|
"entity-type-plural": "{{entity}}-Typen",
|
||||||
"entity-version-detail-plural": "Details zu {{entity}}-Versionen",
|
"entity-version-detail-plural": "Details zu {{entity}}-Versionen",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Ereignisveröffentlicher",
|
"event-publisher-plural": "Ereignisveröffentlicher",
|
||||||
"event-type": "Ereignistyp",
|
"event-type": "Ereignistyp",
|
||||||
"every": "Jede/r/s",
|
"every": "Jede/r/s",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Benutzername oder E-Mail",
|
"username-or-email": "Benutzername oder E-Mail",
|
||||||
"valid-condition": "Gültige Bedingung",
|
"valid-condition": "Gültige Bedingung",
|
||||||
"validating-condition": "Bedingung validieren...",
|
"validating-condition": "Bedingung validieren...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Wert",
|
"value": "Wert",
|
||||||
"value-count": "Wertanzahl",
|
"value-count": "Wertanzahl",
|
||||||
"value-plural": "Werte",
|
"value-plural": "Werte",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} hat Sie in einem Kommentar erwähnt.",
|
"user-mentioned-in-comment": "{{user}} hat Sie in einem Kommentar erwähnt.",
|
||||||
"user-verified-successfully": "Benutzer erfolgreich verifiziert",
|
"user-verified-successfully": "Benutzer erfolgreich verifiziert",
|
||||||
"valid-url-endpoint": "Endpunkte sollten gültige URLs sein",
|
"valid-url-endpoint": "Endpunkte sollten gültige URLs sein",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} Veröffentlicht <0>Sehen Sie, was es Neues gibt!</0>",
|
"version-released-try-now": "{{version}} Veröffentlicht <0>Sehen Sie, was es Neues gibt!</0>",
|
||||||
"view-deleted-entity": "Alle gelöschten {{entity}}, die zu diesem {{parent}} gehören, anzeigen.",
|
"view-deleted-entity": "Alle gelöschten {{entity}}, die zu diesem {{parent}} gehören, anzeigen.",
|
||||||
"view-sample-data-entity": "Um Musterdaten anzuzeigen, führen Sie {{entity}} aus. Bitte beachten Sie dieses Dokument, um die <0>{{entity}}</0> zu planen.",
|
"view-sample-data-entity": "Um Musterdaten anzuzeigen, führen Sie {{entity}} aus. Bitte beachten Sie dieses Dokument, um die <0>{{entity}}</0> zu planen.",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "{{entity}} Service",
|
"entity-service": "{{entity}} Service",
|
||||||
"entity-type-plural": "{{entity}} Type",
|
"entity-type-plural": "{{entity}} Type",
|
||||||
"entity-version-detail-plural": "{{entity}} Version Details",
|
"entity-version-detail-plural": "{{entity}} Version Details",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Event Publishers",
|
"event-publisher-plural": "Event Publishers",
|
||||||
"event-type": "Event Type",
|
"event-type": "Event Type",
|
||||||
"every": "Every",
|
"every": "Every",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Username or Email",
|
"username-or-email": "Username or Email",
|
||||||
"valid-condition": "Valid condition",
|
"valid-condition": "Valid condition",
|
||||||
"validating-condition": "Validating the condition...",
|
"validating-condition": "Validating the condition...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"value-count": "Value Count",
|
"value-count": "Value Count",
|
||||||
"value-plural": "Values",
|
"value-plural": "Values",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} mentioned you in a comment.",
|
"user-mentioned-in-comment": "{{user}} mentioned you in a comment.",
|
||||||
"user-verified-successfully": "User Verified Successfully",
|
"user-verified-successfully": "User Verified Successfully",
|
||||||
"valid-url-endpoint": "Endpoints should be valid URL",
|
"valid-url-endpoint": "Endpoints should be valid URL",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
||||||
"view-deleted-entity": "View All the Deleted {{entity}}, which come under this {{parent}}.",
|
"view-deleted-entity": "View All the Deleted {{entity}}, which come under this {{parent}}.",
|
||||||
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "Servicio de {{entity}}",
|
"entity-service": "Servicio de {{entity}}",
|
||||||
"entity-type-plural": "{{entity}} Type",
|
"entity-type-plural": "{{entity}} Type",
|
||||||
"entity-version-detail-plural": "{{entity}} Version Details",
|
"entity-version-detail-plural": "{{entity}} Version Details",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Publicadores de eventos",
|
"event-publisher-plural": "Publicadores de eventos",
|
||||||
"event-type": "Tipo de evento",
|
"event-type": "Tipo de evento",
|
||||||
"every": "Cada",
|
"every": "Cada",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Nombre de usuario o correo electrónico",
|
"username-or-email": "Nombre de usuario o correo electrónico",
|
||||||
"valid-condition": "Condición válida",
|
"valid-condition": "Condición válida",
|
||||||
"validating-condition": "Validando la condición...",
|
"validating-condition": "Validando la condición...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Valor",
|
"value": "Valor",
|
||||||
"value-count": "Recuento de valor",
|
"value-count": "Recuento de valor",
|
||||||
"value-plural": "Valores",
|
"value-plural": "Valores",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} te mencionó en un comentario.",
|
"user-mentioned-in-comment": "{{user}} te mencionó en un comentario.",
|
||||||
"user-verified-successfully": "Usuario verificado con éxito",
|
"user-verified-successfully": "Usuario verificado con éxito",
|
||||||
"valid-url-endpoint": "Los terminales deben ser URL válidas",
|
"valid-url-endpoint": "Los terminales deben ser URL válidas",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
||||||
"view-deleted-entity": "Ver todas las {{entity}} eliminadas que se encuentran bajo este {{parent}}.",
|
"view-deleted-entity": "Ver todas las {{entity}} eliminadas que se encuentran bajo este {{parent}}.",
|
||||||
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "Service de {{entity}}",
|
"entity-service": "Service de {{entity}}",
|
||||||
"entity-type-plural": "{{entity}} Types",
|
"entity-type-plural": "{{entity}} Types",
|
||||||
"entity-version-detail-plural": "Détails des Versions de {{entity}}",
|
"entity-version-detail-plural": "Détails des Versions de {{entity}}",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Publicateurs d'Événements",
|
"event-publisher-plural": "Publicateurs d'Événements",
|
||||||
"event-type": "Type d'Événement",
|
"event-type": "Type d'Événement",
|
||||||
"every": "Chaque",
|
"every": "Chaque",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Nom d'Utilisateur ou Email",
|
"username-or-email": "Nom d'Utilisateur ou Email",
|
||||||
"valid-condition": "Condition Valide",
|
"valid-condition": "Condition Valide",
|
||||||
"validating-condition": "Validation de la Condition...",
|
"validating-condition": "Validation de la Condition...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Valeur",
|
"value": "Valeur",
|
||||||
"value-count": "Décompte de la Valeur",
|
"value-count": "Décompte de la Valeur",
|
||||||
"value-plural": "Valeurs",
|
"value-plural": "Valeurs",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} vous a mentionné dans un commentaire.",
|
"user-mentioned-in-comment": "{{user}} vous a mentionné dans un commentaire.",
|
||||||
"user-verified-successfully": "L'utilisateur a été vérifié avec succès",
|
"user-verified-successfully": "L'utilisateur a été vérifié avec succès",
|
||||||
"valid-url-endpoint": "Les points de terminaison doivent être une URL valide",
|
"valid-url-endpoint": "Les points de terminaison doivent être une URL valide",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} publié essayez maintenant !",
|
"version-released-try-now": "{{version}} publié essayez maintenant !",
|
||||||
"view-deleted-entity": "Afficher toutes les {{entity}} supprimées qui relèvent de ce {{parent}}.",
|
"view-deleted-entity": "Afficher toutes les {{entity}} supprimées qui relèvent de ce {{parent}}.",
|
||||||
"view-sample-data-entity": "Pour afficher des données d'exemple, exécutez {{entity}}. Veuillez vous référer à ce document pour planifier {{entity}}.",
|
"view-sample-data-entity": "Pour afficher des données d'exemple, exécutez {{entity}}. Veuillez vous référer à ce document pour planifier {{entity}}.",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "{{entity}}サービス",
|
"entity-service": "{{entity}}サービス",
|
||||||
"entity-type-plural": "{{entity}} Type",
|
"entity-type-plural": "{{entity}} Type",
|
||||||
"entity-version-detail-plural": "{{entity}} Version Details",
|
"entity-version-detail-plural": "{{entity}} Version Details",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "イベントの作成者",
|
"event-publisher-plural": "イベントの作成者",
|
||||||
"event-type": "イベントの種類",
|
"event-type": "イベントの種類",
|
||||||
"every": "Every",
|
"every": "Every",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "ユーザ名あるいはEmailアドレス",
|
"username-or-email": "ユーザ名あるいはEmailアドレス",
|
||||||
"valid-condition": "正しい条件",
|
"valid-condition": "正しい条件",
|
||||||
"validating-condition": "条件を検証中...",
|
"validating-condition": "条件を検証中...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "値",
|
"value": "値",
|
||||||
"value-count": "値の数",
|
"value-count": "値の数",
|
||||||
"value-plural": "値",
|
"value-plural": "値",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}}がコメントであなたにメンションしました。",
|
"user-mentioned-in-comment": "{{user}}がコメントであなたにメンションしました。",
|
||||||
"user-verified-successfully": "ユーザ認証に成功しました",
|
"user-verified-successfully": "ユーザ認証に成功しました",
|
||||||
"valid-url-endpoint": "エンドポイントは有効なURLでなければなりません",
|
"valid-url-endpoint": "エンドポイントは有効なURLでなければなりません",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
"version-released-try-now": "{{version}} Released <0>See What's New!</0>",
|
||||||
"view-deleted-entity": "View All the Deleted {{entity}}, which come under this {{parent}}.",
|
"view-deleted-entity": "View All the Deleted {{entity}}, which come under this {{parent}}.",
|
||||||
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
"view-sample-data-entity": "To view Sample Data, run the {{entity}}. Please refer to this doc to schedule the <0>{{entity}}</0>",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "Serviço de {{entity}}",
|
"entity-service": "Serviço de {{entity}}",
|
||||||
"entity-type-plural": "Tipo de {{entity}}",
|
"entity-type-plural": "Tipo de {{entity}}",
|
||||||
"entity-version-detail-plural": "Detalhes da Versão de {{entity}}",
|
"entity-version-detail-plural": "Detalhes da Versão de {{entity}}",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Publicadores de Eventos",
|
"event-publisher-plural": "Publicadores de Eventos",
|
||||||
"event-type": "Tipo de Evento",
|
"event-type": "Tipo de Evento",
|
||||||
"every": "Cada",
|
"every": "Cada",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Nome de Usuário ou Email",
|
"username-or-email": "Nome de Usuário ou Email",
|
||||||
"valid-condition": "Condição Válida",
|
"valid-condition": "Condição Válida",
|
||||||
"validating-condition": "Validando a condição...",
|
"validating-condition": "Validando a condição...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Valor",
|
"value": "Valor",
|
||||||
"value-count": "Contagem de Valor",
|
"value-count": "Contagem de Valor",
|
||||||
"value-plural": "Valores",
|
"value-plural": "Valores",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} mencionou você em um comentário.",
|
"user-mentioned-in-comment": "{{user}} mencionou você em um comentário.",
|
||||||
"user-verified-successfully": "Usuário verificado com sucesso",
|
"user-verified-successfully": "Usuário verificado com sucesso",
|
||||||
"valid-url-endpoint": "Os endpoints devem ser URLs válidas",
|
"valid-url-endpoint": "Os endpoints devem ser URLs válidas",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "{{version}} Lançada <0>Veja o que há de novo!</0>",
|
"version-released-try-now": "{{version}} Lançada <0>Veja o que há de novo!</0>",
|
||||||
"view-deleted-entity": "Visualize todos os {{entity}} excluídos, que fazem parte deste {{parent}}.",
|
"view-deleted-entity": "Visualize todos os {{entity}} excluídos, que fazem parte deste {{parent}}.",
|
||||||
"view-sample-data-entity": "Para visualizar os Dados de Amostra, execute o {{entity}}. Consulte este documento para agendar o <0>{{entity}}</0>",
|
"view-sample-data-entity": "Para visualizar os Dados de Amostra, execute o {{entity}}. Consulte este documento para agendar o <0>{{entity}}</0>",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "Сервис {{entity}}",
|
"entity-service": "Сервис {{entity}}",
|
||||||
"entity-type-plural": "Тип {{entity}}",
|
"entity-type-plural": "Тип {{entity}}",
|
||||||
"entity-version-detail-plural": "{{entity}} Version Details",
|
"entity-version-detail-plural": "{{entity}} Version Details",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "Издатели события",
|
"event-publisher-plural": "Издатели события",
|
||||||
"event-type": "Тип события",
|
"event-type": "Тип события",
|
||||||
"every": "Каждый",
|
"every": "Каждый",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "Имя пользователя или Email",
|
"username-or-email": "Имя пользователя или Email",
|
||||||
"valid-condition": "Действительное условие",
|
"valid-condition": "Действительное условие",
|
||||||
"validating-condition": "Проверка условия...",
|
"validating-condition": "Проверка условия...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "Значение",
|
"value": "Значение",
|
||||||
"value-count": "Количество значений",
|
"value-count": "Количество значений",
|
||||||
"value-plural": "Значения",
|
"value-plural": "Значения",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}} упомянул вас в комментарии.",
|
"user-mentioned-in-comment": "{{user}} упомянул вас в комментарии.",
|
||||||
"user-verified-successfully": "Пользователь успешно проверен",
|
"user-verified-successfully": "Пользователь успешно проверен",
|
||||||
"valid-url-endpoint": "Конечные точки должны быть действительным URL",
|
"valid-url-endpoint": "Конечные точки должны быть действительным URL",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "Выпущена {{версия}} <0>Посмотрите, что нового!</0>",
|
"version-released-try-now": "Выпущена {{версия}} <0>Посмотрите, что нового!</0>",
|
||||||
"view-deleted-entity": "Просмотреть все удаленные {{entity}}, относящиеся к этому {{parent}}.",
|
"view-deleted-entity": "Просмотреть все удаленные {{entity}}, относящиеся к этому {{parent}}.",
|
||||||
"view-sample-data-entity": "Чтобы просмотреть образцы данных, запустите {{entity}}. Пожалуйста, обратитесь к этому документу, чтобы запланировать <0>{{entity}}</0>",
|
"view-sample-data-entity": "Чтобы просмотреть образцы данных, запустите {{entity}}. Пожалуйста, обратитесь к этому документу, чтобы запланировать <0>{{entity}}</0>",
|
||||||
|
@ -396,6 +396,7 @@
|
|||||||
"entity-service": "{{entity}}服务",
|
"entity-service": "{{entity}}服务",
|
||||||
"entity-type-plural": "{{entity}}类型",
|
"entity-type-plural": "{{entity}}类型",
|
||||||
"entity-version-detail-plural": "{{entity}}版本详情",
|
"entity-version-detail-plural": "{{entity}}版本详情",
|
||||||
|
"error": "Error",
|
||||||
"event-publisher-plural": "事件发布者",
|
"event-publisher-plural": "事件发布者",
|
||||||
"event-type": "事件类型",
|
"event-type": "事件类型",
|
||||||
"every": "每个",
|
"every": "每个",
|
||||||
@ -1133,6 +1134,7 @@
|
|||||||
"username-or-email": "用户名或电子邮箱",
|
"username-or-email": "用户名或电子邮箱",
|
||||||
"valid-condition": "有效条件",
|
"valid-condition": "有效条件",
|
||||||
"validating-condition": "正在验证条件...",
|
"validating-condition": "正在验证条件...",
|
||||||
|
"validation-error-plural": "Validation Errors!",
|
||||||
"value": "值",
|
"value": "值",
|
||||||
"value-count": "值数量",
|
"value-count": "值数量",
|
||||||
"value-plural": "值",
|
"value-plural": "值",
|
||||||
@ -1628,6 +1630,7 @@
|
|||||||
"user-mentioned-in-comment": "{{user}}在评论中提到了您",
|
"user-mentioned-in-comment": "{{user}}在评论中提到了您",
|
||||||
"user-verified-successfully": "用户验证成功",
|
"user-verified-successfully": "用户验证成功",
|
||||||
"valid-url-endpoint": "端点应该是有效的 URL",
|
"valid-url-endpoint": "端点应该是有效的 URL",
|
||||||
|
"validation-error-assets": "Please examine all your assets that are being added",
|
||||||
"version-released-try-now": "查看新版本 {{version}} 的新特性!",
|
"version-released-try-now": "查看新版本 {{version}} 的新特性!",
|
||||||
"view-deleted-entity": "查看所有被删除的{{entity}},隶属于该{{parent}}",
|
"view-deleted-entity": "查看所有被删除的{{entity}},隶属于该{{parent}}",
|
||||||
"view-sample-data-entity": "要查看样本数据,请运行{{entity}}。您还可以前往查看任务调度相关的信息<0>{{entity}}</0>。",
|
"view-sample-data-entity": "要查看样本数据,请运行{{entity}}。您还可以前往查看任务调度相关的信息<0>{{entity}}</0>。",
|
||||||
|
@ -305,9 +305,12 @@ const GlossaryPage = () => {
|
|||||||
.finally(() => setDeleteStatus(LOADING_STATE.INITIAL));
|
.finally(() => setDeleteStatus(LOADING_STATE.INITIAL));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAssetClick = (asset?: EntityDetailsObjectInterface) => {
|
const handleAssetClick = useCallback(
|
||||||
setPreviewAsset(asset);
|
(asset?: EntityDetailsObjectInterface) => {
|
||||||
};
|
setPreviewAsset(asset);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
|
@ -103,4 +103,4 @@ jest.mock('react-i18next', () => ({
|
|||||||
|
|
||||||
jest.mock('./utils/ToastUtils', () => ({
|
jest.mock('./utils/ToastUtils', () => ({
|
||||||
showErrorToast: jest.fn(),
|
showErrorToast: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
@ -15,15 +15,20 @@ import { Status } from '../generated/entity/applications/appRunRecord';
|
|||||||
import { PipelineState } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
import { PipelineState } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
|
|
||||||
export const getStatusTypeForApplication = (status: Status) => {
|
export const getStatusTypeForApplication = (status: Status) => {
|
||||||
if (status === Status.Failed) {
|
switch (status) {
|
||||||
return StatusType.Failure;
|
case Status.Failed:
|
||||||
} else if (status === Status.Success) {
|
return StatusType.Failure;
|
||||||
return StatusType.Success;
|
|
||||||
} else if (status === Status.Running) {
|
|
||||||
return StatusType.Warning;
|
|
||||||
}
|
|
||||||
|
|
||||||
return StatusType.Failure;
|
case Status.Success:
|
||||||
|
case Status.Completed:
|
||||||
|
return StatusType.Success;
|
||||||
|
|
||||||
|
case Status.Running:
|
||||||
|
return StatusType.Warning;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return StatusType.Failure;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getStatusFromPipelineState = (status: PipelineState) => {
|
export const getStatusFromPipelineState = (status: PipelineState) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user