fix(ui): persona page feedbacks & customize page improvements (#20631)

* fix(ui): persona and customize page issues

* improve customize page for entities

* fix icons for domain and glossary customization

* organize widgets function with class base approach

* fix type error

* update expand collapse button on tab

* update expand collapse icon for tabs
This commit is contained in:
Chirag Madlani 2025-04-05 17:53:25 +05:30 committed by GitHub
parent 91c411e0e5
commit a67b8ad716
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
89 changed files with 1252 additions and 487 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

View File

@ -0,0 +1,5 @@
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6468 10.0007V6.00065C14.6468 2.66732 13.3135 1.33398 9.98014 1.33398H5.98014C2.64681 1.33398 1.31348 2.66732 1.31348 6.00065V10.0007C1.31348 13.334 2.64681 14.6673 5.98014 14.6673H9.98014C13.3135 14.6673 14.6468 13.334 14.6468 10.0007Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.97998 1.33398V14.6673" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.31348 6.29297L7.02014 7.99964L5.31348 9.7063" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 661 B

View File

@ -288,7 +288,9 @@ const APIEndpointDetails: React.FC<APIEndpointDetailsProps> = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -330,7 +330,6 @@ export const CustomizeTabWidget = () => {
newWidgetData,
placeholderWidgetKey,
widgetSize,
TAB_GRID_MAX_COLUMNS,
currentPageType as PageType
)
);
@ -382,7 +381,7 @@ export const CustomizeTabWidget = () => {
}
title={t('label.customize-tab-plural')}>
<DndProvider backend={HTML5Backend}>
<Space wrap size={16}>
<div className="d-flex flex-wrap gap-4">
{items.map((item, index) => (
<TabItem
index={index}
@ -419,7 +418,7 @@ export const CustomizeTabWidget = () => {
</Button>
</Dropdown>
))}
</Space>
</div>
</DndProvider>
</Card>
</Col>

View File

@ -37,7 +37,16 @@
border: 1px solid @blue-15;
box-shadow: 0px 0px 0px 4px @grey-10;
box-shadow: 0px 1px 2px 0px #0a0d120d;
}
}
.ant-tabs.ant-tabs-top.tabs-new {
.grid-container > #KnowledgePanel\.LeftPanel {
// Let it's content take the height
height: initial !important;
}
.grid-container > #KnowledgePanel\.DomainType {
height: initial !important;
}
}

View File

