Skip to content

Commit fcaf193

Browse files
Origin/feature/new providers table (#6)
1 parent 42cd41d commit fcaf193

File tree

8 files changed

+208
-55
lines changed

8 files changed

+208
-55
lines changed

public/locales/en.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,16 @@
143143
},
144144
"main": {
145145
"failedMessage": "Failed to load frontend configuration"
146+
},
147+
"Providers": {
148+
"headerProviders": "Providers",
149+
"tableHeaderVersion": "Version",
150+
"tableHeaderName": "Name",
151+
"tableHeaderCreated": "Created",
152+
"tableHeaderInstalled": "Installed",
153+
"tableHeaderHealthy": "Healthy"
154+
},
155+
"ProvidersConfig": {
156+
"headerProvidersConfig": "Providers Config"
146157
}
147158
}

src/components/ControlPlane/ManagedResources.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { timeAgo } from '../../utils/i18n/timeAgo';
1212
import IllustratedError from '../Shared/IllustratedError';
1313
import '@ui5/webcomponents-icons/dist/sys-enter-2';
1414
import '@ui5/webcomponents-icons/dist/sys-cancel-2';
15+
import { resourcesInterval } from '../../lib/shared/constants';
16+
import { StatusCellProps } from '../../lib/shared/interfaces';
1517

