mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-03 19:16:10 +00:00
Fix: Miscellaneous UI issues (#4472)
This commit is contained in:
parent
b75fa0fe6f
commit
02bc6f24de
@ -34,6 +34,7 @@ import {
|
||||
getHtmlForNonAdminAction,
|
||||
getUserTeams,
|
||||
isEven,
|
||||
pluralize,
|
||||
} from '../../utils/CommonUtils';
|
||||
import { getEntityFeedLink } from '../../utils/EntityUtils';
|
||||
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||
@ -388,6 +389,14 @@ const DashboardDetails = ({
|
||||
setThreadLink('');
|
||||
};
|
||||
|
||||
const getDeleteEntityMessage = () => {
|
||||
return `Deleting this ${EntityType.DASHBOARD} will also delete ${pluralize(
|
||||
charts.length,
|
||||
'chart',
|
||||
's'
|
||||
)}`;
|
||||
};
|
||||
|
||||
const getLoader = () => {
|
||||
return isentityThreadLoading ? <Loader /> : null;
|
||||
};
|
||||
@ -666,6 +675,7 @@ const DashboardDetails = ({
|
||||
allowDelete
|
||||
currentTier={tier?.tagFQN}
|
||||
currentUser={owner?.id}
|
||||
deletEntityMessage={getDeleteEntityMessage()}
|
||||
entityId={dashboardDetails.id}
|
||||
entityName={dashboardDetails.name}
|
||||
entityType={EntityType.DASHBOARD}
|
||||
|
||||
@ -153,6 +153,7 @@ jest.mock('../../utils/CommonUtils', () => ({
|
||||
getHtmlForNonAdminAction: jest.fn(),
|
||||
getEntityPlaceHolder: jest.fn().mockReturnValue('value'),
|
||||
getEntityName: jest.fn().mockReturnValue('entityName'),
|
||||
pluralize: jest.fn().mockReturnValue('2 charts'),
|
||||
}));
|
||||
|
||||
describe('Test DashboardDetails component', () => {
|
||||
|
||||
@ -220,7 +220,7 @@ const Users = ({
|
||||
const getDisplayNameComponent = () => {
|
||||
if (isAdminUser || isLoggedinUser) {
|
||||
return (
|
||||
<div className="tw-mt-4 tw-w-full tw-text-center">
|
||||
<div className="tw-mt-4 tw-w-full">
|
||||
{isDisplayNameEdit ? (
|
||||
<div className="tw-flex tw-items-center tw-gap-1">
|
||||
<input
|
||||
@ -519,7 +519,7 @@ const Users = ({
|
||||
const fetchLeftPanel = () => {
|
||||
return (
|
||||
<div className="tw-pt-4" data-testid="left-panel">
|
||||
<div className="tw-pb-4 tw-mb-4 tw-border-b tw-flex tw-flex-col tw-items-center">
|
||||
<div className="tw-pb-4 tw-mb-4 tw-border-b tw-flex tw-flex-col">
|
||||
{userData.profile?.images?.image ? (
|
||||
<div className="tw-h-28 tw-w-28">
|
||||
<img
|
||||
@ -537,7 +537,7 @@ const Users = ({
|
||||
)}
|
||||
{getDisplayNameComponent()}
|
||||
<p className="tw-mt-2">{userData.email}</p>
|
||||
{getDescriptionComponent()}
|
||||
<div className="tw--ml-5">{getDescriptionComponent()}</div>
|
||||
</div>
|
||||
{getTeamsComponent()}
|
||||
{getRolesComponent()}
|
||||
|
||||
@ -229,6 +229,7 @@ li.ProseMirror-selectednode:after {
|
||||
/* default UI Styles */
|
||||
.toastui-editor-defaultUI .ProseMirror {
|
||||
padding: 18px 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.toastui-editor-defaultUI {
|
||||
|
||||
@ -11,12 +11,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
faAngleRight,
|
||||
faExclamationCircle,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { isString, isUndefined, startCase, uniqueId } from 'lodash';
|
||||
import { isNil, isString, isUndefined, startCase, uniqueId } from 'lodash';
|
||||
import { ExtraInfo } from 'Models';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
@ -28,6 +25,7 @@ import { CurrentTourPageType } from '../../../enums/tour.enum';
|
||||
import { TableType } from '../../../generated/entity/data/table';
|
||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||
import { serviceTypeLogo } from '../../../utils/ServiceUtils';
|
||||
import { stringToHTML } from '../../../utils/StringsUtils';
|
||||
import { getEntityLink, getUsagePercentile } from '../../../utils/TableUtils';
|
||||
import './TableDataCard.style.css';
|
||||
import TableDataCardBody from './TableDataCardBody';
|
||||
@ -67,6 +65,9 @@ const TableDataCard: FunctionComponent<Props> = ({
|
||||
matches,
|
||||
tableType,
|
||||
deleted = false,
|
||||
name,
|
||||
database,
|
||||
databaseSchema,
|
||||
}: Props) => {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
@ -116,25 +117,17 @@ const TableDataCard: FunctionComponent<Props> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const fqnParts = fullyQualifiedName.split(FQN_SEPARATOR_CHAR);
|
||||
const separatorHtml = (
|
||||
<span className="tw-px-2">
|
||||
<FontAwesomeIcon
|
||||
className="tw-text-xs tw-cursor-default tw-text-gray-400 tw-align-middle"
|
||||
icon={faAngleRight}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
const tableTitle = fqnParts.map((part, i) => {
|
||||
const separator = i !== fqnParts.length - 1 ? separatorHtml : null;
|
||||
|
||||
const getTableMetaInfo = () => {
|
||||
if (!isNil(database) && !isNil(databaseSchema)) {
|
||||
return (
|
||||
<span key={i}>
|
||||
<span>{part}</span>
|
||||
{separator}
|
||||
</span>
|
||||
<span
|
||||
className="tw-text-grey-muted tw-text-xs tw-mb-0.5"
|
||||
data-testid="database-schema">{`${database}${FQN_SEPARATOR_CHAR}${databaseSchema}`}</span>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -142,6 +135,7 @@ const TableDataCard: FunctionComponent<Props> = ({
|
||||
data-testid="table-data-card"
|
||||
id={id}>
|
||||
<div>
|
||||
{getTableMetaInfo()}
|
||||
<div className="tw-flex tw-items-center">
|
||||
<img
|
||||
alt=""
|
||||
@ -154,7 +148,7 @@ const TableDataCard: FunctionComponent<Props> = ({
|
||||
data-testid="table-link"
|
||||
id={`${id}Title`}
|
||||
onClick={handleLinkClick}>
|
||||
<span className="table-title">{tableTitle}</span>
|
||||
{stringToHTML(name)}
|
||||
</button>
|
||||
</h6>
|
||||
{deleted && (
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isEmpty, isUndefined } from 'lodash';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { FormatedTableData } from 'Models';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { ReactNode } from 'react';
|
||||
@ -76,18 +76,7 @@ const SearchedData: React.FC<SearchedDataProp> = ({
|
||||
|
||||
let name = table.name;
|
||||
if (!isUndefined(table.highlight)) {
|
||||
const [assetName] = Object.keys(table.highlight).filter((name) =>
|
||||
ASSETS_NAME.includes(name)
|
||||
);
|
||||
name = !isEmpty(
|
||||
table.highlight?.[assetName as keyof FormatedTableData['highlight']]
|
||||
)
|
||||
? (
|
||||
table.highlight?.[
|
||||
assetName as keyof FormatedTableData['highlight']
|
||||
] as string[]
|
||||
).join(' ')
|
||||
: name;
|
||||
name = table.highlight?.name?.join(' ') || name;
|
||||
}
|
||||
|
||||
const matches = table.highlight
|
||||
|
||||
@ -219,7 +219,7 @@ declare module 'Models' {
|
||||
tier: string | TagLabel;
|
||||
highlight?: {
|
||||
description: string[];
|
||||
table_name: string[];
|
||||
name: string[];
|
||||
};
|
||||
index: string;
|
||||
database?: string;
|
||||
|
||||
@ -67,6 +67,7 @@ import {
|
||||
getEntityName,
|
||||
hasEditAccess,
|
||||
isEven,
|
||||
pluralize,
|
||||
} from '../../utils/CommonUtils';
|
||||
import { getInfoElements } from '../../utils/EntityUtils';
|
||||
import {
|
||||
@ -633,6 +634,43 @@ const ServicePage: FunctionComponent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getDeleteEntityMessage = () => {
|
||||
const service = serviceName?.slice(0, -1);
|
||||
|
||||
switch (serviceName) {
|
||||
case ServiceCategory.DATABASE_SERVICES:
|
||||
return `Deleting this ${service} will also delete ${pluralize(
|
||||
instanceCount,
|
||||
'database',
|
||||
's'
|
||||
)}`;
|
||||
|
||||
case ServiceCategory.MESSAGING_SERVICES:
|
||||
return `Deleting this ${service} will also delete ${pluralize(
|
||||
instanceCount,
|
||||
'topic',
|
||||
's'
|
||||
)}`;
|
||||
|
||||
case ServiceCategory.DASHBOARD_SERVICES:
|
||||
return `Deleting this ${service} will also delete ${pluralize(
|
||||
instanceCount,
|
||||
'dashboard',
|
||||
's'
|
||||
)}`;
|
||||
|
||||
case ServiceCategory.PIPELINE_SERVICES:
|
||||
return `Deleting this ${service} will also delete ${pluralize(
|
||||
instanceCount,
|
||||
'pipeline',
|
||||
's'
|
||||
)}`;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setServiceName(serviceCategory || getServiceCategoryFromType(serviceType));
|
||||
}, [serviceCategory, serviceType]);
|
||||
@ -968,6 +1006,7 @@ const ServicePage: FunctionComponent = () => {
|
||||
hideTier
|
||||
isRecursiveDelete
|
||||
currentUser={serviceDetails?.owner?.id}
|
||||
deletEntityMessage={getDeleteEntityMessage()}
|
||||
entityId={serviceDetails?.id}
|
||||
entityName={serviceDetails?.name}
|
||||
entityType={serviceCategory.slice(0, -1)}
|
||||
|
||||
@ -191,10 +191,7 @@ describe('Test Service page', () => {
|
||||
'service-description'
|
||||
);
|
||||
const type = await findAllByTestId(container, 'service-type');
|
||||
const deleteIcon = await findAllByTestId(
|
||||
container,
|
||||
'delete-icon-container'
|
||||
);
|
||||
|
||||
const icon = await findAllByTestId(container, 'service-icon');
|
||||
|
||||
expect(tabs[0]).toHaveClass('activeCategory');
|
||||
@ -203,7 +200,6 @@ describe('Test Service page', () => {
|
||||
mockDatabaseService.data.data.length
|
||||
);
|
||||
expect(type.length).toBe(mockDatabaseService.data.data.length);
|
||||
expect(deleteIcon.length).toBe(mockDatabaseService.data.data.length);
|
||||
expect(icon.length).toBe(mockDatabaseService.data.data.length);
|
||||
});
|
||||
});
|
||||
|
||||
@ -20,7 +20,6 @@ import { Link, useHistory } from 'react-router-dom';
|
||||
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
||||
import { addAirflowPipeline } from '../../axiosAPIs/airflowPipelineAPI';
|
||||
import {
|
||||
deleteService,
|
||||
getServiceDetails,
|
||||
getServices,
|
||||
postService,
|
||||
@ -35,7 +34,6 @@ import PageContainerV1 from '../../components/containers/PageContainerV1';
|
||||
import PageLayout from '../../components/containers/PageLayout';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import { AddServiceModal } from '../../components/Modals/AddServiceModal/AddServiceModal';
|
||||
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
|
||||
import {
|
||||
getServiceDetailsPath,
|
||||
PAGE_SIZE,
|
||||
@ -73,7 +71,6 @@ import { getDashboardURL } from '../../utils/DashboardServiceUtils';
|
||||
import { getBrokers } from '../../utils/MessagingServiceUtils';
|
||||
import { getAddServicePath } from '../../utils/RouterUtils';
|
||||
import { getErrorText } from '../../utils/StringsUtils';
|
||||
import SVGIcons from '../../utils/SvgUtils';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
|
||||
type ServiceRecord = {
|
||||
@ -106,11 +103,6 @@ const ServicesPage = () => {
|
||||
const { isAdminUser } = useAuth();
|
||||
const { isAuthDisabled } = useAuthContext();
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
|
||||
const [deleteSelection, setDeleteSelection] = useState({
|
||||
id: '',
|
||||
name: '',
|
||||
});
|
||||
const [serviceName, setServiceName] =
|
||||
useState<ServiceTypes>('databaseServices');
|
||||
const [paging, setPaging] = useState<ServicePagingRecord>({
|
||||
@ -363,47 +355,6 @@ const ServicesPage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancelConfirmationModal = () => {
|
||||
setIsConfirmationModalOpen(false);
|
||||
setDeleteSelection({
|
||||
id: '',
|
||||
name: '',
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
deleteService(serviceName, id)
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.statusText === 'OK') {
|
||||
const updatedServiceList = serviceList.filter((s) => s.id !== id);
|
||||
setServices({ ...services, [serviceName]: updatedServiceList });
|
||||
setServicesCount((pre) => ({
|
||||
...servicesCount,
|
||||
[serviceName]: pre[serviceName] - 1,
|
||||
}));
|
||||
setServiceList(updatedServiceList);
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['unexpected-server-response'];
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
showErrorToast(
|
||||
err,
|
||||
jsonData['api-error-messages']['delete-service-error']
|
||||
);
|
||||
});
|
||||
|
||||
handleCancelConfirmationModal();
|
||||
};
|
||||
|
||||
const ConfirmDelete = (id: string, name: string) => {
|
||||
setDeleteSelection({
|
||||
id,
|
||||
name,
|
||||
});
|
||||
setIsConfirmationModalOpen(true);
|
||||
};
|
||||
|
||||
const getServiceTabs = (): Array<{
|
||||
name: ServiceTypes;
|
||||
displayName: string;
|
||||
@ -554,20 +505,6 @@ const ServicesPage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const getConfirmationModal = () => {
|
||||
return isConfirmationModalOpen ? (
|
||||
<ConfirmationModal
|
||||
bodyText={`You want to delete service ${deleteSelection.name} permanently? This action cannot be reverted.`}
|
||||
cancelText="Cancel"
|
||||
confirmButtonCss="tw-bg-error hover:tw-bg-error focus:tw-bg-error"
|
||||
confirmText="Delete"
|
||||
header="Are you sure?"
|
||||
onCancel={handleCancelConfirmationModal}
|
||||
onConfirm={() => handleDelete(deleteSelection.id)}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const getAddServiceModal = () => {
|
||||
return isModalOpen ? (
|
||||
<AddServiceModal
|
||||
@ -670,27 +607,6 @@ const ServicesPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="tw-flex tw-flex-col tw-justify-between tw-flex-none">
|
||||
<div
|
||||
className="tw-flex tw-justify-end"
|
||||
data-testid="delete-icon-container">
|
||||
<NonAdminAction
|
||||
position="top"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<button
|
||||
className="focus:tw-outline-none"
|
||||
data-testid={`delete-service-${service.name}`}
|
||||
onClick={() =>
|
||||
ConfirmDelete(service.id || '', service.name)
|
||||
}>
|
||||
<SVGIcons
|
||||
alt="delete"
|
||||
icon="icon-delete"
|
||||
title="Delete"
|
||||
width="12px"
|
||||
/>
|
||||
</button>
|
||||
</NonAdminAction>
|
||||
</div>
|
||||
<div
|
||||
className="tw-flex tw-justify-end"
|
||||
data-testid="service-icon">
|
||||
@ -741,8 +657,6 @@ const ServicesPage = () => {
|
||||
{getPagination()}
|
||||
|
||||
{getAddServiceModal()}
|
||||
|
||||
{getConfirmationModal()}
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user