From f75b2d9d9f5b5e3aede24acc2bff1f2e80e628cf Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Mon, 8 May 2023 13:06:00 +0530 Subject: [PATCH] refactor (ui): revamp tier component (#11472) * refactor (ui): revamp tier component * fixed failing unit test --- .../CardListItem/CardWithListItem.style.ts | 37 ---- .../CardListItem/CardWithListItem.test.tsx | 138 -------------- .../CardListItem/CardWithListItem.tsx | 170 ------------------ .../TierCard/TierCard.interface.ts} | 27 +-- .../common/TierCard/TierCard.test.tsx | 4 - .../components/common/TierCard/TierCard.tsx | 149 +++++++++++---- .../common/TierCard/tier-card.style.less | 37 ++++ .../src/main/resources/ui/src/styles/app.less | 3 + 8 files changed, 164 insertions(+), 401 deletions(-) delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.style.ts delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.test.tsx delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.tsx rename openmetadata-ui/src/main/resources/ui/src/components/{cardlist/CardListItem/CardWithListItem.interface.ts => common/TierCard/TierCard.interface.ts} (60%) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.style.ts b/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.style.ts deleted file mode 100644 index 891403029f3..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.style.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export const cardStyle = { - base: 'tw-flex tw-flex-col tw-border tw-bg-white', - default: 'tw-border-main', - active: 'tw-border-primary', - selected: 'tw-border-primary', - header: { - base: 'tw-flex tw-px-5 tw-py-3 tw-cursor-pointer tw-justify-between tw-items-center', - default: '', - active: 'tw-bg-primary-lite tw-border-b tw-border-primary', - selected: 'tw-bg-primary tw-text-white', - title: 'tw-text-base tw-mb-0 tw-font-semibold', - description: 'tw-font-medium tw-pr-2 tw-font-normal', - }, - body: { - base: 'tw-py-5 tw-px-10', - default: 'tw-hidden', - active: 'tw-block', - selected: 'tw-block', - content: { - withBorder: 'tw-py-3 tw-border-b tw-border-main', - withoutBorder: 'tw-py-1', - }, - }, -}; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.test.tsx deleted file mode 100644 index ef3523689ea..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.test.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2022 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 { fireEvent, render } from '@testing-library/react'; -import React from 'react'; -import CardListItem from './CardWithListItem'; - -const mockSelectFunction = jest.fn(); -const mockSaveFuntion = jest.fn(); -const mockCard = { - id: 'test1', - title: 'card', - description: 'description*', - data: 'data', -}; - -jest.mock('../../common/rich-text-editor/RichTextEditorPreviewer', () => { - return jest.fn().mockReturnValue(

RichTextEditorPreviewer

); -}); - -describe('Test CardWithListing Component', () => { - it('Component should render', () => { - const { getByTestId } = render( - - ); - - const card = getByTestId('card-list'); - - expect(card).toBeInTheDocument(); - - expect(getByTestId('select-tier-button')).toBeInTheDocument(); - }); - - it('OnClick onSelect function should call', () => { - const { getByTestId } = render( - - ); - - const card = getByTestId('card-list'); - fireEvent( - card, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); - - expect(mockSelectFunction).toHaveBeenCalledTimes(1); - }); - - it('OnClick onSelect function should call and Select tier button should be visible', () => { - const { getByTestId } = render( - - ); - - const card = getByTestId('card-list'); - fireEvent( - card, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); - - expect(mockSelectFunction).toHaveBeenCalledTimes(1); - - const tierSelectButton = getByTestId('select-tier-button'); - - expect(tierSelectButton).toBeInTheDocument(); - }); - - it('onClick of select tier button onSave function should call.', () => { - const { getByTestId } = render( - - ); - - const card = getByTestId('card-list'); - fireEvent( - card, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); - - expect(mockSelectFunction).toHaveBeenCalledTimes(1); - - const tierSelectButton = getByTestId('select-tier-button'); - - expect(tierSelectButton).toBeInTheDocument(); - - fireEvent.click(tierSelectButton); - - expect(mockSaveFuntion).toHaveBeenCalledTimes(1); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.tsx b/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.tsx deleted file mode 100644 index 904bb5a49aa..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.tsx +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2022 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 { DownOutlined, RightOutlined } from '@ant-design/icons'; -import Icon from '@ant-design/icons/lib/components/Icon'; -import { Button } from 'antd'; -import classNames from 'classnames'; -import { t } from 'i18next'; -import React, { FunctionComponent, useEffect, useState } from 'react'; -import { ReactComponent as IconRemove } from '../../../assets/svg/ic-remove.svg'; -import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer'; -import Loader from '../../Loader/Loader'; -import { Props } from './CardWithListItem.interface'; -import { cardStyle } from './CardWithListItem.style'; - -const CardListItem: FunctionComponent = ({ - card, - index, - isActive, - isSelected, - onCardSelect, - onSave, - tierStatus, - className, - onRemove, -}: Props) => { - const [isExpanded, setIsExpanded] = useState(isActive); - - useEffect(() => { - setIsExpanded(isActive); - }, [isActive]); - - const getCardBodyStyle = () => { - const activeStyle = isActive ? cardStyle.active : cardStyle.default; - - return isSelected ? cardStyle.selected : activeStyle; - }; - - const getCardHeaderStyle = () => { - const activeHeaderStyle = isActive - ? cardStyle.header.active - : cardStyle.header.default; - - return isSelected ? cardStyle.header.selected : activeHeaderStyle; - }; - - const getTierSelectButton = (tier: string) => { - switch (tierStatus) { - case 'waiting': - return ( - - ); - - case 'success': - return ( - - ); - - default: - return ( - - ); - } - }; - - const getCardIcon = (cardId: string) => { - if (isSelected || (isSelected && isActive)) { - return ( - - ); - } else if (isActive) { - return getTierSelectButton(cardId); - } else { - return ( - - ); - } - }; - - const handleCardSelect = () => { - onCardSelect(card.id); - }; - - return ( -
-
-
-
- {isExpanded ? ( - setIsExpanded(false)} - /> - ) : ( - setIsExpanded(true)} - /> - )} -
-
-

{card.title}

-

- {card.description.replace(/\*/g, '')} -

-
-
-
{getCardIcon(card.id)}
-
-
- -
-
- ); -}; - -export default CardListItem; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.interface.ts similarity index 60% rename from openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.interface.ts rename to openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.interface.ts index 366f6e6942e..e5852808225 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/cardlist/CardListItem/CardWithListItem.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.interface.ts @@ -1,5 +1,5 @@ /* - * Copyright 2022 Collate. + * 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 @@ -10,9 +10,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { LoadingState } from 'Models'; -import { HTMLAttributes } from 'react'; +import { EntityReference } from 'generated/type/entityReference'; +import { TableDetail } from 'Models'; +import { ReactNode } from 'react'; export type CardWithListItems = { id: string; @@ -21,13 +21,14 @@ export type CardWithListItems = { title: string; }; -export interface Props extends HTMLAttributes { - index: number; - card: CardWithListItems; - isActive: boolean; - isSelected: boolean; - tierStatus: LoadingState; - onSave: (updatedTier: string) => void; - onCardSelect: (cardId: string) => void; - onRemove?: () => void; +export interface TierCardProps { + currentTier?: string; + updateTier?: (value: string) => void; + onSave?: ( + owner?: EntityReference, + tier?: TableDetail['tier'], + isJoinable?: boolean + ) => Promise; + removeTier?: () => void; + children?: ReactNode; } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.test.tsx index 66c8b1308c5..7c17e309d18 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.test.tsx @@ -37,10 +37,6 @@ jest.mock('rest/tagAPI', () => ({ .mockImplementation(() => Promise.resolve({ data: mockTierData })), })); -jest.mock('../../cardlist/CardListItem/CardWithListItem', () => ({ - CardListItem: jest.fn().mockReturnValue(
CardListItem
), -})); - jest.mock('../../Loader/Loader', () => { return jest.fn().mockReturnValue(
Loader
); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.tsx index 319f709b937..0ee4c1fb0f0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/TierCard.tsx @@ -11,33 +11,32 @@ * limitations under the License. */ -import { Card, Col, Popover, Row, Typography } from 'antd'; +import Icon from '@ant-design/icons/lib/components/Icon'; +import { + Button, + Card, + Col, + Collapse, + Popover, + Row, + Space, + Typography, +} from 'antd'; +import { ReactComponent as IconRemove } from 'assets/svg/ic-remove.svg'; import { AxiosError } from 'axios'; import classNames from 'classnames'; import Loader from 'components/Loader/Loader'; import { t } from 'i18next'; -import { LoadingState, TableDetail } from 'Models'; -import React, { ReactNode, useEffect, useState } from 'react'; +import { LoadingState } from 'Models'; +import React, { useEffect, useState } from 'react'; import { getTags } from 'rest/tagAPI'; import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants'; -import { EntityReference } from '../../../generated/type/entityReference'; import { showErrorToast } from '../../../utils/ToastUtils'; -import CardListItem from '../../cardlist/CardListItem/CardWithListItem'; -import { CardWithListItems } from '../../cardlist/CardListItem/CardWithListItem.interface'; +import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer'; import './tier-card.style.less'; +import { CardWithListItems, TierCardProps } from './TierCard.interface'; -export interface TierCardProps { - currentTier?: string; - updateTier?: (value: string) => void; - onSave?: ( - owner?: EntityReference, - tier?: TableDetail['tier'], - isJoinable?: boolean - ) => Promise; - removeTier?: () => void; - children?: ReactNode; -} - +const { Panel } = Collapse; const TierCard = ({ currentTier, updateTier, @@ -105,6 +104,70 @@ const TierCard = ({ updateTier?.(newTier as string); }; + const getTierSelectButton = (tier: string) => { + switch (statusTier) { + case 'waiting': + return ( + + ); + + case 'success': + return ( + + ); + + default: + return ( + + ); + } + }; + + const getCardIcon = (cardId: string) => { + const isSelected = currentTier === cardId; + const isActive = activeTier === cardId; + + if ((isSelected && isActive) || isSelected) { + return ( + + ); + } else if (isActive) { + return getTierSelectButton(cardId); + } else { + return ( + + ); + } + }; + useEffect(() => { setActiveTier(currentTier); if (statusTier === 'waiting') { @@ -135,28 +198,36 @@ const TierCard = ({ }> - {tierData.map((card, i) => ( - handleCardSelection(key as string)}> + {tierData.map((card) => ( + {getCardIcon(card.id)}} + header={ + + + {card.title} + + + {card.description.replace(/\*/g, '')} + + } - )} - index={i} - isActive={activeTier === card.id} - isSelected={card.id === currentTier} - key={i} - tierStatus={statusTier} - onCardSelect={handleCardSelection} - onRemove={removeTier} - onSave={handleTierSave} - /> - ))} + key={card.id}> + + + ))} + {isLoadingTierData && } } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/tier-card.style.less b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/tier-card.style.less index 130183ff383..211578c5418 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/tier-card.style.less +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TierCard/tier-card.style.less @@ -11,6 +11,8 @@ * limitations under the License. */ +@import url('../../../styles/variables.less'); + .tier-card { width: 760px; border: 1px solid #dde3ea; @@ -24,3 +26,38 @@ padding: 0; } } + +.collapse-container { + .collapse-tier-panel { + border: @global-border; + + .ant-collapse-content { + border-color: @primary-color; + } + + &.ant-collapse-item-active { + border: 1px solid @primary-color; + background: #f3f0fd; + } + + &.selected { + border: 1px solid @primary-color; + background: @primary-color; + .ant-collapse-header { + color: @white; + } + } + &:first-child, + &:first-child.ant-collapse-item-active { + border-radius: 4px 4px 0 0; + } + &:last-child { + border-radius: 0 0 4px 4px; + } + } + + &.ant-collapse { + background-color: @white; + border: none; + } +} diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/app.less b/openmetadata-ui/src/main/resources/ui/src/styles/app.less index 9cb00467463..e3da7d2a202 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/app.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/app.less @@ -65,6 +65,9 @@ color: @primary; } } +.text-color-inherit { + color: inherit; +} .error-text { color: #ff4c3b; }