Skip to content

Commit 0ef501e

Browse files
Merge pull request #14965 from logonoff/pageheader
OCPBUGS-54670: Use PF component group for PageHeading
2 parents 4d11b53 + a9afa41 commit 0ef501e

File tree

158 files changed

+1085
-1550
lines changed

Some content is hidden

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

158 files changed

+1085
-1550
lines changed

frontend/__tests__/components/container.spec.tsx

Lines changed: 5 additions & 5 deletions
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();

frontend/__tests__/components/factory/list-page.spec.tsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import * as React from 'react';
22
import { shallow, mount, ShallowWrapper, ReactWrapper } from 'enzyme';
3+
import { render, screen } from '@testing-library/react';
4+
import '@testing-library/jest-dom';
5+
import configureMockStore from 'redux-mock-store';
6+
import { Provider } from 'react-redux';
37
import { TextInput } from '@patternfly/react-core';
48
import {
59
TextFilter,
610
ListPageWrapper,
711
FireMan,
812
MultiListPage,
913
} from '../../../public/components/factory/list-page';
10-
import { Firehose, PageHeading } from '../../../public/components/utils';
14+
import { Firehose } from '../../../public/components/utils';
1115

1216
jest.mock('react-redux', () => {
1317
const ActualReactRedux = jest.requireActual('react-redux');
@@ -74,40 +78,49 @@ describe(TextFilter.displayName, () => {
7478
});
7579

7680
describe(FireMan.displayName, () => {
77-
let wrapper: ShallowWrapper<any>;
78-
79-
beforeEach(() => {
80-
const resources = [{ kind: 'Node', prop: 'obj' }];
81-
wrapper = shallow(<FireMan resources={resources} />);
81+
const mockStore = configureMockStore();
82+
const store = mockStore({
83+
k8s: {
84+
getIn: jest.fn().mockReturnValue({}),
85+
},
86+
sdkCore: {
87+
impersonate: {},
88+
},
8289
});
8390

8491
it('renders `title` if given `title`', () => {
85-
expect(wrapper.find(PageHeading).props().title).toBe(undefined);
86-
87-
const title = 'My pods';
88-
wrapper.setProps({ title });
92+
const { rerender } = render(
93+
<Provider store={store}>
94+
<FireMan resources={[{ kind: 'Node', prop: 'obj' }]} />
95+
</Provider>,
96+
);
97+
expect(screen.queryByText('My pods')).not.toBeInTheDocument();
8998

90-
expect(wrapper.find(PageHeading).props().title).toEqual(title);
99+
rerender(
100+
<Provider store={store}>
101+
<FireMan resources={[{ kind: 'Node', prop: 'obj' }]} title="My pods" />
102+
</Provider>,
103+
);
104+
expect(screen.getByText('My pods')).toBeInTheDocument();
91105
});
92106

93107
it('renders create button if given `canCreate` true', () => {
94-
expect(wrapper.find('button#yaml-create').exists()).toBe(false);
95-
96-
const createProps = { foo: 'bar' };
97-
const button = wrapper
98-
.setProps({
99-
canCreate: true,
100-
createProps,
101-
createButtonText: 'Create Me!',
102-
title: 'Nights Watch',
103-
})
104-
.find('#yaml-create');
105-
106-
expect(wrapper.find('#yaml-create').childAt(0).text()).toEqual('Create Me!');
107-
108-
Object.keys(createProps).forEach((key) => {
109-
expect(createProps[key] === button.props()[key]).toBe(true);
110-
});
108+
const createProps = {};
109+
render(
110+
<Provider store={store}>
111+
<FireMan
112+
resources={[{ kind: 'Node', prop: 'obj' }]}
113+
canCreate
114+
createProps={createProps}
115+
createButtonText="Create Me!"
116+
title="Nights Watch"
117+
/>
118+
</Provider>,
119+
);
120+
121+
const button = screen.getByRole('button', { name: 'Create Me!' });
122+
expect(button).toBeInTheDocument();
123+
expect(button).toHaveAttribute('id', 'yaml-create');
111124
});
112125
});
113126

frontend/__tests__/components/storage-class-form.spec.tsx

Lines changed: 1 addition & 1 deletion
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'),

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

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +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-
// Mock getRootNode
12-
Object.defineProperty(Element.prototype, 'getRootNode', {
13-
value: function () {
14-
let rootNode = this;
15-
while (rootNode.parentNode) {
16-
rootNode = rootNode.parentNode;
17-
}
18-
return rootNode;
19-
},
20-
configurable: true,
21-
});
22-
23-
describe(BreadCrumbs.displayName, () => {
24-
let breadcrumbs: BreadCrumbsProps['breadcrumbs'];
25-
26-
beforeEach(() => {
27-
configure({ testIdAttribute: 'data-test' });
28-
29-
breadcrumbs = [
30-
{ name: 'pods', path: '/pods' },
31-
{ name: 'containers', path: '/pods/containers' },
32-
];
33-
});
34-
35-
it('renders each given breadcrumb', () => {
36-
render(
37-
<MemoryRouter>
38-
<BreadCrumbs breadcrumbs={breadcrumbs} />
39-
</MemoryRouter>,
40-
);
41-
42-
breadcrumbs.forEach((crumb) => {
43-
if (crumb.path) {
44-
const link = screen.getByRole('link', { name: crumb.name });
45-
expect(link).toHaveAttribute('href', crumb.path);
46-
} else {
47-
expect(screen.getByText(crumb.name)).toBeInTheDocument();
48-
}
49-
});
50-
});
51-
});
52-
53-
describe(PageHeading.displayName, () => {
7+
describe(ConnectedPageHeading.displayName, () => {
548
beforeEach(() => {
559
configure({ testIdAttribute: 'data-test' });
5610
});
@@ -59,7 +13,7 @@ describe(PageHeading.displayName, () => {
5913
const kind = 'Pod';
6014
render(
6115
<MemoryRouter>
62-
<PageHeading.WrappedComponent obj={null} kind={kind} />
16+
<ConnectedPageHeading.WrappedComponent obj={null} kind={kind} />
6317
</MemoryRouter>,
6418
);
6519

@@ -72,7 +26,7 @@ describe(PageHeading.displayName, () => {
7226
const title = <span>My Custom Title</span>;
7327
render(
7428
<MemoryRouter>
75-
<PageHeading.WrappedComponent obj={null} title={title} />
29+
<ConnectedPageHeading.WrappedComponent obj={null} title={title} />
7630
</MemoryRouter>,
7731
);
7832

@@ -83,7 +37,7 @@ describe(PageHeading.displayName, () => {
8337
const breadcrumbs = [];
8438
render(
8539
<MemoryRouter>
86-
<PageHeading.WrappedComponent
40+
<ConnectedPageHeading.WrappedComponent
8741
obj={{ data: testResourceInstance, loaded: true, loadError: null }}
8842
breadcrumbsFor={() => breadcrumbs}
8943
/>
@@ -96,7 +50,7 @@ describe(PageHeading.displayName, () => {
9650
it('does not render breadcrumbs if object has not loaded', () => {
9751
render(
9852
<MemoryRouter>
99-
<PageHeading.WrappedComponent obj={null} breadcrumbsFor={() => []} />
53+
<ConnectedPageHeading.WrappedComponent obj={null} breadcrumbsFor={() => []} />
10054
</MemoryRouter>,
10155
);
10256

frontend/before-tests.js

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,51 @@ import { URLSearchParams } from 'url';
66
import fetch, { Headers } from 'node-fetch';
77

88
// FIXME: Remove when jest is updated to at least 25.1.0 -- see https://github.com/jsdom/jsdom/issues/1555
9-
Element.prototype.closest = function (this, selector) {
10-
// eslint-disable-next-line consistent-this
11-
let el = this;
12-
while (el) {
13-
if (el.matches(selector)) {
14-
return el;
9+
if (!Element.prototype.closest) {
10+
Element.prototype.closest = function (this, selector) {
11+
// eslint-disable-next-line consistent-this
12+
let el = this;
13+
while (el) {
14+
if (el.matches(selector)) {
15+
return el;
16+
}
17+
el = el.parentElement;
1518
}
16-
el = el.parentElement;
17-
}
18-
return null;
19-
};
19+
return null;
20+
};
21+
}
22+
if (!Element.prototype.getRootNode) {
23+
Object.defineProperty(Element.prototype, 'getRootNode', {
24+
value: function () {
25+
let rootNode = this;
26+
while (rootNode.parentNode) {
27+
rootNode = rootNode.parentNode;
28+
}
29+
return rootNode;
30+
},
31+
writable: true,
32+
});
33+
}
2034
// FIXME: Remove when jest is updated to at least 25
21-
Object.defineProperty(window, 'Headers', {
22-
value: Headers,
23-
writable: true,
24-
});
35+
if (!window.Headers) {
36+
Object.defineProperty(window, 'Headers', {
37+
value: Headers,
38+
writable: true,
39+
});
40+
}
2541
// FIXME: Remove when jest is updated to at least 22
26-
Object.defineProperty(window, 'URLSearchParams', {
27-
value: URLSearchParams,
28-
writable: true,
29-
});
30-
Object.defineProperty(window, 'fetch', {
31-
value: fetch,
32-
writable: true,
33-
});
42+
if (!window.URLSearchParams) {
43+
Object.defineProperty(window, 'URLSearchParams', {
44+
value: URLSearchParams,
45+
writable: true,
46+
});
47+
}
48+
if (!window.fetch) {
49+
Object.defineProperty(window, 'fetch', {
50+
value: fetch,
51+
writable: true,
52+
});
53+
}
3454

3555
// http://airbnb.io/enzyme/docs/installation/index.html#working-with-react-16
3656
configure({ adapter: new Adapter() });

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"@patternfly/react-catalog-view-extension": "^6.1.0",
141141
"@patternfly/react-charts": "^8.2.1",
142142
"@patternfly/react-code-editor": "^6.2.1",
143-
"@patternfly/react-component-groups": "^6.2.0",
143+
"@patternfly/react-component-groups": "^6.2.1",
144144
"@patternfly/react-console": "^6.0.0",
145145
"@patternfly/react-core": "^6.2.1",
146146
"@patternfly/react-icons": "^6.2.1",

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { IconStatus, Status } from '@patternfly/react-component-groups/dist/dynamic/Status';
23
import {
34
Tabs,
45
Tab,
@@ -8,14 +9,16 @@ import {
89
TabContent,
910
TabContentProps,
1011
TabTitleText,
12+
PageSection,
1113
} from '@patternfly/react-core';
14+
import { ExclamationTriangleIcon } from '@patternfly/react-icons';
1215
import { LockIcon } from '@patternfly/react-icons/dist/esm/icons/lock-icon';
1316
import { useTranslation } from 'react-i18next';
1417
import { useParams } from 'react-router-dom-v5-compat';
1518
import { LoadingBox, history } from '@console/internal/components/utils';
16-
import { PageLayout, isModifiedEvent } from '@console/shared';
19+
import { isModifiedEvent } from '@console/shared';
1720
import { DocumentTitle } from '@console/shared/src/components/document-title/DocumentTitle';
18-
import PrimaryHeading from '@console/shared/src/components/heading/PrimaryHeading';
21+
import { PageHeading } from '@console/shared/src/components/heading/PageHeading';
1922
import ClusterConfigurationForm from './ClusterConfigurationForm';
2023
import { getClusterConfigurationGroups } from './getClusterConfigurationGroups';
2124
import { ClusterConfigurationTabGroup } from './types';
@@ -98,12 +101,13 @@ const ClusterConfigurationPage: React.FC = () => {
98101
return (
99102
<div className="co-cluster-configuration-page">
100103
<DocumentTitle>{t('console-app~Cluster configuration')}</DocumentTitle>
101-
<PageLayout
104+
<PageHeading
102105
title={t('console-app~Cluster configuration')}
103-
hint={t(
106+
helpText={t(
104107
'console-app~Set cluster-wide configuration for the console experience. Your changes will be autosaved and will affect after a refresh.',
105108
)}
106-
>
109+
/>
110+
<PageSection>
107111
{!loaded ? (
108112
<LoadingBox />
109113
) : clusterConfigurationTabs.length === 0 ? (
@@ -138,14 +142,16 @@ const ClusterConfigurationPage: React.FC = () => {
138142
{groupNotFound ? (
139143
/* Similar to a TabContent */
140144
<section className="co-cluster-configuration-page pf-v6-c-tab-content">
141-
<PrimaryHeading>
142-
{t('console-app~{{section}} not found', { section: activeTabId })}
143-
</PrimaryHeading>
145+
<Status
146+
status={IconStatus.warning}
147+
icon={<ExclamationTriangleIcon />}
148+
label={t('console-app~{{section}} not found', { section: activeTabId })}
149+
/>
144150
</section>
145151
) : null}
146152
</>
147153
)}
148-
</PageLayout>
154+
</PageSection>
149155
</div>
150156
);
151157
};

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

Lines changed: 1 addition & 1 deletion
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';

0 commit comments

Comments
 (0)