UI: Revamp Manage Tab UI (#4380)

This commit is contained in:
Sachin Chaurasiya 2022-04-23 01:36:52 +05:30 committed by GitHub
parent d84e2c2a8d
commit b5b42e1ca9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 110 additions and 81 deletions

View File

@ -670,6 +670,7 @@ const DashboardDetails = ({
entityName={dashboardDetails.name}
entityType={EntityType.DASHBOARD}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.DASHBOARD}
onSave={onSettingsUpdate}
/>
</div>

View File

@ -741,6 +741,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
entityName={tableDetails.name}
entityType={EntityType.TABLE}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.TABLE}
onSave={onSettingsUpdate}
/>
</div>

View File

@ -26,8 +26,8 @@ import { useAuth } from '../../hooks/authHooks';
import jsonData from '../../jsons/en';
import { getOwnerList } from '../../utils/ManageUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import CardListItem from '../card-list/CardListItem/CardWithListItems';
import { CardWithListItems } from '../card-list/CardListItem/CardWithListItems.interface';
import CardListItem from '../cardlist/CardListItem/CardWithListItem';
import { CardWithListItems } from '../cardlist/CardListItem/CardWithListItem.interface';
import DeleteWidget from '../common/DeleteWidget/DeleteWidget';
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import OwnerWidget from '../common/OwnerWidget/OwnerWidget';
@ -167,37 +167,48 @@ const ManageTab: FunctionComponent<ManageProps> = ({
};
const getTierCards = () => {
if (!hideTier) {
return isLoadingTierData ? (
<Loader />
) : (
<div className="tw-flex tw-flex-col" data-testid="cards">
{tierData.map((card, i) => (
<NonAdminAction
html={
<Fragment>
<p>You need to be owner to perform this action</p>
<p>Claim ownership from above </p>
</Fragment>
}
isOwner={hasEditAccess || Boolean(owner && !currentUser)}
key={i}
permission={Operation.UpdateTags}
position="left">
<CardListItem
card={card}
isActive={activeTier === card.id}
isSelected={card.id === currentTier}
tierStatus={statusTier}
onSave={handleTierSave}
onSelect={handleCardSelection}
/>
</NonAdminAction>
))}
</div>
);
} else {
return (
<div className="tw-flex tw-flex-col tw-mb-7" data-testid="cards">
{tierData.map((card, i) => (
<NonAdminAction
html={
<Fragment>
<p>You need to be owner to perform this action</p>
<p>Claim ownership from above </p>
</Fragment>
}
isOwner={hasEditAccess || Boolean(owner && !currentUser)}
key={i}
permission={Operation.UpdateTags}
position="left">
<CardListItem
card={card}
className={classNames(
'tw-mb-0 tw-shadow',
{
'tw-rounded-t-md': i === 0,
},
{
'tw-rounded-b-md ': i === tierData.length - 1,
}
)}
isActive={activeTier === card.id}
isSelected={card.id === currentTier}
tierStatus={statusTier}
onCardSelect={handleCardSelection}
onSave={handleTierSave}
/>
</NonAdminAction>
))}
</div>
);
};
const getTierWidget = () => {
if (hideTier) {
return null;
} else {
return isLoadingTierData ? <Loader /> : getTierCards();
}
};
@ -291,12 +302,12 @@ const ManageTab: FunctionComponent<ManageProps> = ({
className="tw-max-w-3xl tw-mx-auto"
data-testid="manage-tab"
id="manageTabDetails">
<p className="tw-text-base tw-font-medium">
<p className="tw-text-base tw-font-medium tw-mt-2">
Manage {manageSectionType ? manageSectionType : 'Section'}
</p>
<div
className={classNames('tw-mt-2 tw-pb-4', {
'tw-border-b tw-border-separator tw-mb-4': !hideTier,
'tw-mb-3': !hideTier,
})}>
<OwnerWidget
allowTeamOwner={allowTeamOwner}
@ -316,7 +327,7 @@ const ManageTab: FunctionComponent<ManageProps> = ({
teamJoinable={teamJoinable}
/>
</div>
{getTierCards()}
{getTierWidget()}
{getDeleteEntityWidget()}
</div>
);

View File

@ -68,7 +68,7 @@ const mockTierData = {
const mockFunction = jest.fn().mockImplementation(() => Promise.resolve());
jest.mock('../card-list/CardListItem/CardWithListItems', () => {
jest.mock('../cardlist/CardListItem/CardWithListItem', () => {
return jest.fn().mockReturnValue(<p data-testid="card">CardWithListItems</p>);
});

View File

@ -601,6 +601,7 @@ const PipelineDetails = ({
entityName={pipelineDetails.name}
entityType={EntityType.PIPELINE}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.PIPELINE}
onSave={onSettingsUpdate}
/>
</div>

View File

@ -440,6 +440,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
entityName={topicDetails.name}
entityType={EntityType.TOPIC}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.TOPIC}
onSave={onSettingsUpdate}
/>
</div>

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import { HTMLAttributes } from 'react';
import { Status } from '../../ManageTab/ManageTab.interface';
export type CardWithListItems = {
@ -20,11 +21,11 @@ export type CardWithListItems = {
title: string;
};
export type Props = {
export interface Props extends HTMLAttributes<HTMLDivElement> {
card: CardWithListItems;
isActive: boolean;
isSelected: boolean;
tierStatus: Status;
onSave: (updatedTier: string) => void;
onSelect: (cardId: string) => void;
};
onCardSelect: (cardId: string) => void;
}

View File

@ -12,15 +12,15 @@
*/
export const cardStyle = {
base: 'tw-flex tw-flex-col tw-rounded-md tw-border tw-mb-4',
default: 'tw-border-main',
active: 'tw-border-primary-lite',
base: 'tw-flex tw-flex-col tw-border tw-bg-white',
default: 'tw-border-main tw-border-b-0',
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: 'tw-bg-badge',
active: 'tw-bg-primary-lite tw-rounded-t-md',
selected: 'tw-bg-primary tw-rounded-t-md tw-text-white',
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',
description: 'tw-font-medium tw-pr-2',
},

View File

@ -13,7 +13,7 @@
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import CardListItem from './CardWithListItems';
import CardListItem from './CardWithListItem';
const mockSelectFunction = jest.fn();
const mockSaveFuntion = jest.fn();
@ -36,8 +36,8 @@ describe('Test CardWithListing Component', () => {
isActive={false}
isSelected={false}
tierStatus="initial"
onCardSelect={mockSelectFunction}
onSave={mockSaveFuntion}
onSelect={mockSelectFunction}
/>
);
@ -55,8 +55,8 @@ describe('Test CardWithListing Component', () => {
isActive={false}
isSelected={false}
tierStatus="initial"
onCardSelect={mockSelectFunction}
onSave={mockSaveFuntion}
onSelect={mockSelectFunction}
/>
);
@ -79,8 +79,8 @@ describe('Test CardWithListing Component', () => {
card={mockCard}
isSelected={false}
tierStatus="initial"
onCardSelect={mockSelectFunction}
onSave={mockSaveFuntion}
onSelect={mockSelectFunction}
/>
);
@ -107,8 +107,8 @@ describe('Test CardWithListing Component', () => {
card={mockCard}
isSelected={false}
tierStatus="initial"
onCardSelect={mockSelectFunction}
onSave={mockSaveFuntion}
onSelect={mockSelectFunction}
/>
);

View File

@ -17,52 +17,58 @@ import React, { FunctionComponent } from 'react';
import { Button } from '../../buttons/Button/Button';
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
import Loader from '../../Loader/Loader';
import { Props } from './CardWithListItems.interface';
import { cardStyle } from './CardWithListItems.style';
import { Props } from './CardWithListItem.interface';
import { cardStyle } from './CardWithListItem.style';
const CardListItem: FunctionComponent<Props> = ({
card,
isActive,
isSelected,
onSelect,
onCardSelect,
onSave,
tierStatus,
className,
}: Props) => {
const getCardBodyStyle = () => {
return isSelected
? cardStyle.selected
: isActive
? cardStyle.active
: cardStyle.default;
const activeStyle = isActive ? cardStyle.active : cardStyle.default;
return isSelected ? cardStyle.selected : activeStyle;
};
const getCardHeaderStyle = () => {
return isSelected
? cardStyle.header.selected
: isActive
const activeHeaderStyle = isActive
? cardStyle.header.active
: cardStyle.header.default;
return isSelected ? cardStyle.header.selected : activeHeaderStyle;
};
const getTierSelectButton = (tier: string) => {
return tierStatus === 'waiting' ? (
<Loader
className="tw-inline-block"
size="small"
style={{ marginBottom: '-4px' }}
type="default"
/>
) : tierStatus === 'success' ? (
<FontAwesomeIcon icon="check" />
) : (
<Button
data-testid="select-tier-buuton"
size="small"
theme="primary"
onClick={() => onSave(tier)}>
Select
</Button>
);
switch (tierStatus) {
case 'waiting':
return (
<Loader
className="tw-inline-block"
size="small"
style={{ marginBottom: '-4px' }}
type="default"
/>
);
case 'success':
return <FontAwesomeIcon icon="check" />;
default:
return (
<Button
data-testid="select-tier-buuton"
size="small"
theme="primary"
onClick={() => onSave(tier)}>
Select
</Button>
);
}
};
const getCardIcon = (cardId: string) => {
@ -77,11 +83,15 @@ const CardListItem: FunctionComponent<Props> = ({
}
};
const handleCardSelect = () => {
onCardSelect(card.id);
};
return (
<div
className={classNames(cardStyle.base, getCardBodyStyle())}
className={classNames(cardStyle.base, getCardBodyStyle(), className)}
data-testid="card-list"
onClick={() => onSelect(card.id)}>
onClick={handleCardSelect}>
<div className={classNames(cardStyle.header.base, getCardHeaderStyle())}>
<div className="tw-flex">
<div className="tw-self-start tw-mr-2">

View File

@ -693,6 +693,7 @@ const DatabaseSchemaPage: FunctionComponent = () => {
databaseSchema?.owner?.type || '',
databaseSchema?.owner?.id || ''
)}
manageSectionType={EntityType.DATABASE_SCHEMA}
onSave={handleUpdateOwner}
/>
)}

View File

@ -802,6 +802,7 @@ const DatabaseDetails: FunctionComponent = () => {
database?.owner?.type || '',
database?.owner?.id || ''
)}
manageSectionType={EntityType.DATABASE}
onSave={handleUpdateOwner}
/>
)}

View File

@ -1000,6 +1000,7 @@ const ServicePage: FunctionComponent = () => {
serviceDetails?.owner?.type || '',
serviceDetails?.owner?.id || ''
)}
manageSectionType={serviceCategory.slice(0, -1)}
onSave={handleUpdateOwner}
/>
</div>