UI Improvements (#10034)

* UI Improvements

* fix restore modal unit test

* Remove tooltip from active button and optimse code

* remove console

* used enum for loading state
This commit is contained in:
Ashish Gupta 2023-02-02 17:09:09 +05:30 committed by GitHub
parent d7b40162fd
commit 66f4136fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 191 additions and 200 deletions

View File

@ -12,9 +12,9 @@
*/ */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Space, Switch, Typography } from 'antd'; import { Button, Space, Switch, Typography } from 'antd';
import classNames from 'classnames';
import Tags from 'components/Tag/Tags/tags'; import Tags from 'components/Tag/Tags/tags';
import { LOADING_STATE } from 'enums/common.enum';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { EntityTags } from 'Models'; import { EntityTags } from 'Models';
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
@ -26,12 +26,10 @@ import { CreateGlossary } from '../../generated/api/data/createGlossary';
import { EntityReference } from '../../generated/type/entityReference'; import { EntityReference } from '../../generated/type/entityReference';
import { getCurrentUserId, requiredField } from '../../utils/CommonUtils'; import { getCurrentUserId, requiredField } from '../../utils/CommonUtils';
import { AddTags } from '../AddTags/add-tags.component'; import { AddTags } from '../AddTags/add-tags.component';
import { Button } from '../buttons/Button/Button';
import RichTextEditor from '../common/rich-text-editor/RichTextEditor'; import RichTextEditor from '../common/rich-text-editor/RichTextEditor';
import { EditorContentRef } from '../common/rich-text-editor/RichTextEditor.interface'; import { EditorContentRef } from '../common/rich-text-editor/RichTextEditor.interface';
import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component'; import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component';
import PageLayout from '../containers/PageLayout'; import PageLayout from '../containers/PageLayout';
import Loader from '../Loader/Loader';
import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component'; import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component';
import { AddGlossaryError, AddGlossaryProps } from './AddGlossary.interface'; import { AddGlossaryError, AddGlossaryProps } from './AddGlossary.interface';
@ -137,44 +135,6 @@ const AddGlossary = ({
} }
}; };
const getSaveButton = () => {
return allowAccess ? (
<>
{saveState === 'waiting' ? (
<Button
disabled
className="tw-w-16 tw-h-10 disabled:tw-opacity-100"
size="regular"
theme="primary"
variant="contained">
<Loader size="small" type="white" />
</Button>
) : saveState === 'success' ? (
<Button
disabled
className="tw-w-16 tw-h-10 disabled:tw-opacity-100"
size="regular"
theme="primary"
variant="contained">
<FontAwesomeIcon icon="check" />
</Button>
) : (
<Button
className={classNames('tw-w-16 tw-h-10', {
'tw-opacity-40': !allowAccess,
})}
data-testid="save-glossary"
size="regular"
theme="primary"
variant="contained"
onClick={handleSave}>
{t('label.save')}
</Button>
)}
</>
) : null;
};
const fetchRightPanel = () => { const fetchRightPanel = () => {
return ( return (
<> <>
@ -270,11 +230,9 @@ const AddGlossary = ({
{t('label.reviewer-plural')}: {t('label.reviewer-plural')}:
</span> </span>
<Button <Button
className="tw-h-5 tw-px-2"
data-testid="add-reviewers" data-testid="add-reviewers"
size="x-small" size="small"
theme="primary" type="primary"
variant="contained"
onClick={() => setShowReviewerModal(true)}> onClick={() => setShowReviewerModal(true)}>
<FontAwesomeIcon icon="plus" /> <FontAwesomeIcon icon="plus" />
</Button> </Button>
@ -300,13 +258,19 @@ const AddGlossary = ({
<div className="flex justify-end"> <div className="flex justify-end">
<Button <Button
data-testid="cancel-glossary" data-testid="cancel-glossary"
size="regular" type="link"
theme="primary"
variant="text"
onClick={onCancel}> onClick={onCancel}>
{t('label.cancel')} {t('label.cancel')}
</Button> </Button>
{getSaveButton()}
<Button
data-testid="save-glossary"
disabled={!allowAccess}
loading={saveState === LOADING_STATE.WAITING}
type="primary"
onClick={handleSave}>
{t('label.save')}
</Button>
</div> </div>
</div> </div>
<ReviewerModal <ReviewerModal

View File

@ -399,12 +399,16 @@ const Ingestion: React.FC<IngestionProps> = ({
<span className="tw-inline-block tw-text-gray-400 tw-self-center">|</span> <span className="tw-inline-block tw-text-gray-400 tw-self-center">|</span>
); );
const getIngestionPermission = (name: string): boolean =>
!isRequiredDetailsAvailable || getEditPermission(name);
const getTriggerDeployButton = (ingestion: IngestionPipeline) => { const getTriggerDeployButton = (ingestion: IngestionPipeline) => {
if (ingestion.deployed) { if (ingestion.deployed) {
return ( return (
<> <>
<Button <Button
data-testid="run" data-testid="run"
disabled={getIngestionPermission(ingestion.name)}
type="link" type="link"
onClick={() => onClick={() =>
handleTriggerIngestion(ingestion.id as string, ingestion.name) handleTriggerIngestion(ingestion.id as string, ingestion.name)
@ -415,9 +419,7 @@ const Ingestion: React.FC<IngestionProps> = ({
<Button <Button
data-testid="re-deploy-btn" data-testid="re-deploy-btn"
disabled={ disabled={getIngestionPermission(ingestion.name)}
!isRequiredDetailsAvailable || getEditPermission(ingestion.name)
}
type="link" type="link"
onClick={() => handleDeployIngestion(ingestion.id as string)}> onClick={() => handleDeployIngestion(ingestion.id as string)}>
{getLoadingStatus(currDeployId, ingestion.id, t('label.re-deploy'))} {getLoadingStatus(currDeployId, ingestion.id, t('label.re-deploy'))}
@ -428,9 +430,7 @@ const Ingestion: React.FC<IngestionProps> = ({
return ( return (
<Button <Button
data-testid="deploy" data-testid="deploy"
disabled={ disabled={getIngestionPermission(ingestion.name)}
!isRequiredDetailsAvailable || getEditPermission(ingestion.name)
}
type="link" type="link"
onClick={() => handleDeployIngestion(ingestion.id as string)}> onClick={() => handleDeployIngestion(ingestion.id as string)}>
{getLoadingStatus(currDeployId, ingestion.id, t('label.deploy'))} {getLoadingStatus(currDeployId, ingestion.id, t('label.deploy'))}
@ -529,10 +529,7 @@ const Ingestion: React.FC<IngestionProps> = ({
{separator} {separator}
<Button <Button
data-testid="pause" data-testid="pause"
disabled={ disabled={getIngestionPermission(record.name)}
!isRequiredDetailsAvailable ||
getEditPermission(record.name)
}
type="link" type="link"
onClick={() => onClick={() =>
handleEnableDisableIngestion(record.id || '') handleEnableDisableIngestion(record.id || '')
@ -543,10 +540,7 @@ const Ingestion: React.FC<IngestionProps> = ({
) : ( ) : (
<Button <Button
data-testid="unpause" data-testid="unpause"
disabled={ disabled={getIngestionPermission(record.name)}
!isRequiredDetailsAvailable ||
getEditPermission(record.name)
}
type="link" type="link"
onClick={() => handleEnableDisableIngestion(record.id || '')}> onClick={() => handleEnableDisableIngestion(record.id || '')}>
{t('label.unpause')} {t('label.unpause')}
@ -555,9 +549,7 @@ const Ingestion: React.FC<IngestionProps> = ({
{separator} {separator}
<Button <Button
data-testid="edit" data-testid="edit"
disabled={ disabled={getIngestionPermission(record.name)}
!isRequiredDetailsAvailable || getEditPermission(record.name)
}
type="link" type="link"
onClick={() => handleUpdate(record)}> onClick={() => handleUpdate(record)}>
{t('label.edit')} {t('label.edit')}
@ -581,7 +573,7 @@ const Ingestion: React.FC<IngestionProps> = ({
{separator} {separator}
<Button <Button
data-testid="kill" data-testid="kill"
disabled={!isRequiredDetailsAvailable} disabled={getIngestionPermission(record.name)}
type="link" type="link"
onClick={() => { onClick={() => {
setIsKillModalOpen(true); setIsKillModalOpen(true);

View File

@ -404,14 +404,6 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
/> />
)} )}
<Tooltip
title={
editTest
? t('label.add-entity', {
entity: t('label.test'),
})
: t('message.no-permission-for-action')
}>
<Link <Link
to={ to={
editTest editTest
@ -421,6 +413,8 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
) )
: '#' : '#'
}> }>
<Tooltip
title={!editTest && t('message.no-permission-for-action')}>
<Button <Button
className="rounded-4" className="rounded-4"
data-testid="profiler-add-table-test-btn" data-testid="profiler-add-table-test-btn"
@ -430,10 +424,11 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
entity: t('label.test'), entity: t('label.test'),
})} })}
</Button> </Button>
</Link>
</Tooltip> </Tooltip>
</Link>
<Tooltip <Tooltip
placement="topRight"
title={ title={
editTest editTest
? t('label.setting-plural') ? t('label.setting-plural')

View File

@ -13,7 +13,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { import {
Button as ButtonAntd, Button,
Col, Col,
Dropdown, Dropdown,
Modal, Modal,
@ -37,6 +37,7 @@ import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { restoreTeam } from 'rest/teamsAPI'; import { restoreTeam } from 'rest/teamsAPI';
import AppState from '../../AppState'; import AppState from '../../AppState';
import { ReactComponent as IconEdit } from '../../assets/svg/ic-edit.svg';
import { import {
getTeamAndUserDetailsPath, getTeamAndUserDetailsPath,
getUserPath, getUserPath,
@ -80,7 +81,6 @@ import {
getDeleteMessagePostFix, getDeleteMessagePostFix,
} from '../../utils/TeamUtils'; } from '../../utils/TeamUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
import { Button } from '../buttons/Button/Button';
import Description from '../common/description/Description'; import Description from '../common/description/Description';
import ManageButton from '../common/entityPageInfo/ManageButton/ManageButton'; import ManageButton from '../common/entityPageInfo/ManageButton/ManageButton';
import EntitySummaryDetails from '../common/EntitySummaryDetails/EntitySummaryDetails'; import EntitySummaryDetails from '../common/EntitySummaryDetails/EntitySummaryDetails';
@ -248,16 +248,15 @@ const TeamDetailsV1 = ({
button ? ( button ? (
button button
) : ( ) : (
<ButtonAntd <Button
ghost ghost
data-testid={datatestid} data-testid={datatestid}
disabled={disabled} disabled={disabled}
size="small"
title={title} title={title}
type="primary" type="primary"
onClick={onClick}> onClick={onClick}>
{label} {label}
</ButtonAntd> </Button>
) )
} }
description={description} description={description}
@ -290,7 +289,7 @@ const TeamDetailsV1 = ({
? t('label.remove') ? t('label.remove')
: t('message.no-permission-for-action') : t('message.no-permission-for-action')
}> }>
<ButtonAntd <Button
data-testid="remove-user-btn" data-testid="remove-user-btn"
disabled={!entityPermissions.EditAll} disabled={!entityPermissions.EditAll}
icon={ icon={
@ -822,17 +821,14 @@ const TeamDetailsV1 = ({
{currentTeamUsers.length > 0 && isActionAllowed() && ( {currentTeamUsers.length > 0 && isActionAllowed() && (
<div> <div>
<Button <Button
className="tw-h-8 tw-px-2"
data-testid="add-user" data-testid="add-user"
disabled={!entityPermissions.EditAll} disabled={!entityPermissions.EditAll}
size="small"
theme="primary"
title={ title={
entityPermissions.EditAll entityPermissions.EditAll
? t('label.add-entity', { entity: t('label.user') }) ? t('label.add-entity', { entity: t('label.user') })
: t('message.no-permission-for-action') : t('message.no-permission-for-action')
} }
variant="contained" type="primary"
onClick={() => { onClick={() => {
handleAddUser(true); handleAddUser(true);
}}> }}>
@ -891,9 +887,9 @@ const TeamDetailsV1 = ({
), ),
button: ( button: (
<Link to="/explore"> <Link to="/explore">
<ButtonAntd ghost size="small" type="primary"> <Button ghost type="primary">
{t('label.explore')} {t('label.explore')}
</ButtonAntd> </Button>
</Link> </Link>
), ),
}); });
@ -938,23 +934,15 @@ const TeamDetailsV1 = ({
const teamActionButton = (alreadyJoined: boolean, isJoinable: boolean) => { const teamActionButton = (alreadyJoined: boolean, isJoinable: boolean) => {
return alreadyJoined ? ( return alreadyJoined ? (
isJoinable || hasAccess ? ( isJoinable || hasAccess ? (
<Button <Button data-testid="join-teams" type="primary" onClick={joinTeam}>
className="tw-h-8 tw-px-2"
data-testid="join-teams"
size="small"
theme="primary"
variant="contained"
onClick={joinTeam}>
{t('label.join-team')} {t('label.join-team')}
</Button> </Button>
) : null ) : null
) : ( ) : (
<Button <Button
className="tw-h-8 tw-rounded" ghost
data-testid="leave-team-button" data-testid="leave-team-button"
size="small" type="primary"
theme="primary"
variant="outlined"
onClick={() => currentUser && deleteUserHandler(currentUser.id, true)}> onClick={() => currentUser && deleteUserHandler(currentUser.id, true)}>
{t('label.leave-team')} {t('label.leave-team')}
</Button> </Button>
@ -980,18 +968,14 @@ const TeamDetailsV1 = ({
<Button <Button
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1" className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1"
data-testid="cancelAssociatedTag" data-testid="cancelAssociatedTag"
size="custom" type="primary"
theme="primary"
variant="contained"
onMouseDown={() => setIsHeadingEditing(false)}> onMouseDown={() => setIsHeadingEditing(false)}>
<FontAwesomeIcon className="tw-w-3.5 tw-h-3.5" icon="times" /> <FontAwesomeIcon className="tw-w-3.5 tw-h-3.5" icon="times" />
</Button> </Button>
<Button <Button
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm" className="tw-px-1 tw-py-1 tw-rounded tw-text-sm"
data-testid="saveAssociatedTag" data-testid="saveAssociatedTag"
size="custom" type="primary"
theme="primary"
variant="contained"
onMouseDown={handleHeadingSave}> onMouseDown={handleHeadingSave}>
<FontAwesomeIcon className="tw-w-3.5 tw-h-3.5" icon="check" /> <FontAwesomeIcon className="tw-w-3.5 tw-h-3.5" icon="check" />
</Button> </Button>
@ -1014,8 +998,8 @@ const TeamDetailsV1 = ({
}) })
: t('message.no-permission-for-action') : t('message.no-permission-for-action')
}> }>
<button <Button
className="tw-ml-2 focus:tw-outline-none" className="m-l-xss p-0"
data-testid="edit-synonyms" data-testid="edit-synonyms"
disabled={ disabled={
!( !(
@ -1023,14 +1007,11 @@ const TeamDetailsV1 = ({
entityPermissions.EditAll entityPermissions.EditAll
) )
} }
onClick={() => setIsHeadingEditing(true)}> icon={<IconEdit height={16} width={16} />}
<SVGIcons size="small"
alt={t('label.edit')} type="text"
className="tw-mb-1" onClick={() => setIsHeadingEditing(true)}
icon="icon-edit"
width="16px"
/> />
</button>
</Tooltip> </Tooltip>
</div> </div>
)} )}
@ -1103,7 +1084,7 @@ const TeamDetailsV1 = ({
placement="bottomRight" placement="bottomRight"
trigger={['click']} trigger={['click']}
onOpenChange={setShowActions}> onOpenChange={setShowActions}>
<ButtonAntd <Button
className="rounded-4 w-6 manage-dropdown-button" className="rounded-4 w-6 manage-dropdown-button"
data-testid="teams-dropdown" data-testid="teams-dropdown"
size="small"> size="small">
@ -1111,7 +1092,7 @@ const TeamDetailsV1 = ({
className="text-primary self-center manage-dropdown-icon" className="text-primary self-center manage-dropdown-icon"
icon="ellipsis-vertical" icon="ellipsis-vertical"
/> />
</ButtonAntd> </Button>
</Dropdown> </Dropdown>
)} )}
</div> </div>
@ -1199,7 +1180,7 @@ const TeamDetailsV1 = ({
</Col> </Col>
<Col> <Col>
<Space align="center"> <Space align="center">
<ButtonAntd <Button
data-testid="add-team" data-testid="add-team"
disabled={!createTeamPermission} disabled={!createTeamPermission}
title={ title={
@ -1210,7 +1191,7 @@ const TeamDetailsV1 = ({
type="primary" type="primary"
onClick={() => handleAddTeam(true)}> onClick={() => handleAddTeam(true)}>
{addTeam} {addTeam}
</ButtonAntd> </Button>
</Space> </Space>
</Col> </Col>
<Col span={24}> <Col span={24}>
@ -1248,7 +1229,7 @@ const TeamDetailsV1 = ({
<Space <Space
className="tw-w-full roles-and-policy" className="tw-w-full roles-and-policy"
direction="vertical"> direction="vertical">
<ButtonAntd <Button
data-testid="add-role" data-testid="add-role"
disabled={!entityPermissions.EditAll} disabled={!entityPermissions.EditAll}
title={ title={
@ -1264,7 +1245,7 @@ const TeamDetailsV1 = ({
}) })
}> }>
{addRole} {addRole}
</ButtonAntd> </Button>
<ListEntities <ListEntities
hasAccess={entityPermissions.EditAll} hasAccess={entityPermissions.EditAll}
list={currentTeam.defaultRoles || []} list={currentTeam.defaultRoles || []}
@ -1296,7 +1277,7 @@ const TeamDetailsV1 = ({
<Space <Space
className="tw-w-full roles-and-policy" className="tw-w-full roles-and-policy"
direction="vertical"> direction="vertical">
<ButtonAntd <Button
data-testid="add-policy" data-testid="add-policy"
disabled={!entityPermissions.EditAll} disabled={!entityPermissions.EditAll}
title={ title={
@ -1312,7 +1293,7 @@ const TeamDetailsV1 = ({
}) })
}> }>
{addPolicy} {addPolicy}
</ButtonAntd> </Button>
<ListEntities <ListEntities
hasAccess={entityPermissions.EditAll} hasAccess={entityPermissions.EditAll}
list={currentTeam.policies || []} list={currentTeam.policies || []}
@ -1331,16 +1312,15 @@ const TeamDetailsV1 = ({
buttons={ buttons={
<div className="tw-text-lg tw-text-center"> <div className="tw-text-lg tw-text-center">
<Button <Button
ghost
data-testid="add-team" data-testid="add-team"
disabled={!createTeamPermission} disabled={!createTeamPermission}
size="small"
theme="primary"
title={ title={
createTeamPermission createTeamPermission
? addTeam ? addTeam
: t('message.no-permission-for-action') : t('message.no-permission-for-action')
} }
variant="outlined" type="primary"
onClick={() => handleAddTeam(true)}> onClick={() => handleAddTeam(true)}>
{t('label.add-new-entity', { entity: t('label.team') })} {t('label.add-new-entity', { entity: t('label.team') })}
</Button> </Button>

View File

@ -11,14 +11,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Space, Tooltip } from 'antd'; import { Button, Space, Tooltip } from 'antd';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
import { useAuth } from '../../hooks/authHooks'; import { useAuth } from '../../hooks/authHooks';
import { IcDeleteColored } from '../../utils/SvgUtils'; import { IcDeleteColored } from '../../utils/SvgUtils';
import { useAuthContext } from '../authentication/auth-provider/AuthProvider'; import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
import { Button } from '../buttons/Button/Button';
import DeleteWidgetModal from '../common/DeleteWidget/DeleteWidgetModal'; import DeleteWidgetModal from '../common/DeleteWidget/DeleteWidgetModal';
import Description from '../common/description/Description'; import Description from '../common/description/Description';
import EntitySummaryDetails from '../common/EntitySummaryDetails/EntitySummaryDetails'; import EntitySummaryDetails from '../common/EntitySummaryDetails/EntitySummaryDetails';
@ -55,20 +54,23 @@ const TestSuiteDetails = ({
titleLinks={slashedBreadCrumb} titleLinks={slashedBreadCrumb}
/> />
<Tooltip <Tooltip
title={hasAccess ? t('label.delete') : NO_PERMISSION_FOR_ACTION}> placement="topRight"
title={!hasAccess && NO_PERMISSION_FOR_ACTION}>
<Button <Button
ghost
data-testid="test-suite-delete" data-testid="test-suite-delete"
disabled={!hasAccess} disabled={!hasAccess}
size="small" icon={
theme="primary"
variant="outlined"
onClick={() => handleDeleteWidgetVisible(true)}>
<IcDeleteColored <IcDeleteColored
className="tw-mr-1.5" className="anticon"
height={14} height={14}
viewBox="0 0 24 24" viewBox="0 0 24 24"
width={14} width={14}
/> />
}
size="small"
type="primary"
onClick={() => handleDeleteWidgetVisible(true)}>
<span>{t('label.delete')}</span> <span>{t('label.delete')}</span>
</Button> </Button>
</Tooltip> </Tooltip>

View File

@ -129,6 +129,15 @@ describe('Test manage button component', () => {
fireEvent.click(restoreOption); fireEvent.click(restoreOption);
const modalBody = await screen.findByTestId('restore-modal-body');
expect(modalBody).toBeInTheDocument();
const modalRestoreButton = await screen.findAllByText('label.restore');
screen.debug(modalRestoreButton);
fireEvent.click(modalRestoreButton[1]);
expect(mockOnRestoreEntity).toHaveBeenCalled(); expect(mockOnRestoreEntity).toHaveBeenCalled();
}); });
}); });

View File

@ -12,7 +12,7 @@
*/ */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Col, Dropdown, Row, Tooltip, Typography } from 'antd'; import { Button, Col, Dropdown, Modal, Row, Tooltip, Typography } from 'antd';
import { ItemType } from 'antd/lib/menu/hooks/useItems'; import { ItemType } from 'antd/lib/menu/hooks/useItems';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { FC, useState } from 'react'; import React, { FC, useState } from 'react';
@ -63,6 +63,7 @@ const ManageButton: FC<Props> = ({
const { t } = useTranslation(); const { t } = useTranslation();
const [showActions, setShowActions] = useState<boolean>(false); const [showActions, setShowActions] = useState<boolean>(false);
const [isDelete, setIsDelete] = useState<boolean>(false); const [isDelete, setIsDelete] = useState<boolean>(false);
const [showReactiveModal, setShowReactiveModal] = useState(false);
const items = [ const items = [
{ {
@ -118,7 +119,7 @@ const ManageButton: FC<Props> = ({
if (canDelete) { if (canDelete) {
e.stopPropagation(); e.stopPropagation();
setShowActions(false); setShowActions(false);
onRestoreEntity && onRestoreEntity(); setShowReactiveModal(true);
} }
}}> }}>
<Col span={3}> <Col span={3}>
@ -233,6 +234,29 @@ const ManageButton: FC<Props> = ({
onCancel={() => setIsDelete(false)} onCancel={() => setIsDelete(false)}
/> />
)} )}
<Modal
centered
cancelButtonProps={{
type: 'link',
}}
className="reactive-modal"
closable={false}
okText={t('label.restore')}
open={showReactiveModal}
title={t('label.restore-entity', {
entity: entityType,
})}
onCancel={() => {
setShowReactiveModal(false);
}}
onOk={onRestoreEntity}>
<Typography.Text data-testid="restore-modal-body">
{t('message.are-you-want-to-restore', {
entity: entityName,
})}
</Typography.Text>
</Modal>
</> </>
); );
}; };

View File

@ -13,10 +13,11 @@
import { faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons'; import { faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from 'antd';
import React, { FC, useEffect, useState } from 'react'; import React, { FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { CursorType } from '../../../enums/pagination.enum'; import { CursorType } from '../../../enums/pagination.enum';
import { Paging } from '../../../generated/type/paging'; import { Paging } from '../../../generated/type/paging';
import { Button } from '../../buttons/Button/Button';
interface Prop { interface Prop {
paging: Paging; paging: Paging;
@ -39,6 +40,7 @@ const NextPrevious: FC<Prop> = ({
isNumberBased = false, isNumberBased = false,
currentPage, currentPage,
}: Prop) => { }: Prop) => {
const { t } = useTranslation();
const [activePage, setActivePage] = useState(1); const [activePage, setActivePage] = useState(1);
const onNextHandler = () => { const onNextHandler = () => {
@ -86,18 +88,14 @@ const NextPrevious: FC<Prop> = ({
className="tw-my-4 tw-flex tw-justify-center tw-items-center tw-gap-2" className="tw-my-4 tw-flex tw-justify-center tw-items-center tw-gap-2"
data-testid="pagination"> data-testid="pagination">
<Button <Button
className="tw-rounded tw-w-24 tw-px-3 tw-py-1.5 tw-text-sm" ghost
className="hover-button text-sm flex-center"
data-testid="previous" data-testid="previous"
disabled={computePrevDisableState()} disabled={computePrevDisableState()}
size="custom" type="primary"
theme="primary"
variant="outlined"
onClick={onPreviousHandler}> onClick={onPreviousHandler}>
<FontAwesomeIcon <FontAwesomeIcon className="text-sm p-r-xs" icon={faArrowLeft} />
className="tw-text-sm tw-align-middle tw-pr-1.5" <span>{t('label.previous')}</span>
icon={faArrowLeft}
/>{' '}
<span>Previous</span>
</Button> </Button>
<span <span
className="tw-px-2" className="tw-px-2"
@ -106,18 +104,14 @@ const NextPrevious: FC<Prop> = ({
totalCount totalCount
)} Page`}</span> )} Page`}</span>
<Button <Button
className="tw-rounded tw-w-24 tw-px-3 tw-py-1.5 tw-text-sm" ghost
className="hover-button text-sm flex-center"
data-testid="next" data-testid="next"
disabled={computeNextDisableState()} disabled={computeNextDisableState()}
size="custom" type="primary"
theme="primary"
variant="outlined"
onClick={onNextHandler}> onClick={onNextHandler}>
<span> Next</span>{' '} <span> {t('label.next')}</span>
<FontAwesomeIcon <FontAwesomeIcon className="text-sm p-l-xs" icon={faArrowRight} />
className="tw-text-sm tw-align-middle tw-pl-1.5"
icon={faArrowRight}
/>
</Button> </Button>
</div> </div>
); );

View File

@ -394,6 +394,7 @@
"press": "Press", "press": "Press",
"preview": "Preview", "preview": "Preview",
"preview-uploaded-data": "Preview uploaded data", "preview-uploaded-data": "Preview uploaded data",
"previous": "Previous",
"primary-key": "Primary Key", "primary-key": "Primary Key",
"private-key": "PrivateKey", "private-key": "PrivateKey",
"profile": "Profile", "profile": "Profile",

View File

@ -42,6 +42,7 @@ import {
updateThread, updateThread,
} from 'rest/feedsAPI'; } from 'rest/feedsAPI';
import AppState from '../../../AppState'; import AppState from '../../../AppState';
import { ReactComponent as IconEdit } from '../../../assets/svg/ic-edit.svg';
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants'; import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
import { PanelTab, TaskOperation } from '../../../constants/Feeds.constants'; import { PanelTab, TaskOperation } from '../../../constants/Feeds.constants';
import { EntityType } from '../../../enums/entity.enum'; import { EntityType } from '../../../enums/entity.enum';
@ -67,7 +68,6 @@ import {
updateThreadData, updateThreadData,
} from '../../../utils/FeedUtils'; } from '../../../utils/FeedUtils';
import { getEncodedFqn } from '../../../utils/StringsUtils'; import { getEncodedFqn } from '../../../utils/StringsUtils';
import SVGIcons from '../../../utils/SvgUtils';
import { getEntityLink } from '../../../utils/TableUtils'; import { getEntityLink } from '../../../utils/TableUtils';
import { import {
fetchEntityDetail, fetchEntityDetail,
@ -629,17 +629,14 @@ const TaskDetailPage = () => {
className="tw-ml-0.5 tw-align-middle tw-inline-flex tw-flex-wrap" className="tw-ml-0.5 tw-align-middle tw-inline-flex tw-flex-wrap"
/> />
{(hasEditAccess() || isCreator) && !isTaskClosed && ( {(hasEditAccess() || isCreator) && !isTaskClosed && (
<button <Button
className="focus:tw-outline-none tw-self-baseline tw-flex-none" className="p-0"
data-testid="edit-suggestion" data-testid="edit-suggestion"
onClick={() => setEditAssignee(true)}> icon={<IconEdit height={14} width={14} />}
<SVGIcons size="small"
alt="edit" type="text"
icon="icon-edit" onClick={() => setEditAssignee(true)}
title="Edit"
width="14px"
/> />
</button>
)} )}
</Fragment> </Fragment>
)} )}

View File

@ -19,11 +19,14 @@ import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichText
import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component'; import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component';
import PageLayoutV1 from 'components/containers/PageLayoutV1'; import PageLayoutV1 from 'components/containers/PageLayoutV1';
import Loader from 'components/Loader/Loader'; import Loader from 'components/Loader/Loader';
import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider';
import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface';
import { isEmpty } from 'lodash'; import { 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 { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { getListTestSuites } from 'rest/testAPI'; import { getListTestSuites } from 'rest/testAPI';
import { checkPermission } from 'utils/PermissionsUtils';
import { import {
INITIAL_PAGING_VALUE, INITIAL_PAGING_VALUE,
MAX_CHAR_LIMIT_TEST_SUITE, MAX_CHAR_LIMIT_TEST_SUITE,
@ -33,6 +36,7 @@ import {
} from '../../constants/constants'; } from '../../constants/constants';
import { WEBHOOK_DOCS } from '../../constants/docs.constants'; import { WEBHOOK_DOCS } from '../../constants/docs.constants';
import { TEST_SUITE_BREADCRUMB } from '../../constants/TestSuite.constant'; import { TEST_SUITE_BREADCRUMB } from '../../constants/TestSuite.constant';
import { Operation } from '../../generated/entity/policies/policy';
import { TestSuite } from '../../generated/tests/testSuite'; import { TestSuite } from '../../generated/tests/testSuite';
import { Paging } from '../../generated/type/paging'; import { Paging } from '../../generated/type/paging';
import { getEntityName, pluralize } from '../../utils/CommonUtils'; import { getEntityName, pluralize } from '../../utils/CommonUtils';
@ -45,6 +49,15 @@ const TestSuitePage = () => {
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const [testSuitePage, setTestSuitePage] = useState(INITIAL_PAGING_VALUE); const [testSuitePage, setTestSuitePage] = useState(INITIAL_PAGING_VALUE);
const [testSuitePaging, setTestSuitePaging] = useState<Paging>(pagingObject); const [testSuitePaging, setTestSuitePaging] = useState<Paging>(pagingObject);
const { permissions } = usePermissionProvider();
const createPermission = useMemo(() => {
return checkPermission(
Operation.Create,
ResourceEntity.TEST_SUITE,
permissions
);
}, [permissions]);
const fetchTestSuites = async (param?: Record<string, string>) => { const fetchTestSuites = async (param?: Record<string, string>) => {
try { try {
@ -144,6 +157,7 @@ const TestSuitePage = () => {
ghost ghost
className="h-8 rounded-4 tw-m-y-sm" className="h-8 rounded-4 tw-m-y-sm"
data-testid="add-test-suite-button" data-testid="add-test-suite-button"
disabled={!createPermission}
size="small" size="small"
type="primary" type="primary"
onClick={onAddTestSuite}> onClick={onAddTestSuite}>
@ -173,14 +187,19 @@ const TestSuitePage = () => {
<PageLayoutV1> <PageLayoutV1>
<Space align="center" className="w-full justify-between" size={16}> <Space align="center" className="w-full justify-between" size={16}>
<TitleBreadcrumb titleLinks={TEST_SUITE_BREADCRUMB} /> <TitleBreadcrumb titleLinks={TEST_SUITE_BREADCRUMB} />
<Tooltip
placement="topRight"
title={!createPermission && t('message.no-permission-for-action')}>
<Button <Button
data-testid="add-test-suite" data-testid="add-test-suite"
disabled={!createPermission}
type="primary" type="primary"
onClick={onAddTestSuite}> onClick={onAddTestSuite}>
{t('label.add-entity', { {t('label.add-entity', {
entity: t('label.test-suite'), entity: t('label.test-suite'),
})} })}
</Button> </Button>
</Tooltip>
</Space> </Space>
<Row className="w-full mt-4"> <Row className="w-full mt-4">

View File

@ -14,7 +14,6 @@
import { Button, Col, Row, Space, Tooltip, Typography } from 'antd'; import { Button, Col, Row, Space, Tooltip, Typography } from 'antd';
import Table, { ColumnsType } from 'antd/lib/table'; import Table, { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { Button as LegacyButton } from 'components/buttons/Button/Button';
import DeleteWidgetModal from 'components/common/DeleteWidget/DeleteWidgetModal'; import DeleteWidgetModal from 'components/common/DeleteWidget/DeleteWidgetModal';
import Description from 'components/common/description/Description'; import Description from 'components/common/description/Description';
import EntitySummaryDetails from 'components/common/EntitySummaryDetails/EntitySummaryDetails'; import EntitySummaryDetails from 'components/common/EntitySummaryDetails/EntitySummaryDetails';
@ -974,26 +973,28 @@ const ServicePage: FunctionComponent = () => {
{serviceDetails?.serviceType !== {serviceDetails?.serviceType !==
MetadataServiceType.OpenMetadata && ( MetadataServiceType.OpenMetadata && (
<Tooltip <Tooltip
placement="topRight"
title={ title={
servicePermission.Delete !servicePermission.Delete &&
? t('label.delete') t('message.no-permission-for-action')
: t('message.no-permission-for-action')
}> }>
<LegacyButton <Button
ghost
data-testid="service-delete" data-testid="service-delete"
disabled={!servicePermission.Delete} disabled={!servicePermission.Delete}
size="small" icon={
theme="primary"
variant="outlined"
onClick={handleDelete}>
<IcDeleteColored <IcDeleteColored
className="m-r-xs" className="anticon"
height={14} height={14}
viewBox="0 0 24 24" viewBox="0 0 24 24"
width={14} width={14}
/> />
}
size="small"
type="primary"
onClick={handleDelete}>
{t('label.delete')} {t('label.delete')}
</LegacyButton> </Button>
</Tooltip> </Tooltip>
)} )}
<DeleteWidgetModal <DeleteWidgetModal

View File

@ -11,6 +11,8 @@
* limitations under the License. * limitations under the License.
*/ */
@import url('../variables.less');
.ant-btn, .ant-btn,
button { button {
&:disabled { &:disabled {
@ -21,3 +23,14 @@ button {
} }
} }
} }
.ant-btn-background-ghost.ant-btn-primary.hover-button:hover {
background: @primary-color;
color: @white;
}
.ant-btn-background-ghost.hover-button.ant-btn-primary[disabled]:hover {
background: initial;
color: initial;
opacity: 0.45;
}