mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-24 09:50:01 +00:00
✨feat(ui)#9809: <title> in HTML heading should reflect the page you're on (#10342)
* ✨feat(ui)#9809: <title> in HTML heading should reflect the page you're on
* chore: add dynamic title for pageLayoutV1
* chore: create separate component for seo
* address comments
* test: add new test and fix failing test
This commit is contained in:
parent
5865466094
commit
82df166d4d
@ -74,6 +74,7 @@
|
||||
"react-dnd-html5-backend": "14.0.2",
|
||||
"react-dom": "^16.14.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
"react-i18next": "^11.18.6",
|
||||
"react-lazylog": "^4.5.3",
|
||||
"react-oidc": "^1.0.3",
|
||||
@ -180,8 +181,8 @@
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-i18next": "^6.0.0-2",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-i18next": "^6.0.0-2",
|
||||
"eslint-plugin-jest": "24.4.0",
|
||||
"eslint-plugin-jest-formatting": "3.0.0",
|
||||
"eslint-plugin-jsonc": "2.5.0",
|
||||
|
@ -21,6 +21,7 @@ import WebSocketProvider from 'components/web-scoket/web-scoket.provider';
|
||||
import WebAnalyticsProvider from 'components/WebAnalytics/WebAnalyticsProvider';
|
||||
import { TOAST_OPTIONS } from 'constants/Toasts.constants';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
@ -35,16 +36,18 @@ const App: FunctionComponent = () => {
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ErrorBoundry>
|
||||
<AuthProvider childComponentType={AppRouter}>
|
||||
<WebAnalyticsProvider>
|
||||
<PermissionProvider>
|
||||
<WebSocketProvider>
|
||||
<GlobalSearchProvider>
|
||||
<Appbar />
|
||||
<AppRouter />
|
||||
</GlobalSearchProvider>
|
||||
</WebSocketProvider>
|
||||
</PermissionProvider>
|
||||
</WebAnalyticsProvider>
|
||||
<HelmetProvider>
|
||||
<WebAnalyticsProvider>
|
||||
<PermissionProvider>
|
||||
<WebSocketProvider>
|
||||
<GlobalSearchProvider>
|
||||
<Appbar />
|
||||
<AppRouter />
|
||||
</GlobalSearchProvider>
|
||||
</WebSocketProvider>
|
||||
</PermissionProvider>
|
||||
</WebAnalyticsProvider>
|
||||
</HelmetProvider>
|
||||
</AuthProvider>
|
||||
</ErrorBoundry>
|
||||
</I18nextProvider>
|
||||
|
@ -255,6 +255,9 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={breadcrumb} />}
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.add-entity', {
|
||||
entity: t('label.data-quality-test'),
|
||||
})}
|
||||
rightPanel={
|
||||
<RightPanel
|
||||
data={
|
||||
|
@ -155,6 +155,7 @@ const AddGlossary = ({
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={slashedBreadcrumb} />}
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.add-entity', { entity: t('label.glossary') })}
|
||||
rightPanel={fetchRightPanel()}>
|
||||
<div className="tw-form-container">
|
||||
<Typography.Title data-testid="form-heading" level={5}>
|
||||
|
@ -16,6 +16,10 @@ import { LoadingState } from 'Models';
|
||||
import React, { forwardRef } from 'react';
|
||||
import AddGlossary from './AddGlossary.component';
|
||||
|
||||
jest.mock('../containers/PageLayout', () =>
|
||||
jest.fn().mockImplementation(({ children }) => <div>{children}</div>)
|
||||
);
|
||||
|
||||
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||
});
|
||||
|
@ -296,6 +296,7 @@ const AddGlossaryTerm = ({
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={slashedBreadcrumb} />}
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.add-entity', { entity: t('label.glossary-term') })}
|
||||
rightPanel={fetchRightPanel()}>
|
||||
<div className="tw-form-container">
|
||||
<h6 className="tw-heading tw-text-base">
|
||||
|
@ -53,6 +53,10 @@ jest.mock('../common/rich-text-editor/RichTextEditor', () => {
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock('../containers/PageLayout', () =>
|
||||
jest.fn().mockImplementation(({ children }) => <div>{children}</div>)
|
||||
);
|
||||
|
||||
const mockOnCancel = jest.fn();
|
||||
const mockOnSave = jest.fn();
|
||||
|
||||
|
@ -320,6 +320,7 @@ const AddService = ({
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={slashedBreadcrumb} />}
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.add-entity', { entity: t('label.service') })}
|
||||
rightPanel={fetchRightPanel()}>
|
||||
<div className="tw-form-container">
|
||||
{addIngestion ? (
|
||||
|
@ -276,6 +276,7 @@ const BotDetails: FC<BotsDetailProps> = ({
|
||||
/>
|
||||
}
|
||||
leftPanel={fetchLeftPanel()}
|
||||
pageTitle={t('label.bot-detail')}
|
||||
rightPanel={
|
||||
<Card className="page-layout-v1-left-panel mt-2">
|
||||
<div data-testid="right-panel">
|
||||
|
@ -122,6 +122,19 @@ jest.mock('./AuthMechanismForm', () =>
|
||||
)
|
||||
);
|
||||
|
||||
jest.mock('../containers/PageLayout', () =>
|
||||
jest
|
||||
.fn()
|
||||
.mockImplementation(({ children, leftPanel, rightPanel, header }) => (
|
||||
<div>
|
||||
{header}
|
||||
<div>{leftPanel}</div>
|
||||
{children}
|
||||
<div>{rightPanel}</div>
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test BotsDetail Component', () => {
|
||||
it('Should render all child elements', async () => {
|
||||
const { container } = render(<BotDetails {...mockProp} />, {
|
||||
|
@ -700,7 +700,8 @@ const CreateUser = ({
|
||||
<PageLayout
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={slashedBreadcrumbList} />}
|
||||
layout={PageLayoutType['2ColRTL']}>
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.create-entity', { entity: t('label.user') })}>
|
||||
<div className="tw-form-container">
|
||||
<h6 className="tw-heading tw-text-base">
|
||||
{t('label.create-entity', {
|
||||
|
@ -174,6 +174,9 @@ const AddCustomProperty = () => {
|
||||
<PageLayout
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.add-entity', {
|
||||
entity: t('label.custom-property'),
|
||||
})}
|
||||
rightPanel={<RightPanel />}>
|
||||
<div
|
||||
className="tw-bg-white tw-p-4 tw-border tw-border-main tw-rounded tw-form-container"
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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 React, { FC } from 'react';
|
||||
import { Helmet } from 'react-helmet-async';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface DocumentTitleProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const DocumentTitle: FC<DocumentTitleProps> = ({ title }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Helmet>
|
||||
<title>{`${title} | ${t('label.open-metadata')}`}</title>
|
||||
</Helmet>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentTitle;
|
@ -31,6 +31,7 @@ import {
|
||||
toUpper,
|
||||
} from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { ENTITY_PATH } from '../../constants/constants';
|
||||
import { tabsInfo } from '../../constants/explore.constants';
|
||||
@ -76,6 +77,7 @@ const Explore: React.FC<ExploreProps> = ({
|
||||
onChangePage = noop,
|
||||
loading,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { tab } = useParams<{ tab: string }>();
|
||||
const [showAdvanceSearchModal, setShowAdvanceSearchModal] = useState(false);
|
||||
|
||||
@ -268,7 +270,8 @@ const Explore: React.FC<ExploreProps> = ({
|
||||
/>
|
||||
</ExploreSkeleton>
|
||||
</Card>
|
||||
}>
|
||||
}
|
||||
pageTitle={t('label.explore')}>
|
||||
<Tabs
|
||||
defaultActiveKey={defaultActiveTab}
|
||||
items={tabItems}
|
||||
|
@ -49,6 +49,10 @@ jest.mock('components/searched-data/SearchedData', () => {
|
||||
|
||||
const mockFunction = jest.fn();
|
||||
|
||||
jest.mock('../containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children }) => <div>{children}</div>)
|
||||
);
|
||||
|
||||
describe('Test Explore component', () => {
|
||||
it('Component should render', async () => {
|
||||
const { container } = render(
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import PageLayoutV1 from '../containers/PageLayoutV1';
|
||||
import GlobalSettingRouter from '../router/GlobalSettingRouter';
|
||||
@ -19,10 +20,13 @@ import './GlobalSetting.less';
|
||||
import GlobalSettingLeftPanel from './GlobalSettingLeftPanel';
|
||||
|
||||
const GlobalSetting = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PageLayoutV1
|
||||
className="tw-h-full tw-px-6"
|
||||
leftPanel={<GlobalSettingLeftPanel />}>
|
||||
leftPanel={<GlobalSettingLeftPanel />}
|
||||
pageTitle={t('label.setting-plural')}>
|
||||
<GlobalSettingRouter />
|
||||
</PageLayoutV1>
|
||||
);
|
||||
|
@ -231,7 +231,10 @@ const MyData: React.FC<MyDataProps> = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<PageLayoutV1 leftPanel={getLeftPanel()} rightPanel={getRightPanel()}>
|
||||
<PageLayoutV1
|
||||
leftPanel={getLeftPanel()}
|
||||
pageTitle={t('label.my-data')}
|
||||
rightPanel={getRightPanel()}>
|
||||
{error ? (
|
||||
<ErrorPlaceHolderES errorMessage={error} type="error" />
|
||||
) : (
|
||||
|
@ -98,6 +98,10 @@ jest.mock('components/PermissionProvider/PermissionProvider', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children }) => <div>{children}</div>)
|
||||
);
|
||||
|
||||
describe('Test ProfilerDashboardPage component', () => {
|
||||
beforeEach(() => cleanup());
|
||||
|
||||
@ -107,7 +111,7 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
const pageContainer = await screen.findByTestId('page-layout-v1');
|
||||
|
||||
const profilerSwitch = await screen.findByTestId('profiler-switch');
|
||||
const EntityPageInfo = await screen.findByText('EntityPageInfo component');
|
||||
const ProfilerTab = await screen.findByText('ProfilerTab component');
|
||||
@ -116,7 +120,6 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
);
|
||||
const DataQualityTab = screen.queryByText('DataQualityTab component');
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(profilerSwitch).toBeInTheDocument();
|
||||
expect(EntityPageInfo).toBeInTheDocument();
|
||||
expect(ProfilerTab).toBeInTheDocument();
|
||||
@ -134,7 +137,7 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
const pageContainer = await screen.findByTestId('page-layout-v1');
|
||||
|
||||
const profilerSwitch = await screen.findByTestId('profiler-switch');
|
||||
const EntityPageInfo = await screen.findByText('EntityPageInfo component');
|
||||
const ProfilerTab = screen.queryByText('ProfilerTab component');
|
||||
@ -144,7 +147,6 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
);
|
||||
const statusDropdown = await screen.findByText('label.status');
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(profilerSwitch).toBeInTheDocument();
|
||||
expect(EntityPageInfo).toBeInTheDocument();
|
||||
expect(DataQualityTab).toBeInTheDocument();
|
||||
@ -163,7 +165,7 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
const pageContainer = await screen.findByTestId('page-layout-v1');
|
||||
|
||||
const profilerSwitch = await screen.findByTestId('profiler-switch');
|
||||
const EntityPageInfo = await screen.findByText('EntityPageInfo component');
|
||||
const ProfilerTab = await screen.findByText('ProfilerTab component');
|
||||
@ -172,7 +174,6 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
);
|
||||
const DataQualityTab = screen.queryByText('DataQualityTab component');
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(profilerSwitch).toBeInTheDocument();
|
||||
expect(EntityPageInfo).toBeInTheDocument();
|
||||
expect(ProfilerTab).toBeInTheDocument();
|
||||
@ -231,10 +232,8 @@ describe('Test ProfilerDashboardPage component', () => {
|
||||
});
|
||||
});
|
||||
|
||||
const pageContainer = await screen.findByTestId('page-layout-v1');
|
||||
const addTest = await screen.findByTestId('add-test');
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(addTest).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
|
@ -456,7 +456,7 @@ const ProfilerDashboard: React.FC<ProfilerDashboardProps> = ({
|
||||
}, [table]);
|
||||
|
||||
return (
|
||||
<PageLayoutV1>
|
||||
<PageLayoutV1 pageTitle={t('label.profiler')}>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<EntityPageInfo
|
||||
|
@ -124,6 +124,16 @@ jest.mock('rest/userAPI', () => ({
|
||||
checkValidImage: jest.fn().mockImplementation(() => Promise.resolve(true)),
|
||||
}));
|
||||
|
||||
jest.mock('../containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test User Component', () => {
|
||||
it('Should render user component', async () => {
|
||||
const { container } = render(
|
||||
|
@ -951,7 +951,10 @@ const Users = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<PageLayoutV1 className="tw-h-full" leftPanel={fetchLeftPanel()}>
|
||||
<PageLayoutV1
|
||||
className="tw-h-full"
|
||||
leftPanel={fetchLeftPanel()}
|
||||
pageTitle={t('label.user')}>
|
||||
<div className="m-b-md">
|
||||
<TabsPane
|
||||
activeTab={activeTab}
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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 { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import PageLayout from './PageLayout';
|
||||
|
||||
jest.mock('components/DocumentTitle/DocumentTitle', () =>
|
||||
jest.fn().mockImplementation(() => <div>DocumentTitle</div>)
|
||||
);
|
||||
|
||||
describe('PageLayout', () => {
|
||||
it('Should render with children', () => {
|
||||
const { getByText } = render(
|
||||
<PageLayout pageTitle="Test Page Title">
|
||||
<div>Test Child Element</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
expect(getByText('Test Child Element')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render with left panel', () => {
|
||||
const { getByText } = render(
|
||||
<PageLayout
|
||||
leftPanel={<div>Test Left Panel</div>}
|
||||
pageTitle="Test Page Title">
|
||||
<div>Test Child Element</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
expect(getByText('Test Left Panel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render with right panel', () => {
|
||||
const { getByText } = render(
|
||||
<PageLayout
|
||||
pageTitle="Test Page Title"
|
||||
rightPanel={<div>Test Right Panel</div>}>
|
||||
<div>Test Child Element</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
expect(getByText('Test Right Panel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render with header', () => {
|
||||
const { getByText } = render(
|
||||
<PageLayout header={<div>Test Header</div>} pageTitle="Test Page Title">
|
||||
<div>Test Child Element</div>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
expect(getByText('Test Header')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import DocumentTitle from 'components/DocumentTitle/DocumentTitle';
|
||||
import React, { FC, Fragment, ReactNode } from 'react';
|
||||
import { PageLayoutType } from '../../enums/layout.enum';
|
||||
|
||||
@ -22,6 +23,7 @@ interface PageLayoutProp {
|
||||
children: ReactNode;
|
||||
layout?: PageLayoutType;
|
||||
classes?: string;
|
||||
pageTitle: string;
|
||||
}
|
||||
|
||||
export const leftPanelAntCardStyle = {
|
||||
@ -40,6 +42,7 @@ const PageLayout: FC<PageLayoutProp> = ({
|
||||
children,
|
||||
rightPanel,
|
||||
layout = PageLayoutType['3Col'],
|
||||
pageTitle,
|
||||
classes = '',
|
||||
}: PageLayoutProp) => {
|
||||
const getLeftPanel = () => {
|
||||
@ -163,7 +166,12 @@ const PageLayout: FC<PageLayoutProp> = ({
|
||||
}
|
||||
};
|
||||
|
||||
return getLayoutByType(layout);
|
||||
return (
|
||||
<Fragment>
|
||||
<DocumentTitle title={pageTitle} />
|
||||
{getLayoutByType(layout)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageLayout;
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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 { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import PageLayoutV1 from './PageLayoutV1';
|
||||
|
||||
jest.mock('components/DocumentTitle/DocumentTitle', () =>
|
||||
jest.fn().mockImplementation(() => <div>DocumentTitle</div>)
|
||||
);
|
||||
|
||||
describe('PageLayoutV1', () => {
|
||||
it('Should render with the left panel, center content, and right panel', () => {
|
||||
const leftPanelText = 'Left panel';
|
||||
const centerText = 'Center content';
|
||||
const rightPanelText = 'Right panel';
|
||||
const { getByText } = render(
|
||||
<PageLayoutV1
|
||||
center
|
||||
leftPanel={<div>{leftPanelText}</div>}
|
||||
pageTitle="Test Page"
|
||||
rightPanel={<div>{rightPanelText}</div>}>
|
||||
{centerText}
|
||||
</PageLayoutV1>
|
||||
);
|
||||
|
||||
expect(getByText(leftPanelText)).toBeInTheDocument();
|
||||
expect(getByText(centerText)).toBeInTheDocument();
|
||||
expect(getByText(rightPanelText)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render with only the center content', () => {
|
||||
const centerText = 'Center content';
|
||||
const { getByText, queryByTestId } = render(
|
||||
<PageLayoutV1 pageTitle="Test Page">{centerText}</PageLayoutV1>
|
||||
);
|
||||
|
||||
expect(queryByTestId('page-layout-v1')).toBeInTheDocument();
|
||||
expect(getByText(centerText)).toBeInTheDocument();
|
||||
expect(queryByTestId('left-panelV1')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('right-panelV1')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -13,7 +13,8 @@
|
||||
|
||||
import { Col, Row } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React, { FC, HTMLAttributes, ReactNode } from 'react';
|
||||
import DocumentTitle from 'components/DocumentTitle/DocumentTitle';
|
||||
import React, { FC, Fragment, HTMLAttributes, ReactNode } from 'react';
|
||||
import './../../styles/layout/page-layout.less';
|
||||
|
||||
interface PageLayoutProp extends HTMLAttributes<HTMLDivElement> {
|
||||
@ -21,6 +22,7 @@ interface PageLayoutProp extends HTMLAttributes<HTMLDivElement> {
|
||||
header?: ReactNode;
|
||||
rightPanel?: ReactNode;
|
||||
center?: boolean;
|
||||
pageTitle: string;
|
||||
}
|
||||
|
||||
export const pageContainerStyles = {
|
||||
@ -35,49 +37,53 @@ const PageLayoutV1: FC<PageLayoutProp> = ({
|
||||
children,
|
||||
rightPanel,
|
||||
className,
|
||||
pageTitle,
|
||||
center = false,
|
||||
}: PageLayoutProp) => {
|
||||
return (
|
||||
<Row
|
||||
className={className}
|
||||
data-testid="page-layout-v1"
|
||||
gutter={[16, 16]}
|
||||
style={pageContainerStyles}>
|
||||
{leftPanel && (
|
||||
<Col
|
||||
className="page-layout-v1-vertical-scroll"
|
||||
flex="284px"
|
||||
id="left-panelV1">
|
||||
{leftPanel}
|
||||
</Col>
|
||||
)}
|
||||
<Col
|
||||
className={classNames(
|
||||
'page-layout-v1-center page-layout-v1-vertical-scroll',
|
||||
{
|
||||
'flex justify-center': center,
|
||||
}
|
||||
<Fragment>
|
||||
<DocumentTitle title={pageTitle} />
|
||||
<Row
|
||||
className={className}
|
||||
data-testid="page-layout-v1"
|
||||
gutter={[16, 16]}
|
||||
style={pageContainerStyles}>
|
||||
{leftPanel && (
|
||||
<Col
|
||||
className="page-layout-v1-vertical-scroll"
|
||||
flex="284px"
|
||||
id="left-panelV1">
|
||||
{leftPanel}
|
||||
</Col>
|
||||
)}
|
||||
flex={
|
||||
leftPanel && rightPanel
|
||||
? 'calc(100% - 568px)'
|
||||
: leftPanel || rightPanel
|
||||
? 'calc(100% - 284px)'
|
||||
: '100%'
|
||||
}
|
||||
offset={center ? 3 : 0}
|
||||
span={center ? 18 : 24}>
|
||||
{children}
|
||||
</Col>
|
||||
{rightPanel && (
|
||||
<Col
|
||||
className="page-layout-v1-vertical-scroll"
|
||||
flex="284px"
|
||||
id="right-panelV1">
|
||||
{rightPanel}
|
||||
className={classNames(
|
||||
'page-layout-v1-center page-layout-v1-vertical-scroll',
|
||||
{
|
||||
'flex justify-center': center,
|
||||
}
|
||||
)}
|
||||
flex={
|
||||
leftPanel && rightPanel
|
||||
? 'calc(100% - 568px)'
|
||||
: leftPanel || rightPanel
|
||||
? 'calc(100% - 284px)'
|
||||
: '100%'
|
||||
}
|
||||
offset={center ? 3 : 0}
|
||||
span={center ? 18 : 24}>
|
||||
{children}
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
{rightPanel && (
|
||||
<Col
|
||||
className="page-layout-v1-vertical-scroll"
|
||||
flex="284px"
|
||||
id="right-panelV1">
|
||||
{rightPanel}
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -79,6 +79,7 @@
|
||||
"basic-configuration": "Basic Configuration",
|
||||
"batch-size": "Batch Size",
|
||||
"bot": "Bot",
|
||||
"bot-detail": "Bot detail",
|
||||
"bot-lowercase": "bot",
|
||||
"bot-plural": "Bots",
|
||||
"broker-plural": "Brokers",
|
||||
@ -180,6 +181,7 @@
|
||||
"data-insight-tier-summary": "Total Data Assets by Tier",
|
||||
"data-insight-top-viewed-entity-summary": "Most Viewed Data Assets",
|
||||
"data-insight-total-entity-summary": "Total Data Assets",
|
||||
"data-quality-test": "Data Quality Test",
|
||||
"data-type": "Data Type",
|
||||
"database": "Database",
|
||||
"database-lowercase": "database",
|
||||
@ -755,6 +757,7 @@
|
||||
"test-entity": "Test {{entity}}",
|
||||
"test-plural": "Tests",
|
||||
"test-suite": "Test Suite",
|
||||
"test-suite-ingestion": "Test suite ingestion",
|
||||
"test-suite-plural": "Test Suites",
|
||||
"test-suite-status": "Test Suite Status",
|
||||
"test-type": "Test type",
|
||||
|
@ -233,7 +233,9 @@ const AddIngestionPage = () => {
|
||||
} else {
|
||||
return (
|
||||
<div className="self-center">
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1
|
||||
center
|
||||
pageTitle={t('label.add-entity', { entity: t('label.ingestion') })}>
|
||||
<Space direction="vertical" size="middle">
|
||||
<TitleBreadcrumb titleLinks={slashedBreadcrumb} />
|
||||
<div className="form-container">
|
||||
|
@ -267,7 +267,9 @@ const DataInsightPage = () => {
|
||||
}, [tab]);
|
||||
|
||||
return (
|
||||
<PageLayoutV1 leftPanel={<DataInsightLeftPanel />}>
|
||||
<PageLayoutV1
|
||||
leftPanel={<DataInsightLeftPanel />}
|
||||
pageTitle={t('label.data-insight')}>
|
||||
<Row data-testid="data-insight-container" gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Space className="w-full justify-between item-start">
|
||||
|
@ -150,7 +150,7 @@ function EditConnectionFormPage() {
|
||||
{getEntityMissingError(serviceCategory, serviceFQN)}
|
||||
</ErrorPlaceHolder>
|
||||
) : (
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1 center pageTitle={t('label.edit-connection')}>
|
||||
<Space direction="vertical" size="middle">
|
||||
<TitleBreadcrumb titleLinks={slashedBreadcrumb} />
|
||||
<div className="form-container">
|
||||
|
@ -23,6 +23,7 @@ import Loader from 'components/Loader/Loader';
|
||||
import { startCase } from 'lodash';
|
||||
import { ServicesUpdateRequest, ServiceTypes } from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import {
|
||||
deployIngestionPipelineById,
|
||||
@ -60,6 +61,7 @@ import {
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
|
||||
const EditIngestionPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isAirflowAvailable, fetchAirflowStatus } = useAirflowStatus();
|
||||
const { ingestionFQN, ingestionType, serviceFQN, serviceCategory } =
|
||||
useParams<{ [key: string]: string }>();
|
||||
@ -265,7 +267,11 @@ const EditIngestionPage = () => {
|
||||
} else {
|
||||
return (
|
||||
<div className="self-center">
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1
|
||||
center
|
||||
pageTitle={t('label.edit-entity', {
|
||||
entity: t('label.ingestion'),
|
||||
})}>
|
||||
<Space direction="vertical" size="middle">
|
||||
<TitleBreadcrumb titleLinks={slashedBreadcrumb} />
|
||||
<div className="form-container">
|
||||
|
@ -252,7 +252,9 @@ const GlossaryPage = () => {
|
||||
|
||||
return (
|
||||
<PageContainerV1>
|
||||
<PageLayoutV1 leftPanel={<GlossaryLeftPanel glossaries={glossaries} />}>
|
||||
<PageLayoutV1
|
||||
leftPanel={<GlossaryLeftPanel glossaries={glossaries} />}
|
||||
pageTitle={t('label.glossary')}>
|
||||
{isRightPanelLoading ? (
|
||||
// Loader for right panel data
|
||||
<Loader />
|
||||
|
@ -74,6 +74,16 @@ jest.mock('rest/glossaryAPI', () => ({
|
||||
.mockImplementation(() => Promise.resolve({ data: MOCK_GLOSSARY })),
|
||||
}));
|
||||
|
||||
jest.mock('components/containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test GlossaryComponent page', () => {
|
||||
it('GlossaryComponent Page Should render', async () => {
|
||||
render(<GlossaryPage />);
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
LoadingNodeState,
|
||||
} from 'components/EntityLineage/EntityLineage.interface';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { getDashboardByFqn } from 'rest/dashboardAPI';
|
||||
import { getLineageByFQN } from 'rest/lineageAPI';
|
||||
@ -65,6 +66,7 @@ import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import './lineagePage.style.less';
|
||||
|
||||
const LineagePage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { entityType, entityFQN } =
|
||||
useParams<{ entityType: EntityType; entityFQN: string }>();
|
||||
const history = useHistory();
|
||||
@ -336,7 +338,7 @@ const LineagePage = () => {
|
||||
|
||||
return (
|
||||
<PageContainerV1>
|
||||
<PageLayoutV1 className="p-x-lg">
|
||||
<PageLayoutV1 className="p-x-lg" pageTitle={t('label.lineage')}>
|
||||
<div className="lineage-page-container">
|
||||
<TitleBreadcrumb titleLinks={titleBreadcrumb} />
|
||||
<Card className="h-full" size="default">
|
||||
|
@ -44,6 +44,16 @@ jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('components/containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test Add Policy Page', () => {
|
||||
it('Should Render the Add Policy page component', async () => {
|
||||
render(<AddPolicyPage />, { wrapper: MemoryRouter });
|
||||
|
@ -103,7 +103,9 @@ const AddPolicyPage = () => {
|
||||
|
||||
return (
|
||||
<div data-testid="add-policy-container">
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1
|
||||
center
|
||||
pageTitle={t('label.add-entity', { entity: t('label.policy') })}>
|
||||
<Row>
|
||||
<Col span={16}>
|
||||
<Space className="w-full" direction="vertical" size="middle">
|
||||
|
@ -45,6 +45,16 @@ jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('components/containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test Add Role Page', () => {
|
||||
it('Should Render the Add Role page component', async () => {
|
||||
render(<AddRolePage />, { wrapper: MemoryRouter });
|
||||
|
@ -98,7 +98,9 @@ const AddRolePage = () => {
|
||||
|
||||
return (
|
||||
<div data-testid="add-role-container">
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1
|
||||
center
|
||||
pageTitle={t('label.add-entity', { entity: t('label.role') })}>
|
||||
<Space direction="vertical" size="middle">
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
<Card>
|
||||
|
@ -18,6 +18,16 @@ const mockProps = {
|
||||
children: <div data-testid="children" />,
|
||||
};
|
||||
|
||||
jest.mock('components/containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test TaskPageLayout Component', () => {
|
||||
it('Should render the component', async () => {
|
||||
render(<TaskPageLayout {...mockProps} />);
|
||||
|
@ -14,14 +14,19 @@
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import React, { FC, HTMLAttributes } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {}
|
||||
|
||||
const TaskPageLayout: FC<Props> = ({ children }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PageContainerV1>
|
||||
<PageLayoutV1 center>{children}</PageLayoutV1>
|
||||
<PageLayoutV1 center pageTitle={t('label.task')}>
|
||||
{children}
|
||||
</PageLayoutV1>
|
||||
</PageContainerV1>
|
||||
);
|
||||
};
|
||||
|
@ -131,6 +131,7 @@ const TestSuiteIngestionPage = () => {
|
||||
classes="tw-max-w-full-hd tw-h-full tw-pt-4"
|
||||
header={<TitleBreadcrumb titleLinks={slashedBreadCrumb} />}
|
||||
layout={PageLayoutType['2ColRTL']}
|
||||
pageTitle={t('label.test-suite-ingestion')}
|
||||
rightPanel={<RightPanel data={INGESTION_DATA} />}>
|
||||
<TestSuiteIngestion
|
||||
ingestionPipeline={ingestionPipeline}
|
||||
|
@ -184,7 +184,7 @@ const TestSuitePage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayoutV1>
|
||||
<PageLayoutV1 pageTitle={t('label.test-suite')}>
|
||||
<Space align="center" className="w-full justify-between" size={16}>
|
||||
<TitleBreadcrumb titleLinks={TEST_SUITE_BREADCRUMB} />
|
||||
<Tooltip
|
||||
|
@ -69,6 +69,16 @@ jest.mock(
|
||||
}
|
||||
);
|
||||
|
||||
jest.mock('components/containers/PageLayoutV1', () =>
|
||||
jest.fn().mockImplementation(({ children, leftPanel, rightPanel }) => (
|
||||
<div>
|
||||
{leftPanel}
|
||||
{children}
|
||||
{rightPanel}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
describe('Test Suite Stepper Page', () => {
|
||||
it('Component should render', async () => {
|
||||
await act(async () => {
|
||||
|
@ -86,7 +86,7 @@ const TestSuiteStepper = () => {
|
||||
|
||||
return (
|
||||
<div data-testid="test-suite-stepper-container">
|
||||
<PageLayoutV1 center>
|
||||
<PageLayoutV1 center pageTitle={t('label.test-suite')}>
|
||||
<Space direction="vertical" size="middle">
|
||||
<TitleBreadcrumb titleLinks={TEST_SUITE_STEPPER_BREADCRUMB} />
|
||||
{addIngestion ? (
|
||||
|
@ -773,7 +773,9 @@ const TagsPage = () => {
|
||||
|
||||
return (
|
||||
<PageContainerV1>
|
||||
<PageLayoutV1 leftPanel={fetchLeftPanel()}>
|
||||
<PageLayoutV1
|
||||
leftPanel={fetchLeftPanel()}
|
||||
pageTitle={t('label.tag-plural')}>
|
||||
{isLoading ? (
|
||||
<Loader />
|
||||
) : error ? (
|
||||
|
@ -12104,6 +12104,22 @@ react-error-boundary@^3.1.4:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
|
||||
react-fast-compare@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
|
||||
react-helmet-async@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.3.0.tgz#7bd5bf8c5c69ea9f02f6083f14ce33ef545c222e"
|
||||
integrity sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
invariant "^2.2.4"
|
||||
prop-types "^15.7.2"
|
||||
react-fast-compare "^3.2.0"
|
||||
shallowequal "^1.1.0"
|
||||
|
||||
react-i18next@^11.18.6:
|
||||
version "11.18.6"
|
||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.6.tgz#e159c2960c718c1314f1e8fcaa282d1c8b167887"
|
||||
|
Loading…
x
Reference in New Issue
Block a user