@ -52,7 +52,11 @@ import TableTags from '../../Database/TableTags/TableTags.component';
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
import { ChartsPermissions } from '../DashboardDetails/DashboardDetails.interface';
export const DashboardChartTable = () => {
export const DashboardChartTable = ({
isCustomizationPage = false,
}: {
isCustomizationPage?: boolean;
}) => {
const { t } = useTranslation();
const { getEntityPermission } = usePermissionProvider();
const { onThreadLinkSelect } = useGenericContext<Dashboard>();
@ -78,7 +82,7 @@ export const DashboardChartTable = () => {
);
return chartPermission;
} catch (error) {
} catch {
return DEFAULT_ENTITY_PERMISSION;
}
}, []);
@ -390,8 +394,14 @@ export const DashboardChartTable = () => {
);
useEffect(() => {
if (isCustomizationPage) {
setCharts(listChartIds as unknown as ChartType[]);
return;
}
initializeCharts();
}, [listChartIds]);
}, [listChartIds, isCustomizationPage]);
if (isEmpty(charts)) {
return <ErrorPlaceHolder />;

View File

@ -319,7 +319,9 @@ const DashboardDetails = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -256,7 +256,9 @@ const DataModelDetails = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -538,7 +538,11 @@ export const DataAssetsHeader = ({
className="data-assets-header-container"
data-testid="data-assets-header"
gutter={[0, 20]}>
<Col className="d-flex flex-col gap-3" span={24}>
<Col
className={classNames('d-flex flex-col gap-3 ', {
'p-l-xs': isCustomizedView,
})}
span={24}>
<TitleBreadcrumb
loading={isBreadcrumbLoading}
titleLinks={breadcrumbs.map((link) =>

View File

@ -287,6 +287,7 @@ export const DatabaseSchemaTable = ({
useEffect(() => {
if (isCustomizationPage) {
setSchemas(DATABASE_SCHEMAS_DUMMY_DATA);
setIsLoading(false);
return;
}

View File

@ -730,7 +730,9 @@ const DomainDetailsPage = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -10,18 +10,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Button, Card, Tooltip, Typography } from 'antd';
import { Card, Typography } from 'antd';
import classNames from 'classnames';
import { t } from 'i18next';
import { cloneDeep, includes, isEqual } from 'lodash';
import { default as React, useMemo } from 'react';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import { ReactComponent as PlusIcon } from '../../../assets/svg/plus-primary.svg';
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
import { TabSpecificField } from '../../../enums/entity.enum';
import { Domain } from '../../../generated/entity/domains/domain';
import { EntityReference } from '../../../generated/tests/testCase';
import { getOwnerVersionLabel } from '../../../utils/EntityVersionUtils';
import { EditIconButton } from '../../common/IconButtons/EditIconButton';
import TagButton from '../../common/TagButton/TagButton.component';
import { UserSelectableList } from '../../common/UserSelectableList/UserSelectableList.component';
import { useGenericContext } from '../../Customization/GenericProvider/GenericProvider';
@ -63,10 +62,7 @@ export const DomainExpertWidget = ({ newLook }: { newLook?: boolean }) => {
};
const header = (
<div
className={`d-flex items-center ${
domain.experts && domain.experts.length > 0 ? 'm-b-xss' : ''
}`}>
<div className={`d-flex items-center gap-2 `}>
<Typography.Text
className={classNames({
'text-sm font-medium': newLook,
@ -81,18 +77,14 @@ export const DomainExpertWidget = ({ newLook }: { newLook?: boolean }) => {
popoverProps={{ placement: 'topLeft' }}
selectedUsers={domain.experts ?? []}
onUpdate={handleExpertsUpdate}>
<Tooltip
<EditIconButton
data-testid="edit-expert-button"
newLook={newLook}
size="small"
title={t('label.edit-entity', {
entity: t('label.expert-plural'),
})}>
<Button
className="cursor-pointer flex-center m-l-xss"
data-testid="edit-expert-button"
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
size="small"
type="text"
/>
</Tooltip>
})}
/>
</UserSelectableList>
)}
</div>

View File

@ -10,16 +10,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Button, Card, Col, Space, Tooltip, Typography } from 'antd';
import { Card, Col, Space, Typography } from 'antd';
import classNames from 'classnames';
import { t } from 'i18next';
import { cloneDeep } from 'lodash';
import React, { useMemo, useState } from 'react';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
import { Domain, DomainType } from '../../../generated/entity/domains/domain';
import { domainTypeTooltipDataRender } from '../../../utils/DomainUtils';
import FormItemLabel from '../../common/Form/FormItemLabel';
import { EditIconButton } from '../../common/IconButtons/EditIconButton';
import { useGenericContext } from '../../Customization/GenericProvider/GenericProvider';
import DomainTypeSelectForm from '../DomainTypeSelectForm/DomainTypeSelectForm.component';
@ -49,10 +48,7 @@ export const DomainTypeWidget = ({
};
const header = (
<div
className={classNames('d-flex items-center ', {
'm-b-xss': !newLook,
})}>
<div className={classNames('d-flex items-center gap-2')}>
<Typography.Text
className="right-panel-label"
data-testid="domainType-heading-name">
@ -66,19 +62,15 @@ export const DomainTypeWidget = ({
</Typography.Text>
{editAllPermission && domain.domainType && (
<Tooltip
<EditIconButton
data-testid="edit-domainType-button"
newLook={newLook}
size="small"
title={t('label.edit-entity', {
entity: t('label.domain-type'),
})}>
<Button
className="cursor-pointer flex-center m-l-xss"
data-testid="edit-domainType-button"
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
size="small"
type="text"
onClick={() => setEditDomainType(true)}
/>
</Tooltip>
})}
onClick={() => setEditDomainType(true)}
/>
)}
</div>
);

View File

@ -176,7 +176,7 @@ const GlossaryDetails = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={isTabExpanded ? t('label.collapse') : t('label.expand')}
onClick={toggleTabExpanded}
/>
)

View File

@ -386,7 +386,9 @@ const GlossaryTermsV1 = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -276,7 +276,9 @@ const MetricDetails: React.FC<MetricDetailsProps> = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -17,11 +17,7 @@ import { isEmpty } from 'lodash';
import React, { FC, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import {
DE_ACTIVE_COLOR,
NO_DATA_PLACEHOLDER,
} from '../../../constants/constants';
import { NO_DATA_PLACEHOLDER } from '../../../constants/constants';
import { TAG_CONSTANT, TAG_START_WITH } from '../../../constants/Tag.constants';
import { Metric } from '../../../generated/entity/data/metric';
import { EntityReference } from '../../../generated/type/entityReference';
@ -29,6 +25,7 @@ import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEntityIcon } from '../../../utils/TableUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
import { EditIconButton } from '../../common/IconButtons/EditIconButton';
import { useGenericContext } from '../../Customization/GenericProvider/GenericProvider';
import { DataAssetOption } from '../../DataAssets/DataAssetAsyncSelectList/DataAssetAsyncSelectList.interface';
import TagsV1 from '../../Tag/TagsV1/TagsV1.component';
@ -170,12 +167,10 @@ const RelatedMetrics: FC<RelatedMetricsProps> = ({
!isEmpty(relatedMetrics) &&
permissions.EditAll &&
!metricDetails.deleted && (
<EditIcon
className="cursor-pointer"
color={DE_ACTIVE_COLOR}
<EditIconButton
data-testid="edit-related-metrics"
style={{ verticalAlign: 'middle' }}
width="14px"
newLook={newLook}
size="small"
onClick={() => setIsEdit(true)}
/>
)}

View File

@ -416,7 +416,9 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -25,6 +25,9 @@ import {
} from 'antd';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PageType } from '../../../../generated/system/ui/page';
import { useCustomizeStore } from '../../../../pages/CustomizablePage/CustomizeStore';
import customizeDetailPageClassBase from '../../../../utils/CustomizeDetailPage/CustomizeDetailPageClassBase';
import customizePageClassBase from '../../../../utils/CustomizeMyDataPageClassBase';
import { AddWidgetTabContentProps } from './AddWidgetModal.interface';
@ -38,20 +41,33 @@ function AddWidgetTabContent({
const [selectedWidgetSize, setSelectedWidgetSize] = useState<number>(
widgetSizeOptions[0].value
);
const { currentPageType } = useCustomizeStore();
const widgetAddable = useMemo(
() => selectedWidgetSize <= maxGridSizeSupport,
[selectedWidgetSize, maxGridSizeSupport]
);
const widgetImage = useMemo(
() =>
customizePageClassBase.getWidgetImageFromKey(
widget.fullyQualifiedName,
selectedWidgetSize
),
[widget, selectedWidgetSize]
);
const widgetImage = useMemo(() => {
switch (currentPageType) {
case PageType.Glossary:
case PageType.GlossaryTerm:
return customizeDetailPageClassBase.getGlossaryWidgetImageFromKey(
widget.fullyQualifiedName,
selectedWidgetSize
);
case PageType.LandingPage:
return customizePageClassBase.getWidgetImageFromKey(
widget.fullyQualifiedName,
selectedWidgetSize
);
default:
return customizeDetailPageClassBase.getDetailPageWidgetImageFromKey(
widget.fullyQualifiedName,
selectedWidgetSize
);
}
}, [widget, selectedWidgetSize, currentPageType]);
const handleSizeChange = useCallback((e: RadioChangeEvent) => {
setSelectedWidgetSize(e.target.value);

View File

@ -358,7 +358,9 @@ const PipelineDetails = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -61,7 +61,7 @@ export const CustomizeUI = () => {
}, [activeCat]);
return (
<Row gutter={[16, 16]}>
<Row className="bg-grey" gutter={[16, 16]}>
{items.map((value) => (
<Col key={value.key} span={8}>
<SettingItemCard data={value} onClick={handleCustomizeItemClick} />

View File

@ -280,6 +280,7 @@ const TagsContainerV2 = ({
{!isEmpty(tags?.[tagType]) && !isEditTags && (
<EditIconButton
data-testid="edit-button"
newLook={newLook}
size="small"
title={t('label.edit-entity', {
entity:

View File

@ -422,7 +422,9 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -16,7 +16,7 @@ import classNames from 'classnames';
import React from 'react';
import { ReactComponent as CommentIcon } from '../../../assets/svg/comment.svg';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import { ReactComponent as AlignRightIcon } from '../../../assets/svg/ic-align-right.svg';
import { ReactComponent as ExpandIcon } from '../../../assets/svg/ic-expand-right.svg';
import { ReactComponent as RequestIcon } from '../../../assets/svg/request-icon.svg';
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
@ -116,9 +116,10 @@ export const AlignRightIconButton = ({
return (
<Tooltip title={title}>
<Button
className={classNames('bordered', className)}
icon={<AlignRightIcon />}
className={classNames('border-none tab-expand-icon', className)}
icon={<ExpandIcon />}
size={size}
type="text"
{...props}
/>
</Tooltip>

View File

@ -13,6 +13,7 @@
import {
Dashboard,
DashboardServiceType,
DashboardType,
} from '../generated/entity/data/dashboard';
import {
DashboardDataModel,
@ -112,31 +113,42 @@ export const DASHBOARD_DATA_MODEL_DUMMY_DATA: DashboardDataModel = {
};
export const DASHBOARD_DUMMY_DATA: Dashboard = {
id: '574c383c-735f-44c8-abbb-355f87c8b19f',
name: 'customers',
displayName: 'Customers dashboard',
fullyQualifiedName: 'SampleLookerService.customers',
description: 'This is a sample Dashboard for Looker',
id: '21dd6360-d1f2-4810-8759-6ab92c4f033e',
name: '31',
displayName: 'Sales Dashboard',
fullyQualifiedName: 'sample_superset.31',
description: '',
version: 0.1,
updatedAt: 1736493713236,
updatedAt: 1743682276991,
updatedBy: 'admin',
dashboardType: DashboardType.Dashboard,
sourceUrl: 'http://localhost:808/superset/dashboard/6/',
charts: [
{
id: '81cdc1f3-66ae-462f-bf3e-b5fbbfe7792f',
id: '7c3d1e8f-82f0-44c2-a00a-d721c0b88eb1',
type: 'chart',
name: 'chart_1',
fullyQualifiedName: 'SampleLookerService.chart_1',
description: 'This is a sample Chart for Looker',
displayName: 'Chart 1',
name: '117',
fullyQualifiedName: 'sample_superset.117',
description: '',
displayName: 'Age distribution of respondents',
deleted: false,
},
{
id: '6f5057aa-8d7c-41a7-ab93-76bf8ed2bc27',
id: 'be02ba8d-3935-48aa-8daa-ef5e7ecb3534',
type: 'chart',
name: 'chart_2',
fullyQualifiedName: 'SampleLookerService.chart_2',
description: 'This is a sample Chart for Looker',
displayName: 'Chart 2',
name: '166',
fullyQualifiedName: 'sample_superset.166',
description: '',
displayName: '% Rural',
deleted: false,
},
{
id: '9b94f5fd-b16f-4d24-8ed5-60a9b67057ae',
type: 'chart',
name: '92',
fullyQualifiedName: 'sample_superset.92',
description: '',
displayName: '✈️ Relocation ability',
deleted: false,
},
],
@ -144,14 +156,14 @@ export const DASHBOARD_DUMMY_DATA: Dashboard = {
followers: [],
tags: [],
service: {
id: 'fb4df3ed-75b9-45d3-a2df-da07785893d7',
id: '917a8613-8398-48e7-95dd-5e6c57027cc2',
type: 'dashboardService',
name: 'SampleLookerService',
fullyQualifiedName: 'SampleLookerService',
displayName: 'SampleLookerService',
name: 'sample_superset',
fullyQualifiedName: 'sample_superset',
displayName: 'sample_superset',
deleted: false,
},
serviceType: DashboardServiceType.Looker,
serviceType: DashboardServiceType.Superset,
usageSummary: {
dailyStats: {
count: 0,
@ -165,7 +177,7 @@ export const DASHBOARD_DUMMY_DATA: Dashboard = {
count: 0,
percentileRank: 0,
},
date: new Date('2025-02-03'),
date: new Date('2025-04-03'),
},
deleted: false,
dataProducts: [],

View File

@ -1,3 +1,4 @@
/* eslint-disable max-len */
/*
* Copyright 2025 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,6 +16,7 @@ import {
DatabaseServiceType,
} from '../generated/entity/data/database';
import { DatabaseSchema } from '../generated/entity/data/databaseSchema';
import { Table, TableType } from '../generated/entity/data/table';
export const DATABASE_DUMMY_DATA: Database = {
id: '77147d45-888b-42dd-a369-8b7ba882dffb',
@ -195,3 +197,605 @@ export const DATABASE_SCHEMA_DUMMY_DATA: DatabaseSchema = {
],
},
};
export const DUMMY_DATABASE_SCHEMA_TABLES_DETAILS: Table[] = [
{
id: '56e2399d-b968-4eed-b705-8ff287800e93',
name: 'dim___reserved__colon____reserved__arrow__address',
fullyQualifiedName:
'sample_data.ecommerce_db.shopify.dim___reserved__colon____reserved__arrow__address',
description:
'This dimension table contains the billing and shipping addresses of customers. You can join this table with the sales table to generate lists of the billing and shipping addresses. Customers can enter their addresses more than once, so the same address can appear in more than one row in this table. This table contains one row per customer address.',
version: 0.1,
updatedAt: 1743682266125,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_::>address',
processedLineage: false,
},
{
id: '3cc7cd6f-5b31-4d6c-8eae-c05fd2fac51e',
name: 'dim_address',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_address',
description:
'This dimension table contains the billing and shipping addresses of customers. You can join this table with the sales table to generate lists of the billing and shipping addresses. Customers can enter their addresses more than once, so the same address can appear in more than one row in this table. This table contains one row per customer address.',
version: 0.3,
updatedAt: 1743727722854,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_address',
lifeCycle: {
created: {
timestamp: 1743724800000,
accessedBy: {
id: 'd1b44eb0-03e2-4031-9834-0fd534895e1a',
type: 'user',
fullyQualifiedName: 'admin',
},
},
},
processedLineage: false,
},
{
id: '6be0133e-033e-4582-b779-ed65b8fe9a92',
name: 'dim_address_clean',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_address_clean',
description: 'Created from dim_address after a small cleanup.',
version: 0.5,
updatedAt: 1743741484432,
updatedBy: 'admin',
tableType: TableType.View,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_address_clean',
lifeCycle: {
created: {
timestamp: 1743724800000,
accessedBy: {
id: 'd1b44eb0-03e2-4031-9834-0fd534895e1a',
type: 'user',
fullyQualifiedName: 'admin',
},
},
updated: {
timestamp: 1738981540085,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1738981540085,
accessedByAProcess: 'Charlie',
},
},
processedLineage: false,
},
{
id: 'e5977bd7-9cd8-489c-9fb9-837df00516a3',
name: 'dim_customer',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_customer',
description:
'The dimension table contains data about your customers. The customers table contains one row per customer. It includes historical metrics (such as the total amount that each customer has spent in your store) as well as forward-looking metrics (such as the predicted number of days between future orders and the expected order value in the next 30 days). This table also includes columns that segment customers into various categories (such as new, returning, promising, at risk, dormant, and loyal), which you can use to target marketing activities.',
version: 0.4,
updatedAt: 1743733539305,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_customer',
lifeCycle: {
created: {
timestamp: 1743128739254,
accessedByAProcess: 'Alice',
},
updated: {
timestamp: 1743215139254,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1743724800000,
},
},
processedLineage: false,
},
{
id: '3ce4008f-a1f9-43a9-b768-94c3261b3ec2',
name: 'dim_location',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_location',
description:
'The dimension table contains metrics about your Shopify POS. This table contains one row per Shopify POS location. You can use this table to generate a list of the Shopify POS locations or you can join the table with the sales table to measure sales performance.',
version: 0.3,
updatedAt: 1743733539457,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_location',
lifeCycle: {
created: {
timestamp: 1743387939421,
accessedBy: {
id: 'ef635c2e-e2ad-4cbd-bb52-9e58e33b1454',
type: 'user',
fullyQualifiedName: 'anthony_wall4',
},
},
updated: {
timestamp: 1743387939421,
accessedByAProcess: 'Alice',
},
accessed: {
timestamp: 1743387939421,
accessedByAProcess: 'David',
},
},
processedLineage: false,
},
{
id: '342708c8-5d87-4337-8861-873852a95cd7',
name: 'dim_staff',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_staff',
description:
'This dimension table contains information about the staff accounts in the store. It contains one row per staff account. Use this table to generate a list of your staff accounts, or join it with the sales, API clients and locations tables to analyze staff performance at Shopify POS locations.',
version: 0.3,
updatedAt: 1743733539520,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim_staff',
lifeCycle: {
created: {
timestamp: 1743560739487,
accessedByAProcess: 'Alice',
},
updated: {
timestamp: 1743560739487,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1743560739487,
accessedByAProcess: 'Charlie',
},
},
processedLineage: false,
},
{
id: '85925869-62a0-4f91-b028-53f3d101ecac',
name: 'dim.api/client',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify."dim.api/client"',
description:
'This dimension table contains a row for each channel or app that your customers use to create orders. Some examples of these include Facebook and Online Store. You can join this table with the sales table to measure channel performance.',
version: 0.1,
updatedAt: 1743682268010,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim.api/client',
processedLineage: false,
},
{
id: 'b3077b79-5e31-4c6c-b614-baa08b2c4905',
name: 'dim.product',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify."dim.product"',
description:
'This dimension table contains information about each of the products in your store. This table contains one row per product. This table reflects the current state of products in your Shopify admin.',
version: 0.3,
updatedAt: 1743733540050,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim.product',
lifeCycle: {
created: {
timestamp: 1739413540011,
accessedByAProcess: 'Alice',
},
updated: {
timestamp: 1739413540011,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1739499940011,
accessedByAProcess: 'Charlie',
},
},
processedLineage: false,
},
{
id: '927cd0c9-8de3-4690-b754-d85ba62c4876',
name: 'dim.product.variant',
fullyQualifiedName:
'sample_data.ecommerce_db.shopify."dim.product.variant"',
description:
'This dimension table contains current information about each of the product variants in your store. This table contains one row per product variant.',
version: 0.3,
updatedAt: 1743733539605,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
changeDescription: {
fieldsAdded: [],
fieldsUpdated: [
{
name: 'lifeCycle',
oldValue:
'{"created":{"timestamp":1743250301180,"accessedByAProcess":"Alice"},"updated":{"timestamp":1743336701180,"accessedByAProcess":"Bob"},"accessed":{"timestamp":1743423101180,"accessedByAProcess":"Charlie"}}',
newValue:
'{"created":{"timestamp":1743301539583,"accessedByAProcess":"Alice"},"updated":{"timestamp":1743387939583,"accessedByAProcess":"Bob"},"accessed":{"timestamp":1743474339583,"accessedByAProcess":"Charlie"}}',
},
],
fieldsDeleted: [],
previousVersion: 0.2,
changeSummary: {},
},
incrementalChangeDescription: {
fieldsAdded: [],
fieldsUpdated: [
{
name: 'lifeCycle',
oldValue:
'{"created":{"timestamp":1743250301180,"accessedByAProcess":"Alice"},"updated":{"timestamp":1743336701180,"accessedByAProcess":"Bob"},"accessed":{"timestamp":1743423101180,"accessedByAProcess":"Charlie"}}',
newValue:
'{"created":{"timestamp":1743301539583,"accessedByAProcess":"Alice"},"updated":{"timestamp":1743387939583,"accessedByAProcess":"Bob"},"accessed":{"timestamp":1743474339583,"accessedByAProcess":"Charlie"}}',
},
],
fieldsDeleted: [],
previousVersion: 0.2,
changeSummary: {},
},
deleted: false,
sourceUrl: 'http://localhost:8080/dim.product.variant',
lifeCycle: {
created: {
timestamp: 1743301539583,
accessedByAProcess: 'Alice',
},
updated: {
timestamp: 1743387939583,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1743474339583,
accessedByAProcess: 'Charlie',
},
},
processedLineage: false,
},
{
id: '561ea446-6e47-4d51-843a-31a9b7e16b04',
name: 'dim.shop',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify."dim.shop"',
description:
'This dimension table contains online shop information. This table contains one shop per row.',
version: 0.3,
updatedAt: 1743733540213,
updatedBy: 'admin',
tableType: TableType.Regular,
columns: [],
databaseSchema: {
id: '31a0a37b-f547-4264-835f-45424e417dbd',
type: 'databaseSchema',
name: 'shopify',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify',
description:
'This **mock** database contains schema related to shopify sales and orders with related dimension tables.',
displayName: 'shopify',
deleted: false,
},
database: {
id: '35a624d9-1355-4226-8664-3e503313301e',
type: 'database',
name: 'ecommerce_db',
fullyQualifiedName: 'sample_data.ecommerce_db',
description:
'This **mock** database contains schemas related to shopify sales and orders with related dimension tables.',
displayName: 'ecommerce_db',
deleted: false,
},
service: {
id: 'cda79445-9e98-4e2e-8e73-38a4f0d794c8',
type: 'databaseService',
name: 'sample_data',
fullyQualifiedName: 'sample_data',
displayName: 'sample_data',
deleted: false,
},
serviceType: DatabaseServiceType.BigQuery,
deleted: false,
sourceUrl: 'http://localhost:8080/dim.shop',
lifeCycle: {
created: {
timestamp: 1737685540191,
accessedByAProcess: 'Alice',
},
updated: {
timestamp: 1738463140191,
accessedByAProcess: 'Bob',
},
accessed: {
timestamp: 1738376740191,
accessedByAProcess: 'Charlie',
},
},
processedLineage: false,
},
];

View File

@ -0,0 +1,118 @@
/* eslint-disable max-len */
/*
* Copyright 2025 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 {
LabelType,
Language,
Metric,
MetricGranularity,
MetricType,
State,
TagSource,
UnitOfMeasurement,
} from '../generated/entity/data/metric';
export const METRIC_DUMMY_DATA: Metric = {
id: '60c367be-a3d0-492a-b7be-8e38c970e0a7',
name: 'Engagement Rate',
fullyQualifiedName: 'Engagement Rate',
description:
'The **Engagement Rate** measures how actively your audience is interacting with your content, usually in the form of likes, comments, and shares.\n\n$$latex\n\\text{Engagement Rate} = \\left( \\frac{\\text{Engagements (Likes, Comments, Shares)}}{\\text{Total Followers or Views}} \\right) \\times 100\n$$\n\n👆this is the basic formula used internally. You can follow this to reimplement it in a different language',
metricExpression: {
language: Language.Python,
code: 'def calculate_engagement_rate(total_engagements, total_views):\n if total_views <= 0:\n raise ValueError("Total views or followers must be greater than 0.")\n return (total_engagements / total_views) * 100\n',
},
metricType: MetricType.Percentage,
unitOfMeasurement: UnitOfMeasurement.Percentage,
granularity: MetricGranularity.Year,
relatedMetrics: [
{
id: 'aa80b81d-c033-4cb4-b00c-3adbf6ec5cd5',
type: 'metric',
name: 'Conversion Rate',
fullyQualifiedName: 'Conversion Rate',
displayName: 'Conversion Rate',
deleted: false,
},
{
id: '0b50f3d1-d906-4027-b687-f533b19aadce',
type: 'metric',
name: 'Gross Profit Margin',
fullyQualifiedName: 'Gross Profit Margin',
displayName: 'Gross Profit Margin',
deleted: false,
},
],
version: 0.6,
owners: [
{
id: 'ab85a6ee-379a-4d44-8fa6-beddbd158809',
type: 'team',
name: 'Marketing',
fullyQualifiedName: 'Marketing',
description: '',
displayName: 'Marketing',
deleted: false,
},
],
followers: [],
tags: [
{
tagFQN: 'Customer Success.Annual Business Review',
name: 'Annual Business Review',
displayName: 'Annual Business Review (ABR)',
description: 'Annual Business Review',
style: {},
source: TagSource.Glossary,
labelType: LabelType.Manual,
state: State.Confirmed,
},
{
tagFQN: 'Tier.Tier2',
name: 'Tier2',
description:
'**Important business datasets for your company (not as critical as Tier 1)**\n\n- Used in important business metrics, product metrics, and dashboards to drive internal decisions\n\n- Used in important compliance reporting to major regulators, govt entities, and third party\n\n- Used for less critical online user-facing experiences (user activity, user behavior)\n\n- Source used to derive other critical Tier-2 datasets',
source: TagSource.Classification,
labelType: LabelType.Manual,
state: State.Confirmed,
},
],
changeDescription: {
fieldsAdded: [],
fieldsUpdated: [
{
name: 'granularity',
oldValue: 'QUARTER',
newValue: 'YEAR',
},
],
fieldsDeleted: [],
previousVersion: 0.5,
},
deleted: false,
domain: {
id: '635cf2af-5175-44e4-91f1-030beab290d5',
type: 'domain',
name: 'Marketing',
fullyQualifiedName: 'Marketing',
description: 'Marketing',
displayName: 'Marketing',
},
dataProducts: [],
votes: {
upVotes: 0,
downVotes: 0,
upVoters: [],
downVoters: [],
},
};

View File

@ -1,48 +0,0 @@
/*
* Copyright 2025 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 {
Language,
Metric,
MetricGranularity,
MetricType,
UnitOfMeasurement,
} from '../generated/entity/data/metric';
export const METRIC_DUMMY_DATA: Metric = {
id: '2be869f2-a8c6-4781-89fa-df45d671e449',
name: 'LTV',
fullyQualifiedName: 'LTV',
displayName: 'Lifetime Value',
metricExpression: {
language: Language.Python,
code: 'def ltv(customer: Customer, orders: List[Order]):\n\tlifetime = customer.lifetime\n ltv: float = sum([o.amount for o in orders if o.customer_id == customer.id])\n \n return ltv',
},
metricType: MetricType.Other,
unitOfMeasurement: UnitOfMeasurement.Dollars,
granularity: MetricGranularity.Quarter,
relatedMetrics: [],
version: 0.1,
updatedAt: 1727366423816,
updatedBy: 'teddy',
owners: [],
followers: [],
tags: [],
deleted: false,
dataProducts: [],
votes: {
upVotes: 0,
downVotes: 0,
upVoters: [],
downVoters: [],
},
};

View File

@ -519,7 +519,9 @@ const APICollectionPage: FunctionComponent = () => {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -581,7 +581,10 @@ const ContainerPage = () => {
tabBarExtraContent={
isExpandViewSupported && (
<AlignRightIconButton
size="small"
className={isTabExpanded ? 'rotate-180' : ''}
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -11,9 +11,9 @@
* limitations under the License.
*/
import { Col, Row } from 'antd';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import gridBgImg from '../../assets/img/grid-bg-img.png';
import { ReactComponent as DomainIcon } from '../../assets/svg/ic-domain.svg';
import { CustomizeTabWidget } from '../../components/Customization/CustomizeTabWidget/CustomizeTabWidget';
import { EntityHeader } from '../../components/Entity/EntityHeader/EntityHeader.component';
@ -31,6 +31,7 @@ import { getEntityName } from '../../utils/EntityUtils';
import Fqn from '../../utils/Fqn';
import { getDomainPath } from '../../utils/RouterUtils';
import { useCustomizeStore } from '../CustomizablePage/CustomizeStore';
import '../CustomizeDetailsPage/customize-details-page.less';
const CustomizableDomainPage = ({
personaDetails,
@ -79,36 +80,38 @@ const CustomizableDomainPage = ({
return (
<PageLayoutV1
mainContainerClassName="p-t-0"
pageContainerStyle={{
backgroundImage: `url(${gridBgImg})`,
}}
className="bg-grey"
pageTitle={t('label.customize-entity', {
entity: t('label.domain'),
})}>
<CustomizablePageHeader
personaName={getEntityName(personaDetails)}
onReset={handleReset}
onSave={handleSave}
/>
<div className="m-md">
<EntityHeader
breadcrumb={breadcrumbs}
entityData={entityDummyData}
entityType={EntityType.DOMAIN}
icon={
<DomainIcon
className="align-middle"
color={DE_ACTIVE_COLOR}
height={36}
name="folder"
width={32}
/>
}
serviceName=""
/>
</div>
<CustomizeTabWidget />
<Row className="customize-details-page" gutter={[0, 20]}>
<Col span={24}>
<CustomizablePageHeader
personaName={getEntityName(personaDetails)}
onReset={handleReset}
onSave={handleSave}
/>
</Col>
<Col className="p-l-xs" span={24}>
<EntityHeader
breadcrumb={breadcrumbs}
entityData={entityDummyData}
entityType={EntityType.DOMAIN}
icon={
<DomainIcon
className="align-middle"
color={DE_ACTIVE_COLOR}
height={36}
name="folder"
width={32}
/>
}
serviceName=""
/>
</Col>
{/* It will render cols inside the row */}
<CustomizeTabWidget />
</Row>
</PageLayoutV1>
);
};

View File

@ -497,7 +497,9 @@ const DatabaseDetails: FunctionComponent = () => {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -569,7 +569,9 @@ const DatabaseSchemaPage: FunctionComponent = () => {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -30,6 +30,7 @@ import {
INITIAL_TABLE_FILTERS,
PAGE_SIZE,
} from '../../constants/constants';
import { DUMMY_DATABASE_SCHEMA_TABLES_DETAILS } from '../../constants/Database.constants';
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
import { ERROR_PLACEHOLDER_TYPE } from '../../enums/common.enum';
import { EntityType } from '../../enums/entity.enum';
@ -51,10 +52,12 @@ import { showErrorToast } from '../../utils/ToastUtils';
interface SchemaTablesTabProps {
isVersionView?: boolean;
isCustomizationPage?: boolean;
}
function SchemaTablesTab({
isVersionView = false,
isCustomizationPage = false,
}: Readonly<SchemaTablesTabProps>) {
const { t } = useTranslation();
const history = useHistory();
@ -103,7 +106,7 @@ function SchemaTablesTab({
}
const updatedData = {
...tableDetails,
displayName: data.displayName || undefined,
displayName: data.displayName,
};
const jsonPatch = compare(tableDetails, updatedData);
const response = await patchTableDetails(tableDetails.id, jsonPatch);
@ -213,6 +216,12 @@ function SchemaTablesTab({
};
useEffect(() => {
if (isCustomizationPage) {
setTableData(DUMMY_DATABASE_SCHEMA_TABLES_DETAILS);
setTableDataLoading(false);
return;
}
if (viewDatabaseSchemaPermission && decodedDatabaseSchemaFQN) {
if (pagingCursor?.cursorData?.cursorType) {
// Fetch data if cursorType is present in state with cursor Value to handle browser back navigation
@ -229,8 +238,8 @@ function SchemaTablesTab({
tableFilters.showDeletedTables,
decodedDatabaseSchemaFQN,
viewDatabaseSchemaPermission,
pageSize,
isCustomizationPage,
]);
useEffect(() => {

View File

@ -575,7 +575,9 @@ function SearchIndexDetailsPage() {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -581,7 +581,9 @@ const StoredProcedurePage = () => {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -822,7 +822,9 @@ const TableDetailsPageV1: React.FC = () => {
isExpandViewSupported && (
<AlignRightIconButton
className={isTabExpanded ? 'rotate-180' : ''}
size="small"
title={
isTabExpanded ? t('label.collapse') : t('label.expand')
}
onClick={toggleTabExpanded}
/>
)

View File

@ -43,6 +43,16 @@
.ant-tabs.tabs-new {
width: 100%;
.ant-btn.ant-btn-icon-only.tab-expand-icon {
padding: 0;
height: 20px;
width: 20px;
vertical-align: middle;
* {
font-size: 20px !important;
}
}
.ant-tabs-nav {
margin: 0;
padding: 0 20px;

View File

@ -61,7 +61,7 @@ class APICollectionClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.API_ENDPOINTS]: 8,
[DetailPageWidgetKeys.API_ENDPOINTS]: 4,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -96,7 +96,10 @@ class APICollectionClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.API_ENDPOINTS] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -97,7 +97,10 @@ class APIEndpointClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.API_SCHEMA] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -164,8 +167,8 @@ class APIEndpointClassBase {
return [
DESCRIPTION_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.API_ENDPOINTS,
name: i18n.t('label.api-endpoint'),
fullyQualifiedName: DetailPageWidgetKeys.API_SCHEMA,
name: i18n.t('label.schema'),
data: {
gridSizes: ['large'] as GridSizes[],
},

View File

@ -67,7 +67,7 @@ class ContainerDetailsClassBase {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.CONTAINER_CHILDREN]: 8,
[DetailPageWidgetKeys.CONTAINER_SCHEMA]: 8,
[DetailPageWidgetKeys.CONTAINER_SCHEMA]: 5,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -117,7 +117,10 @@ class ContainerDetailsClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.CONTAINER_SCHEMA] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -184,6 +187,13 @@ class ContainerDetailsClassBase {
public getCommonWidgetList() {
return [
DESCRIPTION_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.CONTAINER_SCHEMA,
name: i18n.t('label.schema'),
data: {
gridSizes: ['large'] as GridSizes[],
},
},
{
fullyQualifiedName: DetailPageWidgetKeys.CONTAINER_CHILDREN,
name: i18n.t('label.children'),

View File

@ -1,198 +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 { FC } from 'react';
import { GenericWidget } from '../../components/Customization/GenericWidget/GenericWidget';
import {
CUSTOM_PROPERTIES_WIDGET,
DESCRIPTION_WIDGET,
DOMAIN_WIDGET,
OWNER_WIDGET,
TAGS_WIDGET,
} from '../../constants/CustomizeWidgets.constants';
import { DetailPageWidgetKeys } from '../../enums/CustomizeDetailPage.enum';
import {
WidgetCommonProps,
WidgetConfig,
} from '../../pages/CustomizablePage/CustomizablePage.interface';
class CustomizeDetailPageClassBase {
defaultWidgetHeight = 3;
detailPageWidgetMargin = 16;
detailPageRowHeight = 50;
detailPageMaxGridSize = 4;
detailPageWidgetDefaultHeights: Record<string, number> = {
header: 1,
description: 6,
tableSchema: 3,
topicSchema: 3,
announcement: 3,
frequentlyJoinedTables: 3,
dataProduct: 3,
tags: 3,
glossaryTerms: 3,
customProperty: 4,
tabs: 1,
announcements: 3,
};
announcementWidget: WidgetConfig = {
h: this.detailPageWidgetDefaultHeights.announcements,
i: DetailPageWidgetKeys.ANNOUNCEMENTS,
w: 1,
x: 3,
y: 0,
static: false, // Making announcement widget fixed on top right position
};
defaultLayout: Array<WidgetConfig> = [
{
h: this.detailPageWidgetDefaultHeights.header,
i: DetailPageWidgetKeys.HEADER,
w: 4,
x: 0,
y: 0,
static: true,
},
{
h: this.detailPageWidgetDefaultHeights.tabs,
i: DetailPageWidgetKeys.TABS,
w: 4,
x: 0,
y: 1,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.tableSchema,
i: DetailPageWidgetKeys.TABLE_SCHEMA,
w: 1,
x: 3,
y: 6,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.dataProduct,
i: DetailPageWidgetKeys.DATA_PRODUCTS,
w: 2,
x: 0,
y: 9,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.tags,
i: DetailPageWidgetKeys.TAGS,
w: 3,
x: 0,
y: 6,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.glossaryTerms,
i: DetailPageWidgetKeys.GLOSSARY_TERMS,
w: 1,
x: 3,
y: 1.5,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.frequentlyJoinedTables,
i: DetailPageWidgetKeys.GLOSSARY_TERMS,
w: 1,
x: 3,
y: 3,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.customProperty,
i: DetailPageWidgetKeys.CUSTOM_PROPERTIES,
w: 1,
x: 3,
y: 4.5,
static: false,
},
{
h: this.detailPageWidgetDefaultHeights.announcement,
i: DetailPageWidgetKeys.ANNOUNCEMENTS,
w: 1,
x: 3,
y: 0,
static: true,
},
];
protected updateDefaultLayoutLayout(layout: Array<WidgetConfig>) {
this.defaultLayout = layout;
}
protected updateLandingPageWidgetDefaultHeights(obj: Record<string, number>) {
this.detailPageWidgetDefaultHeights = obj;
}
/**
*
* @param string widgetKey
* @returns React.FC<
{
isEditView?: boolean;
widgetKey: string;
handleRemoveWidget?: (widgetKey: string) => void;
announcements: Thread[];
followedData: EntityReference[];
followedDataCount: number;
isLoadingOwnedData: boolean;
}
>
*/
public getWidgetsFromKey(_widgetKey: string): FC<WidgetCommonProps> {
return GenericWidget;
}
public getWidgetHeight(widgetName: string) {
switch (widgetName) {
case 'ActivityFeed':
return this.detailPageWidgetDefaultHeights.activityFeed;
case 'DataAssets':
return this.detailPageWidgetDefaultHeights.DataAssets;
case 'Announcements':
return this.detailPageWidgetDefaultHeights.announcements;
case 'Following':
return this.detailPageWidgetDefaultHeights.following;
case 'RecentlyViewed':
return this.detailPageWidgetDefaultHeights.recentlyViewed;
case 'MyData':
return this.detailPageWidgetDefaultHeights.myData;
case 'KPI':
return this.detailPageWidgetDefaultHeights.kpi;
case 'TotalAssets':
return this.detailPageWidgetDefaultHeights.totalAssets;
default:
return this.defaultWidgetHeight;
}
}
public getCommonWidgetList() {
return [
DESCRIPTION_WIDGET,
TAGS_WIDGET,
DOMAIN_WIDGET,
OWNER_WIDGET,
CUSTOM_PROPERTIES_WIDGET,
];
}
}
const customizeDetailPageClassBase = new CustomizeDetailPageClassBase();
export default customizeDetailPageClassBase;
export { CustomizeDetailPageClassBase };

View File

@ -0,0 +1,155 @@
/*
* 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 ApiEndpointsImg from '../../assets/img/widgets/api-endpoints.png';
import ApiSchemaImg from '../../assets/img/widgets/api-schema.png';
import ContainerChildrenImg from '../../assets/img/widgets/container-children.png';
import ContainerSchemaImg from '../../assets/img/widgets/container-schema.png';
import CustomPropertyImg from '../../assets/img/widgets/custom_properties.png';
import ChartsTableImg from '../../assets/img/widgets/dashboard-charts.png';
import DataModelImg from '../../assets/img/widgets/dashboard-data-model.png';
import DataProductImg from '../../assets/img/widgets/data-products.png';
import DatabaseSchemaImg from '../../assets/img/widgets/database-schema-table.png';
import DescriptionLargeImg from '../../assets/img/widgets/description-large.png';
import DescriptionImg from '../../assets/img/widgets/description.png';
import DomainTypeImg from '../../assets/img/widgets/domain-type.png';
import DomainImg from '../../assets/img/widgets/domain.png';
import ExpertsImg from '../../assets/img/widgets/experts.png';
import FrequentlyJoinedTablesImg from '../../assets/img/widgets/frequently-joined-tables.png';
import GlossaryTermImg from '../../assets/img/widgets/glossary-terms.png';
import MlModelFeaturesImg from '../../assets/img/widgets/ml-features.png';
import OwnersImg from '../../assets/img/widgets/owners.png';
import PipelineTasksImg from '../../assets/img/widgets/pipeline-tasks.png';
import ReferencesImg from '../../assets/img/widgets/references.png';
import RelatedMetricsImg from '../../assets/img/widgets/related-metrics.png';
import RelatedTermsImg from '../../assets/img/widgets/related-term.png';
import ReviewersImg from '../../assets/img/widgets/reviewers.png';
import SchemaTablesImg from '../../assets/img/widgets/schema-tables.png';
import SearchIndexFieldsImg from '../../assets/img/widgets/search-index-fields.png';
import StoredProcedureCodeImg from '../../assets/img/widgets/stored-procedure-code.png';
import SynonymsImg from '../../assets/img/widgets/synonyms.png';
import TableConstraints from '../../assets/img/widgets/table-constraints.png';
import TablesSchemaImg from '../../assets/img/widgets/tables-schema.png';
import TagsImg from '../../assets/img/widgets/tags.png';
import TermsImg from '../../assets/img/widgets/Terms.png';
import TopicSchemaImg from '../../assets/img/widgets/topic-schema.png';
import {
DetailPageWidgetKeys,
GlossaryTermDetailPageWidgetKeys,
WidgetWidths,
} from '../../enums/CustomizeDetailPage.enum';
class CustomizeDetailPageClassBase {
public getGlossaryWidgetImageFromKey(
widgetKey: string,
size?: number
): string {
switch (widgetKey) {
case GlossaryTermDetailPageWidgetKeys.DESCRIPTION:
if (size === WidgetWidths.large) {
return DescriptionLargeImg;
}
return DescriptionImg;
case GlossaryTermDetailPageWidgetKeys.CUSTOM_PROPERTIES:
return CustomPropertyImg;
case GlossaryTermDetailPageWidgetKeys.DOMAIN:
return DomainImg;
case GlossaryTermDetailPageWidgetKeys.OWNER:
return OwnersImg;
case GlossaryTermDetailPageWidgetKeys.REFERENCES:
return ReferencesImg;
case GlossaryTermDetailPageWidgetKeys.RELATED_TERMS:
return RelatedTermsImg;
case GlossaryTermDetailPageWidgetKeys.REVIEWER:
return ReviewersImg;
case GlossaryTermDetailPageWidgetKeys.SYNONYMS:
return SynonymsImg;
case GlossaryTermDetailPageWidgetKeys.TERMS_TABLE:
return TermsImg;
case GlossaryTermDetailPageWidgetKeys.TAGS:
return TagsImg;
default:
return '';
}
}
public getDetailPageWidgetImageFromKey(
widgetKey: string,
size?: number
): string {
switch (widgetKey) {
case DetailPageWidgetKeys.DESCRIPTION:
if (size === WidgetWidths.large) {
return DescriptionLargeImg;
}
return DescriptionImg;
case DetailPageWidgetKeys.CUSTOM_PROPERTIES:
return CustomPropertyImg;
case DetailPageWidgetKeys.OWNERS:
return OwnersImg;
case DetailPageWidgetKeys.EXPERTS:
return ExpertsImg;
case DetailPageWidgetKeys.TAGS:
return TagsImg;
case DetailPageWidgetKeys.DATA_PRODUCTS:
return DataProductImg;
case DetailPageWidgetKeys.FREQUENTLY_JOINED_TABLES:
return FrequentlyJoinedTablesImg;
case DetailPageWidgetKeys.GLOSSARY_TERMS:
return GlossaryTermImg;
case DetailPageWidgetKeys.TABLE_SCHEMA:
return TablesSchemaImg;
case DetailPageWidgetKeys.TABLE_CONSTRAINTS:
return TableConstraints;
case DetailPageWidgetKeys.API_ENDPOINTS:
return ApiEndpointsImg;
case DetailPageWidgetKeys.API_SCHEMA:
return ApiSchemaImg;
case DetailPageWidgetKeys.CONTAINER_SCHEMA:
return ContainerSchemaImg;
case DetailPageWidgetKeys.CONTAINER_CHILDREN:
return ContainerChildrenImg;
case DetailPageWidgetKeys.CHARTS_TABLE:
return ChartsTableImg;
case DetailPageWidgetKeys.DATA_MODEL:
return DataModelImg;
case DetailPageWidgetKeys.DATABASE_SCHEMA:
return DatabaseSchemaImg;
case DetailPageWidgetKeys.TABLES:
return SchemaTablesImg;
case DetailPageWidgetKeys.RELATED_METRICS:
return RelatedMetricsImg;
case DetailPageWidgetKeys.ML_MODEL_FEATURES:
return MlModelFeaturesImg;
case DetailPageWidgetKeys.PIPELINE_TASKS:
return PipelineTasksImg;
case DetailPageWidgetKeys.SEARCH_INDEX_FIELDS:
return SearchIndexFieldsImg;
case DetailPageWidgetKeys.STORED_PROCEDURE_CODE:
return StoredProcedureCodeImg;
case DetailPageWidgetKeys.TOPIC_SCHEMA:
return TopicSchemaImg;
case DetailPageWidgetKeys.DOMAIN_TYPE:
return DomainTypeImg;
default:
return '';
}
}
}
const customizeDetailPageClassBase = new CustomizeDetailPageClassBase();
export default customizeDetailPageClassBase;
export { CustomizeDetailPageClassBase };

View File

@ -22,22 +22,6 @@ import MyDataImg from '../assets/img/my-data.png';
import RecentViewsImg from '../assets/img/recent-views.png';
import TotalAssetsMediumImg from '../assets/img/total-assets-medium.png';
import TotalAssetsImg from '../assets/img/total-assets.png';
import CustomPropertyImg from '../assets/img/widgets/custom_properties.png';
import DataProductImg from '../assets/img/widgets/data-products.png';
import DescriptionLargeImg from '../assets/img/widgets/description-large.png';
import DescriptionImg from '../assets/img/widgets/description.png';
import DomainImg from '../assets/img/widgets/Domain.png';
import FrequentlyJoinedTablesImg from '../assets/img/widgets/frequently-joined-tables.png';
import GlossaryTermImg from '../assets/img/widgets/glossary-terms.png';
import OwnersImg from '../assets/img/widgets/owners.png';
import ReferencesImg from '../assets/img/widgets/References.png';
import RelatedTermsImg from '../assets/img/widgets/RelatedTerms.png';
import ReviewersImg from '../assets/img/widgets/Reviewers.png';
import SynonymsImg from '../assets/img/widgets/Synonyms.png';
import TableConstraints from '../assets/img/widgets/table-constraints.png';
import SchemaImg from '../assets/img/widgets/table-schema.png';
import TagsImg from '../assets/img/widgets/tags.png';
import TermsImg from '../assets/img/widgets/Terms.png';
import { MyDataWidget } from '../components/MyData/MyDataWidget/MyDataWidget.component';
import AnnouncementsWidget, {
AnnouncementsWidgetProps,
@ -54,10 +38,6 @@ import {
LandingPageWidgetKeys,
WidgetWidths,
} from '../enums/CustomizablePage.enum';
import {
DetailPageWidgetKeys,
GlossaryTermDetailPageWidgetKeys,
} from '../enums/CustomizeDetailPage.enum';
import {
WidgetCommonProps,
WidgetConfig,
@ -236,42 +216,6 @@ class CustomizeMyDataPageClassBase {
case LandingPageWidgetKeys.RECENTLY_VIEWED: {
return RecentViewsImg;
}
case DetailPageWidgetKeys.DESCRIPTION:
case GlossaryTermDetailPageWidgetKeys.DESCRIPTION:
if (size === WidgetWidths.large) {
return DescriptionLargeImg;
}
return DescriptionImg;
case DetailPageWidgetKeys.CUSTOM_PROPERTIES:
case GlossaryTermDetailPageWidgetKeys.CUSTOM_PROPERTIES:
return CustomPropertyImg;
case GlossaryTermDetailPageWidgetKeys.DOMAIN:
return DomainImg;
case GlossaryTermDetailPageWidgetKeys.OWNER:
return OwnersImg;
case GlossaryTermDetailPageWidgetKeys.REFERENCES:
return ReferencesImg;
case GlossaryTermDetailPageWidgetKeys.RELATED_TERMS:
return RelatedTermsImg;
case GlossaryTermDetailPageWidgetKeys.REVIEWER:
return ReviewersImg;
case GlossaryTermDetailPageWidgetKeys.SYNONYMS:
return SynonymsImg;
case GlossaryTermDetailPageWidgetKeys.TERMS_TABLE:
return TermsImg;
case GlossaryTermDetailPageWidgetKeys.TAGS:
return TagsImg;
case DetailPageWidgetKeys.DATA_PRODUCTS:
return DataProductImg;
case DetailPageWidgetKeys.FREQUENTLY_JOINED_TABLES:
return FrequentlyJoinedTablesImg;
case DetailPageWidgetKeys.GLOSSARY_TERMS:
return GlossaryTermImg;
case DetailPageWidgetKeys.TABLE_SCHEMA:
return SchemaImg;
case DetailPageWidgetKeys.TABLE_CONSTRAINTS:
return TableConstraints;
default: {
return '';
}

View File

@ -406,12 +406,50 @@ export const getWidgetHeight = (pageType: PageType, widgetName: string) => {
}
};
const calculateNewPosition = (
currentLayout: WidgetConfig[],
newWidget: { w: number; h: number },
maxCols = 8
) => {
// Sort layout by y position to find last row
const sortedLayout = [...currentLayout].sort(
(a, b) => a.y + a.h - (b.y + b.h)
);
// Get the last widget
const lastWidget = sortedLayout[sortedLayout.length - 1];
if (!lastWidget) {
// If no widgets exist, start at 0,0
return { x: 0, y: 0 };
}
// Calculate next position
const lastRowY = lastWidget.y + lastWidget.h;
const lastRowWidgets = sortedLayout.filter(
(widget) => widget.y + widget.h === lastRowY
);
// Find the rightmost x position in the last row
const lastX = lastRowWidgets.reduce(
(maxX, widget) => Math.max(maxX, widget.x + widget.w),
0
);
// If there's room in the current row
if (lastX + newWidget.w <= maxCols) {
return { x: lastX, y: lastRowY - lastWidget.h };
}
// Otherwise, start a new row
return { x: 0, y: lastRowY };
};
export const getAddWidgetHandler =
(
newWidgetData: CommonWidgetType,
placeholderWidgetKey: string,
widgetWidth: number,
maxGridSize: number,
pageType: PageType
) =>
(currentLayout: Array<WidgetConfig>): WidgetConfig[] => {
@ -440,22 +478,28 @@ export const getAddWidgetHandler =
},
];
} else {
return currentLayout.map((widget: WidgetConfig) => {
const widgetX =
widget.x + widgetWidth <= maxGridSize
? widget.x
: maxGridSize - widgetWidth;
// To handle case of adding widget from top button instead of empty widget placeholder
const { x: widgetX, y: widgetY } = calculateNewPosition(
currentLayout.filter(
(widget) =>
widget.i !== LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
),
{
w: widgetWidth,
h: widgetHeight,
}
);
return widget.i === placeholderWidgetKey
? {
...widget,
i: widgetFQN,
h: widgetHeight,
w: widgetWidth,
x: widgetX,
}
: widget;
});
return [
...currentLayout,
{
i: widgetFQN,
h: widgetHeight,
w: widgetWidth,
x: widgetX,
y: widgetY,
},
];
}
};

View File

@ -97,7 +97,10 @@ class DashboardDataModelBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.DATA_MODEL] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -61,7 +61,7 @@ class DashboardDetailsClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.CHARTS_TABLE]: 6,
[DetailPageWidgetKeys.CHARTS_TABLE]: 4,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -97,7 +97,10 @@ class DashboardDetailsClassBase {
return [
{
h: 8.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.CHARTS_TABLE] +
0.3,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -61,7 +61,7 @@ class DatabaseClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.DATABASE_SCHEMA]: 8,
[DetailPageWidgetKeys.DATABASE_SCHEMA]: 4,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -95,7 +95,10 @@ class DatabaseClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.DATABASE_SCHEMA] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -163,7 +166,7 @@ class DatabaseClassBase {
return [
DESCRIPTION_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.TABLE_SCHEMA,
fullyQualifiedName: DetailPageWidgetKeys.DATABASE_SCHEMA,
name: i18n.t('label.schema'),
data: {
gridSizes: ['large'] as GridSizes[],

View File

@ -62,7 +62,7 @@ class DatabaseSchemaClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.TABLES]: 8,
[DetailPageWidgetKeys.TABLES]: 8.5,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -98,7 +98,10 @@ class DatabaseSchemaClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.TABLES] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -162,7 +165,7 @@ class DatabaseSchemaClassBase {
return [
DESCRIPTION_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.TABLE_SCHEMA,
fullyQualifiedName: DetailPageWidgetKeys.TABLES,
name: i18n.t('label.table-plural'),
data: {
gridSizes: ['large'] as GridSizes[],

View File

@ -108,7 +108,7 @@ class DomainClassBase {
return [
{
h: 4.3,
h: this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] + 0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -23,9 +23,12 @@ import { DashboardChartTable } from '../../components/Dashboard/DashboardChartTa
import ModelTab from '../../components/Dashboard/DataModel/DataModels/ModelTab/ModelTab.component';
import { DatabaseSchemaTable } from '../../components/Database/DatabaseSchema/DatabaseSchemaTable/DatabaseSchemaTable';
import SchemaTable from '../../components/Database/SchemaTable/SchemaTable.component';
import { StoredProcedureCodeCard } from '../../components/Database/StoredProcedureCodeCard/StoredProcedureCodeCard';
import DataProductsContainer from '../../components/DataProducts/DataProductsContainer/DataProductsContainer.component';
import { EntityUnion } from '../../components/Explore/ExplorePage.interface';
import GlossaryTermTab from '../../components/Glossary/GlossaryTermTab/GlossaryTermTab.component';
import MlModelFeaturesList from '../../components/MlModel/MlModelDetail/MlModelFeaturesList';
import { PipelineTaskTab } from '../../components/Pipeline/PipelineTaskTab/PipelineTaskTab';
import TagsViewer from '../../components/Tag/TagsViewer/TagsViewer';
import { DisplayType } from '../../components/Tag/TagsViewer/TagsViewer.interface';
import TopicSchemaFields from '../../components/Topic/TopicSchema/TopicSchema';
@ -40,6 +43,8 @@ import {
import { EntityType } from '../../enums/entity.enum';
import { EntityReference, TagSource } from '../../generated/tests/testCase';
import APIEndpointsTab from '../../pages/APICollectionPage/APIEndpointsTab';
import SchemaTablesTab from '../../pages/DatabaseSchemaPage/SchemaTablesTab';
import SearchIndexFieldsTab from '../../pages/SearchIndexDetailsPage/SearchIndexFieldsTab/SearchIndexFieldsTab';
import { FrequentlyJoinedTables } from '../../pages/TableDetailsPageV1/FrequentlyJoinedTables/FrequentlyJoinedTables.component';
import TableConstraints from '../../pages/TableDetailsPageV1/TableConstraints/TableConstraints';
import domainClassBase from '../Domain/DomainClassBase';
@ -133,7 +138,9 @@ export const WIDGET_COMPONENTS = {
[DetailPageWidgetKeys.CONTAINER_CHILDREN]: () => (
<ContainerChildren isReadOnly />
),
[DetailPageWidgetKeys.CHARTS_TABLE]: () => <DashboardChartTable />,
[DetailPageWidgetKeys.CHARTS_TABLE]: () => (
<DashboardChartTable isCustomizationPage />
),
[DetailPageWidgetKeys.EXPERTS]: () => (
<OwnerLabel
hasPermission={false}
@ -145,5 +152,14 @@ export const WIDGET_COMPONENTS = {
),
[DetailPageWidgetKeys.API_SCHEMA]: () => <APIEndpointSchema />,
[DetailPageWidgetKeys.CONTAINER_SCHEMA]: () => <ContainerWidget />,
[DetailPageWidgetKeys.DATABASE_SCHEMA]: () => <DatabaseSchemaTable />,
[DetailPageWidgetKeys.DATABASE_SCHEMA]: () => (
<DatabaseSchemaTable isCustomizationPage />
),
[DetailPageWidgetKeys.TABLES]: () => <SchemaTablesTab isCustomizationPage />,
[DetailPageWidgetKeys.ML_MODEL_FEATURES]: () => <MlModelFeaturesList />,
[DetailPageWidgetKeys.PIPELINE_TASKS]: () => <PipelineTaskTab />,
[DetailPageWidgetKeys.SEARCH_INDEX_FIELDS]: () => <SearchIndexFieldsTab />,
[DetailPageWidgetKeys.STORED_PROCEDURE_CODE]: () => (
<StoredProcedureCodeCard />
),
} as const;

View File

@ -20,7 +20,7 @@ import {
GridSizes,
TAGS_WIDGET,
} from '../../constants/CustomizeWidgets.constants';
import { METRIC_DUMMY_DATA } from '../../constants/Metric.constnsts';
import { METRIC_DUMMY_DATA } from '../../constants/Metric.constants';
import { DetailPageWidgetKeys } from '../../enums/CustomizeDetailPage.enum';
import { EntityTabs } from '../../enums/entity.enum';
import { Metric } from '../../generated/entity/data/metric';
@ -60,7 +60,7 @@ class MetricDetailsClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 6,
[DetailPageWidgetKeys.DESCRIPTION]: 4,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -98,7 +98,7 @@ class MetricDetailsClassBase {
return [
{
h: 6.3,
h: this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] + 0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -169,7 +169,7 @@ class MetricDetailsClassBase {
GLOSSARY_TERMS_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.RELATED_METRICS,
name: i18n.t('label.related-metrics'),
name: i18n.t('label.related-metric-plural'),
data: {
gridSizes: ['large'] as GridSizes[],
},

View File

@ -170,8 +170,8 @@ class MlModelDetailsClassBase {
TAGS_WIDGET,
GLOSSARY_TERMS_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.RELATED_METRICS,
name: i18n.t('label.related-metrics'),
fullyQualifiedName: DetailPageWidgetKeys.ML_MODEL_FEATURES,
name: i18n.t('label.feature-plural'),
data: {
gridSizes: ['large'] as GridSizes[],
},

View File

@ -64,7 +64,7 @@ class PipelineClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.PIPELINE_TASKS]: 8,
[DetailPageWidgetKeys.PIPELINE_TASKS]: 4,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -101,7 +101,10 @@ class PipelineClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.PIPELINE_TASKS] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,
@ -170,7 +173,7 @@ class PipelineClassBase {
DESCRIPTION_WIDGET,
{
fullyQualifiedName: DetailPageWidgetKeys.PIPELINE_TASKS,
name: i18n.t('label.schema'),
name: i18n.t('label.task-plural'),
data: {
gridSizes: ['large'] as GridSizes[],
},

View File

@ -64,7 +64,7 @@ class SearchIndexClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.SEARCH_INDEX_FIELDS]: 7.6,
[DetailPageWidgetKeys.SEARCH_INDEX_FIELDS]: 6,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -105,7 +105,7 @@ class SearchIndexClassBase {
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.SEARCH_INDEX_FIELDS] +
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
0.3,
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -67,7 +67,7 @@ class StoredProcedureClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.STORED_PROCEDURE_CODE]: 8,
[DetailPageWidgetKeys.STORED_PROCEDURE_CODE]: 6,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -103,7 +103,10 @@ class StoredProcedureClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.STORED_PROCEDURE_CODE] +
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -74,7 +74,7 @@ class TableClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.TABLE_SCHEMA]: 8,
[DetailPageWidgetKeys.TABLE_SCHEMA]: 8.5,
[DetailPageWidgetKeys.FREQUENTLY_JOINED_TABLES]: 2,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
@ -118,7 +118,11 @@ class TableClassBase {
return [
{
h: 10.5,
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.TABLE_SCHEMA] +
// Padding for left panel container
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,

View File

@ -61,7 +61,7 @@ class TopicClassBase {
constructor() {
this.defaultWidgetHeight = {
[DetailPageWidgetKeys.DESCRIPTION]: 2,
[DetailPageWidgetKeys.TOPIC_SCHEMA]: 8.5,
[DetailPageWidgetKeys.TOPIC_SCHEMA]: 8,
[DetailPageWidgetKeys.DATA_PRODUCTS]: 1.2,
[DetailPageWidgetKeys.TAGS]: 2,
[DetailPageWidgetKeys.GLOSSARY_TERMS]: 2,
@ -102,7 +102,7 @@ class TopicClassBase {
h:
this.defaultWidgetHeight[DetailPageWidgetKeys.DESCRIPTION] +
this.defaultWidgetHeight[DetailPageWidgetKeys.TOPIC_SCHEMA] +
0.3,
0.5,
i: DetailPageWidgetKeys.LEFT_PANEL,
w: 6,
x: 0,