mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-26 09:22:14 +00:00
Chore(ui): Layout and styling fixes according to the new design (#20647)
* Refactor: Remove AlertsActivityFeedPage and update related components - Deleted AlertsActivityFeedPage component since it was old and not being used. - Removed unused import and route for AlertsActivityFeedPage in SettingsRouter. - Fix the layout for the following pages: 1. Add and edit alert page 2. Alert details page 3. Role details page 4. Policy details page 5. Add user and admin page 6. Add and edit Rule page 7. Custom property settings page. * Fix the type error in the CI * Fix the vertical alignment of ingestion table rows * Fix the unit tests * Fix SettingsRouter test
This commit is contained in:
parent
188f575180
commit
7331dea463
@ -26,11 +26,6 @@ jest.mock('../../pages/AlertDetailsPage/AlertDetailsPage', () => ({
|
||||
default: jest.fn().mockReturnValue(<div>AlertDetailsPage</div>),
|
||||
}));
|
||||
|
||||
jest.mock('../../pages/AlertsActivityFeedPage/AlertsActivityFeedPage', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockReturnValue(<div>AlertsActivityFeedPage</div>),
|
||||
}));
|
||||
|
||||
jest.mock('../../pages/Application/ApplicationPage', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockReturnValue(<div>ApplicationPage</div>),
|
||||
@ -450,18 +445,6 @@ describe('SettingsRouter', () => {
|
||||
expect(await screen.findByText('ApplicationPage')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render AlertsActivityFeedPage component for alerts activity feed route', async () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={[`/settings/notifications/activityFeeds`]}>
|
||||
<SettingsRouter />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(
|
||||
await screen.findByText('AlertsActivityFeedPage')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render AlertDetailsPage component for alert details route', async () => {
|
||||
render(
|
||||
<MemoryRouter
|
||||
|
@ -23,7 +23,6 @@ import { Operation } from '../../generated/entity/policies/accessControl/resourc
|
||||
import { TeamType } from '../../generated/entity/teams/team';
|
||||
import AddNotificationPage from '../../pages/AddNotificationPage/AddNotificationPage';
|
||||
import AlertDetailsPage from '../../pages/AlertDetailsPage/AlertDetailsPage';
|
||||
import AlertsActivityFeedPage from '../../pages/AlertsActivityFeedPage/AlertsActivityFeedPage';
|
||||
import AppearanceConfigSettingsPage from '../../pages/AppearanceConfigSettingsPage/AppearanceConfigSettingsPage';
|
||||
import ApplicationPage from '../../pages/Application/ApplicationPage';
|
||||
import BotsPageV1 from '../../pages/BotsPageV1/BotsPageV1.component';
|
||||
@ -375,16 +374,6 @@ const SettingsRouter = () => {
|
||||
path={getSettingCategoryPath(GlobalSettingsMenuCategory.SERVICES)}
|
||||
/>
|
||||
|
||||
<AdminProtectedRoute
|
||||
exact
|
||||
component={AlertsActivityFeedPage}
|
||||
hasPermission={false}
|
||||
path={getSettingPath(
|
||||
GlobalSettingsMenuCategory.NOTIFICATIONS,
|
||||
GlobalSettingOptions.ACTIVITY_FEED
|
||||
)}
|
||||
/>
|
||||
|
||||
<AdminProtectedRoute
|
||||
exact
|
||||
component={CustomPropertiesPageV1}
|
||||
|
@ -66,6 +66,7 @@ import Table from '../../../../common/Table/Table';
|
||||
import EntityDeleteModal from '../../../../Modals/EntityDeleteModal/EntityDeleteModal';
|
||||
import { SelectedRowDetails } from '../ingestion.interface';
|
||||
import { IngestionRecentRuns } from '../IngestionRecentRun/IngestionRecentRuns.component';
|
||||
import './ingestion-list-table.less';
|
||||
import {
|
||||
IngestionListTableProps,
|
||||
ModifiedIngestionPipeline,
|
||||
@ -448,7 +449,7 @@ function IngestionListTable({
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames(tableContainerClassName)}
|
||||
className={classNames('ingestion-list-table', tableContainerClassName)}
|
||||
data-testid="ingestion-table">
|
||||
<Table
|
||||
className={tableClassName}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 Collate.
|
||||
* Copyright 2025 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,24 +10,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.roles-detail {
|
||||
.list-table {
|
||||
.ant-table-row .ant-table-cell:first-child,
|
||||
.ant-table-thead .ant-table-cell:first-child {
|
||||
padding-left: 16px;
|
||||
.ingestion-list-table {
|
||||
.ant-table {
|
||||
.ant-table-thead tr > th {
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
.role-detail-tab.ant-space {
|
||||
> .ant-space-item:first-child {
|
||||
align-self: flex-end;
|
||||
.ant-table-cell {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link-hover {
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
@ -54,12 +54,6 @@
|
||||
tr > td:first-child.name-column {
|
||||
padding-left: 16px;
|
||||
}
|
||||
.ant-table-thead tr > th {
|
||||
text-transform: none;
|
||||
}
|
||||
.ant-table-cell {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
export enum AlertDetailTabs {
|
||||
CONFIGURATION = 'configuration',
|
||||
RECENT_EVENTS = 'recentEvents',
|
||||
DIAGNOSTIC_INFO = 'diagnostic info',
|
||||
DIAGNOSTIC_INFO = 'diagnostic-info',
|
||||
}
|
||||
|
||||
export enum AlertRecentEventFilters {
|
||||
|
@ -1508,6 +1508,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -286,6 +286,10 @@ export interface Connection {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -3377,6 +3377,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -1392,6 +1392,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -1924,6 +1924,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -48,10 +48,6 @@ export interface SnowflakeConnection {
|
||||
* Optional configuration for ingestion of streams, By default, it will skip the streams.
|
||||
*/
|
||||
includeStreams?: boolean;
|
||||
/**
|
||||
* Optional configuration for ingestion of streams, By default, it will skip the streams.
|
||||
*/
|
||||
includeStreams?: boolean;
|
||||
/**
|
||||
* Optional configuration for ingestion of TRANSIENT tables, By default, it will skip the
|
||||
* TRANSIENT tables.
|
||||
|
@ -1549,6 +1549,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -3888,6 +3888,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -392,6 +392,10 @@ export interface Connection {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -1593,6 +1593,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -1629,6 +1629,10 @@ export interface ConfigClass {
|
||||
* List of IDs of your DBT cloud jobs seperated by comma `,`
|
||||
*/
|
||||
jobIds?: string[];
|
||||
/**
|
||||
* Number of runs to fetch from DBT cloud
|
||||
*/
|
||||
numberOfRuns?: number;
|
||||
/**
|
||||
* List of IDs of your DBT cloud projects seperated by comma `,`
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
@ -226,8 +227,8 @@ const AddNotificationPage = () => {
|
||||
firstPanel={{
|
||||
className: 'content-resizable-panel-containere',
|
||||
children: (
|
||||
<div className="steps-form-container service-form-container">
|
||||
<Row className="page-container" gutter={[16, 16]}>
|
||||
<Card className="steps-form-container">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
</Col>
|
||||
@ -344,10 +345,11 @@ const AddNotificationPage = () => {
|
||||
</Form>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Card>
|
||||
),
|
||||
minWidth: 700,
|
||||
flex: 0.7,
|
||||
wrapInCard: false,
|
||||
}}
|
||||
pageTitle={t('label.add-entity', {
|
||||
entity: t('label.notification-alert'),
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Divider, Form, Input, Row, Typography } from 'antd';
|
||||
import { Button, Card, Col, Divider, Form, Input, Row, Typography } from 'antd';
|
||||
import { useForm } from 'antd/lib/form/Form';
|
||||
import { isEmpty, isUndefined } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
@ -203,8 +203,8 @@ function AddObservabilityPage() {
|
||||
firstPanel={{
|
||||
className: 'content-resizable-panel-container ',
|
||||
children: (
|
||||
<div className="steps-form-container service-form-container">
|
||||
<Row className="p-x-lg p-t-md" gutter={[16, 16]}>
|
||||
<Card className="steps-form-container">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
</Col>
|
||||
@ -329,10 +329,11 @@ function AddObservabilityPage() {
|
||||
</Form>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Card>
|
||||
),
|
||||
minWidth: 700,
|
||||
flex: 0.7,
|
||||
wrapInCard: false,
|
||||
}}
|
||||
pageTitle={t('label.add-entity', {
|
||||
entity: t('label.observability'),
|
||||
|
@ -136,10 +136,8 @@ jest.mock(
|
||||
})
|
||||
);
|
||||
|
||||
jest.mock('../../components/common/ResizablePanels/ResizablePanels', () =>
|
||||
jest
|
||||
.fn()
|
||||
.mockImplementation(({ firstPanel }) => <div>{firstPanel.children}</div>)
|
||||
jest.mock('../../components/PageLayoutV1/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children }) => <div>{children}</div>)
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import { SyncOutlined } from '@ant-design/icons';
|
||||
import { Button, Col, Row, Skeleton, Space, Tabs, Tooltip } from 'antd';
|
||||
import { Button, Card, Col, Row, Skeleton, Space, Tabs, Tooltip } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { isUndefined, omitBy } from 'lodash';
|
||||
@ -29,9 +29,9 @@ import DescriptionV1 from '../../components/common/EntityDescription/Description
|
||||
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||
import Loader from '../../components/common/Loader/Loader';
|
||||
import { OwnerLabel } from '../../components/common/OwnerLabel/OwnerLabel.component';
|
||||
import ResizablePanels from '../../components/common/ResizablePanels/ResizablePanels';
|
||||
import TitleBreadcrumb from '../../components/common/TitleBreadcrumb/TitleBreadcrumb.component';
|
||||
import EntityHeaderTitle from '../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component';
|
||||
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
|
||||
import { DE_ACTIVE_COLOR, ROUTES } from '../../constants/constants';
|
||||
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
|
||||
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
|
||||
@ -48,7 +48,6 @@ import {
|
||||
EventSubscription,
|
||||
ProviderType,
|
||||
} from '../../generated/events/eventSubscription';
|
||||
import { withPageLayout } from '../../hoc/withPageLayout';
|
||||
import { useFqn } from '../../hooks/useFqn';
|
||||
import { updateNotificationAlert } from '../../rest/alertsAPI';
|
||||
import {
|
||||
@ -59,7 +58,6 @@ import {
|
||||
} from '../../rest/observabilityAPI';
|
||||
import { getAlertExtraInfo } from '../../utils/Alerts/AlertsUtil';
|
||||
import { getEntityName } from '../../utils/EntityUtils';
|
||||
import i18n from '../../utils/i18next/LocalUtil';
|
||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||
import {
|
||||
getNotificationAlertDetailsPath,
|
||||
@ -336,20 +334,17 @@ function AlertDetailsPage({
|
||||
}
|
||||
|
||||
return (
|
||||
<ResizablePanels
|
||||
hideSecondPanel
|
||||
className="content-height-with-resizable-panel"
|
||||
firstPanel={{
|
||||
className: 'content-resizable-panel-container ',
|
||||
children: loadingCount ? (
|
||||
<PageLayoutV1
|
||||
pageTitle={t('label.entity-detail-plural', {
|
||||
entity: t('label.alert'),
|
||||
})}>
|
||||
{loadingCount ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<div
|
||||
className="steps-form-container service-form-container"
|
||||
<Card
|
||||
className="steps-form-container"
|
||||
data-testid="alert-details-container">
|
||||
<Row
|
||||
className="add-notification-container p-x-lg p-t-md"
|
||||
gutter={[0, 16]}>
|
||||
<Row className="add-notification-container" gutter={[0, 16]}>
|
||||
<Col span={24}>
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
</Col>
|
||||
@ -469,25 +464,10 @@ function AlertDetailsPage({
|
||||
visible={showDeleteModal}
|
||||
onCancel={hideDeleteModal}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
minWidth: 700,
|
||||
flex: 0.7,
|
||||
}}
|
||||
pageTitle={t('label.entity-detail-plural', {
|
||||
entity: t('label.alert'),
|
||||
})}
|
||||
secondPanel={{
|
||||
children: <></>,
|
||||
minWidth: 0,
|
||||
className: 'content-resizable-panel-container',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
</PageLayoutV1>
|
||||
);
|
||||
}
|
||||
|
||||
export default withPageLayout<AlertDetailsPageProps>(
|
||||
i18n.t('label.entity-detail-plural', {
|
||||
entity: i18n.t('label.alert'),
|
||||
})
|
||||
)(AlertDetailsPage);
|
||||
export default AlertDetailsPage;
|
||||
|
@ -1,103 +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 { Card } from 'antd';
|
||||
import { noop, trim } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Loader from '../../components/common/Loader/Loader';
|
||||
import { AlertDetailsComponent } from '../../components/Settings/Alerts/AlertsDetails/AlertDetails.component';
|
||||
import { EventFilterRule } from '../../generated/events/eventFilterRule';
|
||||
import {
|
||||
EventSubscription,
|
||||
FilteringRules,
|
||||
} from '../../generated/events/eventSubscription';
|
||||
import { withPageLayout } from '../../hoc/withPageLayout';
|
||||
import { getAlertsFromName } from '../../rest/alertsAPI';
|
||||
import { getEntityName } from '../../utils/EntityUtils';
|
||||
import i18n from '../../utils/i18next/LocalUtil';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
|
||||
const AlertsActivityFeedPage = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [alert, setAlert] = useState<EventSubscription>();
|
||||
const { t } = useTranslation();
|
||||
const fetchActivityFeedAlert = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await getAlertsFromName('ActivityFeedAlert');
|
||||
|
||||
const requestFilteringRules =
|
||||
response.filteringRules?.rules?.map((curr) => {
|
||||
const [fullyQualifiedName, filterRule] = curr.condition.split('(');
|
||||
|
||||
return {
|
||||
...curr,
|
||||
fullyQualifiedName,
|
||||
condition: filterRule
|
||||
.replaceAll("'", '')
|
||||
.replace(new RegExp(`\\)`), '')
|
||||
.split(',')
|
||||
.map(trim),
|
||||
} as unknown as EventFilterRule;
|
||||
}) ?? [];
|
||||
|
||||
setAlert({
|
||||
...response,
|
||||
filteringRules: {
|
||||
...(response.filteringRules as FilteringRules),
|
||||
rules: requestFilteringRules,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
t('server.entity-fetch-error', {
|
||||
entity: t('label.activity-feed-plural'),
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchActivityFeedAlert();
|
||||
}, []);
|
||||
|
||||
const pageHeaderData = useMemo(
|
||||
() => ({
|
||||
header: getEntityName(alert),
|
||||
subHeader: alert?.description || '',
|
||||
}),
|
||||
[alert]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <Card loading={loading} />;
|
||||
}
|
||||
|
||||
return alert ? (
|
||||
<AlertDetailsComponent
|
||||
alerts={alert}
|
||||
allowDelete={false}
|
||||
pageHeaderData={pageHeaderData}
|
||||
onDelete={noop}
|
||||
/>
|
||||
) : (
|
||||
<Loader />
|
||||
);
|
||||
};
|
||||
|
||||
export default withPageLayout(i18n.t('label.alert-details'))(
|
||||
AlertsActivityFeedPage
|
||||
);
|
@ -11,6 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
@ -216,7 +217,7 @@ const CreateUserPage = () => {
|
||||
<PageLayoutV1
|
||||
center
|
||||
pageTitle={t('label.create-entity', { entity: t('label.user') })}>
|
||||
<div className="service-form-container w-800">
|
||||
<Card className="service-form-container w-800">
|
||||
<TitleBreadcrumb titleLinks={slashedBreadcrumbList} />
|
||||
<div className="m-t-md">
|
||||
<CreateUserComponent
|
||||
@ -227,7 +228,7 @@ const CreateUserPage = () => {
|
||||
onSave={handleAddUserSave}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</PageLayoutV1>
|
||||
);
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Row, Tabs } from 'antd';
|
||||
import { Button, Card, Col, Row, Tabs } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { isUndefined, startCase } from 'lodash';
|
||||
@ -228,11 +228,11 @@ const CustomEntityDetailV1 = () => {
|
||||
),
|
||||
key: EntityTabs.CUSTOM_PROPERTIES,
|
||||
children: (
|
||||
<div data-testid="entity-custom-fields">
|
||||
<Card data-testid="entity-custom-fields">
|
||||
<div className="flex justify-end">
|
||||
{editPermission && (
|
||||
<Button
|
||||
className="m-b-md p-y-xss p-x-xs rounded-4"
|
||||
className="m-b-md"
|
||||
data-testid="add-field-button"
|
||||
size="middle"
|
||||
type="primary"
|
||||
@ -250,20 +250,18 @@ const CustomEntityDetailV1 = () => {
|
||||
isLoading={isLoading}
|
||||
updateEntityType={updateEntityType}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: t('label.schema'),
|
||||
key: EntityTabs.SCHEMA,
|
||||
children: (
|
||||
<div data-testid="entity-schema">
|
||||
<SchemaEditor
|
||||
className="custom-properties-schemaEditor p-y-md"
|
||||
className="custom-properties-schemaEditor"
|
||||
editorClass="custom-entity-schema"
|
||||
value={JSON.parse(schema ?? '{}')}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
@ -11,7 +11,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import (reference) url('../../styles/variables.less');
|
||||
|
||||
.custom-properties-schemaEditor {
|
||||
border: 1px solid #dce3ec;
|
||||
border-radius: 6px;
|
||||
border: 1px solid @border-color;
|
||||
border-radius: @border-radius-sm;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ const ObservabilityAlertsPage = () => {
|
||||
|
||||
return (
|
||||
<PageLayoutV1 pageTitle={t('label.observability-alert')}>
|
||||
<Row className="p-x-lg p-t-md" gutter={[0, 16]}>
|
||||
<Row gutter={[0, 16]}>
|
||||
<Col span={24}>
|
||||
<div className="d-flex justify-between">
|
||||
<PageHeader data={pageHeaderData} />
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Form, Row, Space, Typography } from 'antd';
|
||||
import { Button, Card, Form, Space, Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { trim } from 'lodash';
|
||||
@ -144,8 +144,7 @@ const AddRulePage = () => {
|
||||
pageTitle={t('label.add-new-entity', {
|
||||
entity: t('label.rule'),
|
||||
})}>
|
||||
<Row className="h-auto p-y-xss" gutter={[16, 16]}>
|
||||
<Col offset={5} span={14}>
|
||||
<Card className="service-form-container w-800">
|
||||
<TitleBreadcrumb className="m-b-md" titleLinks={breadcrumb} />
|
||||
|
||||
<Typography.Paragraph
|
||||
@ -175,8 +174,7 @@ const AddRulePage = () => {
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</PageLayoutV1>
|
||||
);
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Card, Col, Form, Row, Space, Typography } from 'antd';
|
||||
import { Button, Card, Form, Space, Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { trim } from 'lodash';
|
||||
@ -164,10 +164,8 @@ const EditRulePage = () => {
|
||||
return (
|
||||
<PageLayoutV1
|
||||
pageTitle={t('label.edit-entity', { entity: t('label.rule') })}>
|
||||
<Row className="h-auto p-y-xss" gutter={[16, 16]}>
|
||||
<Col offset={5} span={14}>
|
||||
<Card className="service-form-container w-800">
|
||||
<TitleBreadcrumb className="m-b-md" titleLinks={breadcrumb} />
|
||||
<Card>
|
||||
<Typography.Paragraph
|
||||
className="text-base"
|
||||
data-testid="edit-rule-title">
|
||||
@ -192,10 +190,7 @@ const EditRulePage = () => {
|
||||
setRuleData={setRuleData}
|
||||
/>
|
||||
<Space align="center" className="w-full justify-end">
|
||||
<Button
|
||||
data-testid="cancel-btn"
|
||||
type="link"
|
||||
onClick={handleBack}>
|
||||
<Button data-testid="cancel-btn" type="link" onClick={handleBack}>
|
||||
{t('label.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
@ -208,8 +203,6 @@ const EditRulePage = () => {
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</PageLayoutV1>
|
||||
);
|
||||
};
|
||||
|
@ -71,11 +71,8 @@ import {
|
||||
getSettingPath,
|
||||
} from '../../../utils/RouterUtils';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import './policies-detail.less';
|
||||
import PoliciesDetailsList from './PoliciesDetailsList.component';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
type Attribute = 'roles' | 'teams';
|
||||
|
||||
const PoliciesDetailPage = () => {
|
||||
@ -371,6 +368,150 @@ const PoliciesDetailPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const rulesTab = useMemo(() => {
|
||||
return (
|
||||
<Card>
|
||||
{isEmpty(policy.rules) ? (
|
||||
<ErrorPlaceHolder />
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-end m-b-md">
|
||||
<Button
|
||||
data-testid="add-rule"
|
||||
type="primary"
|
||||
onClick={() => history.push(getAddPolicyRulePath(fqn))}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.rule'),
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Space className="w-full" direction="vertical" size={20}>
|
||||
{policy.rules.map((rule) => (
|
||||
<Card data-testid="rule-card" key={rule.name || 'rule'}>
|
||||
<Space
|
||||
align="baseline"
|
||||
className="w-full justify-between p-b-lg"
|
||||
direction="horizontal">
|
||||
<Typography.Text
|
||||
className="font-medium text-base text-grey-body"
|
||||
data-testid="rule-name">
|
||||
{rule.name}
|
||||
</Typography.Text>
|
||||
{getRuleActionElement(rule)}
|
||||
</Space>
|
||||
|
||||
<Space className="w-full" direction="vertical" size={12}>
|
||||
{rule.description && (
|
||||
<Row data-testid="description">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.description')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<RichTextEditorPreviewerV1
|
||||
markdown={rule.description || ''}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<Row data-testid="resources">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted m-b-0">
|
||||
{`${t('label.resource-plural')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{rule.resources
|
||||
?.map((resource) => startCase(resource))
|
||||
?.join(', ')}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row data-testid="operations">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.operation-plural')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{rule.operations?.join(', ')}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row data-testid="effect">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.effect')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{startCase(rule.effect)}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
{rule.condition && (
|
||||
<Row data-testid="condition">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.condition')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<code>{rule.condition}</code>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}, [policy]);
|
||||
|
||||
const tabItems = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
key: 'rules',
|
||||
label: t('label.rule-plural'),
|
||||
children: rulesTab,
|
||||
},
|
||||
{
|
||||
key: 'roles',
|
||||
label: t('label.role-plural'),
|
||||
children: (
|
||||
<PoliciesDetailsList
|
||||
hasAccess
|
||||
list={policy.roles ?? []}
|
||||
type="role"
|
||||
onDelete={(record) => setEntity({ record, attribute: 'roles' })}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'teams',
|
||||
label: t('label.team-plural'),
|
||||
children: (
|
||||
<PoliciesDetailsList
|
||||
hasAccess
|
||||
list={policy.teams ?? []}
|
||||
type="team"
|
||||
onDelete={(record) => setEntity({ record, attribute: 'teams' })}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [rulesTab, policy]);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, [fqn, policyPermission]);
|
||||
@ -449,138 +590,11 @@ const PoliciesDetailPage = () => {
|
||||
onDescriptionUpdate={handleDescriptionUpdate}
|
||||
/>
|
||||
|
||||
<Tabs className="tabs-new" defaultActiveKey="rules">
|
||||
<TabPane key="rules" tab={t('label.rule-plural')}>
|
||||
{isEmpty(policy.rules) ? (
|
||||
<ErrorPlaceHolder />
|
||||
) : (
|
||||
<Space
|
||||
className="w-full tabpane-space"
|
||||
direction="vertical">
|
||||
<Button
|
||||
data-testid="add-rule"
|
||||
type="primary"
|
||||
onClick={() => history.push(getAddPolicyRulePath(fqn))}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.rule'),
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<Space className="w-full" direction="vertical" size={20}>
|
||||
{policy.rules.map((rule) => (
|
||||
<Card
|
||||
data-testid="rule-card"
|
||||
key={rule.name || 'rule'}>
|
||||
<Space
|
||||
align="baseline"
|
||||
className="w-full justify-between p-b-lg"
|
||||
direction="horizontal">
|
||||
<Typography.Text
|
||||
className="font-medium text-base text-grey-body"
|
||||
data-testid="rule-name">
|
||||
{rule.name}
|
||||
</Typography.Text>
|
||||
{getRuleActionElement(rule)}
|
||||
</Space>
|
||||
|
||||
<Space
|
||||
className="w-full"
|
||||
direction="vertical"
|
||||
size={12}>
|
||||
{rule.description && (
|
||||
<Row data-testid="description">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.description')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<RichTextEditorPreviewerV1
|
||||
markdown={rule.description || ''}
|
||||
<Tabs
|
||||
className="tabs-new"
|
||||
defaultActiveKey="rules"
|
||||
items={tabItems}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<Row data-testid="resources">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted m-b-0">
|
||||
{`${t('label.resource-plural')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{rule.resources
|
||||
?.map((resource) => startCase(resource))
|
||||
?.join(', ')}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row data-testid="operations">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.operation-plural')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{rule.operations?.join(', ')}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row data-testid="effect">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.effect')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Typography.Text className="text-grey-body">
|
||||
{startCase(rule.effect)}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
{rule.condition && (
|
||||
<Row data-testid="condition">
|
||||
<Col span={2}>
|
||||
<Typography.Text className="text-grey-muted">
|
||||
{`${t('label.condition')}:`}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<code>{rule.condition}</code>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
</Space>
|
||||
)}
|
||||
</TabPane>
|
||||
<TabPane key="roles" tab={t('label.role-plural')}>
|
||||
<PoliciesDetailsList
|
||||
hasAccess
|
||||
list={policy.roles ?? []}
|
||||
type="role"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'roles' })
|
||||
}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane key="teams" tab={t('label.team-plural')}>
|
||||
<PoliciesDetailsList
|
||||
hasAccess
|
||||
list={policy.teams ?? []}
|
||||
type="team"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'teams' })
|
||||
}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,51 +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 url('../../../styles/variables.less');
|
||||
|
||||
.policies-detail {
|
||||
.list-table {
|
||||
.ant-table-row .ant-table-cell:first-child,
|
||||
.ant-table-thead .ant-table-cell:first-child {
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-collapse {
|
||||
background-color: @white;
|
||||
border: 1px solid @border-color;
|
||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.12);
|
||||
border-radius: 4px;
|
||||
.ant-collapse-item {
|
||||
.ant-collapse-header {
|
||||
padding: 16px;
|
||||
align-items: flex-start;
|
||||
.ant-collapse-arrow {
|
||||
color: @text-color;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-collapse-content {
|
||||
border-top: none;
|
||||
.ant-collapse-content-box {
|
||||
padding-top: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-space.tabpane-space {
|
||||
> .ant-space-item:first-child {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import Icon from '@ant-design/icons';
|
||||
import { Button, Col, Modal, Row, Space, Tabs, Typography } from 'antd';
|
||||
import { Button, Card, Col, Modal, Row, Tabs, Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { isEmpty, isUndefined } from 'lodash';
|
||||
@ -49,11 +49,8 @@ import { getEntityName } from '../../../utils/EntityUtils';
|
||||
import { getSettingPath } from '../../../utils/RouterUtils';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import AddAttributeModal from '../AddAttributeModal/AddAttributeModal';
|
||||
import './roles-detail.less';
|
||||
import RolesDetailPageList from './RolesDetailPageList.component';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
type Attribute = 'policies' | 'teams' | 'users';
|
||||
|
||||
interface AddAttribute {
|
||||
@ -292,6 +289,67 @@ const RolesDetailPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const tabItems = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
key: 'policies',
|
||||
label: t('label.policy-plural'),
|
||||
children: (
|
||||
<Card>
|
||||
<div className="flex justify-end m-b-md">
|
||||
<Button
|
||||
data-testid="add-policy"
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
setAddAttribute({
|
||||
type: EntityType.POLICY,
|
||||
selectedData: role.policies || [],
|
||||
})
|
||||
}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.policy'),
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.policies ?? []}
|
||||
type="policy"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'policies' })
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'teams',
|
||||
label: t('label.team-plural'),
|
||||
children: (
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.teams ?? []}
|
||||
type="team"
|
||||
onDelete={(record) => setEntity({ record, attribute: 'teams' })}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'users',
|
||||
label: t('label.user-plural'),
|
||||
children: (
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.users ?? []}
|
||||
type="user"
|
||||
onDelete={(record) => setEntity({ record, attribute: 'users' })}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [role]);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, [fqn, rolePermission]);
|
||||
@ -307,7 +365,6 @@ const RolesDetailPage = () => {
|
||||
})}>
|
||||
<div data-testid="role-details-container">
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
|
||||
<>
|
||||
{isEmpty(role) ? (
|
||||
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.CUSTOM}>
|
||||
@ -328,7 +385,7 @@ const RolesDetailPage = () => {
|
||||
</div>
|
||||
</ErrorPlaceHolder>
|
||||
) : (
|
||||
<div className="roles-detail" data-testid="role-details">
|
||||
<>
|
||||
<Row className="flex justify-between">
|
||||
<Col span={23}>
|
||||
<EntityHeaderTitle
|
||||
@ -377,57 +434,10 @@ const RolesDetailPage = () => {
|
||||
<Tabs
|
||||
className="tabs-new"
|
||||
data-testid="tabs"
|
||||
defaultActiveKey="policies">
|
||||
<TabPane key="policies" tab={t('label.policy-plural')}>
|
||||
<Space
|
||||
className="role-detail-tab w-full"
|
||||
direction="vertical">
|
||||
<Button
|
||||
data-testid="add-policy"
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
setAddAttribute({
|
||||
type: EntityType.POLICY,
|
||||
selectedData: role.policies || [],
|
||||
})
|
||||
}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.policy'),
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.policies ?? []}
|
||||
type="policy"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'policies' })
|
||||
}
|
||||
defaultActiveKey="policies"
|
||||
items={tabItems}
|
||||
/>
|
||||
</Space>
|
||||
</TabPane>
|
||||
<TabPane key="teams" tab={t('label.team-plural')}>
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.teams ?? []}
|
||||
type="team"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'teams' })
|
||||
}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane key="users" tab={t('label.user-plural')}>
|
||||
<RolesDetailPageList
|
||||
hasAccess
|
||||
list={role.users ?? []}
|
||||
type="user"
|
||||
onDelete={(record) =>
|
||||
setEntity({ record, attribute: 'users' })
|
||||
}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
|
@ -13,8 +13,7 @@
|
||||
// Common add edit form page styling
|
||||
.steps-form-container {
|
||||
width: 70%;
|
||||
margin: 16px auto 0;
|
||||
padding-bottom: 16px;
|
||||
margin: 0 auto;
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0px;
|
||||
|
@ -25,7 +25,7 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.ant-btn.ant-btn-default {
|
||||
.ant-btn.ant-btn-default:not(:hover) {
|
||||
border-color: @blue-15;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user