fix(ui): ui feedbacks for 1.2 release (#13522)

* fix(ui): ui feedbacks for 1.2 release

* fix notification panel height issue and data model expand icon issue

* Data Quality, test creation, and minimizing the side panel. It shows the name as "Setup Guide.", It should be "Data Profiler Metrics."

* changes locales

* fix: displayName for the test cases

* fix: Remove Domain shows tool tip as "Remove Owner"

* chore: remove box shadow from primary buttons

* fix: icon alignment in activity feed tab

* Long names should be truncated

* Increase the profile picture size to align with both the name and the persona

* Text in Knowledge panels should be of the same size

* Domain should be displayed on the explore card if the domain is available for any entity

* If the Domains not configure the search filter is empty. "No data available." -> "No Domains are Assigned to Tables" etc.

* fix: unit tests

* fix: unit tets

---------

Co-authored-by: Ashish Gupta <ashish@getcollate.io>
Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com>
This commit is contained in:
Chirag Madlani 2023-10-14 19:40:01 +05:30 committed by GitHub
parent 753e182e21
commit 7c25b5fddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 218 additions and 86 deletions

View File

@ -1,7 +1,7 @@
{
"name": "columnValueMaxToBeBetween",
"fullyQualifiedName": "columnValueMaxToBeBetween",
"displayName": "Column Value Max. to be Between",
"displayName": "Column Value Max. To Be Between",
"description": "This schema defines the test ColumnValueMaxToBeBetween. Test the maximum value in a col is within a range.",
"entityType": "COLUMN",
"testPlatforms": ["OpenMetadata", "DBT"],

View File

@ -1,7 +1,7 @@
{
"name": "columnValueMeanToBeBetween",
"fullyQualifiedName": "columnValueMeanToBeBetween",
"displayName": "Column Value Mean To BeBetween",
"displayName": "Column Value Mean To Be Between",
"description": "This schema defines the test ColumnValueMeanToBeBetween. Test the mean value in a col is within a range.",
"entityType": "COLUMN",
"testPlatforms": ["OpenMetadata"],

View File

@ -29,7 +29,10 @@ import { ReactComponent as CheckIcon } from '../../../assets/svg/ic-check.svg';
import { ReactComponent as MentionIcon } from '../../../assets/svg/ic-mentions.svg';
import { ReactComponent as TaskIcon } from '../../../assets/svg/ic-task.svg';
import { ReactComponent as TaskListIcon } from '../../../assets/svg/task-ic.svg';
import { ICON_DIMENSION } from '../../../constants/constants';
import {
COMMON_ICON_STYLES,
ICON_DIMENSION,
} from '../../../constants/constants';
import { observerOptions } from '../../../constants/Mydata.constants';
import { EntityTabs, EntityType } from '../../../enums/entity.enum';
import { FeedFilter } from '../../../enums/mydata.enum';
@ -298,7 +301,10 @@ export const ActivityFeedTab = ({
label: (
<div className="d-flex justify-between">
<Space align="center" size="small">
<AllActivityIcon {...ICON_DIMENSION} />
<AllActivityIcon
style={COMMON_ICON_STYLES}
{...ICON_DIMENSION}
/>
<span>{t('label.all')}</span>
</Space>
@ -316,7 +322,7 @@ export const ActivityFeedTab = ({
{
label: (
<Space align="center" size="small">
<MentionIcon {...ICON_DIMENSION} />
<MentionIcon style={COMMON_ICON_STYLES} {...ICON_DIMENSION} />
<span>{t('label.mention-plural')}</span>
</Space>
),
@ -326,7 +332,10 @@ export const ActivityFeedTab = ({
label: (
<div className="d-flex justify-between">
<Space align="center" size="small">
<TaskListIcon {...ICON_DIMENSION} />
<TaskListIcon
style={COMMON_ICON_STYLES}
{...ICON_DIMENSION}
/>
<span>{t('label.task-plural')}</span>
</Space>
<span>{getCountBadge(tasksCount, '', isTaskActiveTab)}</span>

View File

@ -293,7 +293,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
flex: 0.4,
overlay: {
displayThreshold: 200,
header: t('label.setup-guide'),
header: t('label.data-profiler-metrics'),
rotation: 'counter-clockwise',
},
}}

View File

@ -22,7 +22,7 @@ import {
Switch,
} from 'antd';
import { AxiosError } from 'axios';
import { isEmpty, isUndefined, map, trim } from 'lodash';
import { compact, isEmpty, map, trim } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { VALIDATION_MESSAGES } from '../../constants/constants';
@ -33,6 +33,7 @@ import {
CreatePasswordType,
CreateUser as CreateUserSchema,
} from '../../generated/api/teams/createUser';
import { EntityReference } from '../../generated/entity/type';
import { AuthProvider } from '../../generated/settings/settings';
import { checkEmailInUse, generateRandomPwd } from '../../rest/auth-API';
import { getJWTTokenExpiryOptions } from '../../utils/BotsUtils';
@ -60,9 +61,9 @@ const CreateUser = ({
const { authConfig } = useAuthContext();
const [isAdmin, setIsAdmin] = useState(false);
const [isBot, setIsBot] = useState(forceBot);
const [selectedTeams, setSelectedTeams] = useState<Array<string | undefined>>(
[]
);
const [selectedTeams, setSelectedTeams] = useState<
Array<EntityReference | undefined>
>([]);
const [isPasswordGenerating, setIsPasswordGenerating] = useState(false);
const isAuthProviderBasic = useMemo(
@ -105,9 +106,7 @@ const CreateUser = ({
const handleSave: FormProps['onFinish'] = (values) => {
const isPasswordGenerated =
passwordGenerator === CreatePasswordGenerator.AutomaticGenerate;
const validTeam = selectedTeams.filter(
(id) => !isUndefined(id)
) as string[];
const validTeam = compact(selectedTeams).map((team) => team.id);
const { email, displayName, tokenExpiry, confirmPassword, description } =
values;

View File

@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Table, Typography } from 'antd';
import { Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { cloneDeep, isUndefined } from 'lodash';
import { EntityTags } from 'Models';
@ -25,6 +25,7 @@ import { TagLabel, TagSource } from '../../../generated/type/tagLabel';
import { updateDataModelColumnDescription } from '../../../utils/DataModelsUtils';
import { getEntityName } from '../../../utils/EntityUtils';
import { updateFieldTags } from '../../../utils/TableUtils';
import Table from '../../common/Table/Table';
import { ModelTabProps } from './ModelTab.interface';
const ModelTab = ({

View File

@ -34,6 +34,7 @@ import { showErrorToast } from '../../utils/ToastUtils';
import SearchDropdown from '../SearchDropdown/SearchDropdown';
import { SearchDropdownOption } from '../SearchDropdown/SearchDropdown.interface';
import { useAdvanceSearch } from './AdvanceSearchProvider/AdvanceSearchProvider.component';
import { ExploreSearchIndex } from './explore.interface';
import { ExploreQuickFiltersProps } from './ExploreQuickFilters.interface';
const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
@ -196,6 +197,7 @@ const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
<SearchDropdown
highlight
fixedOrderOptions={field.key === TIER_FQN_KEY}
index={index as ExploreSearchIndex}
isSuggestionsLoading={isOptionsLoading}
key={field.key}
label={field.label}

View File

@ -30,6 +30,7 @@ import {
getEntityLinkFromType,
getEntityName,
} from '../../../utils/EntityUtils';
import { getDomainPath } from '../../../utils/RouterUtils';
import { stringToHTML } from '../../../utils/StringsUtils';
import { getServiceIcon, getUsagePercentile } from '../../../utils/TableUtils';
import TitleBreadcrumb from '../../common/title-breadcrumb/title-breadcrumb.component';
@ -81,6 +82,18 @@ const ExploreSearchCard: React.FC<ExploreSearchCardProps> = forwardRef<
},
];
if (source?.domain) {
const domain = getEntityName(source.domain);
const domainLink = getDomainPath(source.domain.fullyQualifiedName);
_otherDetails.push({
key: 'Domain',
value: domainLink,
placeholderText: domain,
isLink: true,
openInNewTab: false,
});
}
if (
source.entityType !== EntityType.GLOSSARY_TERM &&
source.entityType !== EntityType.TAG

View File

@ -49,7 +49,7 @@ const LeftSidebar = () => {
label: (
<Tooltip
overlayClassName="left-panel-tooltip"
placement="right"
placement="topLeft"
title={
<Typography.Text className="left-panel-label">
{t('label.govern')}

View File

@ -146,10 +146,12 @@ const MyDataWidgetInternal = ({
);
})
) : (
<Transi18next
i18nKey="message.no-owned-data"
renderElement={<Link to={ROUTES.EXPLORE} />}
/>
<span className="text-sm">
<Transi18next
i18nKey="message.no-owned-data"
renderElement={<Link to={ROUTES.EXPLORE} />}
/>
</span>
)}
</div>
</>

View File

@ -168,7 +168,7 @@ const NotificationBox = ({
</div>
) : (
<List
className="h-min-64"
className="notification-content-container"
dataSource={notificationDropDownList}
footer={
<Button block href={viewAllPath} type="link">

View File

@ -26,3 +26,12 @@
}
}
}
.notification-content-container {
min-height: 16rem;
.ant-spin-nested-loading {
height: 200px;
overflow-y: scroll;
}
}

View File

@ -315,22 +315,22 @@ const SchemaTable = ({
tableConstraints,
})}
{/* If we do not have displayName name only be shown in the bold from the below code */}
{!isEmpty(displayName) ? (
<Typography.Text
className="m-b-0 d-block text-grey-muted"
data-testid="column-name">
{name}
</Typography.Text>
) : null}
{/* It will render displayName fallback to name */}
<Typography.Text
className="m-b-0 d-block text-grey-muted"
data-testid="column-name">
{name}
</Typography.Text>
</div>
{!isEmpty(displayName) ? (
// It will render displayName fallback to name
<Typography.Text
className="m-b-0 d-block"
data-testid="column-display-name"
ellipsis={{ tooltip: true }}>
{getEntityName(record)}
</Typography.Text>
</div>
) : null}
<Icon
className="hover-cell-icon text-left m-t-xss"
component={IconEdit}

View File

@ -221,7 +221,7 @@ describe('Test EntityTable Component', () => {
wrapper: MemoryRouter,
});
const columnNames = await screen.findAllByTestId('column-display-name');
const columnNames = await screen.findAllByTestId('column-name');
expect(columnNames).toHaveLength(3);
@ -244,12 +244,12 @@ describe('Test EntityTable Component', () => {
const columnDisplayName = await screen.findAllByTestId(
'column-display-name'
);
const columnName = await screen.findByTestId('column-name');
const columnName = await screen.findAllByTestId('column-name');
expect(columnDisplayName[0]).toBeInTheDocument();
expect(columnName).toBeInTheDocument();
expect(columnName[0]).toBeInTheDocument();
expect(columnDisplayName[0].textContent).toBe('Comments');
expect(columnName.textContent).toBe('comments');
expect(columnName[0].textContent).toBe('comments');
});
});

View File

@ -11,6 +11,8 @@
* limitations under the License.
*/
import { ExploreSearchIndex } from '../Explore/explore.interface';
export interface SearchDropdownProps {
label: string;
isSuggestionsLoading?: boolean;
@ -20,6 +22,7 @@ export interface SearchDropdownProps {
highlight?: boolean;
showProfilePicture?: boolean;
fixedOrderOptions?: boolean;
index?: ExploreSearchIndex;
onChange: (values: SearchDropdownOption[], searchKey: string) => void;
onGetInitialOptions?: (searchKey: string) => void;
onSearch: (searchText: string, searchKey: string) => void;

View File

@ -36,6 +36,7 @@ const mockProps: SearchDropdownProps = {
selectedKeys: [{ key: 'User 1', label: 'User 1' }],
onChange: mockOnChange,
onSearch: mockOnSearch,
index: 'table_search_index' as SearchDropdownProps['index'],
};
jest.mock('lodash', () => ({

View File

@ -37,6 +37,7 @@ import React, {
} from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as DropDown } from '../../assets/svg/DropDown.svg';
import { tabsInfo } from '../../constants/explore.constants';
import {
generateSearchDropdownLabel,
getSearchDropdownLabels,
@ -61,6 +62,7 @@ const SearchDropdown: FC<SearchDropdownProps> = ({
onChange,
onGetInitialOptions,
onSearch,
index,
}) => {
const { t } = useTranslation();
@ -170,6 +172,8 @@ const SearchDropdown: FC<SearchDropdownProps> = ({
const getDropdownBody = useCallback(
(menuNode: ReactNode) => {
const entityLabel = index && tabsInfo[index]?.label;
const isDomainKey = searchKey.startsWith('domain');
if (isSuggestionsLoading) {
return (
<Row align="middle" className="p-y-sm" justify="center">
@ -185,12 +189,18 @@ const SearchDropdown: FC<SearchDropdownProps> = ({
) : (
<Row align="middle" className="m-y-sm" justify="center">
<Col>
<Typography.Text>{t('message.no-data-available')}</Typography.Text>
<Typography.Text className="m-x-sm">
{isDomainKey && entityLabel
? t('message.no-domain-assigned-to-entity', {
entity: entityLabel,
})
: t('message.no-data-available')}
</Typography.Text>
</Col>
</Row>
);
},
[isSuggestionsLoading, options, selectedOptions]
[isSuggestionsLoading, options, selectedOptions, index, searchKey]
);
const dropdownCardComponent = useCallback(

View File

@ -339,7 +339,7 @@ const Services = ({ serviceName }: ServicesProps) => {
serviceName
)}>
<Typography.Text
className="text-base text-grey-body font-medium truncate w-48"
className="text-base text-grey-body font-medium truncate w-48 d-inline-block"
data-testid={`service-name-${service.name}`}
title={getEntityName(service)}>
{getEntityName(service)}

View File

@ -1,3 +1,5 @@
import { EntityReference } from '../../generated/entity/type';
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
@ -12,9 +14,9 @@
*/
export interface TeamsSelectableProps {
showTeamsAlert?: boolean;
onSelectionChange?: (teams: string[]) => void;
onSelectionChange?: (teams: EntityReference[]) => void;
filterJoinable?: boolean;
placeholder?: string;
selectedTeams?: string[];
selectedTeams?: EntityReference[];
maxValueCount?: number;
}

View File

@ -16,6 +16,7 @@ import { BaseOptionType } from 'antd/lib/select';
import { t } from 'i18next';
import React, { useEffect, useMemo, useState } from 'react';
import { TeamHierarchy } from '../../generated/entity/teams/teamHierarchy';
import { EntityReference } from '../../generated/entity/type';
import { getTeamsHierarchy } from '../../rest/teamsAPI';
import { getEntityName } from '../../utils/EntityUtils';
import { showErrorToast } from '../../utils/ToastUtils';
@ -31,19 +32,23 @@ const TeamsSelectable = ({
selectedTeams,
maxValueCount,
}: TeamsSelectableProps) => {
const [value, setValue] = useState<Array<string>>();
const [noTeam, setNoTeam] = useState<boolean>(false);
const [teams, setTeams] = useState<Array<TeamHierarchy>>([]);
const onChange = (newValue: string[]) => {
onSelectionChange && onSelectionChange(newValue);
setValue(newValue);
const onChange = (newValue: { label: string; value: string }[]) => {
onSelectionChange &&
onSelectionChange(
newValue.map(
(val) =>
({
id: val.value,
displayName: val.label,
type: 'team',
} as EntityReference)
)
);
};
useEffect(() => {
setValue(selectedTeams ?? []);
}, [selectedTeams]);
const loadOptions = () => {
getTeamsHierarchy(filterJoinable)
.then((res) => {
@ -84,10 +89,18 @@ const TeamsSelectable = ({
});
}, [teams]);
const selectedTeamsInternal = useMemo(() => {
return selectedTeams?.map((selectedTeam) => ({
label: getEntityName(selectedTeam),
value: selectedTeam.id,
}));
}, [selectedTeams]);
return (
<>
<TreeSelect
allowClear
labelInValue
multiple
showSearch
treeDefaultExpandAll
@ -100,7 +113,7 @@ const TeamsSelectable = ({
treeData={teamsTree}
treeLine={{ showLeafIcon }}
treeNodeFilterProp="title"
value={value}
value={selectedTeamsInternal}
onChange={onChange}
/>
{noTeam && (

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { CheckOutlined } from '@ant-design/icons';
import { Dropdown, Tag, Typography } from 'antd';
import { Dropdown, Tag, Tooltip, Typography } from 'antd';
import { ItemType } from 'antd/lib/menu/hooks/useItems';
import { isEmpty } from 'lodash';
import React, {
@ -293,21 +293,20 @@ export const UserProfileIcon = () => {
{isImgUrlValid ? (
<img
alt="user"
className="profile-image circle"
className="app-bar-user-avatar"
referrerPolicy="no-referrer"
src={profilePicture ?? ''}
width={36}
onError={handleOnImageError}
/>
) : (
<Avatar name={userName} type="circle" width="36" />
)}
<div className="d-flex flex-col flex-1">
<Typography.Text
className="usename w-28"
ellipsis={{ tooltip: true }}>
{getEntityName(currentUser)}
</Typography.Text>
<div className="d-flex flex-col">
<Tooltip title={getEntityName(currentUser)}>
<Typography.Text className="username truncate w-max-112">
{getEntityName(currentUser)}
</Typography.Text>
</Tooltip>
<Typography.Text
className="text-grey-muted text-xs w-28"
ellipsis={{ tooltip: true }}>

View File

@ -23,6 +23,7 @@ import {
DE_ACTIVE_COLOR,
ICON_DIMENSION,
} from '../../../../constants/constants';
import { EntityReference } from '../../../../generated/entity/type';
import { useAuth } from '../../../../hooks/authHooks';
import { getNonDeletedTeams } from '../../../../utils/CommonUtils';
import { UserProfileTeamsProps } from './UserProfileTeams.interface';
@ -35,11 +36,11 @@ const UserProfileTeams = ({
const { isAdminUser } = useAuth();
const [isTeamsEdit, setIsTeamsEdit] = useState(false);
const [selectedTeams, setSelectedTeams] = useState<string[]>([]);
const [selectedTeams, setSelectedTeams] = useState<EntityReference[]>([]);
const handleTeamsSave = () => {
updateUserDetails({
teams: selectedTeams.map((teamId) => ({ id: teamId, type: 'team' })),
teams: selectedTeams.map((teamId) => ({ id: teamId.id, type: 'team' })),
});
setIsTeamsEdit(false);
@ -57,7 +58,7 @@ const UserProfileTeams = ({
);
useEffect(() => {
setSelectedTeams(getNonDeletedTeams(teams ?? []).map((team) => team.id));
setSelectedTeams(getNonDeletedTeams(teams ?? []));
}, [teams]);
return (

View File

@ -113,6 +113,9 @@ const DomainSelectableList = ({
customTagRenderer={DomainListItemRenderer}
fetchOptions={fetchOptions}
multiSelect={false}
removeIconTooltipLabel={t('label.remove-entity', {
entity: t('label.domain-lowercase'),
})}
searchPlaceholder={t('label.search-for-type', {
type: t('label.domain'),
})}

View File

@ -20,6 +20,7 @@ import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import { ReactComponent as IconExternalLink } from '../../../assets/svg/external-links.svg';
import { ReactComponent as DomainIcon } from '../../../assets/svg/ic-domain.svg';
import { ReactComponent as IconTeamsGrey } from '../../../assets/svg/teams-grey.svg';
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
import { Tag } from '../../../generated/entity/classification/tag';
@ -186,6 +187,20 @@ const EntitySummaryDetails = ({
break;
case 'Domain':
{
retVal = (
<DomainIcon
className="d-flex"
color={DE_ACTIVE_COLOR}
height={16}
name="folder"
width={16}
/>
);
}
break;
default:
{
retVal = (

View File

@ -38,6 +38,7 @@ export const SelectableList = ({
searchPlaceholder,
customTagRenderer,
searchBarDataTestId,
removeIconTooltipLabel,
}: SelectableListProps) => {
const [uniqueOptions, setUniqueOptions] = useState<EntityReference[]>([]);
const [searchText, setSearchText] = useState('');
@ -230,7 +231,10 @@ export const SelectableList = ({
<Checkbox checked={selectedItemsInternal.has(item.id)} />
) : (
selectedItemsInternal.has(item.id) && (
<RemoveIcon removeOwner={handleRemoveClick} />
<RemoveIcon
removeIconTooltipLabel={removeIconTooltipLabel}
removeOwner={handleRemoveClick}
/>
)
)
}
@ -249,14 +253,23 @@ export const SelectableList = ({
);
};
const RemoveIcon = ({ removeOwner }: { removeOwner?: () => void }) => {
const RemoveIcon = ({
removeOwner,
removeIconTooltipLabel,
}: {
removeOwner?: () => void;
removeIconTooltipLabel?: string;
}) => {
const { t } = useTranslation();
return (
<Tooltip
title={t('label.remove-entity', {
entity: t('label.owner-lowercase'),
})}>
title={
removeIconTooltipLabel ??
t('label.remove-entity', {
entity: t('label.owner-lowercase'),
})
}>
<SVGIcons
data-testid="remove-owner"
icon={Icons.ICON_REMOVE_COLORED}

View File

@ -26,4 +26,5 @@ export interface SelectableListProps {
searchPlaceholder?: string;
customTagRenderer?: (props: EntityReference) => ReactNode;
searchBarDataTestId?: string;
removeIconTooltipLabel?: string;
}

View File

@ -23,7 +23,7 @@
align-items: center;
cursor: pointer;
.usename {
.username {
font-weight: 500;
line-height: 21px;
}

View File

@ -43,7 +43,8 @@ type Fields =
| 'serviceType'
| 'displayName'
| 'deleted'
| 'service';
| 'service'
| 'domain';
export type SourceType = (
| Pick<

View File

@ -14,6 +14,7 @@
import { t } from 'i18next';
import { isUndefined } from 'lodash';
import Qs from 'qs';
import { CSSProperties } from 'react';
import { COOKIE_VERSION } from '../components/Modals/WhatsNewModal/whatsNewData';
import { EntityTabs } from '../enums/entity.enum';
import { SearchIndex } from '../enums/search.enum';
@ -835,3 +836,7 @@ export const ICON_DIMENSION = {
with: 14,
height: 14,
};
export const COMMON_ICON_STYLES: CSSProperties = {
verticalAlign: 'middle',
};

View File

@ -112,6 +112,12 @@ export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
sortField: INITIAL_SORT_FIELD,
path: 'containers',
},
[SearchIndex.SEARCH_INDEX]: {
label: i18n.t('label.search-index-plural'),
sortingFields: entitySortingFields,
sortField: INITIAL_SORT_FIELD,
path: 'searchIndexes',
},
[SearchIndex.GLOSSARY]: {
label: i18n.t('label.glossary-plural'),
sortingFields: entitySortingFields,
@ -124,12 +130,6 @@ export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
sortField: INITIAL_SORT_FIELD,
path: 'tags',
},
[SearchIndex.SEARCH_INDEX]: {
label: i18n.t('label.search-index-plural'),
sortingFields: entitySortingFields,
sortField: INITIAL_SORT_FIELD,
path: 'searchIndexes',
},
};
export const COMMON_FILTERS_FOR_DIFFERENT_TABS = [

View File

@ -251,6 +251,7 @@
"data-model-type": "Datenmodelltyp",
"data-product": "Datenprodukt",
"data-product-plural": "Datenprodukte",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Datenverhältnisse",
"data-quality": "Datenqualität",
"data-quality-test": "Datenqualitätstest",
@ -1362,6 +1363,7 @@
"no-data": "Keine Daten",
"no-data-available": "Keine Daten verfügbar.",
"no-data-available-for-selected-filter": "Keine Daten gefunden. Versuchen Sie, die Filter zu ändern.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "Es gibt noch keine Aktivität auf {{entity}}. Starten Sie ein Gespräch, indem Sie auf das",
"no-entity-available-with-name": "Keine {{entity}} mit dem Namen verfügbar",
"no-entity-data-available": "Keine {{entity}}-Daten verfügbar.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Data Model Type",
"data-product": "Data Product",
"data-product-plural": "Data Products",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "Data Quality Test",
@ -1362,6 +1363,7 @@
"no-data": "No data",
"no-data-available": "No data available.",
"no-data-available-for-selected-filter": "No data found. Try changing the filters.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "There is no activity on the {{entity}} yet. Start a conversation by clicking on the",
"no-entity-available-with-name": "No {{entity}} available with name",
"no-entity-data-available": "No {{entity}} data available.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Data Model Type",
"data-product": "Data Product",
"data-product-plural": "Data Products",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "Prueba de calidad de datos",
@ -1362,6 +1363,7 @@
"no-data": "No hay datos",
"no-data-available": "No hay datos disponibles.",
"no-data-available-for-selected-filter": "No se encontraron datos. Intenta cambiar los filtros.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "No hay actividad en {{entity}} todavía. Comienza una conversación haciendo clic en",
"no-entity-available-with-name": "No hay {{entity}} disponible con el nombre",
"no-entity-data-available": "No hay datos disponibles de {{entity}}.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Type de Modèle de Données",
"data-product": "Produit de Données",
"data-product-plural": "Produits de Données",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Proportions des Données",
"data-quality": "Qualité des Données",
"data-quality-test": "Test de Qualité des Données",
@ -1362,6 +1363,7 @@
"no-data": "Aucune donnée",
"no-data-available": "Aucune donnée disponible",
"no-data-available-for-selected-filter": "Aucune donnée trouvée. Essayez de modifier les filtres.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "Il n'y a aucune activité sur {{entity}} pour le moment. Démarrez une conversation en cliquant sur le bouton",
"no-entity-available-with-name": "Aucun {{entity}} disponible avec le nom",
"no-entity-data-available": "Aucun {{entity}} disponible.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Data Model Type",
"data-product": "Data Product",
"data-product-plural": "Data Products",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "データ品質テスト",
@ -1362,6 +1363,7 @@
"no-data": "データがありません",
"no-data-available": "利用できるデータがありません",
"no-data-available-for-selected-filter": "No data found. Try changing the filters.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "There is no activity on the {{entity}} yet. Start a conversation by clicking on the",
"no-entity-available-with-name": "No {{entity}} available with name",
"no-entity-data-available": "No {{entity}} data available.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Data Model Type",
"data-product": "Data Product",
"data-product-plural": "Data Products",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "Teste de qualidade de dados",
@ -1362,6 +1363,7 @@
"no-data": "Nenhum dado",
"no-data-available": "Nenhum dado disponível.",
"no-data-available-for-selected-filter": "Nenhum dado encontrado. Tente alterar os filtros.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "Não há atividade em {{entity}} ainda. Inicie uma conversa clicando em",
"no-entity-available-with-name": "Não há {{entity}} disponível com o nome",
"no-entity-data-available": "Nenhum dado disponível para {{entity}}.",

View File

@ -251,6 +251,7 @@
"data-model-type": "Тип модели данных",
"data-product": "Data Product",
"data-product-plural": "Data Products",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "Распределение данных",
"data-quality": "Качество данных",
"data-quality-test": "Тест качества данных",
@ -1362,6 +1363,7 @@
"no-data": "Нет данных",
"no-data-available": "Данные недоступны.",
"no-data-available-for-selected-filter": "Данные не найдены. Попробуйте поменять фильтры.",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "В {{entity}} пока нет активности. Начните обсуждение, нажав на кнопку",
"no-entity-available-with-name": "Нет доступного {{entity}} с именем",
"no-entity-data-available": "Данные {{entity}} недоступны.",

View File

@ -251,6 +251,7 @@
"data-model-type": "数据模型类型",
"data-product": "数据产品",
"data-product-plural": "数据产品",
"data-profiler-metrics": "Data Profiler Metrics",
"data-proportion-plural": "数据比例",
"data-quality": "数据质控",
"data-quality-test": "数据质控测试",
@ -1362,6 +1363,7 @@
"no-data": "没有数据",
"no-data-available": "没有可用的数据",
"no-data-available-for-selected-filter": "未找到数据,请尝试更改筛选条件",
"no-domain-assigned-to-entity": "No Domains are Assigned to {{entity}}",
"no-entity-activity-message": "{{entity}}上还没有任何活动,单击开始对话",
"no-entity-available-with-name": "名称为{{entity}}不可用",
"no-entity-data-available": "没有可用的{{entity}}数据。",

View File

@ -738,3 +738,10 @@ a[href].link-text-grey,
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.app-bar-user-avatar {
display: inline-block;
height: 36px;
width: 36px;
border-radius: 50%;
}

View File

@ -65,3 +65,7 @@ button {
.ant-btn-group .ant-btn-primary:first-child:not(:last-child) {
border-right-color: #ffffff;
}
.ant-btn-primary {
box-shadow: none;
}

View File

@ -95,6 +95,9 @@
.w-max-90 {
max-width: 90%;
}
.w-max-112 {
max-width: 112px;
}
.w-max-200 {
max-width: 200px;
}

View File

@ -34,15 +34,15 @@ import React from 'react';
import { ListItem } from 'react-awesome-query-builder';
import { LegendProps, Surface } from 'recharts';
import { SearchDropdownOption } from '../components/SearchDropdown/SearchDropdown.interface';
import {
ENTITIES_SUMMARY_LIST,
WEB_SUMMARY_LIST,
} from '../constants/DataInsight.constants';
import {
GRAYED_OUT_COLOR,
PLACEHOLDER_ROUTE_TAB,
ROUTES,
} from '../constants/constants';
import {
ENTITIES_SUMMARY_LIST,
WEB_SUMMARY_LIST,
} from '../constants/DataInsight.constants';
import { KpiTargetType } from '../generated/api/dataInsight/kpi/createKpiRequest';
import {
DataInsightChartResult,

View File

@ -180,15 +180,6 @@ export const getGlobalSettingsMenuWithPermission = (
key: 'services.mlModels',
icon: <MlModelIcon className="side-panel-icons" />,
},
{
label: i18next.t('label.metadata'),
isProtected: userPermissions.hasViewPermissions(
ResourceEntity.METADATA_SERVICE,
permissions
),
key: 'services.metadata',
icon: <OMLogo className="side-panel-icons w-4 h-4" />,
},
{
label: i18next.t('label.storage-plural'),
isProtected: userPermissions.hasViewPermissions(
@ -207,6 +198,15 @@ export const getGlobalSettingsMenuWithPermission = (
key: 'services.search',
icon: <SearchOutlined className="side-panel-icons w-4 h-4" />,
},
{
label: i18next.t('label.metadata'),
isProtected: userPermissions.hasViewPermissions(
ResourceEntity.METADATA_SERVICE,
permissions
),
key: 'services.metadata',
icon: <OMLogo className="side-panel-icons w-4 h-4" />,
},
],
},