From 39c1a09706f3903cd66c558fc0ec97c5b9ebb204 Mon Sep 17 00:00:00 2001 From: fabianwolski Date: Tue, 29 Apr 2025 15:42:00 +0100 Subject: [PATCH 1/5] DocumentationUrl ONLY implementation --- src/context/FrontendConfigContext.tsx | 26 +++++++----------- src/lib/shared/links.ts | 39 ++++++++++++--------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/context/FrontendConfigContext.tsx b/src/context/FrontendConfigContext.tsx index 3005076f..f12a9c94 100644 --- a/src/context/FrontendConfigContext.tsx +++ b/src/context/FrontendConfigContext.tsx @@ -1,5 +1,4 @@ import { ReactNode, createContext, use } from 'react'; -import { DocLinkCreator } from '../lib/shared/links'; import { z } from 'zod'; export enum Landscape { @@ -10,16 +9,11 @@ export enum Landscape { Local = 'LOCAL', } +export const FrontendConfigContext = createContext(null); - -interface FrontendConfigContextType extends FrontendConfig { - links: DocLinkCreator; -} - -export const FrontendConfigContext = - createContext(null); - -const fetchPromise = fetch('/frontend-config.json').then((res) => res.json()).then((data) => validateAndCastFrontendConfig(data)); +const fetchPromise = fetch('/frontend-config.json') + .then((res) => res.json()) + .then((data) => validateAndCastFrontendConfig(data)); interface FrontendConfigProviderProps { children: ReactNode; @@ -29,13 +23,11 @@ export function FrontendConfigProvider({ children, }: FrontendConfigProviderProps) { const config = use(fetchPromise); - const docLinks = new DocLinkCreator(config.documentationBaseUrl); - const value: FrontendConfigContextType = { - links: docLinks, - ...config, - }; + return ( - {children} + + {children} + ); } @@ -72,4 +64,4 @@ function validateAndCastFrontendConfig(config: unknown): FrontendConfig { } catch (error) { throw new Error(`Invalid frontend config: ${error}`); } -} \ No newline at end of file +} diff --git a/src/lib/shared/links.ts b/src/lib/shared/links.ts index ac0c39b0..6e36b15a 100644 --- a/src/lib/shared/links.ts +++ b/src/lib/shared/links.ts @@ -1,29 +1,24 @@ -export class DocLinkCreator { - private baseUrl: string; +import { useFrontendConfig } from '../../context/FrontendConfigContext'; - constructor(baseUrl: string) { - this.baseUrl = baseUrl; - } - private createLink(path: string) { - return `${this.baseUrl}${path}`; - } +export function useLink() { + const { documentationBaseUrl } = useFrontendConfig(); - public get COMMUNITY_PAGE(): string { - return this.createLink('/'); + if (!documentationBaseUrl) { + throw new Error('useLink must be used within a FrontendConfigProvider'); } - public get COM_PAGE_GETTING_STARTED(): string { - return this.createLink( + + const createLink = (path: string) => `${documentationBaseUrl}${path}`; + + return { + documentationHomepage: createLink('/'), + gettingStartedGuide: createLink( '/docs/managed-control-planes/get-started/get-started-mcp', - ); - } - public get COM_PAGE_GETTING_STARTED_WORKSPACE(): string { - return this.createLink( + ), + workspaceCreationGuide: createLink( '/docs/managed-control-planes/get-started/get-started-mcp#4-create-workspace', - ); - } - public get COM_PAGE_GETTING_STARTED_MCP(): string { - return this.createLink( + ), + mcpCreationGuide: createLink( '/docs/managed-control-planes/get-started/get-started-mcp#5-create-managedcontrolplane', - ); - } + ), + }; } From 98febf082160dce85d77d172bfa72ae1735ef191 Mon Sep 17 00:00:00 2001 From: fabianwolski Date: Fri, 2 May 2025 18:02:33 +0100 Subject: [PATCH 2/5] Full DocLinkCreator class rework - useLink Hook --- src/context/FrontendConfigContext.tsx | 8 ++------ src/lib/shared/links.ts | 7 ++++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/context/FrontendConfigContext.tsx b/src/context/FrontendConfigContext.tsx index 87756c24..3baea10b 100644 --- a/src/context/FrontendConfigContext.tsx +++ b/src/context/FrontendConfigContext.tsx @@ -9,12 +9,7 @@ export enum Landscape { Local = 'LOCAL', } -interface FrontendConfigContextType extends FrontendConfig { - links: DocLinkCreator; -} - -export const FrontendConfigContext = - createContext(null); +export const FrontendConfigContext = createContext(null); const fetchPromise = fetch('/frontend-config.json') .then((res) => res.json()) @@ -58,6 +53,7 @@ const FrontendConfigSchema = z.object({ backendUrl: z.string(), gatewayUrl: z.string(), documentationBaseUrl: z.string(), + githubBaseUrl: z.string(), oidcConfig: OidcConfigSchema, landscape: z.optional(z.nativeEnum(Landscape)), }); diff --git a/src/lib/shared/links.ts b/src/lib/shared/links.ts index 6e36b15a..90957805 100644 --- a/src/lib/shared/links.ts +++ b/src/lib/shared/links.ts @@ -1,13 +1,13 @@ import { useFrontendConfig } from '../../context/FrontendConfigContext'; export function useLink() { - const { documentationBaseUrl } = useFrontendConfig(); + const { documentationBaseUrl, githubBaseUrl } = useFrontendConfig(); - if (!documentationBaseUrl) { + if (!documentationBaseUrl || !githubBaseUrl) { throw new Error('useLink must be used within a FrontendConfigProvider'); } - const createLink = (path: string) => `${documentationBaseUrl}${path}`; + const createGithubLink = (path: string) => `${githubBaseUrl}${path}`; return { documentationHomepage: createLink('/'), @@ -20,5 +20,6 @@ export function useLink() { mcpCreationGuide: createLink( '/docs/managed-control-planes/get-started/get-started-mcp#5-create-managedcontrolplane', ), + githubIssuesSupportTicket: createGithubLink('/support/issues/new'), }; } From ce67582227428f3e94df7c7e5ba59103d923f805 Mon Sep 17 00:00:00 2001 From: fabianwolski Date: Fri, 2 May 2025 18:30:41 +0100 Subject: [PATCH 3/5] Utilizing new useLink hook across components --- .../ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx | 6 +++--- .../List/ControlPlaneListWorkspaceGridTile.tsx | 6 +++--- .../Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx | 9 +++------ src/utils/testing.ts | 7 ++++--- src/views/Login.tsx | 6 +++--- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx b/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx index 268e785b..67bf76da 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx @@ -8,7 +8,7 @@ import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; import { ControlPlaneListWorkspaceGridTile } from './ControlPlaneListWorkspaceGridTile.tsx'; import { useApiResource } from '../../../lib/api/useApiResource.ts'; import { ListWorkspaces } from '../../../lib/api/types/crate/listWorkspaces.ts'; -import { useFrontendConfig } from '../../../context/FrontendConfigContext.tsx'; +import { useLink } from '../../../lib/shared/links.ts'; import { useTranslation } from 'react-i18next'; interface Props { @@ -16,7 +16,7 @@ interface Props { } export default function ControlPlaneListAllWorkspaces({ projectName }: Props) { - const { links } = useFrontendConfig(); + const { workspaceCreationGuide } = useLink(); const { data: allWorkspaces, error } = useApiResource( ListWorkspaces(projectName), ); @@ -45,7 +45,7 @@ export default function ControlPlaneListAllWorkspaces({ projectName }: Props) { design={ButtonDesign.Emphasized} icon="sap-icon://question-mark" onClick={() => { - window.open(links.COM_PAGE_GETTING_STARTED_WORKSPACE, '_blank'); + window.open(workspaceCreationGuide, '_blank'); }} > Help diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 5eee5d0d..93062c3e 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -35,7 +35,7 @@ import { APIError } from '../../../lib/api/error.ts'; import { useTranslation } from 'react-i18next'; import { YamlViewButton } from '../../Yaml/YamlViewButton.tsx'; import { IllustratedBanner } from '../../Ui/IllustratedBanner/IllustratedBanner.tsx'; -import { useFrontendConfig } from '../../../context/FrontendConfigContext.tsx'; +import { useLink } from '../../../lib/shared/links.ts'; import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js'; interface Props { @@ -65,7 +65,7 @@ export function ControlPlaneListWorkspaceGridTile({ DeleteWorkspaceResource(projectNamespace, workspaceName), ); - const { links } = useFrontendConfig(); + const { mcpCreationGuide } = useLink(); const errorView = createErrorView(cpsError); function createErrorView(error: APIError) { @@ -155,7 +155,7 @@ export function ControlPlaneListWorkspaceGridTile({ subtitle={t('IllustratedBanner.subtitleMessage')} illustrationName={IllustrationMessageType.NoData} help={{ - link: links.COM_PAGE_GETTING_STARTED_MCP, + link: mcpCreationGuide, buttonText: t('IllustratedBanner.helpButton'), }} /> diff --git a/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx b/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx index c99cc3c4..6fdc82e0 100644 --- a/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx +++ b/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx @@ -14,6 +14,7 @@ import { import { KubectlTerminal } from './KubectlTerminal'; import { useState, useEffect, ReactNode } from 'react'; import { useTranslation, Trans } from 'react-i18next'; +import { useLink } from '../../../lib/shared/links'; export interface FormField { id: string; @@ -46,6 +47,7 @@ export const KubectlBaseDialog = ({ customCommands, }: KubectlBaseDialogProps) => { const { t } = useTranslation(); + const { gettingStartedGuide } = useLink(); const [formValues, setFormValues] = useState>({}); useEffect(() => { @@ -163,12 +165,7 @@ export const KubectlBaseDialog = ({ - ), + link1: , }} /> diff --git a/src/utils/testing.ts b/src/utils/testing.ts index fbced788..ab7c96ff 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -1,11 +1,12 @@ -import { DocLinkCreator } from '../lib/shared/links.ts'; import { Landscape } from '../context/FrontendConfigContext.tsx'; export const isInTestingMode: boolean = !!window.Cypress; const documentationBaseUrl = 'http://localhost:3000'; +const githubBaseUrl = 'https://github.com/example/repo'; + export const mockedFrontendConfig = { backendUrl: 'http://localhost:3000', landscape: Landscape.Local, - documentationBaseUrl: 'http://localhost:3000', - links: new DocLinkCreator(documentationBaseUrl), + documentationBaseUrl: documentationBaseUrl, + githubBaseUrl: githubBaseUrl, }; diff --git a/src/views/Login.tsx b/src/views/Login.tsx index c1860313..aa88c401 100644 --- a/src/views/Login.tsx +++ b/src/views/Login.tsx @@ -3,12 +3,12 @@ import { Button, Card, FlexBox, Text } from '@ui5/webcomponents-react'; import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; import './login.css'; import { ThemingParameters } from '@ui5/webcomponents-react-base'; -import { useFrontendConfig } from '../context/FrontendConfigContext'; +import { useLink } from '../lib/shared/links'; import { useTranslation } from 'react-i18next'; export default function LoginView() { const auth = useAuth(); - const { links } = useFrontendConfig(); + const { documentationHomepage } = useLink(); const { t } = useTranslation(); return ( @@ -26,7 +26,7 @@ export default function LoginView() { {t('Login.description')}

- + {t('Login.learnMore')}

From c3d60669c036cb60a488acdd4c82674feda42acf Mon Sep 17 00:00:00 2001 From: fabianwolski Date: Tue, 6 May 2025 16:09:59 +0100 Subject: [PATCH 4/5] . --- src/components/ControlPlane/MCPHealthPopoverButton.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ControlPlane/MCPHealthPopoverButton.tsx b/src/components/ControlPlane/MCPHealthPopoverButton.tsx index 373601f3..97dc0462 100644 --- a/src/components/ControlPlane/MCPHealthPopoverButton.tsx +++ b/src/components/ControlPlane/MCPHealthPopoverButton.tsx @@ -17,7 +17,7 @@ import { import ReactTimeAgo from 'react-time-ago'; import { AnimatedHoverTextButton } from '../Helper/AnimatedHoverTextButton.tsx'; import { useTranslation } from 'react-i18next'; -import { useFrontendConfig } from '../../context/FrontendConfigContext.tsx'; +import { useLink } from '../../lib/shared/links.ts'; export default function MCPHealthPopoverButton({ mcpStatus, projectName, @@ -31,7 +31,7 @@ export default function MCPHealthPopoverButton({ }) { const popoverRef = useRef(null); const [open, setOpen] = useState(false); - const { links } = useFrontendConfig(); + const { githubIssuesSupportTicket } = useLink(); const { t } = useTranslation(); @@ -82,7 +82,7 @@ export default function MCPHealthPopoverButton({ 'what-happened': statusDetails, }); - return `${links.COM_PAGE_SUPPORT_GITHUB_ISSUE}?${params}`; + return `${githubIssuesSupportTicket}?${params}`; }; const statusTableColumns: AnalyticalTableColumnDefinition[] = [ From 760bf4ddb709ba3ef4d859b4e9833af79bbc10cd Mon Sep 17 00:00:00 2001 From: Andreas Kienle Date: Thu, 15 May 2025 08:14:36 +0200 Subject: [PATCH 5/5] Refactor useLink --- src/components/ControlPlane/MCPHealthPopoverButton.tsx | 2 +- .../ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx | 2 +- .../ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx | 2 +- .../Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx | 2 +- src/lib/shared/{links.ts => useLink.ts} | 3 --- src/views/Login.tsx | 2 +- 6 files changed, 5 insertions(+), 8 deletions(-) rename src/lib/shared/{links.ts => useLink.ts} (86%) diff --git a/src/components/ControlPlane/MCPHealthPopoverButton.tsx b/src/components/ControlPlane/MCPHealthPopoverButton.tsx index 97dc0462..a44751ce 100644 --- a/src/components/ControlPlane/MCPHealthPopoverButton.tsx +++ b/src/components/ControlPlane/MCPHealthPopoverButton.tsx @@ -17,7 +17,7 @@ import { import ReactTimeAgo from 'react-time-ago'; import { AnimatedHoverTextButton } from '../Helper/AnimatedHoverTextButton.tsx'; import { useTranslation } from 'react-i18next'; -import { useLink } from '../../lib/shared/links.ts'; +import { useLink } from '../../lib/shared/useLink.ts'; export default function MCPHealthPopoverButton({ mcpStatus, projectName, diff --git a/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx b/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx index 67bf76da..a0ee6c31 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx @@ -8,7 +8,7 @@ import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; import { ControlPlaneListWorkspaceGridTile } from './ControlPlaneListWorkspaceGridTile.tsx'; import { useApiResource } from '../../../lib/api/useApiResource.ts'; import { ListWorkspaces } from '../../../lib/api/types/crate/listWorkspaces.ts'; -import { useLink } from '../../../lib/shared/links.ts'; +import { useLink } from '../../../lib/shared/useLink.ts'; import { useTranslation } from 'react-i18next'; interface Props { diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 93062c3e..f05a82ff 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -35,7 +35,7 @@ import { APIError } from '../../../lib/api/error.ts'; import { useTranslation } from 'react-i18next'; import { YamlViewButton } from '../../Yaml/YamlViewButton.tsx'; import { IllustratedBanner } from '../../Ui/IllustratedBanner/IllustratedBanner.tsx'; -import { useLink } from '../../../lib/shared/links.ts'; +import { useLink } from '../../../lib/shared/useLink.ts'; import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js'; interface Props { diff --git a/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx b/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx index 6fdc82e0..0bc450ff 100644 --- a/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx +++ b/src/components/Dialogs/KubectlCommandInfo/KubectlBaseDialog.tsx @@ -14,7 +14,7 @@ import { import { KubectlTerminal } from './KubectlTerminal'; import { useState, useEffect, ReactNode } from 'react'; import { useTranslation, Trans } from 'react-i18next'; -import { useLink } from '../../../lib/shared/links'; +import { useLink } from '../../../lib/shared/useLink.ts'; export interface FormField { id: string; diff --git a/src/lib/shared/links.ts b/src/lib/shared/useLink.ts similarity index 86% rename from src/lib/shared/links.ts rename to src/lib/shared/useLink.ts index 90957805..1d20e703 100644 --- a/src/lib/shared/links.ts +++ b/src/lib/shared/useLink.ts @@ -3,9 +3,6 @@ import { useFrontendConfig } from '../../context/FrontendConfigContext'; export function useLink() { const { documentationBaseUrl, githubBaseUrl } = useFrontendConfig(); - if (!documentationBaseUrl || !githubBaseUrl) { - throw new Error('useLink must be used within a FrontendConfigProvider'); - } const createLink = (path: string) => `${documentationBaseUrl}${path}`; const createGithubLink = (path: string) => `${githubBaseUrl}${path}`; diff --git a/src/views/Login.tsx b/src/views/Login.tsx index aa88c401..b78d3d83 100644 --- a/src/views/Login.tsx +++ b/src/views/Login.tsx @@ -3,7 +3,7 @@ import { Button, Card, FlexBox, Text } from '@ui5/webcomponents-react'; import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; import './login.css'; import { ThemingParameters } from '@ui5/webcomponents-react-base'; -import { useLink } from '../lib/shared/links'; +import { useLink } from '../lib/shared/useLink.ts'; import { useTranslation } from 'react-i18next'; export default function LoginView() {