mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-27 02:16:18 +00:00
revamp table constraint modal design (#18455)
This commit is contained in:
parent
aea12fe4d5
commit
843f8439ce
@ -10,6 +10,16 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { EntityTabs } from '../../../enums/entity.enum';
|
||||||
|
|
||||||
|
export interface TabProps {
|
||||||
|
label: JSX.Element;
|
||||||
|
key: EntityTabs;
|
||||||
|
children?: JSX.Element;
|
||||||
|
isHidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TabsLabelProps {
|
export interface TabsLabelProps {
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -84,7 +84,7 @@ const TableConstraints: FC<TableConstraintsProps> = ({
|
|||||||
})}>
|
})}>
|
||||||
<Button
|
<Button
|
||||||
className="cursor-pointer hover-cell-icon w-fit-content"
|
className="cursor-pointer hover-cell-icon w-fit-content"
|
||||||
data-testid="edit-displayName-button"
|
data-testid="edit-table-constraint-button"
|
||||||
style={{
|
style={{
|
||||||
color: DE_ACTIVE_COLOR,
|
color: DE_ACTIVE_COLOR,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@ -103,7 +103,7 @@ const TableConstraints: FC<TableConstraintsProps> = ({
|
|||||||
{hasPermission && supportedConstraints.length === 0 && (
|
{hasPermission && supportedConstraints.length === 0 && (
|
||||||
<TagButton
|
<TagButton
|
||||||
className="text-primary cursor-pointer"
|
className="text-primary cursor-pointer"
|
||||||
dataTestId="synonym-add-button"
|
dataTestId="table-constraints-add-button"
|
||||||
icon={<PlusIcon height={16} name="plus" width={16} />}
|
icon={<PlusIcon height={16} name="plus" width={16} />}
|
||||||
label={t('label.add')}
|
label={t('label.add')}
|
||||||
tooltip=""
|
tooltip=""
|
||||||
|
@ -10,13 +10,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import Icon from '@ant-design/icons/lib/components/Icon';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import { Button, Col, Form, Modal, Row, Select } from 'antd';
|
import { Button, Form, Modal, Select } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { debounce, isEmpty } from 'lodash';
|
import { debounce, isEmpty } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ReactComponent as IconDelete } from '../../../../assets/svg/ic-delete.svg';
|
|
||||||
import { ReactComponent as PlusIcon } from '../../../../assets/svg/plus-primary.svg';
|
import { ReactComponent as PlusIcon } from '../../../../assets/svg/plus-primary.svg';
|
||||||
import { PAGE_SIZE } from '../../../../constants/constants';
|
import { PAGE_SIZE } from '../../../../constants/constants';
|
||||||
import { RELATIONSHIP_TYPE_OPTION } from '../../../../constants/Table.constants';
|
import { RELATIONSHIP_TYPE_OPTION } from '../../../../constants/Table.constants';
|
||||||
@ -25,6 +24,7 @@ import { ConstraintType, Table } from '../../../../generated/entity/data/table';
|
|||||||
import { searchQuery } from '../../../../rest/searchAPI';
|
import { searchQuery } from '../../../../rest/searchAPI';
|
||||||
import { getServiceNameQueryFilter } from '../../../../utils/ServiceUtils';
|
import { getServiceNameQueryFilter } from '../../../../utils/ServiceUtils';
|
||||||
import { showErrorToast } from '../../../../utils/ToastUtils';
|
import { showErrorToast } from '../../../../utils/ToastUtils';
|
||||||
|
import './table-constraint.style.less';
|
||||||
import {
|
import {
|
||||||
SelectOptions,
|
SelectOptions,
|
||||||
TableConstraintForm,
|
TableConstraintForm,
|
||||||
@ -171,7 +171,6 @@ const TableConstraintsModal = ({
|
|||||||
title={t(`label.${isEmpty(constraint) ? 'add' : 'update'}-entity`, {
|
title={t(`label.${isEmpty(constraint) ? 'add' : 'update'}-entity`, {
|
||||||
entity: t('label.table-constraint-plural'),
|
entity: t('label.table-constraint-plural'),
|
||||||
})}
|
})}
|
||||||
width={600}
|
|
||||||
onCancel={onClose}>
|
onCancel={onClose}>
|
||||||
<Form
|
<Form
|
||||||
className="table-constraint-form"
|
className="table-constraint-form"
|
||||||
@ -182,106 +181,91 @@ const TableConstraintsModal = ({
|
|||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
<>
|
<>
|
||||||
{fields.map(({ key, name, ...restField }) => (
|
{fields.map(({ key, name, ...restField }) => (
|
||||||
<Row gutter={8} key={key}>
|
<div className="table-constraint-form-container" key={key}>
|
||||||
<Col span={12}>
|
<Form.Item
|
||||||
<Form.Item
|
className="w-full"
|
||||||
className="w-full"
|
{...restField}
|
||||||
{...restField}
|
label={t('label.entity-name', {
|
||||||
label={t('label.entity-name', {
|
entity: t('label.column'),
|
||||||
entity: t('label.column'),
|
})}
|
||||||
})}
|
name={[name, 'columns']}
|
||||||
name={[name, 'columns']}
|
rules={[
|
||||||
rules={[
|
{
|
||||||
{
|
required: true,
|
||||||
required: true,
|
message: t('label.field-required', {
|
||||||
message: t('label.field-required', {
|
field: t('label.entity-name', {
|
||||||
field: t('label.entity-name', {
|
entity: t('label.column'),
|
||||||
entity: t('label.column'),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
},
|
}),
|
||||||
]}>
|
},
|
||||||
<Select
|
]}>
|
||||||
data-testid={`${key}-column-type-select`}
|
<Select
|
||||||
options={tableColumnNameOptions}
|
data-testid={`${key}-column-type-select`}
|
||||||
/>
|
options={tableColumnNameOptions}
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
{...restField}
|
|
||||||
label={t('label.entity-type-plural', {
|
|
||||||
entity: t('label.relationship'),
|
|
||||||
})}
|
|
||||||
name={[name, 'relationshipType']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t('label.field-required', {
|
|
||||||
field: t('label.entity-type-plural', {
|
|
||||||
entity: t('label.relationship'),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Select
|
|
||||||
data-testid={`${key}-relationship-type-select`}
|
|
||||||
options={RELATIONSHIP_TYPE_OPTION}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col span={23}>
|
|
||||||
<Form.Item
|
|
||||||
{...restField}
|
|
||||||
label={t('label.related-column')}
|
|
||||||
name={[name, 'referredColumns']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t('label.field-required', {
|
|
||||||
field: t('label.related-column'),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
data-testid={`${key}-related-column-select`}
|
|
||||||
loading={isRelatedColumnLoading}
|
|
||||||
options={relatedColumns}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
onSearch={handleSearch}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col span={1}>
|
|
||||||
<Button
|
|
||||||
data-testid={`${key}-delete-constraint-button`}
|
|
||||||
icon={
|
|
||||||
<Icon
|
|
||||||
className="align-middle"
|
|
||||||
component={IconDelete}
|
|
||||||
style={{ fontSize: '16px' }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
size="small"
|
|
||||||
type="text"
|
|
||||||
onClick={() => remove(name)}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Form.Item>
|
||||||
</Row>
|
<Form.Item
|
||||||
|
{...restField}
|
||||||
|
className="w-full"
|
||||||
|
label={t('label.entity-type-plural', {
|
||||||
|
entity: t('label.relationship'),
|
||||||
|
})}
|
||||||
|
name={[name, 'relationshipType']}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('label.field-required', {
|
||||||
|
field: t('label.entity-type-plural', {
|
||||||
|
entity: t('label.relationship'),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Select
|
||||||
|
data-testid={`${key}-relationship-type-select`}
|
||||||
|
options={RELATIONSHIP_TYPE_OPTION}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...restField}
|
||||||
|
className="w-full"
|
||||||
|
label={t('label.related-column')}
|
||||||
|
name={[name, 'referredColumns']}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('label.field-required', {
|
||||||
|
field: t('label.related-column'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Select
|
||||||
|
showSearch
|
||||||
|
data-testid={`${key}-related-column-select`}
|
||||||
|
loading={isRelatedColumnLoading}
|
||||||
|
options={relatedColumns}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Button
|
||||||
|
className="delete-constraint-button"
|
||||||
|
data-testid={`${key}-delete-constraint-button`}
|
||||||
|
icon={<CloseOutlined className="text-grey-muted" />}
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
onClick={() => remove(name)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
<Form.Item>
|
<Button
|
||||||
<Button
|
className="text-primary d-flex items-center m-t-md"
|
||||||
className="text-primary d-flex items-center"
|
data-testid="add-constraint-button"
|
||||||
data-testid="add-constraint-button"
|
icon={<PlusIcon className="anticon" />}
|
||||||
icon={<PlusIcon className="anticon" />}
|
size="small"
|
||||||
size="small"
|
onClick={() => add()}>
|
||||||
onClick={() => add()}>
|
{t('label.add')}
|
||||||
{t('label.add')}
|
</Button>
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 url('../../../../styles/variables.less');
|
||||||
|
|
||||||
|
.table-constraint-form-container {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
background: @grey-6;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: @global-border;
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-constraint-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { TabsProps } from 'antd';
|
|
||||||
import { EntityTags, PagingResponse } from 'Models';
|
import { EntityTags, PagingResponse } from 'Models';
|
||||||
import { PagingHandlerParams } from '../components/common/NextPrevious/NextPrevious.interface';
|
import { PagingHandlerParams } from '../components/common/NextPrevious/NextPrevious.interface';
|
||||||
|
import { TabProps } from '../components/common/TabsLabel/TabsLabel.interface';
|
||||||
import { EntityTabs } from '../enums/entity.enum';
|
import { EntityTabs } from '../enums/entity.enum';
|
||||||
import { DatabaseSchema } from '../generated/entity/data/databaseSchema';
|
import { DatabaseSchema } from '../generated/entity/data/databaseSchema';
|
||||||
import { Table } from '../generated/entity/data/table';
|
import { Table } from '../generated/entity/data/table';
|
||||||
@ -56,7 +56,7 @@ export interface DatabaseSchemaPageTabProps {
|
|||||||
class DatabaseSchemaClassBase {
|
class DatabaseSchemaClassBase {
|
||||||
public getDatabaseSchemaPageTabs(
|
public getDatabaseSchemaPageTabs(
|
||||||
databaseSchemaTabData: DatabaseSchemaPageTabProps
|
databaseSchemaTabData: DatabaseSchemaPageTabProps
|
||||||
): TabsProps['items'] {
|
): TabProps[] {
|
||||||
return getDataBaseSchemaPageBaseTabs(databaseSchemaTabData);
|
return getDataBaseSchemaPageBaseTabs(databaseSchemaTabData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { ActivityFeedTab } from '../components/ActivityFeed/ActivityFeedTab/Acti
|
|||||||
import { CustomPropertyTable } from '../components/common/CustomPropertyTable/CustomPropertyTable';
|
import { CustomPropertyTable } from '../components/common/CustomPropertyTable/CustomPropertyTable';
|
||||||
import ResizablePanels from '../components/common/ResizablePanels/ResizablePanels';
|
import ResizablePanels from '../components/common/ResizablePanels/ResizablePanels';
|
||||||
import TabsLabel from '../components/common/TabsLabel/TabsLabel.component';
|
import TabsLabel from '../components/common/TabsLabel/TabsLabel.component';
|
||||||
|
import { TabProps } from '../components/common/TabsLabel/TabsLabel.interface';
|
||||||
import EntityRightPanel from '../components/Entity/EntityRightPanel/EntityRightPanel';
|
import EntityRightPanel from '../components/Entity/EntityRightPanel/EntityRightPanel';
|
||||||
import { COMMON_RESIZABLE_PANEL_CONFIG } from '../constants/ResizablePanel.constants';
|
import { COMMON_RESIZABLE_PANEL_CONFIG } from '../constants/ResizablePanel.constants';
|
||||||
import { EntityTabs, EntityType, TabSpecificField } from '../enums/entity.enum';
|
import { EntityTabs, EntityType, TabSpecificField } from '../enums/entity.enum';
|
||||||
@ -57,7 +58,7 @@ export const getDataBaseSchemaPageBaseTabs = ({
|
|||||||
getEntityFeedCount,
|
getEntityFeedCount,
|
||||||
fetchDatabaseSchemaDetails,
|
fetchDatabaseSchemaDetails,
|
||||||
handleFeedCount,
|
handleFeedCount,
|
||||||
}: DatabaseSchemaPageTabProps) => {
|
}: DatabaseSchemaPageTabProps): TabProps[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { TabProps } from '../components/common/TabsLabel/TabsLabel.interface';
|
||||||
import { OperationPermission } from '../context/PermissionProvider/PermissionProvider.interface';
|
import { OperationPermission } from '../context/PermissionProvider/PermissionProvider.interface';
|
||||||
import { EntityTabs } from '../enums/entity.enum';
|
import { EntityTabs } from '../enums/entity.enum';
|
||||||
import { Table } from '../generated/entity/data/table';
|
import { Table } from '../generated/entity/data/table';
|
||||||
@ -43,7 +44,7 @@ export interface TableDetailPageTabProps {
|
|||||||
class TableClassBase {
|
class TableClassBase {
|
||||||
public getTableDetailPageTabs(
|
public getTableDetailPageTabs(
|
||||||
tableDetailsPageProps: TableDetailPageTabProps
|
tableDetailsPageProps: TableDetailPageTabProps
|
||||||
) {
|
): TabProps[] {
|
||||||
return getTableDetailPageBaseTabs(tableDetailsPageProps);
|
return getTableDetailPageBaseTabs(tableDetailsPageProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ import { CustomPropertyTable } from '../components/common/CustomPropertyTable/Cu
|
|||||||
import ErrorPlaceHolder from '../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||||
import QueryViewer from '../components/common/QueryViewer/QueryViewer.component';
|
import QueryViewer from '../components/common/QueryViewer/QueryViewer.component';
|
||||||
import TabsLabel from '../components/common/TabsLabel/TabsLabel.component';
|
import TabsLabel from '../components/common/TabsLabel/TabsLabel.component';
|
||||||
|
import { TabProps } from '../components/common/TabsLabel/TabsLabel.interface';
|
||||||
import TableProfiler from '../components/Database/Profiler/TableProfiler/TableProfiler';
|
import TableProfiler from '../components/Database/Profiler/TableProfiler/TableProfiler';
|
||||||
import SampleDataTableComponent from '../components/Database/SampleDataTable/SampleDataTable.component';
|
import SampleDataTableComponent from '../components/Database/SampleDataTable/SampleDataTable.component';
|
||||||
import TableQueries from '../components/Database/TableQueries/TableQueries';
|
import TableQueries from '../components/Database/TableQueries/TableQueries';
|
||||||
@ -643,7 +644,7 @@ export const getTableDetailPageBaseTabs = ({
|
|||||||
fetchTableDetails,
|
fetchTableDetails,
|
||||||
testCaseSummary,
|
testCaseSummary,
|
||||||
isViewTableType,
|
isViewTableType,
|
||||||
}: TableDetailPageTabProps) => {
|
}: TableDetailPageTabProps): TabProps[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />,
|
label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user