Skip to content

Commit bd6ef9a

Browse files
authored
CONSOLE-4201: Migrate ExtensionCatalog to use extensible Catalog system (#14769)
* CONSOLE-4201: Migrate ExtensionCatalog to use console-shared catalog system and dynamic plugin catalog extensions * Update new console shared component exports to match convention in the package * fix contrib/catalogd-route.yaml * fix bundles sort order
1 parent 8e845cf commit bd6ef9a

Some content is hidden

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

50 files changed

+1222
-779
lines changed

cmd/bridge/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const (
3232
k8sInClusterCA = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
3333
k8sInClusterBearerToken = "/var/run/secrets/kubernetes.io/serviceaccount/token"
3434

35-
catalogdHost = "catalogd-catalogserver.openshift-catalogd.svc:443"
35+
catalogdHost = "catalogd-service.openshift-catalogd.svc:443"
3636

3737
// Well-known location of the tenant aware Thanos service for OpenShift exposing the query and query_range endpoints. This is only accessible in-cluster.
3838
// Thanos proxies requests to both cluster monitoring and user workload monitoring prometheus instances.

contrib/catalogd-route.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
kind: Route
2+
apiVersion: route.openshift.io/v1
3+
metadata:
4+
name: catalogd-route
5+
namespace: openshift-catalogd
6+
spec:
7+
to:
8+
kind: Service
9+
name: catalogd-service
10+
weight: 100
11+
port:
12+
targetPort: https
13+
tls:
14+
termination: passthrough
15+
insecureEdgeTerminationPolicy: Redirect

contrib/oc-environment.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fi
3939

4040
# This route will not exist by default. If we want olmv1 to work off cluster, we will need to
4141
# manually create a route for the catalogd service.
42-
CATALOGD_HOSTNAME=$(oc -n openshift-catalogd get route catalogd-catalogserver -o jsonpath='{.spec.host}' 2>/dev/null)
42+
CATALOGD_HOSTNAME=$(oc -n openshift-catalogd get route catalogd-route -o jsonpath='{.spec.host}' 2>/dev/null)
4343
if [ -n "$CATALOGD_HOSTNAME" ]; then
4444
BRIDGE_K8S_MODE_OFF_CLUSTER_CATALOGD="https://$CATALOGD_HOSTNAME"
4545
export BRIDGE_K8S_MODE_OFF_CLUSTER_CATALOGD

frontend/packages/console-app/src/components/nav/ExternalLink.tsx renamed to frontend/packages/console-app/src/components/nav/ExternalNavLink.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { NavItem } from '@patternfly/react-core';
33

4-
export const ExternalLink = ({ href, name }: ExternalLinkProps): React.ReactElement => (
4+
export const ExternalNavLink = ({ href, name }: ExternalLinkProps): React.ReactElement => (
55
<NavItem isActive={false}>
66
<a
77
className="pf-v6-c-nav__link"

frontend/packages/console-dynamic-plugin-sdk/src/api/dynamic-core-api.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,8 @@ export const usePrometheusPoll: UsePrometheusPoll = (options) => {
714714
* @param {TimestampProps['omitSuffix']} omitSuffix - formats the date ommiting the suffix.
715715
* @param {TimestampProps['className']} className - additional class name for the component.
716716
*/
717-
export const Timestamp: React.FC<TimestampProps> = require('@console/internal/components/utils/timestamp')
718-
.Timestamp;
717+
export const Timestamp: React.FC<TimestampProps> = require('@console/shared/src/components/datetime/Timestamp')
718+
.default;
719719

720720
export { useModal } from '../app/modal-support/useModal';
721721

frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ export type CatalogItemAttribute = {
181181
label: string;
182182
attribute: string;
183183
description?: string;
184+
comparator?: CodeRef<(a: string, b: string) => number>;
184185
};
185186

186187
export type CatalogItemBadge = {

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

+5-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as _ from 'lodash';
33
import { useTranslation } from 'react-i18next';
44
import { useLocation } from 'react-router-dom-v5-compat';
55
import { ResolvedExtension, CatalogItemType } from '@console/dynamic-plugin-sdk';
6-
import { CatalogItem, CatalogItemAttribute } from '@console/dynamic-plugin-sdk/src/extensions';
6+
import { CatalogItem } from '@console/dynamic-plugin-sdk/src/extensions';
77
import {
88
PageHeading,
99
skeletonCatalog,
@@ -33,7 +33,7 @@ type CatalogControllerProps = CatalogService & {
3333
enableDetailsPanel?: boolean;
3434
hideSidebar?: boolean;
3535
title: string;
36-
description: string;
36+
description: string | React.ReactElement;
3737
categories?: CatalogCategory[];
3838
};
3939

@@ -72,15 +72,12 @@ const CatalogController: React.FC<CatalogControllerProps> = ({
7272
};
7373

7474
const filterGroups: string[] = React.useMemo(() => {
75-
return (
76-
typeExtension?.properties.filters?.map((filter: CatalogItemAttribute) => filter.attribute) ??
77-
[]
78-
);
75+
return typeExtension?.properties.filters?.map((filter) => filter.attribute) ?? [];
7976
}, [typeExtension]);
8077

8178
const filterGroupMap: CatalogFilterGroupMap = React.useMemo(() => {
8279
return (
83-
typeExtension?.properties.filters?.reduce((map, filter: CatalogItemAttribute) => {
80+
typeExtension?.properties.filters?.reduce((map, filter) => {
8481
map[filter.attribute] = filter;
8582
return map;
8683
}, {}) ?? {}
@@ -89,7 +86,7 @@ const CatalogController: React.FC<CatalogControllerProps> = ({
8986

9087
const groupings: CatalogStringMap = React.useMemo(() => {
9188
return (
92-
typeExtension?.properties.groupings?.reduce((map, group: CatalogItemAttribute) => {
89+
typeExtension?.properties.groupings?.reduce((map, group) => {
9390
map[group.attribute] = group.label;
9491
return map;
9592
}, {}) ?? {}

frontend/packages/console-shared/src/components/catalog/catalog-view/CatalogFilters.tsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
} from '@patternfly/react-catalog-view-extension';
77
import * as _ from 'lodash';
88
import { CatalogItemAttribute } from '@console/dynamic-plugin-sdk';
9+
import { ResolvedCodeRefProperties } from '@console/dynamic-plugin-sdk/src/types';
910
import { FieldLevelHelp } from '@console/internal/components/utils';
11+
import { alphanumericCompare } from '@console/shared/src/utils/utils';
1012
import {
1113
CatalogFilter,
1214
CatalogFilterCounts,
@@ -17,7 +19,7 @@ import {
1719
type CatalogFiltersProps = {
1820
activeFilters: CatalogFilters;
1921
filterGroupCounts: CatalogFilterCounts;
20-
filterGroupMap: { [key: string]: CatalogItemAttribute };
22+
filterGroupMap: { [key: string]: ResolvedCodeRefProperties<CatalogItemAttribute> };
2123
filterGroupsShowAll: { [key: string]: boolean };
2224
onFilterChange: (filterType: string, id: string, value: boolean) => void;
2325
onShowAllToggle: (groupName: string) => void;
@@ -58,11 +60,14 @@ const CatalogFilters: React.FC<CatalogFiltersProps> = ({
5860

5961
const renderFilterGroup = (filterGroup: CatalogFilter, groupName: string) => {
6062
const filterGroupKeys = Object.keys(filterGroup);
63+
const filterGroupComparator = filterGroupMap[groupName]?.comparator ?? alphanumericCompare;
6164
if (filterGroupKeys.length > 0) {
62-
const sortedFilterGroup = filterGroupKeys.sort().reduce<CatalogFilter>((acc, filterName) => {
63-
acc[filterName] = filterGroup[filterName];
64-
return acc;
65-
}, {});
65+
const sortedFilterGroup = filterGroupKeys
66+
.sort(filterGroupComparator || alphanumericCompare)
67+
.reduce<CatalogFilter>((acc, filterName) => {
68+
acc[filterName] = filterGroup[filterName];
69+
return acc;
70+
}, {});
6671
return (
6772
<FilterSidePanelCategory
6873
key={groupName}

frontend/packages/console-shared/src/components/catalog/utils/filter-utils.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,25 @@ export const determineAvailableFilters = (
8181
filterGroups: string[],
8282
): CatalogFilters => {
8383
const filters = _.cloneDeep(initialFilters);
84-
8584
_.each(filterGroups, (field) => {
8685
_.each(items, (item) => {
8786
const value = item[field] || item.attributes?.[field];
8887
if (value) {
89-
_.set(filters, [field, value], {
90-
label: value,
91-
value,
92-
active: false,
93-
});
88+
if (Array.isArray(value)) {
89+
_.each(value, (v) => {
90+
_.set(filters, [field, v], {
91+
label: v,
92+
value: v,
93+
active: false,
94+
});
95+
});
96+
} else {
97+
_.set(filters, [field, value], {
98+
label: value,
99+
value,
100+
active: false,
101+
});
102+
}
94103
}
95104
});
96105
});

frontend/packages/console-shared/src/components/catalog/utils/types.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
CatalogItemAttribute,
44
CatalogItemType,
55
} from '@console/dynamic-plugin-sdk/src/extensions';
6-
import { ResolvedExtension } from '@console/dynamic-plugin-sdk/src/types';
6+
import {
7+
ResolvedCodeRefProperties,
8+
ResolvedExtension,
9+
} from '@console/dynamic-plugin-sdk/src/types';
710

811
export enum CatalogQueryParams {
912
TYPE = 'catalogType',
@@ -35,7 +38,9 @@ export type CatalogTypeCounts = Record<string, number>;
3538

3639
export type CatalogStringMap = Record<string, string>;
3740

38-
export type CatalogFilterGroupMap = { [key: string]: CatalogItemAttribute };
41+
export type CatalogFilterGroupMap = {
42+
[key: string]: ResolvedCodeRefProperties<CatalogItemAttribute>;
43+
};
3944

4045
export type CatalogType = {
4146
label: string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Tooltip } from '@patternfly/react-core';
2+
import { GlobeAmericasIcon } from '@patternfly/react-icons/dist/esm/icons/globe-americas-icon';
3+
import classNames from 'classnames';
4+
import { useSelector } from 'react-redux';
5+
import { getLastLanguage } from '@console/app/src/components/user-preferences/language/getLastLanguage';
6+
import { TimestampProps } from '@console/dynamic-plugin-sdk';
7+
import { RootState } from '@console/internal/redux';
8+
import * as dateTime from '../../utils/datetime';
9+
10+
const Timestamp = (props: TimestampProps) => {
11+
const now = useSelector<RootState, string>(({ UI }) => UI.get('lastTick'));
12+
13+
// Workaround for Date&Time values are not showing in supported languages onchange of language selector.
14+
const lang = getLastLanguage();
15+
16+
// Check for null. If props.timestamp is null, it returns incorrect date and time of Wed Dec 31 1969 19:00:00 GMT-0500 (Eastern Standard Time)
17+
if (!props.timestamp) {
18+
return <div className="co-timestamp">-</div>;
19+
}
20+
21+
const mdate = new Date(props.timestamp);
22+
23+
const timestamp = dateTime.timestampFor(mdate, new Date(now), props.omitSuffix, lang);
24+
25+
if (!dateTime.isValid(mdate)) {
26+
return <div className="co-timestamp">-</div>;
27+
}
28+
29+
if (props.simple) {
30+
return <>{timestamp}</>;
31+
}
32+
33+
return (
34+
<div className={classNames('co-timestamp co-icon-and-text', props.className)}>
35+
<GlobeAmericasIcon className="co-icon-and-text__icon" />
36+
<Tooltip
37+
content={[
38+
<span className="co-nowrap" key="co-timestamp">
39+
{dateTime.utcDateTimeFormatter.format(mdate)}
40+
</span>,
41+
]}
42+
>
43+
<span data-test="timestamp">{timestamp}</span>
44+
</Tooltip>
45+
</div>
46+
);
47+
};
48+
49+
export default Timestamp;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as Timestamp } from './Timestamp';

frontend/packages/console-shared/src/components/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ export * from './quick-search';
3030
export * from './namespace';
3131
export * from './catalog';
3232
export * from './progressive-list';
33+
export * from './links';
34+
export * from './datetime';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from 'react';
2+
import * as cx from 'classnames';
3+
4+
const ExternalLink: React.FC<ExternalLinkProps> = ({
5+
children,
6+
href,
7+
text,
8+
additionalClassName = '',
9+
dataTestID,
10+
stopPropagation,
11+
...props
12+
}) => (
13+
<a
14+
{...props}
15+
className={cx('co-external-link', additionalClassName, props?.className)}
16+
href={href}
17+
target="_blank"
18+
rel="noopener noreferrer"
19+
data-test-id={dataTestID}
20+
{...(stopPropagation ? { onClick: (e) => e.stopPropagation() } : {})}
21+
>
22+
{children || text}
23+
</a>
24+
);
25+
26+
type ExternalLinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
27+
href: string;
28+
text?: React.ReactNode;
29+
additionalClassName?: string;
30+
dataTestID?: string;
31+
stopPropagation?: boolean;
32+
};
33+
34+
export default ExternalLink;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as ExternalLink } from './ExternalLink';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as React from 'react';
2+
import { List, ListItem } from '@patternfly/react-core';
3+
4+
const PlainList: React.FCC<PlainListProps> = ({ items }) =>
5+
items ? (
6+
<List isPlain>
7+
{items.map((i) => (
8+
<ListItem key={i}>{i}</ListItem>
9+
))}
10+
</List>
11+
) : null;
12+
13+
type PlainListProps = {
14+
items: string[];
15+
};
16+
17+
export default PlainList;
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as DetailPropertyList } from './DetailPropertyList';
22
export { default as DetailPropertyListItem } from './DetailPropertyListItem';
3+
export { default as PlainList } from './PlainList';

0 commit comments

Comments
 (0)