Skip to content

Commit 071e917

Browse files
committed
CONSOLE-4492: Move BasePageHeading to shared
- adopt `BasePageHeading` when possible (as many pages don't use the extra functionality provided by the `connect`) - Rename `PageHeading` to `ConnectedPageHeading` - Rename `BasePageHeading` to `PageHeading` - move `PageHeading`, `Breadcrumbs` to console/shared - update cypress test to reflect changes
1 parent 75ec94f commit 071e917

File tree

105 files changed

+485
-440
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+485
-440
lines changed

Diff for: frontend/__tests__/components/container.spec.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {
1111
Firehose,
1212
HorizontalNav,
1313
LoadingBox,
14-
PageHeading,
15-
PageHeadingProps,
14+
ConnectedPageHeading,
15+
ConnectedPageHeadingProps,
1616
} from '@console/internal/components/utils';
1717
import { testPodInstance } from '../../__mocks__/k8sResourcesMocks';
1818
import { Status } from '@console/shared';
@@ -53,13 +53,13 @@ describe(ContainersDetailsPage.displayName, () => {
5353
describe(ContainerDetails.displayName, () => {
5454
const obj = { data: { ...testPodInstance } };
5555

56-
it('renders a `PageHeading` and a `ContainerDetails` with the same state', async () => {
56+
it('renders a `ConnectedPageHeading` and a `ContainerDetails` with the same state', async () => {
5757
jest
5858
.spyOn(ReactRouter, 'useParams')
5959
.mockReturnValue({ podName: 'test-name', ns: 'default', name: 'crash-app' });
6060

6161
jest.spyOn(ReactRouter, 'useLocation').mockReturnValue({ pathname: '' });
62-
// Full mount needed to get the children of the PageHeading within the ContainerDetails without warning
62+
// Full mount needed to get the children of the ConnectedPageHeading within the ContainerDetails without warning
6363
let containerDetails: ReactWrapper;
6464
await act(async () => {
6565
containerDetails = mount(<ContainerDetails obj={obj} loaded={true} />, {
@@ -72,7 +72,7 @@ describe(ContainerDetails.displayName, () => {
7272
});
7373

7474
const pageHeadingStatusProps = containerDetails
75-
.find<PageHeadingProps>(PageHeading)
75+
.find<ConnectedPageHeadingProps>(ConnectedPageHeading)
7676
.children()
7777
.find<StatusProps>(Status)
7878
.props();

Diff for: frontend/__tests__/components/storage-class-form.spec.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ConnectedStorageClassForm,
77
StorageClassFormProps,
88
} from '../../public/components/storage-class-form';
9-
import { PageHeading } from '../../public/components/utils';
9+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
1010

1111
jest.mock('react-router-dom-v5-compat', () => ({
1212
...jest.requireActual('react-router-dom-v5-compat'),

Diff for: frontend/__tests__/components/utils/page-heading.spec.tsx renamed to frontend/__tests__/components/utils/connected-page-heading.spec.tsx

+6-40
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,10 @@
11
import { configure, render, screen } from '@testing-library/react';
22
import '@testing-library/jest-dom';
3-
import {
4-
PageHeading,
5-
BreadCrumbs,
6-
BreadCrumbsProps,
7-
} from '../../../public/components/utils/headings';
3+
import { ConnectedPageHeading } from '../../../public/components/utils/headings';
84
import { testResourceInstance } from '../../../__mocks__/k8sResourcesMocks';
95
import { MemoryRouter } from 'react-router-dom-v5-compat';
106

11-
describe(BreadCrumbs.displayName, () => {
12-
let breadcrumbs: BreadCrumbsProps['breadcrumbs'];
13-
14-
beforeEach(() => {
15-
configure({ testIdAttribute: 'data-test' });
16-
17-
breadcrumbs = [
18-
{ name: 'pods', path: '/pods' },
19-
{ name: 'containers', path: '/pods/containers' },
20-
];
21-
});
22-
23-
it('renders each given breadcrumb', () => {
24-
render(
25-
<MemoryRouter>
26-
<BreadCrumbs breadcrumbs={breadcrumbs} />
27-
</MemoryRouter>,
28-
);
29-
30-
breadcrumbs.forEach((crumb) => {
31-
if (crumb.path) {
32-
const link = screen.getByRole('link', { name: crumb.name });
33-
expect(link).toHaveAttribute('href', crumb.path);
34-
} else {
35-
expect(screen.getByText(crumb.name)).toBeInTheDocument();
36-
}
37-
});
38-
});
39-
});
40-
41-
describe(PageHeading.displayName, () => {
7+
describe(ConnectedPageHeading.displayName, () => {
428
beforeEach(() => {
439
configure({ testIdAttribute: 'data-test' });
4410
});
@@ -47,7 +13,7 @@ describe(PageHeading.displayName, () => {
4713
const kind = 'Pod';
4814
render(
4915
<MemoryRouter>
50-
<PageHeading.WrappedComponent obj={null} kind={kind} />
16+
<ConnectedPageHeading.WrappedComponent obj={null} kind={kind} />
5117
</MemoryRouter>,
5218
);
5319

@@ -60,7 +26,7 @@ describe(PageHeading.displayName, () => {
6026
const title = <span>My Custom Title</span>;
6127
render(
6228
<MemoryRouter>
63-
<PageHeading.WrappedComponent obj={null} title={title} />
29+
<ConnectedPageHeading.WrappedComponent obj={null} title={title} />
6430
</MemoryRouter>,
6531
);
6632

@@ -71,7 +37,7 @@ describe(PageHeading.displayName, () => {
7137
const breadcrumbs = [];
7238
render(
7339
<MemoryRouter>
74-
<PageHeading.WrappedComponent
40+
<ConnectedPageHeading.WrappedComponent
7541
obj={{ data: testResourceInstance, loaded: true, loadError: null }}
7642
breadcrumbsFor={() => breadcrumbs}
7743
/>
@@ -84,7 +50,7 @@ describe(PageHeading.displayName, () => {
8450
it('does not render breadcrumbs if object has not loaded', () => {
8551
render(
8652
<MemoryRouter>
87-
<PageHeading.WrappedComponent obj={null} breadcrumbsFor={() => []} />
53+
<ConnectedPageHeading.WrappedComponent obj={null} breadcrumbsFor={() => []} />
8854
</MemoryRouter>,
8955
);
9056

Diff for: frontend/packages/console-app/src/components/cluster-configuration/ClusterConfigurationPage.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import { ExclamationTriangleIcon } from '@patternfly/react-icons';
1515
import { LockIcon } from '@patternfly/react-icons/dist/esm/icons/lock-icon';
1616
import { useTranslation } from 'react-i18next';
1717
import { useParams } from 'react-router-dom-v5-compat';
18-
import { LoadingBox, BasePageHeading, history } from '@console/internal/components/utils';
18+
import { LoadingBox, history } from '@console/internal/components/utils';
1919
import { isModifiedEvent } from '@console/shared';
2020
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
21+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
2122
import ClusterConfigurationForm from './ClusterConfigurationForm';
2223
import { getClusterConfigurationGroups } from './getClusterConfigurationGroups';
2324
import { ClusterConfigurationTabGroup } from './types';
@@ -100,7 +101,7 @@ const ClusterConfigurationPage: React.FC = () => {
100101
return (
101102
<div className="co-cluster-configuration-page">
102103
<DocumentTitle>{t('console-app~Cluster configuration')}</DocumentTitle>
103-
<BasePageHeading
104+
<PageHeading
104105
title={t('console-app~Cluster configuration')}
105106
helpText={t(
106107
'console-app~Set cluster-wide configuration for the console experience. Your changes will be autosaved and will affect after a refresh.',

Diff for: frontend/packages/console-app/src/components/network-policies/create-network-policy.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import * as _ from 'lodash';
33
import { useTranslation } from 'react-i18next';
44
import { useParams } from 'react-router-dom-v5-compat';
55
import { AsyncResourceYAMLEditor } from '@console/internal/components/AsyncResourceYAMLEditor';
6-
import { PageHeading } from '@console/internal/components/utils';
76
import { MultiNetworkPolicyModel, NetworkPolicyModel } from '@console/internal/models';
87
import { NetworkPolicyKind } from '@console/internal/module/k8s';
8+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
99
import { SyncedEditor } from '@console/shared/src/components/synced-editor';
1010
import { EditorType } from '@console/shared/src/components/synced-editor/editor-toggle';
1111
import { safeYAMLToJS } from '@console/shared/src/utils/yaml';

Diff for: frontend/packages/console-app/src/components/pdb/PDBFormPage.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import * as React from 'react';
22
import { useTranslation, Trans } from 'react-i18next';
33
import { useParams, useLocation } from 'react-router-dom-v5-compat';
44
import { CreateYAML } from '@console/internal/components/create-yaml';
5-
import { PageHeading, LoadingBox } from '@console/internal/components/utils';
5+
import { LoadingBox } from '@console/internal/components/utils';
66
import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook';
77
import { K8sPodControllerKind, getGroupVersionKind } from '@console/internal/module/k8s';
8+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
89
import { SyncedEditor } from '@console/shared/src/components/synced-editor';
910
import { EditorType } from '@console/shared/src/components/synced-editor/editor-toggle';
1011
import { safeJSToYAML } from '@console/shared/src/utils/yaml';

Diff for: frontend/packages/console-app/src/components/quick-starts/QuickStartCatalogPage.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@ import { QuickStartCatalogPage as PfQuickStartCatalogPage } from '@patternfly/qu
33
import { useTranslation } from 'react-i18next';
44
import { LoadingBox } from '@console/internal/components/utils';
55
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
6+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
67
import QuickStartsLoader from './loader/QuickStartsLoader';
78

89
const QuickStartCatalogPage: React.FC = () => {
910
const { t } = useTranslation();
1011
return (
1112
<>
1213
<DocumentTitle>{t('console-app~Quick Starts')}</DocumentTitle>
14+
<PageHeading
15+
title={t('console-app~Quick Starts')}
16+
helpText={t(
17+
'console-app~Learn how to create, import, and run applications on OpenShift with step-by-step instructions and tasks.',
18+
)}
19+
/>
1320
<QuickStartsLoader>
1421
{(quickStarts, loaded) =>
1522
loaded ? (
16-
<PfQuickStartCatalogPage
17-
quickStarts={quickStarts}
18-
showFilter
19-
title={t('console-app~Quick Starts')}
20-
hint={t(
21-
'console-app~Learn how to create, import, and run applications on OpenShift with step-by-step instructions and tasks.',
22-
)}
23-
/>
23+
<PfQuickStartCatalogPage showTitle={false} quickStarts={quickStarts} showFilter />
2424
) : (
2525
<LoadingBox />
2626
)

Diff for: frontend/packages/console-app/src/components/user-preferences/UserPreferencePage.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
UserPreferenceItem,
1818
isUserPreferenceItem,
1919
} from '@console/dynamic-plugin-sdk';
20-
import { LoadingBox, BasePageHeading, history } from '@console/internal/components/utils';
20+
import { LoadingBox, history } from '@console/internal/components/utils';
2121
import { useExtensions } from '@console/plugin-sdk/src';
2222
import {
2323
isModifiedEvent,
@@ -26,6 +26,7 @@ import {
2626
Spotlight,
2727
} from '@console/shared';
2828
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
29+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
2930
import { USER_PREFERENCES_BASE_URL } from './const';
3031
import {
3132
UserPreferenceTabGroup,
@@ -127,7 +128,7 @@ const UserPreferencePage: React.FC = () => {
127128
? t('console-app~User Preferences {{activeTab}}', { activeTab })
128129
: t('console-app~User Preferences')}
129130
</DocumentTitle>
130-
<BasePageHeading
131+
<PageHeading
131132
title={t('console-app~User Preferences')}
132133
helpText={t(
133134
'console-app~Set your individual preferences for the console experience. Any changes will be autosaved.',

Diff for: frontend/packages/console-app/src/components/volume-snapshot/create-volume-snapshot/create-volume-snapshot.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import {
3232
convertToBaseValue,
3333
humanizeBinaryBytes,
3434
getURLSearchParams,
35-
PageHeading,
3635
} from '@console/internal/components/utils';
3736
import { useK8sGet } from '@console/internal/components/utils/k8s-get-hook';
3837
import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook';
@@ -57,6 +56,7 @@ import {
5756
} from '@console/internal/module/k8s';
5857
import { getName, getNamespace, getAnnotations } from '@console/shared';
5958
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
59+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
6060
import PaneBody from '@console/shared/src/components/layout/PaneBody';
6161
import { LinkTo } from '@console/shared/src/components/links/LinkTo';
6262
import './_create-volume-snapshot.scss';

Diff for: frontend/packages/console-dynamic-plugin-sdk/src/extensions/console-types.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,16 @@ export type UseActiveColumns = <D = any>({
347347
}) => [TableColumn<D>[], boolean];
348348

349349
export type ListPageHeaderProps = {
350+
/** If no title is set, only the `children` and `badge` props will be rendered */
350351
title: string;
352+
/** A subtitle placed below the title. */
351353
helpText?: React.ReactNode;
354+
/** A badge that is displayed next to the title of the heading */
352355
badge?: React.ReactNode;
353-
/** Actions rendered in the header */
356+
/** A primary action that is always rendered. */
354357
children?: React.ReactNode;
355-
/** The favourites button will be hidden by default if no title is set. */
358+
/** By default the favourites button is only shown while in the administrator perspective.
359+
* This prop allows you to hide the button in the administrator perspective. */
356360
hideFavoriteButton?: boolean;
357361
};
358362

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Breadcrumb, BreadcrumbItem } from '@patternfly/react-core';
2+
import { LinkTo } from '@console/shared/src/components/links/LinkTo';
3+
4+
type Breadcrumb = {
5+
/** The text to be displayed in the breadcrumb */
6+
name: string;
7+
/** The react router path to be used for the breadcrumb */
8+
path: string;
9+
};
10+
11+
export type BreadcrumbsProps = {
12+
breadcrumbs: Breadcrumb[];
13+
};
14+
15+
/**
16+
* A helper around the PatternFly Breadcrumb component.
17+
*/
18+
export const Breadcrumbs = ({ breadcrumbs }: BreadcrumbsProps) => (
19+
<Breadcrumb data-test="page-heading-breadcrumbs">
20+
{breadcrumbs.map((crumb, i, { length }) => {
21+
return (
22+
<BreadcrumbItem
23+
to={crumb.path}
24+
key={`${crumb.path}-${crumb.name}`}
25+
data-test-id={`breadcrumb-link-${i}`}
26+
isActive={i === length - 1}
27+
component={LinkTo(crumb.path)}
28+
>
29+
{crumb.name}
30+
</BreadcrumbItem>
31+
);
32+
})}
33+
</Breadcrumb>
34+
);
35+
36+
Breadcrumbs.displayName = 'Breadcrumbs';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import '@testing-library/jest-dom';
2+
import { render, screen } from '@testing-library/react';
3+
import { MemoryRouter } from 'react-router-dom-v5-compat';
4+
import { Breadcrumbs, BreadcrumbsProps } from '../Breadcrumbs';
5+
6+
describe('Breadcrumbs', () => {
7+
let breadcrumbs: BreadcrumbsProps['breadcrumbs'];
8+
9+
beforeEach(() => {
10+
breadcrumbs = [
11+
{ name: 'pods', path: '/pods' },
12+
{ name: 'containers', path: '/pods/containers' },
13+
];
14+
});
15+
16+
it('renders each given breadcrumb', () => {
17+
render(
18+
<MemoryRouter>
19+
<Breadcrumbs breadcrumbs={breadcrumbs} />
20+
</MemoryRouter>,
21+
);
22+
23+
breadcrumbs.forEach((crumb) => {
24+
if (crumb.path) {
25+
const link = screen.getByRole('link', { name: crumb.name });
26+
expect(link).toHaveAttribute('href', crumb.path);
27+
} else {
28+
expect(screen.getByText(crumb.name)).toBeInTheDocument();
29+
}
30+
});
31+
});
32+
});

Diff for: frontend/packages/console-shared/src/components/catalog/CatalogController.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import { useLocation } from 'react-router-dom-v5-compat';
55
import { ResolvedExtension, CatalogItemType } from '@console/dynamic-plugin-sdk';
66
import { CatalogItem, CatalogItemAttribute } from '@console/dynamic-plugin-sdk/src/extensions';
77
import {
8-
PageHeading,
98
skeletonCatalog,
109
StatusBox,
1110
removeQueryArgument,
1211
setQueryArgument,
1312
} from '@console/internal/components/utils';
1413
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
14+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
1515
import { useQueryParams } from '../../hooks';
1616
import PageBody from '../layout/PageBody';
1717
import CatalogView from './catalog-view/CatalogView';

Diff for: frontend/packages/console-shared/src/components/catalog/__tests__/CatalogController.spec.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { shallow } from 'enzyme';
3-
import { PageHeading } from '@console/internal/components/utils';
3+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
44
import * as UseQueryParams from '@console/shared/src/hooks/useQueryParams';
55
import CatalogController from '../CatalogController';
66

Diff for: frontend/packages/console-shared/src/components/editor/CodeEditor.scss

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@import '../../../../../public/style/vars';
1+
@use '../../../../../public/style/vars';
22

33
.ocs-yaml-editor {
44
// ensure editor stays fills the parent container while remaining in bounds
@@ -26,7 +26,7 @@
2626
}
2727

2828
// hide CodeEditor toolbar on mobile
29-
@media (max-width: $screen-sm-max) {
29+
@media (max-width: vars.$screen-sm-max) {
3030
.pf-v6-c-code-editor__header {
3131
display: none;
3232

@@ -38,12 +38,8 @@
3838

3939
.pf-v6-c-code-editor__controls {
4040
align-items: center;
41-
// the height+padding of a PatternFly standard button.
42-
// ensures that all toolbars are of the same height regardless of content
43-
min-height: calc(
44-
var(--pf-t--global--font--size--body--default) * var(--pf-t--global--font--line-height--body) +
45-
var(--pf-t--global--spacer--control--vertical--default) * 2
46-
);
41+
// ensure all toolbars are of the same height regardless of content
42+
min-height: vars.$co-button-height;
4743
width: 100%;
4844
}
4945
}

0 commit comments

Comments
 (0)