Skip to content

Commit 24f0413

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/kubectl-command-helper-dialogs
2 parents e548ffe + a1cb565 commit 24f0413

File tree

15 files changed

+204
-1147
lines changed

15 files changed

+204
-1147
lines changed

package-lock.json

Lines changed: 42 additions & 1030 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"testE2E:open": "cypress open --e2e --browser chrome"
1818
},
1919
"dependencies": {
20-
"@dagrejs/dagre": "^1.1.4",
2120
"@hookform/resolvers": "^4.1.3",
2221
"@ui5/webcomponents": "^2.7.2",
2322
"@ui5/webcomponents-fiori": "^2.7.2",
@@ -27,25 +26,22 @@
2726
"i18next": "^24.2.2",
2827
"javascript-time-ago": "^2.5.11",
2928
"js-yaml": "^4.1.0",
30-
"json-to-pretty-yaml": "^1.2.2",
3129
"oidc-client-ts": "^3.1.0",
3230
"react": "19.0.0",
33-
"react-code-blocks": "^0.1.6",
3431
"react-dom": "19.0.0",
32+
"react-error-boundary": "^5.0.0",
3533
"react-hook-form": "^7.54.2",
3634
"react-i18next": "^15.4.1",
3735
"react-oidc-context": "^3.2.0",
3836
"react-router-dom": "^7.2.0",
3937
"react-time-ago": "^7.3.3",
40-
"reactflow": "^11.11.4",
4138
"swr": "^2.3.0",
4239
"zod": "^3.24.2"
4340
},
4441
"devDependencies": {
4542
"@eslint/eslintrc": "^3.3.0",
4643
"@eslint/js": "^9.22.0",
4744
"@types/js-yaml": "^4.0.9",
48-
"@types/json-to-pretty-yaml": "^1.2.1",
4945
"@types/node": "^22.13.5",
5046
"@types/react": "^19.0.10",
5147
"@types/react-dom": "19.0.4",
@@ -67,6 +63,6 @@
6763
"sass-embedded": "^1.86.0",
6864
"typescript": "^5.7.3",
6965
"typescript-eslint": "^8.26.1",
70-
"vite": "^6.2.3"
66+
"vite": "^6.2.4"
7167
}
7268
}