1618
interface CellData<T> {
1719
cell: {
@@ -40,7 +42,7 @@ export function ManagedResources() {
4042
error,
4143
isLoading,
4244
} = useResource(ManagedResourcesRequest, {
43-
refreshInterval: 30000, // Resources are quite expensive to fetch, so we refresh every 30 seconds
45+
refreshInterval: resourcesInterval, // Resources are quite expensive to fetch, so we refresh every 30 seconds
4446
});
4547

4648
const columns: AnalyticalTableColumnDefinition[] = [
@@ -136,15 +138,10 @@ export function ManagedResources() {
136138
);
137139
}
138140

139-
interface ResourceStatusCellProps {
140-
value: boolean;
141-
transitionTime: string;
142-
}
143-
144141
function ResourceStatusCell({
145142
value,
146143
transitionTime,
147-
}: ResourceStatusCellProps) {
144+
}: StatusCellProps) {
148145
return (
149146
<Icon
150147
design={value ? 'Positive' : 'Negative'}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
2+
import { useTranslation } from 'react-i18next';
3+
import { AnalyticalTable, AnalyticalTableColumnDefinition, AnalyticalTableScaleWidthMode, Icon, Title } from '@ui5/webcomponents-react';
4+
import useResource from '../../lib/api/useApiResource';
5+
import IllustratedError from '../Shared/IllustratedError';
6+
import '@ui5/webcomponents-icons/dist/sys-enter-2';
7+
import '@ui5/webcomponents-icons/dist/sys-cancel-2';
8+
import { ProvidersListRequest } from '../../lib/api/types/crossplane/listProviders';
9+
import { resourcesInterval } from '../../lib/shared/constants';
10+
import { timeAgo } from '../../utils/i18n/timeAgo';
11+
import { StatusCellProps } from '../../lib/shared/interfaces';
12+
13+
interface CellData<T> {
14+
cell: {
15+
value: T | null; // null for grouping rows
16+
row: {
17+
original?: ProvidersRow; // missing for grouping rows
18+
}
19+
};
20+
}
21+
22+
type ProvidersRow = {
23+
name: string
24+
version: string;
25+
healthy: boolean;
26+
healthyTransitionTime: string;
27+
installed: boolean;
28+
installedTransitionTime: string;
29+
created: string;
30+
}
31+
32+
export function Providers() {
33+
const { t } = useTranslation();
34+
35+
let {data: providers, error, isLoading} = useResource(ProvidersListRequest, {
36+
refreshInterval: resourcesInterval
37+
});
38+
39+
const columns: AnalyticalTableColumnDefinition[] = [
40+
{
41+
Header: t('Providers.tableHeaderName'),
42+
accessor: 'name',
43+
},
44+
{
45+
Header: t('Providers.tableHeaderVersion'),
46+
accessor: 'version',
47+
},
48+
{
49+
Header: t('Providers.tableHeaderInstalled'),
50+
accessor: 'installed',
51+
Cell: (cellData: CellData<ProvidersRow['installed']>) => cellData.cell.row.original?.installed != null ? <ResourceStatusCell value={cellData.cell.row.original?.installed} transitionTime={cellData.cell.row.original?.installedTransitionTime} /> : null
52+
},
53+
{
54+
Header: t('Providers.tableHeaderHealthy'),
55+
accessor: 'healthy',
56+
Cell: (cellData: CellData<ProvidersRow['healthy']>) => cellData.cell.row.original?.installed != null ? <ResourceStatusCell value={cellData.cell.row.original?.healthy} transitionTime={cellData.cell.row.original?.healthyTransitionTime} /> : null
57+
},
58+
{
59+
Header: t('Providers.tableHeaderCreated'),
60+
accessor: 'created',
61+
},
62+
];
63+
64+
const rows: ProvidersRow[] =
65+
providers?.items?.map((item) => {
66+
const installed = item.status.conditions?.find((condition) => condition.type === 'Installed');
67+
const healthy = item.status.conditions?.find((condition) => condition.type === 'Healthy');
68+
69+
return {
70+
name: item.metadata.name,
71+
created: timeAgo.format(new Date(item.metadata.creationTimestamp)),
72+
installed: installed?.status === "True",
73+
installedTransitionTime: installed?.lastTransitionTime ?? "",
74+
healthy: healthy?.status === "True",
75+
healthyTransitionTime: healthy?.lastTransitionTime ?? "",
76+
version: item.spec.package.match(/\d+(\.\d+)+/g)?.toString() ?? "",
77+
}
78+
})
79+
?? [];
80+
81+
return (
82+
<>
83+
<Title level='H4'>{t('Providers.headerProviders')}</Title>
84+
85+
{error && <IllustratedError error={error}/>}
86+
87+
{!error &&
88+
<AnalyticalTable
89+
columns={columns}
90+
data={rows}
91+
minRows={1}
92+
scaleWidthMode={AnalyticalTableScaleWidthMode.Smart}
93+
loading={isLoading}
94+
filterable
95+
// Prevent the table from resetting when the data changes
96+
retainColumnWidth
97+
reactTableOptions={{
98+
autoResetHiddenColumns: false,
99+
autoResetPage: false,
100+
autoResetExpanded: false,
101+
autoResetGroupBy: false,
102+
autoResetSelectedRows: false,
103+
autoResetSortBy: false,
104+
autoResetFilters: false,
105+
autoResetRowState: false,
106+
autoResetResize: false
107+
}}
108+
/>
109+
}
110+
</>
111+
)
112+
}
113+
114+
function ResourceStatusCell({ value, transitionTime }: StatusCellProps) {
115+
return <Icon
116+
design={value ? 'Positive' : 'Negative'}
117+
name={value ? 'sys-enter-2' : 'sys-cancel-2'}
118+
showTooltip={true}
119+
accessibleName={timeAgo.format(new Date(transitionTime))}
120+
/>
121+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
import { useTranslation } from 'react-i18next';
3+
import { AnalyticalTable, AnalyticalTableColumnDefinition, AnalyticalTableScaleWidthMode, Title } from '@ui5/webcomponents-react';
4+
import '@ui5/webcomponents-icons/dist/sys-enter-2';
5+
import '@ui5/webcomponents-icons/dist/sys-cancel-2';
6+
7+
//empty table TBD
8+
export function ProvidersConfig() {
9+
const { t } = useTranslation();
10+
11+
const columns: AnalyticalTableColumnDefinition[] = [];
12+
13+
return (
14+
<>
15+
<Title level='H4'>{t('ProvidersConfig.headerProvidersConfig')}</Title>
16+
<AnalyticalTable
17+
columns={columns}
18+
data={[]}
19+
minRows={1}
20+
groupBy={['name']}
21+
scaleWidthMode={AnalyticalTableScaleWidthMode.Smart}
22+
loading={false}
23+
filterable
24+
// Prevent the table from resetting when the data changes
25+
retainColumnWidth
26+
reactTableOptions={{
27+
autoResetHiddenColumns: false,
28+
autoResetPage: false,
29+
autoResetExpanded: false,
30+
autoResetGroupBy: false,
31+
autoResetSelectedRows: false,
32+
autoResetSortBy: false,
33+
autoResetFilters: false,
34+
autoResetRowState: false,
35+
autoResetResize: false
36+
}}
37+
/>
38+
</>
39+
)
40+
}

src/components/ControlPlane/ProvidersList.tsx

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,12 @@
1-
import ConfiguredAnalyticstable from '../Shared/ConfiguredAnalyticsTable.tsx';
2-
import {
3-
AnalyticalTableColumnDefinition,
4-
Title,
5-
} from '@ui5/webcomponents-react';
6-
import ReactTimeAgo from 'react-time-ago';
7-
import IllustratedError from '../Shared/IllustratedError.tsx';
8-
import useResource from '../../lib/api/useApiResource';
9-
import { ListProviders } from '../../lib/api/types/crossplane/listProviders';
10-
import { useTranslation } from 'react-i18next';
1+
import { Providers } from "./Providers.tsx";
2+
import { ProvidersConfig } from "./ProvidersConfig.tsx";
113
import { ManagedResources } from './ManagedResources';
124

135
export default function ProvidersList() {
14-
const { data, error, isLoading } = useResource(ListProviders);
15-
const { t } = useTranslation();
16-
17-
if (error) {
18-
return <IllustratedError error={error} />;
19-
}
20-
21-
const columns: AnalyticalTableColumnDefinition[] = [
22-
{
23-
Header: t('ProvidersList.tableNameHeader'),
24-
accessor: 'metadata.name',
25-
},
26-
{
27-
Header: t('ProvidersList.tableStatusHeader'),
28-
accessor: 'status.phase',
29-
},
30-
{
31-
Header: t('ProvidersList.tableCreatedHeader'),
32-
accessor: 'metadata.creationTimestamp',
33-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34-
Cell: (props: any) => <ReactTimeAgo date={new Date(props.cell.value)} />,
35-
},
36-
];
37-
386
return (
397
<>
40-
<Title level="H4">Providers</Title>
41-
<ConfiguredAnalyticstable
42-
columns={columns}
43-
isLoading={isLoading}
44-
data={data ?? []}
45-
/>
46-
<Title level="H2">ProviderConfigs</Title>
47-
<ConfiguredAnalyticstable columns={columns} data={[]} />
48-
8+
<Providers />
9+
<ProvidersConfig />
4910
<ManagedResources />
5011
</>
5112
);
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
import { Resource } from '../resource';
22

3-
//TODO: type any to correct type and adapt the jq query to the required paramters
4-
export const ListProviders: Resource<any> = {
5-
path: '/apis/pkg.crossplane.io/v1/providers',
6-
jq: '[.items[]]',
7-
};
3+
export type ProvidersListResponse = {
4+
items: [{
5+
spec: {
6+
package: string;
7+
};
8+
kind: string;
9+
metadata: {
10+
name: string;
11+
creationTimestamp: string;
12+
};
13+
status: {
14+
conditions: [{
15+
type: "Healthy" | "Installed" | unknown;
16+
status: "True" | "False";
17+
lastTransitionTime: string;
18+
}]
19+
};
20+
}];
21+
};
22+
23+
export const ProvidersListRequest: Resource<ProvidersListResponse> = {
24+
path: "/apis/pkg.crossplane.io/v1/providers",
25+
};

src/lib/shared/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const resourcesInterval = 30000;

src/lib/shared/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface StatusCellProps {
2+
value: boolean;
3+
transitionTime: string;
4+
}

0 commit comments

Comments
 (0)