mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-25 09:28:23 +00:00
262 lines
9.6 KiB
TypeScript
262 lines
9.6 KiB
TypeScript
/*
|
|
* 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 { Col, Row, Space, Switch, Table, Typography } from 'antd';
|
|
import { ColumnsType } from 'antd/lib/table';
|
|
import { isEmpty, isNil } from 'lodash';
|
|
import { EntityTags, ServiceTypes } from 'Models';
|
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useParams } from 'react-router-dom';
|
|
import DescriptionV1 from '../../components/common/EntityDescription/DescriptionV1';
|
|
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
|
import Loader from '../../components/common/Loader/Loader';
|
|
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 { PAGE_SIZE } from '../../constants/constants';
|
|
import { COMMON_RESIZABLE_PANEL_CONFIG } from '../../constants/ResizablePanel.constants';
|
|
import { OperationPermission } from '../../context/PermissionProvider/PermissionProvider.interface';
|
|
import { EntityType } from '../../enums/entity.enum';
|
|
import { DatabaseService } from '../../generated/entity/services/databaseService';
|
|
import { Paging } from '../../generated/type/paging';
|
|
import { useFqn } from '../../hooks/useFqn';
|
|
import { ServicesType } from '../../interface/service.interface';
|
|
import { getServiceMainTabColumns } from '../../utils/ServiceMainTabContentUtils';
|
|
import { getEntityTypeFromServiceCategory } from '../../utils/ServiceUtils';
|
|
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
|
|
import { createTagObject } from '../../utils/TagsUtils';
|
|
import { ServicePageData } from './ServiceDetailsPage';
|
|
|
|
interface ServiceMainTabContentProps {
|
|
serviceName: string;
|
|
servicePermission: OperationPermission;
|
|
serviceDetails: ServicesType;
|
|
onDescriptionUpdate: (updatedHTML: string) => Promise<void>;
|
|
showDeleted: boolean;
|
|
onShowDeletedChange: (value: boolean) => void;
|
|
data: ServicePageData[];
|
|
isServiceLoading: boolean;
|
|
paging: Paging;
|
|
currentPage: number;
|
|
pagingHandler: NextPreviousProps['pagingHandler'];
|
|
saveUpdatedServiceData: (updatedData: ServicesType) => Promise<void>;
|
|
}
|
|
|
|
function ServiceMainTabContent({
|
|
serviceName,
|
|
servicePermission,
|
|
onDescriptionUpdate,
|
|
showDeleted,
|
|
onShowDeletedChange,
|
|
data,
|
|
isServiceLoading,
|
|
paging,
|
|
pagingHandler,
|
|
currentPage,
|
|
serviceDetails,
|
|
saveUpdatedServiceData,
|
|
}: Readonly<ServiceMainTabContentProps>) {
|
|
const { t } = useTranslation();
|
|
const { serviceCategory } = useParams<{
|
|
serviceCategory: ServiceTypes;
|
|
}>();
|
|
|
|
const { fqn: serviceFQN } = useFqn();
|
|
const [isEdit, setIsEdit] = useState(false);
|
|
|
|
const tier = getTierTags(serviceDetails?.tags ?? []);
|
|
const tags = getTagsWithoutTier(serviceDetails?.tags ?? []);
|
|
|
|
/**
|
|
* Formulates updated tags and updates table entity data for API call
|
|
* @param selectedTags
|
|
*/
|
|
const onTagUpdate = async (selectedTags?: Array<EntityTags>) => {
|
|
if (selectedTags) {
|
|
const updatedTags = [...(tier ? [tier] : []), ...selectedTags];
|
|
const updatedTable = { ...serviceDetails, tags: updatedTags };
|
|
await saveUpdatedServiceData(updatedTable);
|
|
}
|
|
};
|
|
|
|
const handleTagSelection = async (selectedTags: EntityTags[]) => {
|
|
if (selectedTags) {
|
|
const prevTags =
|
|
tags?.filter((tag) =>
|
|
selectedTags
|
|
.map((selTag) => selTag.tagFQN)
|
|
.includes(tag?.tagFQN as string)
|
|
) || [];
|
|
const newTags = createTagObject(
|
|
selectedTags.filter((tag) => {
|
|
return !prevTags
|
|
?.map((prevTag) => prevTag.tagFQN)
|
|
.includes(tag.tagFQN);
|
|
})
|
|
);
|
|
|
|
await onTagUpdate([...prevTags, ...newTags]);
|
|
}
|
|
};
|
|
|
|
const handleDescriptionUpdate = useCallback(async (updatedHTML: string) => {
|
|
try {
|
|
await onDescriptionUpdate(updatedHTML);
|
|
} catch (e) {
|
|
// Error
|
|
} finally {
|
|
setIsEdit(false);
|
|
}
|
|
}, []);
|
|
|
|
const onDescriptionEdit = (): void => {
|
|
setIsEdit(true);
|
|
};
|
|
|
|
const onCancel = () => {
|
|
setIsEdit(false);
|
|
};
|
|
|
|
const tableColumn: ColumnsType<ServicePageData> = useMemo(
|
|
() => getServiceMainTabColumns(serviceCategory),
|
|
[serviceCategory]
|
|
);
|
|
|
|
const entityType = useMemo(
|
|
() => getEntityTypeFromServiceCategory(serviceCategory),
|
|
[serviceCategory]
|
|
);
|
|
|
|
const { editTagsPermission, editDescriptionPermission } = useMemo(
|
|
() => ({
|
|
editTagsPermission:
|
|
(servicePermission.EditTags || servicePermission.EditAll) &&
|
|
!serviceDetails.deleted,
|
|
editDescriptionPermission:
|
|
(servicePermission.EditDescription || servicePermission.EditAll) &&
|
|
!serviceDetails.deleted,
|
|
}),
|
|
[servicePermission, serviceDetails]
|
|
);
|
|
|
|
return (
|
|
<Row gutter={[0, 16]} wrap={false}>
|
|
<Col className="tab-content-height-with-resizable-panel" span={24}>
|
|
<ResizablePanels
|
|
firstPanel={{
|
|
className: 'entity-resizable-panel-container',
|
|
children: (
|
|
<div className="p-t-sm m-x-lg">
|
|
<Row gutter={[16, 16]}>
|
|
<Col data-testid="description-container" span={24}>
|
|
<DescriptionV1
|
|
description={serviceDetails.description}
|
|
entityFqn={serviceFQN}
|
|
entityName={serviceName}
|
|
entityType={entityType}
|
|
hasEditAccess={editDescriptionPermission}
|
|
isEdit={isEdit}
|
|
showActions={!serviceDetails.deleted}
|
|
showCommentsIcon={false}
|
|
onCancel={onCancel}
|
|
onDescriptionEdit={onDescriptionEdit}
|
|
onDescriptionUpdate={handleDescriptionUpdate}
|
|
/>
|
|
</Col>
|
|
<Col span={24}>
|
|
<Row justify="end">
|
|
<Col>
|
|
<Switch
|
|
checked={showDeleted}
|
|
data-testid="show-deleted"
|
|
onClick={onShowDeletedChange}
|
|
/>
|
|
<Typography.Text className="m-l-xs">
|
|
{t('label.deleted')}
|
|
</Typography.Text>{' '}
|
|
</Col>
|
|
</Row>
|
|
</Col>
|
|
<Col data-testid="table-container" span={24}>
|
|
<Space
|
|
className="w-full m-b-md"
|
|
direction="vertical"
|
|
size="large">
|
|
{isServiceLoading ? (
|
|
<Loader />
|
|
) : (
|
|
<Table
|
|
bordered
|
|
columns={tableColumn}
|
|
data-testid="service-children-table"
|
|
dataSource={data}
|
|
locale={{
|
|
emptyText: <ErrorPlaceHolder className="m-y-md" />,
|
|
}}
|
|
pagination={false}
|
|
rowKey="id"
|
|
size="small"
|
|
/>
|
|
)}
|
|
{Boolean(!isNil(paging.after) || !isNil(paging.before)) &&
|
|
!isEmpty(data) && (
|
|
<NextPrevious
|
|
currentPage={currentPage}
|
|
isLoading={isServiceLoading}
|
|
pageSize={PAGE_SIZE}
|
|
paging={paging}
|
|
pagingHandler={pagingHandler}
|
|
/>
|
|
)}
|
|
</Space>
|
|
</Col>
|
|
</Row>
|
|
</div>
|
|
),
|
|
...COMMON_RESIZABLE_PANEL_CONFIG.LEFT_PANEL,
|
|
}}
|
|
secondPanel={{
|
|
children: (
|
|
<div data-testid="entity-right-panel">
|
|
<EntityRightPanel
|
|
dataProducts={
|
|
(serviceDetails as DatabaseService)?.dataProducts ?? []
|
|
}
|
|
domain={(serviceDetails as DatabaseService)?.domain}
|
|
editTagPermission={editTagsPermission}
|
|
entityFQN={serviceFQN}
|
|
entityId={serviceDetails.id}
|
|
entityType={entityType}
|
|
selectedTags={tags}
|
|
showDataProductContainer={
|
|
entityType !== EntityType.METADATA_SERVICE
|
|
}
|
|
showTaskHandler={false}
|
|
onTagSelectionChange={handleTagSelection}
|
|
/>
|
|
</div>
|
|
),
|
|
...COMMON_RESIZABLE_PANEL_CONFIG.RIGHT_PANEL,
|
|
className:
|
|
'entity-resizable-right-panel-container entity-resizable-panel-container',
|
|
}}
|
|
/>
|
|
</Col>
|
|
</Row>
|
|
);
|
|
}
|
|
|
|
export default ServiceMainTabContent;
|