public/locales/en.json

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"signInButton": "Sign in"
77
},
88
"ComponentList": {
9-
"tableComponentHeader": "Component",
9+
"tableComponentHeader": "Name",
1010
"tableVersionHeader": "Version"
1111
},
1212
"FluxList": {
@@ -20,7 +20,7 @@
2020
"tableCreatedHeader": "Created"
2121
},
2222
"ManagedResources": {
23-
"headerManagedResources": "Resources",
23+
"header": "Managed Resources",
2424
"tableHeaderKind": "Kind",
2525
"tableHeaderName": "Name",
2626
"tableHeaderCreated": "Created",
@@ -118,18 +118,19 @@
118118
"EditMembers": {
119119
"addButton": "Add"
120120
},
121-
"FrontendConfigContext": {
122-
"errorMessage": "useFrontendConfig must be used within a FrontendConfigProvider"
123-
},
124121
"ControlPlaneListView": {
122+
"header": "Your instances of <span>ManagedControlPlane</span>",
125123
"projectHeader": "Project:"
126124
},
127125
"ProjectsListView": {
128126
"pageTitle": "Let's get started",
129127
"title": "Projects"
130128
},
131129
"ControlPlaneView": {
132-
"accessError": "Managed Control Plane does not have access information yet"
130+
"accessError": "Managed Control Plane does not have access information yet",
131+
"componentsTitle": "Components",
132+
"crossplaneTitle": "Crossplane",
133+
"gitOpsTitle": "GitOps"
133134
},
134135
"ToastContext": {
135136
"errorMessage": "useToast must be used within a ToastProvider"
@@ -141,9 +142,6 @@
141142
"App": {
142143
"loading": "Loading..."
143144
},
144-
"main": {
145-
"failedMessage": "Failed to load frontend configuration"
146-
},
147145
"Providers": {
148146
"headerProviders": "Providers",
149147
"tableHeaderVersion": "Version",
@@ -153,7 +151,7 @@
153151
"tableHeaderHealthy": "Healthy"
154152
},
155153
"ProvidersConfig": {
156-
"headerProvidersConfig": "Providers Config"
154+
"header": "Provider Configs"
157155
},
158156
"validationErrors": {
159157
"required": "This field is required!",

renovate.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
3+
"extends": [
4+
"config:recommended"
5+
]
6+
}

src/components/ControlPlane/ComponentList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export default function ComponentList({ mcp }: { mcp: ControlPlaneType }) {
4949
columns={componentTableColumns}
5050
minRows={0}
5151
data={data}
52+
style={{marginLeft: "12px", marginRight: "12px"}}
5253
/>
5354
</div>
5455
);

src/components/ControlPlane/ManagedResources.tsx

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,35 +83,38 @@ export function ManagedResources() {
8383
];
8484

8585
const rows: ResourceRow[] =
86-
managedResources?.flatMap((managedResource) =>
87-
managedResource.items?.map((item) => {
88-
const conditionSynced = item.status.conditions?.find(
89-
(condition) => condition.type === 'Synced',
90-
);
91-
const conditionReady = item.status.conditions?.find(
92-
(condition) => condition.type === 'Ready',
93-
);
86+
managedResources
87+
?.filter((managedResource) => managedResource.items)
88+
.flatMap((managedResource) =>
89+
managedResource.items?.map((item) => {
90+
const conditionSynced = item.status.conditions?.find(
91+
(condition) => condition.type === 'Synced',
92+
);
93+
const conditionReady = item.status.conditions?.find(
94+
(condition) => condition.type === 'Ready',
95+
);
9496

95-
return {
96-
kind: item.kind,
97-
name: item.metadata.name,
98-
created: timeAgo.format(new Date(item.metadata.creationTimestamp)),
99-
synced: conditionSynced?.status === 'True',
100-
syncedTransitionTime: conditionSynced?.lastTransitionTime ?? '',
101-
ready: conditionReady?.status === 'True',
102-
readyTransitionTime: conditionReady?.lastTransitionTime ?? '',
103-
};
104-
}),
105-
) ?? [];
97+
return {
98+
kind: item.kind,
99+
name: item.metadata.name,
100+
created: timeAgo.format(new Date(item.metadata.creationTimestamp)),
101+
synced: conditionSynced?.status === 'True',
102+
syncedTransitionTime: conditionSynced?.lastTransitionTime ?? '',
103+
ready: conditionReady?.status === 'True',
104+
readyTransitionTime: conditionReady?.lastTransitionTime ?? '',
105+
};
106+
}),
107+
) ?? [];
106108

107109
return (
108110
<>
109-
<Title level="H4">{t('ManagedResources.headerManagedResources')}</Title>
111+
<Title level="H4">{t('ManagedResources.header')}</Title>
110112

111113
{error && <IllustratedError error={error} />}
112114

113115
{!error && (
114116
<AnalyticalTable
117+
style={{ margin: '12px' }}
115118
columns={columns}
116119
data={rows}
117120
minRows={1}
@@ -138,10 +141,7 @@ export function ManagedResources() {
138141
);
139142
}
140143

141-
function ResourceStatusCell({
142-
value,
143-
transitionTime,
144-
}: StatusCellProps) {
144+
function ResourceStatusCell({ value, transitionTime }: StatusCellProps) {
145145
return (
146146
<Icon
147147
design={value ? 'Positive' : 'Negative'}

src/components/ControlPlane/ProvidersConfig.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function ProvidersConfig() {
1212

1313
return (
1414
<>
15-
<Title level='H4'>{t('ProvidersConfig.headerProvidersConfig')}</Title>
15+
<Title level='H4'>{t('ProvidersConfig.header')}</Title>
1616
<AnalyticalTable
1717
columns={columns}
1818
data={[]}

src/components/Shared/ConfiguredAnalyticsTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default function ConfiguredAnalyticsTable(props: Props) {
2323
scaleWidthMode={AnalyticalTableScaleWidthMode.Smart}
2424
loading={props.isLoading}
2525
filterable
26+
style={{margin: "12px"}}
2627
/>
2728
);
2829
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ReactNode, use } from 'react';
2+
import { AuthProvider, AuthProviderProps } from 'react-oidc-context';
3+
import { useFrontendConfig } from './FrontendConfigContext.tsx';
4+
import { LoadCrateKubeConfig } from '../lib/oidc/crate.ts';
5+
6+
interface AuthProviderOnboardingProps {
7+
children?: ReactNode;
8+
}
9+
10+
// Promise needs to be cached
11+
// https://react.dev/blog/2024/12/05/react-19#use-does-not-support-promises-created-in-render
12+
const fetchAuthPromiseCache = new Map<string, Promise<AuthProviderProps>>();
13+
14+
export function AuthProviderOnboarding({
15+
children,
16+
}: AuthProviderOnboardingProps) {
17+
const { backendUrl } = useFrontendConfig();
18+
19+
const fetchAuthConfigPromise =
20+
fetchAuthPromiseCache.get(backendUrl) ?? LoadCrateKubeConfig(backendUrl);
21+
fetchAuthPromiseCache.set(backendUrl, fetchAuthConfigPromise);
22+
23+
const authConfig = use(fetchAuthConfigPromise);
24+
25+
return <AuthProvider {...authConfig}>{children}</AuthProvider>;
26+
}
Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { FC, ReactNode, createContext, useContext } from 'react';
1+
import { ReactNode, createContext, use } from 'react';
22
import { DocLinkCreator } from '../lib/shared/links';
3-
import { useTranslation } from 'react-i18next';
43

54
export enum Landscape {
65
Live = 'LIVE',
@@ -9,49 +8,47 @@ export enum Landscape {
98
Development = 'DEV',
109
}
1110

12-
export interface FrontendConfig {
11+
interface FrontendConfigContextProps {
1312
backendUrl: string;
1413
landscape?: Landscape;
1514
documentationBaseUrl: string;
16-
}
17-
18-
export interface FrontendConfigProviderProps extends FrontendConfig {
1915
links: DocLinkCreator;
2016
}
2117

22-
const FrontendConfigContext = createContext<FrontendConfigProviderProps | null>(
18+
const FrontendConfigContext = createContext<FrontendConfigContextProps | null>(
2319
null,
2420
);
2521

26-
export const useFrontendConfig = () => {
27-
const c = useContext(FrontendConfigContext);
28-
const { t } = useTranslation();
29-
30-
if (!c) {
31-
throw new Error(t('FrontendConfigContext.errorMessage'));
32-
}
33-
return c;
34-
};
22+
const fetchPromise = fetch('/frontend-config.json').then((res) => res.json());
3523

36-
export const FrontendConfigProvider: FC<{
24+
interface FrontendConfigProviderProps {
3725
children: ReactNode;
38-
config: FrontendConfig;
39-
}> = ({ children, config }) => {
26+
}
27+
28+
export function FrontendConfigProvider({
29+
children,
30+
}: FrontendConfigProviderProps) {
31+
const config = use(fetchPromise);
4032
const docLinks = new DocLinkCreator(config.documentationBaseUrl);
33+
const value: FrontendConfigContextProps = {
34+
links: docLinks,
35+
backendUrl: config.backendUrl,
36+
landscape: config.landscape,
37+
documentationBaseUrl: config.documentationBaseUrl,
38+
};
39+
4140
return (
42-
<FrontendConfigContext.Provider
43-
value={{
44-
links: docLinks,
45-
backendUrl: config.backendUrl,
46-
landscape: config.landscape,
47-
documentationBaseUrl: config.documentationBaseUrl,
48-
}}
49-
>
50-
{children}
51-
</FrontendConfigContext.Provider>
41+
<FrontendConfigContext value={value}>{children}</FrontendConfigContext>
5242
);
53-
};
54-
55-
export async function LoadFrontendConfig(): Promise<FrontendConfig> {
56-
return fetch('/frontend-config.json').then((res) => res.json());
5743
}
44+
45+
export const useFrontendConfig = () => {
46+
const context = use(FrontendConfigContext);
47+
48+
if (!context) {
49+
throw new Error(
50+
'useFrontendConfig must be used within a FrontendConfigProvider.',
51+
);
52+
}
53+
return context;
54+
};

0 commit comments

Comments
 (0)