From eee775a50d45f50d20371d4e327dc0d4d0757780 Mon Sep 17 00:00:00 2001 From: Hubert Date: Wed, 19 Mar 2025 09:12:06 +0100 Subject: [PATCH 1/4] Base base before rebase --- public/locales/en.json | 11 ++ src/components/ControlPlane/Providers.tsx | 102 ++++++++++++++++++ .../ControlPlane/ProvidersConfig.tsx | 39 +++++++ src/components/ControlPlane/ProvidersList.tsx | 47 +------- src/lib/api/types/crossplane/listProviders.ts | 23 +++- 5 files changed, 174 insertions(+), 48 deletions(-) create mode 100644 src/components/ControlPlane/Providers.tsx create mode 100644 src/components/ControlPlane/ProvidersConfig.tsx diff --git a/public/locales/en.json b/public/locales/en.json index 1c24f1b6..69466187 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -143,5 +143,16 @@ }, "main": { "failedMessage": "Failed to load frontend configuration" + }, + "Providers": { + "headerProviders": "Providers", + "tableHeaderVersion": "Version", + "tableHeaderName": "Name", + "tableHeaderCreated": "Created", + "tableHeaderInstalled": "Installed", + "tableHeaderHealthy": "Healthy" + }, + "ProvidersConfig": { + "headerProvidersConfig": "Providers Config" } } \ No newline at end of file diff --git a/src/components/ControlPlane/Providers.tsx b/src/components/ControlPlane/Providers.tsx new file mode 100644 index 00000000..95c33f20 --- /dev/null +++ b/src/components/ControlPlane/Providers.tsx @@ -0,0 +1,102 @@ + +import { useTranslation } from 'react-i18next'; +import { AnalyticalTable, AnalyticalTableColumnDefinition, AnalyticalTableScaleWidthMode, Icon, Title } from '@ui5/webcomponents-react'; +import useResource from '../../lib/api/useApiResource'; +import IllustratedError from '../Shared/IllustratedError'; +import '@ui5/webcomponents-icons/dist/sys-enter-2'; +import '@ui5/webcomponents-icons/dist/sys-cancel-2'; +import { ProvidersListRequest } from '../../lib/api/types/crossplane/listProviders'; +import ReactTimeAgo from 'react-time-ago'; + +interface CellData { + cell: { + value: T | null; + }; + } + +export function Providers() { + const { t } = useTranslation(); + + let {data: providers, error, isLoading} = useResource(ProvidersListRequest, { + refreshInterval: 300000 + }); + + const columns: AnalyticalTableColumnDefinition[] = [ + { + Header: t('Providers.tableHeaderName'), + accessor: 'metadata.name', + }, + { + Header: t('Providers.tableHeaderVersion'), + accessor: 'spec.package', + Cell: (cellData: CellData) => cellData.cell.value?.match(/\d+(\.\d+)+/) + }, + { + Header: t('Providers.tableHeaderInstalled'), + accessor: 'status.conditions[1].status', + Cell: (cellData: CellData) => + }, + //last.transitiontime on hover + { + Header: t('Providers.tableHeaderHealthy'), + accessor: 'status.conditions[0].status', + Cell: (cellData: CellData) => + }, + { + Header: t('Providers.tableHeaderCreated'), + accessor: 'metadata.creationTimestamp', + Cell: (props: any) => , + }, + ]; + + return ( + <> + {t('Providers.headerProviders')} + + {error && } + + {!error && + + } + + ) +} + +interface ResourceStatusCellProps { + cellData: CellData; + } + +function ResourceStatusCell({ cellData }: ResourceStatusCellProps) { + const { t } = useTranslation(); + + if (cellData.cell.value === null) { + return null; + } + + return + } diff --git a/src/components/ControlPlane/ProvidersConfig.tsx b/src/components/ControlPlane/ProvidersConfig.tsx new file mode 100644 index 00000000..5f86181a --- /dev/null +++ b/src/components/ControlPlane/ProvidersConfig.tsx @@ -0,0 +1,39 @@ + +import { useTranslation } from 'react-i18next'; +import { AnalyticalTable, AnalyticalTableColumnDefinition, AnalyticalTableScaleWidthMode, Title } from '@ui5/webcomponents-react'; +import '@ui5/webcomponents-icons/dist/sys-enter-2'; +import '@ui5/webcomponents-icons/dist/sys-cancel-2'; + +export function ProvidersConfig() { + const { t } = useTranslation(); + + const columns: AnalyticalTableColumnDefinition[] = []; + + return ( + <> + {t('ProvidersConfig.headerProvidersConfig')} + + + ) +} diff --git a/src/components/ControlPlane/ProvidersList.tsx b/src/components/ControlPlane/ProvidersList.tsx index 95dd16bf..5d00613f 100644 --- a/src/components/ControlPlane/ProvidersList.tsx +++ b/src/components/ControlPlane/ProvidersList.tsx @@ -1,51 +1,12 @@ -import ConfiguredAnalyticstable from '../Shared/ConfiguredAnalyticsTable.tsx'; -import { - AnalyticalTableColumnDefinition, - Title, -} from '@ui5/webcomponents-react'; -import ReactTimeAgo from 'react-time-ago'; -import IllustratedError from '../Shared/IllustratedError.tsx'; -import useResource from '../../lib/api/useApiResource'; -import { ListProviders } from '../../lib/api/types/crossplane/listProviders'; -import { useTranslation } from 'react-i18next'; +import { Providers } from "./Providers.tsx"; +import { ProvidersConfig } from "./ProvidersConfig.tsx"; import { ManagedResources } from './ManagedResources'; export default function ProvidersList() { - const { data, error, isLoading } = useResource(ListProviders); - const { t } = useTranslation(); - - if (error) { - return ; - } - - const columns: AnalyticalTableColumnDefinition[] = [ - { - Header: t('ProvidersList.tableNameHeader'), - accessor: 'metadata.name', - }, - { - Header: t('ProvidersList.tableStatusHeader'), - accessor: 'status.phase', - }, - { - Header: t('ProvidersList.tableCreatedHeader'), - accessor: 'metadata.creationTimestamp', - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Cell: (props: any) => , - }, - ]; - return ( <> - Providers - - ProviderConfigs - - + + ); diff --git a/src/lib/api/types/crossplane/listProviders.ts b/src/lib/api/types/crossplane/listProviders.ts index 36571c28..2efde330 100644 --- a/src/lib/api/types/crossplane/listProviders.ts +++ b/src/lib/api/types/crossplane/listProviders.ts @@ -1,7 +1,20 @@ import { Resource } from '../resource'; -//TODO: type any to correct type and adapt the jq query to the required paramters -export const ListProviders: Resource = { - path: '/apis/pkg.crossplane.io/v1/providers', - jq: '[.items[]]', -}; + export type ProvidersListResponse = { + items: [{ + kind: string; + metadata: { + name: string; + creationTimestamp: string; + }; + status: { + conditions: [{ + type: "Ready" | "Synced" | unknown; + }] + }; + }]; + }; + + export const ProvidersListRequest: Resource = { + path: "/apis/pkg.crossplane.io/v1/providers", + }; \ No newline at end of file From a2405b768f7a7bfec4dc7ccc423dd914d302f12a Mon Sep 17 00:00:00 2001 From: Hubert Date: Wed, 19 Mar 2025 10:22:52 +0100 Subject: [PATCH 2/4] after rebase Adjusting to resources approach + adding transition time --- .../ControlPlane/ManagedResources.tsx | 11 +-- src/components/ControlPlane/Providers.tsx | 89 +++++++++++-------- .../ControlPlane/ProvidersConfig.tsx | 1 + src/lib/api/types/crossplane/listProviders.ts | 5 +- src/lib/shared/constants.ts | 1 + src/lib/shared/interfaces.ts | 4 + 6 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 src/lib/shared/constants.ts create mode 100644 src/lib/shared/interfaces.ts diff --git a/src/components/ControlPlane/ManagedResources.tsx b/src/components/ControlPlane/ManagedResources.tsx index ec50f248..c2342f32 100644 --- a/src/components/ControlPlane/ManagedResources.tsx +++ b/src/components/ControlPlane/ManagedResources.tsx @@ -12,6 +12,8 @@ import { timeAgo } from '../../utils/i18n/timeAgo'; import IllustratedError from '../Shared/IllustratedError'; import '@ui5/webcomponents-icons/dist/sys-enter-2'; import '@ui5/webcomponents-icons/dist/sys-cancel-2'; +import { resourcesInterval } from '../../lib/shared/constants'; +import { StatusCellProps } from '../../lib/shared/interfaces'; interface CellData { cell: { @@ -40,7 +42,7 @@ export function ManagedResources() { error, isLoading, } = useResource(ManagedResourcesRequest, { - refreshInterval: 30000, // Resources are quite expensive to fetch, so we refresh every 30 seconds + refreshInterval: resourcesInterval, // Resources are quite expensive to fetch, so we refresh every 30 seconds }); const columns: AnalyticalTableColumnDefinition[] = [ @@ -136,15 +138,10 @@ export function ManagedResources() { ); } -interface ResourceStatusCellProps { - value: boolean; - transitionTime: string; -} - function ResourceStatusCell({ value, transitionTime, -}: ResourceStatusCellProps) { +}: StatusCellProps) { return ( { - cell: { - value: T | null; - }; - } + cell: { + value: T | null; // null for grouping rows + row: { + original?: providersRow; // missing for grouping rows + } + }; +} + +type providersRow = { + name: string + version: string; + healthy: boolean; + healthyTransitionTime: string; + installed: boolean; + installedTransitionTime: string; + created: string; +} export function Providers() { const { t } = useTranslation(); let {data: providers, error, isLoading} = useResource(ProvidersListRequest, { - refreshInterval: 300000 + refreshInterval: resourcesInterval }); const columns: AnalyticalTableColumnDefinition[] = [ { Header: t('Providers.tableHeaderName'), - accessor: 'metadata.name', + accessor: 'name', }, { Header: t('Providers.tableHeaderVersion'), - accessor: 'spec.package', - Cell: (cellData: CellData) => cellData.cell.value?.match(/\d+(\.\d+)+/) + accessor: 'version', }, { Header: t('Providers.tableHeaderInstalled'), - accessor: 'status.conditions[1].status', - Cell: (cellData: CellData) => + accessor: 'installed', + Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null }, - //last.transitiontime on hover { Header: t('Providers.tableHeaderHealthy'), - accessor: 'status.conditions[0].status', - Cell: (cellData: CellData) => + accessor: 'healthy', + Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null }, { Header: t('Providers.tableHeaderCreated'), - accessor: 'metadata.creationTimestamp', - Cell: (props: any) => , + accessor: 'created', }, ]; + const rows: providersRow[] = + providers?.items?.map((item) => { + const installed = item.status.conditions?.find((condition) => condition.type === 'Installed'); + const healhty = item.status.conditions?.find((condition) => condition.type === 'Healthy'); + + return { + name: item.metadata.name, + created: timeAgo.format(new Date(item.metadata.creationTimestamp)), + installed: installed?.status === "True", + installedTransitionTime: installed?.lastTransitionTime ?? "", + healthy: healhty?.status === "True", + healthyTransitionTime: healhty?.lastTransitionTime ?? "", + version: item.spec.package.match(/\d+(\.\d+)+/), + } + }) + ?? []; + return ( <> {t('Providers.headerProviders')} @@ -58,9 +87,8 @@ export function Providers() { {!error && ; - } - -function ResourceStatusCell({ cellData }: ResourceStatusCellProps) { - const { t } = useTranslation(); - - if (cellData.cell.value === null) { - return null; - } - - return - } +function ResourceStatusCell({ value, transitionTime }: StatusCellProps) { + return +} diff --git a/src/components/ControlPlane/ProvidersConfig.tsx b/src/components/ControlPlane/ProvidersConfig.tsx index 5f86181a..4c4dd8de 100644 --- a/src/components/ControlPlane/ProvidersConfig.tsx +++ b/src/components/ControlPlane/ProvidersConfig.tsx @@ -4,6 +4,7 @@ import { AnalyticalTable, AnalyticalTableColumnDefinition, AnalyticalTableScaleW import '@ui5/webcomponents-icons/dist/sys-enter-2'; import '@ui5/webcomponents-icons/dist/sys-cancel-2'; +//empty table TBD export function ProvidersConfig() { const { t } = useTranslation(); diff --git a/src/lib/api/types/crossplane/listProviders.ts b/src/lib/api/types/crossplane/listProviders.ts index 2efde330..8763a517 100644 --- a/src/lib/api/types/crossplane/listProviders.ts +++ b/src/lib/api/types/crossplane/listProviders.ts @@ -2,6 +2,7 @@ import { Resource } from '../resource'; export type ProvidersListResponse = { items: [{ + spec: any; kind: string; metadata: { name: string; @@ -9,7 +10,9 @@ import { Resource } from '../resource'; }; status: { conditions: [{ - type: "Ready" | "Synced" | unknown; + type: "Healthy" | "Installed" | unknown; + status: "True" | "False"; + lastTransitionTime: string; }] }; }]; diff --git a/src/lib/shared/constants.ts b/src/lib/shared/constants.ts new file mode 100644 index 00000000..8465326c --- /dev/null +++ b/src/lib/shared/constants.ts @@ -0,0 +1 @@ +export const resourcesInterval = 30000; diff --git a/src/lib/shared/interfaces.ts b/src/lib/shared/interfaces.ts new file mode 100644 index 00000000..5493b25d --- /dev/null +++ b/src/lib/shared/interfaces.ts @@ -0,0 +1,4 @@ +export interface StatusCellProps { + value: boolean; + transitionTime: string; +} \ No newline at end of file From 363fdbadd7bab5f3aaf215f8ed04ad5f24dfaa1f Mon Sep 17 00:00:00 2001 From: Hubert Date: Wed, 19 Mar 2025 10:28:39 +0100 Subject: [PATCH 3/4] regex fix regex fix --- src/components/ControlPlane/Providers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ControlPlane/Providers.tsx b/src/components/ControlPlane/Providers.tsx index 818f9ee9..3996b10a 100644 --- a/src/components/ControlPlane/Providers.tsx +++ b/src/components/ControlPlane/Providers.tsx @@ -73,7 +73,7 @@ export function Providers() { installedTransitionTime: installed?.lastTransitionTime ?? "", healthy: healhty?.status === "True", healthyTransitionTime: healhty?.lastTransitionTime ?? "", - version: item.spec.package.match(/\d+(\.\d+)+/), + version: item.spec.package.match(/\d+(\.\d+)+/g), } }) ?? []; From 3e24e72de0b726e88ea7207391cfcee6eb7e1307 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 20 Mar 2025 10:00:32 +0100 Subject: [PATCH 4/4] PR changes review changes --- src/components/ControlPlane/Providers.tsx | 18 +++++++++--------- src/lib/api/types/crossplane/listProviders.ts | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/components/ControlPlane/Providers.tsx b/src/components/ControlPlane/Providers.tsx index 3996b10a..92ad9287 100644 --- a/src/components/ControlPlane/Providers.tsx +++ b/src/components/ControlPlane/Providers.tsx @@ -14,12 +14,12 @@ interface CellData { cell: { value: T | null; // null for grouping rows row: { - original?: providersRow; // missing for grouping rows + original?: ProvidersRow; // missing for grouping rows } }; } -type providersRow = { +type ProvidersRow = { name: string version: string; healthy: boolean; @@ -48,12 +48,12 @@ export function Providers() { { Header: t('Providers.tableHeaderInstalled'), accessor: 'installed', - Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null + Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null }, { Header: t('Providers.tableHeaderHealthy'), accessor: 'healthy', - Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null + Cell: (cellData: CellData) => cellData.cell.row.original?.installed != null ? : null }, { Header: t('Providers.tableHeaderCreated'), @@ -61,19 +61,19 @@ export function Providers() { }, ]; - const rows: providersRow[] = + const rows: ProvidersRow[] = providers?.items?.map((item) => { const installed = item.status.conditions?.find((condition) => condition.type === 'Installed'); - const healhty = item.status.conditions?.find((condition) => condition.type === 'Healthy'); + const healthy = item.status.conditions?.find((condition) => condition.type === 'Healthy'); return { name: item.metadata.name, created: timeAgo.format(new Date(item.metadata.creationTimestamp)), installed: installed?.status === "True", installedTransitionTime: installed?.lastTransitionTime ?? "", - healthy: healhty?.status === "True", - healthyTransitionTime: healhty?.lastTransitionTime ?? "", - version: item.spec.package.match(/\d+(\.\d+)+/g), + healthy: healthy?.status === "True", + healthyTransitionTime: healthy?.lastTransitionTime ?? "", + version: item.spec.package.match(/\d+(\.\d+)+/g)?.toString() ?? "", } }) ?? []; diff --git a/src/lib/api/types/crossplane/listProviders.ts b/src/lib/api/types/crossplane/listProviders.ts index 8763a517..ffd92c4b 100644 --- a/src/lib/api/types/crossplane/listProviders.ts +++ b/src/lib/api/types/crossplane/listProviders.ts @@ -2,7 +2,9 @@ import { Resource } from '../resource'; export type ProvidersListResponse = { items: [{ - spec: any; + spec: { + package: string; + }; kind: string; metadata: { name: string;