Feat: edit display name (#18720)

* feat: edit display name

* refactor: logic and style changes

* fix: minor changes

* style: update style for edit button

* style: remove inline styles and update hover effect

* refactor: remove edit permission for version page and fix handleEditDisplayName function

* refactor: updated displayName

* fix: data-testid for the Link

---------

Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com>
This commit is contained in:
Pranita Fulsundar 2024-11-28 19:49:58 +05:30 committed by GitHub
parent cb33f274fc
commit 9d37ff0e34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 550 additions and 45 deletions

View File

@ -13,4 +13,5 @@
export interface DatabaseSchemaTableProps {
isDatabaseDeleted?: boolean;
isVersionPage?: boolean;
}

View File

@ -11,45 +11,70 @@
* limitations under the License.
*/
import { Col, Row, Switch, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch';
import { t } from 'i18next';
import { isEmpty } from 'lodash';
import QueryString from 'qs';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useHistory } from 'react-router-dom';
import {
getEntityDetailsPath,
INITIAL_PAGING_VALUE,
NO_DATA_PLACEHOLDER,
PAGE_SIZE,
} from '../../../../constants/constants';
import { TabSpecificField } from '../../../../enums/entity.enum';
import { usePermissionProvider } from '../../../../context/PermissionProvider/PermissionProvider';
import { EntityType, TabSpecificField } from '../../../../enums/entity.enum';
import { SearchIndex } from '../../../../enums/search.enum';
import { DatabaseSchema } from '../../../../generated/entity/data/databaseSchema';
import { EntityReference } from '../../../../generated/entity/type';
import { UsageDetails } from '../../../../generated/type/entityUsage';
import { Include } from '../../../../generated/type/include';
import { Paging } from '../../../../generated/type/paging';
import { usePaging } from '../../../../hooks/paging/usePaging';
import useCustomLocation from '../../../../hooks/useCustomLocation/useCustomLocation';
import { useFqn } from '../../../../hooks/useFqn';
import { getDatabaseSchemas } from '../../../../rest/databaseAPI';
import {
getDatabaseSchemas,
patchDatabaseSchemaDetails,
} from '../../../../rest/databaseAPI';
import { searchQuery } from '../../../../rest/searchAPI';
import { schemaTableColumns } from '../../../../utils/Database/Database.util';
import { getEntityName } from '../../../../utils/EntityUtils';
import { getUsagePercentile } from '../../../../utils/TableUtils';
import { showErrorToast } from '../../../../utils/ToastUtils';
import DisplayName from '../../../common/DisplayName/DisplayName';
import ErrorPlaceHolder from '../../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import NextPrevious from '../../../common/NextPrevious/NextPrevious';
import { PagingHandlerParams } from '../../../common/NextPrevious/NextPrevious.interface';
import RichTextEditorPreviewer from '../../../common/RichTextEditor/RichTextEditorPreviewer';
import Searchbar from '../../../common/SearchBarComponent/SearchBar.component';
import Table from '../../../common/Table/Table';
import { EntityName } from '../../../Modals/EntityNameModal/EntityNameModal.interface';
import { DatabaseSchemaTableProps } from './DatabaseSchemaTable.interface';
export const DatabaseSchemaTable = ({
isDatabaseDeleted,
isVersionPage = false,
}: Readonly<DatabaseSchemaTableProps>) => {
const { fqn: decodedDatabaseFQN } = useFqn();
const history = useHistory();
const location = useCustomLocation();
const { permissions } = usePermissionProvider();
const [schemas, setSchemas] = useState<DatabaseSchema[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [showDeletedSchemas, setShowDeletedSchemas] = useState<boolean>(false);
const allowEditDisplayNamePermission = useMemo(() => {
return (
!isVersionPage &&
(permissions.databaseSchema.EditAll ||
permissions.databaseSchema.EditDisplayName)
);
}, [permissions, isVersionPage]);
const searchValue = useMemo(() => {
const param = location.search;
const searchData = QueryString.parse(
@ -160,6 +185,98 @@ export const DatabaseSchemaTable = ({
}
};
const handleDisplayNameUpdate = useCallback(
async (data: EntityName, id?: string) => {
try {
const schemaDetails = schemas.find((schema) => schema.id === id);
if (!schemaDetails) {
return;
}
const updatedData = {
...schemaDetails,
displayName: data.displayName || undefined,
};
const jsonPatch = compare(schemaDetails, updatedData);
await patchDatabaseSchemaDetails(schemaDetails.id ?? '', jsonPatch);
setSchemas((prevData) =>
prevData.map((schema) =>
schema.id === id
? { ...schema, displayName: data.displayName }
: schema
)
);
} catch (error) {
showErrorToast(error as AxiosError);
}
},
[schemas]
);
const schemaTableColumns: ColumnsType<DatabaseSchema> = useMemo(
() => [
{
title: t('label.schema-name'),
dataIndex: 'name',
key: 'name',
width: 250,
render: (_, record: DatabaseSchema) => (
<DisplayName
allowRename={allowEditDisplayNamePermission}
displayName={record.displayName}
id={record.id ?? ''}
key={record.id}
link={
record.fullyQualifiedName
? getEntityDetailsPath(
EntityType.DATABASE_SCHEMA,
record.fullyQualifiedName
)
: ''
}
name={record.name}
onEditDisplayName={handleDisplayNameUpdate}
/>
),
},
{
title: t('label.description'),
dataIndex: 'description',
key: 'description',
render: (text: string) =>
text?.trim() ? (
<RichTextEditorPreviewer markdown={text} />
) : (
<span className="text-grey-muted">
{t('label.no-entity', { entity: t('label.description') })}
</span>
),
},
{
title: t('label.owner-plural'),
dataIndex: 'owners',
key: 'owners',
width: 120,
render: (owners: EntityReference[]) =>
!isEmpty(owners) && owners.length > 0 ? (
owners.map((owner: EntityReference) => getEntityName(owner))
) : (
<Typography.Text data-testid="no-owner-text">
{NO_DATA_PLACEHOLDER}
</Typography.Text>
),
},
{
title: t('label.usage'),
dataIndex: 'usageSummary',
key: 'usageSummary',
width: 120,
render: (text: UsageDetails) =>
getUsagePercentile(text?.weeklyStats?.percentileRank ?? 0),
},
],
[handleDisplayNameUpdate, allowEditDisplayNamePermission]
);
useEffect(() => {
fetchDatabaseSchema();
}, [decodedDatabaseFQN, pageSize, showDeletedSchemas, isDatabaseDeleted]);

View File

@ -13,7 +13,7 @@
import { Rule } from 'antd/lib/form';
import { Constraint } from '../../../generated/entity/data/table';
export type EntityName = { name: string; displayName?: string };
export type EntityName = { name: string; displayName?: string; id?: string };
export type EntityNameWithAdditionFields = EntityName & {
constraint: Constraint;

View File

@ -0,0 +1,22 @@
/*
* Copyright 2024 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 { EntityName } from '../../Modals/EntityNameModal/EntityNameModal.interface';
export interface DisplayNameProps {
id: string;
name?: string;
displayName?: string;
link: string;
onEditDisplayName?: (data: EntityName, id?: string) => Promise<void>;
allowRename?: boolean;
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2024 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 { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import DisplayName from './DisplayName';
import { DisplayNameProps } from './DisplayName.interface';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
Link: jest
.fn()
.mockImplementation(({ children, ...props }) => (
<span {...props}>{children}</span>
)),
}));
jest.mock('../../../constants/constants', () => ({
DE_ACTIVE_COLOR: '#BFBFBF',
ICON_DIMENSION: { width: 16, height: 16 },
}));
jest.mock('../../Modals/EntityNameModal/EntityNameModal.component', () =>
jest.fn().mockImplementation(() => <p>Mocked Modal</p>)
);
const mockOnEditDisplayName = jest.fn();
const mockProps: DisplayNameProps = {
id: '1',
name: 'Sample Entity',
displayName: 'Sample Display Name',
link: '/entity/1',
allowRename: true,
onEditDisplayName: mockOnEditDisplayName,
};
describe('Test DisplayName Component', () => {
it('Should render the component with the display name', async () => {
await act(async () => {
render(
<MemoryRouter>
<DisplayName {...mockProps} />
</MemoryRouter>
);
const displayNameField = await screen.getByTestId('column-display-name');
expect(displayNameField).toBeInTheDocument();
expect(displayNameField).toHaveTextContent('Sample Display Name');
const editButton = screen.queryByTestId('edit-displayName-button');
expect(editButton).toBeInTheDocument();
});
});
it('Should render the component with name when display name is empty', async () => {
await act(async () => {
render(
<MemoryRouter>
<DisplayName {...mockProps} displayName={undefined} />
</MemoryRouter>
);
const nameField = screen.getByTestId('column-name');
expect(nameField).toBeInTheDocument();
expect(nameField).toHaveTextContent('Sample Entity');
});
});
it('Should open the edit modal on edit button click', async () => {
await act(async () => {
render(
<MemoryRouter>
<DisplayName {...mockProps} />
</MemoryRouter>
);
const editButton = screen.getByTestId('edit-displayName-button');
fireEvent.click(editButton);
const nameField = await screen.findByTestId('column-name');
expect(nameField).toBeInTheDocument();
const displayNameField = await screen.findByTestId('column-display-name');
expect(displayNameField).toBeInTheDocument();
});
});
});

View File

@ -0,0 +1,103 @@
/*
* Copyright 2024 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 { Button, Tooltip, Typography } from 'antd';
import { AxiosError } from 'axios';
import { isEmpty } from 'lodash';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg';
import { DE_ACTIVE_COLOR, ICON_DIMENSION } from '../../../constants/constants';
import { showErrorToast } from '../../../utils/ToastUtils';
import EntityNameModal from '../../Modals/EntityNameModal/EntityNameModal.component';
import { EntityName } from '../../Modals/EntityNameModal/EntityNameModal.interface';
import { DisplayNameProps } from './DisplayName.interface';
const DisplayName: React.FC<DisplayNameProps> = ({
id,
name,
displayName,
onEditDisplayName,
link,
allowRename,
}) => {
const { t } = useTranslation();
const [isDisplayNameEditing, setIsDisplayNameEditing] = useState(false);
const handleDisplayNameUpdate = async (data: EntityName) => {
setIsDisplayNameEditing(true);
try {
await onEditDisplayName?.(data, id);
} catch (error) {
showErrorToast(error as AxiosError);
} finally {
setIsDisplayNameEditing(false);
}
};
return (
<div className="flex-column hover-icon-group w-max-full">
<Typography.Text
className="m-b-0 d-block text-grey-muted break-word"
data-testid="column-name">
{isEmpty(displayName) ? (
<Link className="break-word" data-testid={name} to={link}>
{name}
</Link>
) : (
<>
{name}
<Typography.Text
className="m-b-0 d-block break-word"
data-testid="column-display-name">
<Link className="break-word" data-testid={name} to={link}>
{displayName}
</Link>
</Typography.Text>
</>
)}
</Typography.Text>
{allowRename ? (
<Tooltip placement="right" title={t('label.edit')}>
<Button
ghost
className="hover-cell-icon"
data-testid="edit-displayName-button"
icon={<IconEdit color={DE_ACTIVE_COLOR} {...ICON_DIMENSION} />}
type="text"
onClick={() => setIsDisplayNameEditing(true)}
/>
</Tooltip>
) : null}
{isDisplayNameEditing && (
<EntityNameModal
allowRename={allowRename}
entity={{
name: name ?? '',
displayName,
}}
title={t('label.edit-entity', {
entity: t('label.display-name'),
})}
visible={isDisplayNameEditing}
onCancel={() => setIsDisplayNameEditing(false)}
onSave={handleDisplayNameUpdate}
/>
)}
</div>
);
};
export default DisplayName;

View File

@ -13,23 +13,29 @@
import { Col, Row, Switch, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch';
import { isEmpty, isUndefined } from 'lodash';
import React, { useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import DisplayName from '../../components/common/DisplayName/DisplayName';
import DescriptionV1 from '../../components/common/EntityDescription/DescriptionV1';
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
import NextPrevious from '../../components/common/NextPrevious/NextPrevious';
import { NextPreviousProps } from '../../components/common/NextPrevious/NextPrevious.interface';
import RichTextEditorPreviewer from '../../components/common/RichTextEditor/RichTextEditorPreviewer';
import TableAntd from '../../components/common/Table/Table';
import { EntityName } from '../../components/Modals/EntityNameModal/EntityNameModal.interface';
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
import { ERROR_PLACEHOLDER_TYPE } from '../../enums/common.enum';
import { EntityType } from '../../enums/entity.enum';
import { DatabaseSchema } from '../../generated/entity/data/databaseSchema';
import { Table } from '../../generated/entity/data/table';
import { UsePagingInterface } from '../../hooks/paging/usePaging';
import { patchTableDetails } from '../../rest/tableAPI';
import entityUtilClassBase from '../../utils/EntityUtilClassBase';
import { getEntityName } from '../../utils/EntityUtils';
import { showErrorToast } from '../../utils/ToastUtils';
interface SchemaTablesTabProps {
databaseSchemaDetails: DatabaseSchema;
@ -69,6 +75,48 @@ function SchemaTablesTab({
pagingInfo,
}: Readonly<SchemaTablesTabProps>) {
const { t } = useTranslation();
const [localTableData, setLocalTableData] = useState<Table[]>([]);
const { permissions } = usePermissionProvider();
const allowEditDisplayNamePermission = useMemo(() => {
return (
!isVersionView &&
(permissions.table.EditAll || permissions.table.EditDisplayName)
);
}, [permissions, isVersionView]);
const handleDisplayNameUpdate = useCallback(
async (data: EntityName, id?: string) => {
try {
const tableDetails = localTableData.find((table) => table.id === id);
if (!tableDetails) {
return;
}
const updatedData = {
...tableDetails,
displayName: data.displayName || undefined,
};
const jsonPatch = compare(tableDetails, updatedData);
await patchTableDetails(tableDetails.id, jsonPatch);
setLocalTableData((prevData) =>
prevData.map((table) =>
table.id === id
? { ...table, displayName: data.displayName }
: table
)
);
} catch (error) {
showErrorToast(error as AxiosError);
}
},
[localTableData]
);
useEffect(() => {
setLocalTableData(tableData);
}, [tableData]);
const tableColumn: ColumnsType<Table> = useMemo(
() => [
@ -79,17 +127,18 @@ function SchemaTablesTab({
width: 500,
render: (_, record: Table) => {
return (
<div className="d-inline-flex w-max-90">
<Link
className="break-word"
data-testid={record.name}
to={entityUtilClassBase.getEntityLink(
EntityType.TABLE,
record.fullyQualifiedName as string
)}>
{getEntityName(record)}
</Link>
</div>
<DisplayName
allowRename={allowEditDisplayNamePermission}
displayName={record.displayName}
id={record.id}
key={record.id}
link={entityUtilClassBase.getEntityLink(
EntityType.TABLE,
record.fullyQualifiedName as string
)}
name={record.name}
onEditDisplayName={handleDisplayNameUpdate}
/>
);
},
},
@ -105,7 +154,7 @@ function SchemaTablesTab({
),
},
],
[]
[handleDisplayNameUpdate, allowEditDisplayNamePermission]
);
return (
@ -158,7 +207,7 @@ function SchemaTablesTab({
bordered
columns={tableColumn}
data-testid="databaseSchema-tables"
dataSource={tableData}
dataSource={localTableData}
loading={tableDataLoading}
locale={{
emptyText: (

View File

@ -209,7 +209,7 @@ function DatabaseVersionPage() {
/>
</Col>
<Col span={24}>
<DatabaseSchemaTable />
<DatabaseSchemaTable isVersionPage />
</Col>
</Row>
</Col>

View File

@ -13,9 +13,11 @@
import { Col, Row, Space, Switch, Table, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch';
import { isUndefined } from 'lodash';
import { EntityTags, ServiceTypes } from 'Models';
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import DescriptionV1 from '../../components/common/EntityDescription/DescriptionV1';
@ -25,7 +27,9 @@ import NextPrevious from '../../components/common/NextPrevious/NextPrevious';
import { NextPreviousProps } from '../../components/common/NextPrevious/NextPrevious.interface';
import ResizablePanels from '../../components/common/ResizablePanels/ResizablePanels';
import EntityRightPanel from '../../components/Entity/EntityRightPanel/EntityRightPanel';
import { EntityName } from '../../components/Modals/EntityNameModal/EntityNameModal.interface';
import { COMMON_RESIZABLE_PANEL_CONFIG } from '../../constants/ResizablePanel.constants';
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
import { OperationPermission } from '../../context/PermissionProvider/PermissionProvider.interface';
import { EntityType } from '../../enums/entity.enum';
import { DatabaseService } from '../../generated/entity/services/databaseService';
@ -33,10 +37,14 @@ import { Paging } from '../../generated/type/paging';
import { UsePagingInterface } from '../../hooks/paging/usePaging';
import { useFqn } from '../../hooks/useFqn';
import { ServicesType } from '../../interface/service.interface';
import { getServiceMainTabColumns } from '../../utils/ServiceMainTabContentUtils';
import {
callServicePatchAPI,
getServiceMainTabColumns,
} from '../../utils/ServiceMainTabContentUtils';
import { getEntityTypeFromServiceCategory } from '../../utils/ServiceUtils';
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
import { createTagObject } from '../../utils/TagsUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import { ServicePageData } from './ServiceDetailsPage';
interface ServiceMainTabContentProps {
@ -53,6 +61,7 @@ interface ServiceMainTabContentProps {
pagingHandler: NextPreviousProps['pagingHandler'];
saveUpdatedServiceData: (updatedData: ServicesType) => Promise<void>;
pagingInfo: UsePagingInterface;
isVersionPage?: boolean;
}
function ServiceMainTabContent({
@ -69,6 +78,7 @@ function ServiceMainTabContent({
serviceDetails,
saveUpdatedServiceData,
pagingInfo,
isVersionPage = false,
}: Readonly<ServiceMainTabContentProps>) {
const { t } = useTranslation();
const { serviceCategory } = useParams<{
@ -76,7 +86,10 @@ function ServiceMainTabContent({
}>();
const { fqn: serviceFQN } = useFqn();
const { permissions } = usePermissionProvider();
const [isEdit, setIsEdit] = useState(false);
const [pageData, setPageData] = useState<ServicePageData[]>([]);
const tier = getTierTags(serviceDetails?.tags ?? []);
const tags = getTagsWithoutTier(serviceDetails?.tags ?? []);
@ -131,9 +144,69 @@ function ServiceMainTabContent({
setIsEdit(false);
};
const handleDisplayNameUpdate = useCallback(
async (entityData: EntityName, id?: string) => {
try {
const pageDataDetails = pageData.find((data) => data.id === id);
if (!pageDataDetails) {
return;
}
const updatedData = {
...pageDataDetails,
displayName: entityData.displayName || undefined,
};
const jsonPatch = compare(pageDataDetails, updatedData);
await callServicePatchAPI(
serviceCategory,
pageDataDetails.id,
jsonPatch
);
setPageData((prevData) =>
prevData.map((data) =>
data.id === id
? { ...data, displayName: entityData.displayName }
: data
)
);
} catch (error) {
showErrorToast(error as AxiosError);
}
},
[pageData, serviceCategory]
);
const editDisplayNamePermission = useMemo(() => {
if (isVersionPage) {
return false;
}
const servicePermissions = {
databaseServices: permissions.databaseService,
messagingServices: permissions.messagingService,
dashboardServices: permissions.dashboardService,
pipelineServices: permissions.pipelineService,
mlmodelServices: permissions.mlmodelService,
storageServices: permissions.storageService,
searchServices: permissions.searchService,
apiServices: permissions.apiService,
};
const currentPermission =
servicePermissions[serviceCategory as keyof typeof servicePermissions];
return (
currentPermission?.EditAll || currentPermission?.EditDisplayName || false
);
}, [permissions, serviceCategory, isVersionPage]);
const tableColumn: ColumnsType<ServicePageData> = useMemo(
() => getServiceMainTabColumns(serviceCategory),
[serviceCategory]
() =>
getServiceMainTabColumns(
serviceCategory,
editDisplayNamePermission,
handleDisplayNameUpdate
),
[serviceCategory, handleDisplayNameUpdate, editDisplayNamePermission]
);
const entityType = useMemo(
@ -160,6 +233,10 @@ function ServiceMainTabContent({
[servicePermission, serviceDetails]
);
useEffect(() => {
setPageData(data);
}, [data]);
return (
<Row gutter={[0, 16]} wrap={false}>
<Col className="tab-content-height-with-resizable-panel" span={24}>
@ -210,7 +287,7 @@ function ServiceMainTabContent({
bordered
columns={tableColumn}
data-testid="service-children-table"
dataSource={data}
dataSource={pageData}
locale={{
emptyText: <ErrorPlaceHolder className="m-y-md" />,
}}

View File

@ -17,44 +17,51 @@ import { t } from 'i18next';
import { isUndefined } from 'lodash';
import { ServiceTypes } from 'Models';
import React from 'react';
import { Link } from 'react-router-dom';
import DisplayName from '../components/common/DisplayName/DisplayName';
import { OwnerLabel } from '../components/common/OwnerLabel/OwnerLabel.component';
import RichTextEditorPreviewer from '../components/common/RichTextEditor/RichTextEditorPreviewer';
import { EntityName } from '../components/Modals/EntityNameModal/EntityNameModal.interface';
import TagsViewer from '../components/Tag/TagsViewer/TagsViewer';
import { NO_DATA_PLACEHOLDER } from '../constants/constants';
import { ServiceCategory } from '../enums/service.enum';
import { Database } from '../generated/entity/data/database';
import { Pipeline } from '../generated/entity/data/pipeline';
import { ServicePageData } from '../pages/ServiceDetailsPage/ServiceDetailsPage';
import { getEntityName } from './EntityUtils';
import { patchApiCollection } from '../rest/apiCollectionsAPI';
import { patchDashboardDetails } from '../rest/dashboardAPI';
import { patchDatabaseDetails } from '../rest/databaseAPI';
import { patchMlModelDetails } from '../rest/mlModelAPI';
import { patchPipelineDetails } from '../rest/pipelineAPI';
import { patchSearchIndexDetails } from '../rest/SearchIndexAPI';
import { patchContainerDetails } from '../rest/storageAPI';
import { patchTopicDetails } from '../rest/topicsAPI';
import { getLinkForFqn } from './ServiceUtils';
import { getUsagePercentile } from './TableUtils';
export const getServiceMainTabColumns = (
serviceCategory: ServiceTypes
serviceCategory: ServiceTypes,
editDisplayNamePermission?: boolean,
handleDisplayNameUpdate?: (
entityData: EntityName,
id?: string
) => Promise<void>
): ColumnsType<ServicePageData> => [
{
title: t('label.name'),
dataIndex: 'name',
key: 'name',
width: 280,
render: (_, record: ServicePageData) => {
return (
<Link
data-testid={record.name}
to={getLinkForFqn(serviceCategory, record.fullyQualifiedName ?? '')}>
<Typography.Paragraph
data-testid="child-asset-name-link"
ellipsis={{
rows: 2,
tooltip: true,
}}
style={{ width: 280, color: 'inherit' }}>
{getEntityName(record)}
</Typography.Paragraph>
</Link>
);
},
render: (_, record: ServicePageData) => (
<DisplayName
allowRename={editDisplayNamePermission}
displayName={record.displayName}
id={record.id}
key={record.id}
link={getLinkForFqn(serviceCategory, record.fullyQualifiedName ?? '')}
name={record.name}
onEditDisplayName={handleDisplayNameUpdate}
/>
),
},
{
title: t('label.description'),
@ -123,3 +130,30 @@ export const getServiceMainTabColumns = (
]
: []),
];
export const callServicePatchAPI = async (
serviceCategory: ServiceTypes,
id: string,
jsonPatch: any
) => {
switch (serviceCategory) {
case ServiceCategory.DATABASE_SERVICES:
return await patchDatabaseDetails(id, jsonPatch);
case ServiceCategory.MESSAGING_SERVICES:
return await patchTopicDetails(id, jsonPatch);
case ServiceCategory.DASHBOARD_SERVICES:
return await patchDashboardDetails(id, jsonPatch);
case ServiceCategory.PIPELINE_SERVICES:
return await patchPipelineDetails(id, jsonPatch);
case ServiceCategory.ML_MODEL_SERVICES:
return await patchMlModelDetails(id, jsonPatch);
case ServiceCategory.STORAGE_SERVICES:
return await patchContainerDetails(id, jsonPatch);
case ServiceCategory.SEARCH_SERVICES:
return await patchSearchIndexDetails(id, jsonPatch);
case ServiceCategory.API_SERVICES:
return await patchApiCollection(id, jsonPatch);
default:
return;
}
};