Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 5 additions & 1 deletion frontend/apps/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,16 @@
"@thunderid/configure-agent-types": "workspace:^",
"@thunderid/configure-applications": "workspace:^",
"@thunderid/configure-connections": "workspace:^",
"@thunderid/configure-design": "workspace:^",
"@thunderid/configure-groups": "workspace:^",
"@thunderid/configure-import-export": "workspace:^",
"@thunderid/configure-users": "workspace:^",
"@thunderid/configure-user-types": "workspace:^",
"@thunderid/configure-organization-units": "workspace:^",
"@thunderid/configure-translations": "workspace:^",
"@thunderid/configure-resource-servers": "workspace:^",
"@thunderid/configure-verifiable-presentations": "workspace:^",
"@thunderid/configure-settings": "workspace:^",
"@thunderid/configure-verifiable-credentials": "workspace:^",
"@thunderid/utils": "workspace:^",
"@wso2/oxygen-ui": "catalog:",
"@wso2/oxygen-ui-icons-react": "catalog:",
Expand Down
67 changes: 37 additions & 30 deletions frontend/apps/console/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

import {PageLoader} from '@thunderid/components';
import {LayoutBuilderProvider, ThemeBuilderProvider} from '@thunderid/configure-design';
import {GroupCreateProvider} from '@thunderid/configure-groups';
import {OrganizationUnitProvider} from '@thunderid/configure-organization-units';
import {TranslationCreateProvider} from '@thunderid/configure-translations';
import {UserTypeCreateProvider} from '@thunderid/configure-user-types';
Expand All @@ -12,9 +14,6 @@ import {BrowserRouter, Navigate, Outlet, Route, Routes} from 'react-router';
import RouteConfig, {ROUTE_SEGMENTS} from './configs/RouteConfig';
import AgentCreateProvider from './features/agents/contexts/AgentCreate/AgentCreateProvider';
import ApplicationCreateProvider from './features/applications/contexts/ApplicationCreate/ApplicationCreateProvider';
import LayoutBuilderProvider from './features/design/contexts/LayoutBuilder/LayoutBuilderProvider';
import ThemeBuilderProvider from './features/design/contexts/ThemeBuilder/ThemeBuilderProvider';
import GroupCreateProvider from './features/groups/contexts/GroupCreate/GroupCreateProvider';
import OrganizationUnitDefaultFlowsSettings from './features/organization-units/OrganizationUnitDefaultFlowsSettings';
import RoleCreateProvider from './features/roles/contexts/RoleCreate/RoleCreateProvider';
import WelcomeRedirect from './features/welcome/components/WelcomeRedirect';
Expand Down Expand Up @@ -71,31 +70,39 @@ const ApplicationEditPage = lazy(() =>
);
const ApplicationsListPage = lazy(() => import('./features/applications/pages/ApplicationsListPage'));
const ApplicationTemplateSelectPage = lazy(() => import('./features/applications/pages/ApplicationTemplateSelectPage'));
const DesignPage = lazy(() => import('./features/design/pages/DesignPage'));
const DesignPage = lazy(() => import('@thunderid/configure-design').then((m) => ({default: m.DesignPage})));
const LayoutBuilderPage = lazy(() =>
import('./lib/monaco-setup').then(() => import('./features/design/pages/LayoutBuilderPage')),
import('./lib/monaco-setup').then(() =>
import('@thunderid/configure-design').then((m) => ({default: m.LayoutBuilderPage})),
),
);
const ThemeBuilderPage = lazy(() => import('./features/design/pages/ThemeBuilderPage'));
const ThemeCreatePage = lazy(() => import('./features/design/pages/ThemeCreatePage'));
const ThemeBuilderPage = lazy(() => import('@thunderid/configure-design').then((m) => ({default: m.ThemeBuilderPage})));
const ThemeCreatePage = lazy(() => import('@thunderid/configure-design').then((m) => ({default: m.ThemeCreatePage})));
const FlowCreatePage = lazy(() => import('./features/flows/pages/FlowCreatePage'));
const FlowsListPage = lazy(() => import('./features/flows/pages/FlowsListPage'));
const CreateGroupPage = lazy(() => import('./features/groups/pages/CreateGroupPage'));
const GroupEditPage = lazy(() => import('./features/groups/pages/GroupEditPage'));
const GroupsListPage = lazy(() => import('./features/groups/pages/GroupsListPage'));
const CreateGroupPage = lazy(() => import('@thunderid/configure-groups').then((m) => ({default: m.CreateGroupPage})));
const GroupEditPage = lazy(() => import('@thunderid/configure-groups').then((m) => ({default: m.GroupEditPage})));
const GroupsListPage = lazy(() => import('@thunderid/configure-groups').then((m) => ({default: m.GroupsListPage})));
const HomePage = lazy(() => import('./features/home/pages/HomePage'));
const ExportPage = lazy(() =>
import('./lib/monaco-setup').then(() => import('./features/import-export/pages/ExportPage')),
import('./lib/monaco-setup').then(() =>
import('@thunderid/configure-import-export').then((m) => ({default: m.ExportPage})),
),
);
const ImportConfigurationSummaryPage = lazy(() =>
import('./lib/monaco-setup').then(() => import('./features/import-export/pages/ImportConfigurationSummaryPage')),
import('./lib/monaco-setup').then(() =>
import('@thunderid/configure-import-export').then((m) => ({default: m.ImportConfigurationSummaryPage})),
),
);
const ImportConfigurationUploadPage = lazy(() =>
import('@thunderid/configure-import-export').then((m) => ({default: m.ImportConfigurationUploadPage})),
);
const ImportConfigurationUploadPage = lazy(
() => import('./features/import-export/pages/ImportConfigurationUploadPage'),
const ImportConfigurationValidatePage = lazy(() =>
import('@thunderid/configure-import-export').then((m) => ({default: m.ImportConfigurationValidatePage})),
);
const ImportConfigurationValidatePage = lazy(
() => import('./features/import-export/pages/ImportConfigurationValidatePage'),
const ImportExportPage = lazy(() =>
import('@thunderid/configure-import-export').then((m) => ({default: m.ImportExportPage})),
);
const ImportExportPage = lazy(() => import('./features/import-export/pages/ImportExportPage'));
const ConnectionsListPage = lazy(() =>
import('@thunderid/configure-connections').then((m) => ({default: m.ConnectionsListPage})),
);
Expand All @@ -112,27 +119,27 @@ const FlowBuilderPage = lazy(() => import('./features/flows/pages/FlowBuilderPag
const CreateRolePage = lazy(() => import('./features/roles/pages/CreateRolePage'));
const RoleEditPage = lazy(() => import('./features/roles/pages/RoleEditPage'));
const RolesListPage = lazy(() => import('./features/roles/pages/RolesListPage'));
const SettingsPage = lazy(() => import('./features/settings/pages/SettingsPage'));
const SettingsPage = lazy(() => import('@thunderid/configure-settings').then((m) => ({default: m.SettingsPage})));
const TrustedIssuerDetailPage = lazy(() =>
import('@thunderid/configure-connections').then((m) => ({default: m.TrustedIssuerDetailPage})),
);
const VerifiablePresentationsListPage = lazy(
() => import('./features/verifiable-presentations/pages/VerifiablePresentationsListPage'),
const VerifiablePresentationsListPage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiablePresentationsListPage})),
);
const VerifiablePresentationCreatePage = lazy(
() => import('./features/verifiable-presentations/pages/VerifiablePresentationCreatePage'),
const VerifiablePresentationCreatePage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiablePresentationCreatePage})),
);
const VerifiablePresentationEditPage = lazy(
() => import('./features/verifiable-presentations/pages/VerifiablePresentationEditPage'),
const VerifiablePresentationEditPage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiablePresentationEditPage})),
);
const VerifiableCredentialsListPage = lazy(
() => import('./features/verifiable-credentials/pages/VerifiableCredentialsListPage'),
const VerifiableCredentialsListPage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiableCredentialsListPage})),
);
const VerifiableCredentialCreatePage = lazy(
() => import('./features/verifiable-credentials/pages/VerifiableCredentialCreatePage'),
const VerifiableCredentialCreatePage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiableCredentialCreatePage})),
);
const VerifiableCredentialEditPage = lazy(
() => import('./features/verifiable-credentials/pages/VerifiableCredentialEditPage'),
const VerifiableCredentialEditPage = lazy(() =>
import('@thunderid/configure-verifiable-credentials').then((m) => ({default: m.VerifiableCredentialEditPage})),
);
const CreateUserTypePage = lazy(() =>
import('@thunderid/configure-user-types').then((m) => ({default: m.CreateUserTypePage})),
Expand Down
109 changes: 99 additions & 10 deletions frontend/apps/console/src/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,37 @@ vi.mock('../features/applications/pages/ApplicationEditPage', () => ({
default: () => <div data-testid="application-edit-page">Application Edit Page</div>,
}));

vi.mock('../features/design/pages/LayoutBuilderPage', () => ({
default: () => <div data-testid="layout-builder-page">Layout Builder Page</div>,
vi.mock('@thunderid/configure-design', async (importOriginal) => ({
...(await importOriginal<typeof import('@thunderid/configure-design')>()),
LayoutBuilderPage: () => <div data-testid="layout-builder-page">Layout Builder Page</div>,
LayoutBuilderProvider: ({children}: {children: React.ReactNode}) => children as React.ReactElement,
DesignPage: () => <div data-testid="design-page">Design Page</div>,
ThemeBuilderPage: () => <div data-testid="theme-builder-page">Theme Builder Page</div>,
ThemeCreatePage: () => <div data-testid="theme-create-page">Theme Create Page</div>,
ThemeBuilderProvider: ({children}: {children: React.ReactNode}) => children as React.ReactElement,
}));

vi.mock('../features/design/contexts/LayoutBuilder/LayoutBuilderProvider', () => ({
default: ({children}: {children: React.ReactNode}) => children as React.ReactElement,
vi.mock('@thunderid/configure-groups', async (importOriginal) => ({
...(await importOriginal<typeof import('@thunderid/configure-groups')>()),
GroupsListPage: () => <div data-testid="groups-list-page">Groups List Page</div>,
GroupEditPage: () => <div data-testid="group-edit-page">Group Edit Page</div>,
CreateGroupPage: () => <div data-testid="create-group-page">Create Group Page</div>,
GroupCreateProvider: ({children}: {children: React.ReactNode}) => children as React.ReactElement,
}));

vi.mock('../features/import-export/pages/ExportPage', () => ({
default: () => <div data-testid="export-page">Export Page</div>,
}));

vi.mock('../features/import-export/pages/ImportConfigurationSummaryPage', () => ({
default: () => <div data-testid="import-configuration-summary-page">Import Configuration Summary Page</div>,
vi.mock('@thunderid/configure-import-export', async (importOriginal) => ({
...(await importOriginal<typeof import('@thunderid/configure-import-export')>()),
ExportPage: () => <div data-testid="export-page">Export Page</div>,
ImportConfigurationSummaryPage: () => (
<div data-testid="import-configuration-summary-page">Import Configuration Summary Page</div>
),
ImportConfigurationUploadPage: () => (
<div data-testid="import-configuration-upload-page">Import Configuration Upload Page</div>
),
ImportConfigurationValidatePage: () => (
<div data-testid="import-configuration-validate-page">Import Configuration Validate Page</div>
),
ImportExportPage: () => <div data-testid="import-export-page">Import Export Page</div>,
}));

vi.mock('@thunderid/configure-resource-servers', () => ({
Expand Down Expand Up @@ -239,4 +256,76 @@ describe('App', () => {
expect(screen.getByTestId('trusted-issuer-detail-page')).toBeInTheDocument();
});
});

it('loads DesignPage lazily at /design', async () => {
window.history.pushState({}, '', '/design');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('design-page')).toBeInTheDocument();
});
});

it('loads ThemeCreatePage lazily at /design/themes/create', async () => {
window.history.pushState({}, '', '/design/themes/create');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('theme-create-page')).toBeInTheDocument();
});
});

it('loads ThemeBuilderPage lazily at /design/themes/:themeId', async () => {
window.history.pushState({}, '', '/design/themes/theme-123');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('theme-builder-page')).toBeInTheDocument();
});
});

it('loads GroupsListPage lazily at /groups', async () => {
window.history.pushState({}, '', '/groups');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('groups-list-page')).toBeInTheDocument();
});
});

it('loads GroupEditPage lazily at /groups/:groupId', async () => {
window.history.pushState({}, '', '/groups/group-123');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('group-edit-page')).toBeInTheDocument();
});
});

it('loads CreateGroupPage lazily at /groups/create', async () => {
window.history.pushState({}, '', '/groups/create');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('create-group-page')).toBeInTheDocument();
});
});

it('loads ImportExportPage lazily at /import-export', async () => {
window.history.pushState({}, '', '/import-export');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('import-export-page')).toBeInTheDocument();
});
});

it('loads ImportConfigurationUploadPage lazily at /import-configuration', async () => {
window.history.pushState({}, '', '/import-configuration');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('import-configuration-upload-page')).toBeInTheDocument();
});
});

it('loads ImportConfigurationValidatePage lazily at /import-configuration/validate', async () => {
window.history.pushState({}, '', '/import-configuration/validate');
render(<App />);
await waitFor(() => {
expect(screen.getByTestId('import-configuration-validate-page')).toBeInTheDocument();
});
});
});
40 changes: 8 additions & 32 deletions frontend/apps/console/src/configs/RouteConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@

import type {AgentTypeRoutePaths} from '@thunderid/configure-agent-types';
import type {ConnectionRoutePaths} from '@thunderid/configure-connections';
import type {DesignRoutePaths} from '@thunderid/configure-design';
import type {GroupRoutePaths} from '@thunderid/configure-groups';
import type {ImportExportRoutePaths} from '@thunderid/configure-import-export';
import type {OrganizationUnitRoutePaths} from '@thunderid/configure-organization-units';
import type {ResourceServerRoutePaths} from '@thunderid/configure-resource-servers';
import type {TranslationRoutePaths} from '@thunderid/configure-translations';
import type {UserTypeRoutePaths} from '@thunderid/configure-user-types';
import type {UserRoutePaths} from '@thunderid/configure-users';
import type {VerifiableCredentialRoutePaths} from '@thunderid/configure-verifiable-credentials';

/**
* Route paths for the domains Console implements itself, rather than through a
Expand All @@ -33,48 +37,16 @@ export interface ConsoleRoutePaths {
detail: (id: string) => string;
create: () => string;
};
groups: {
list: () => string;
detail: (id: string) => string;
create: () => string;
};
roles: {
list: () => string;
detail: (id: string) => string;
create: () => string;
};
verifiableCredentials: {
list: () => string;
detail: (id: string) => string;
create: () => string;
};
verifiablePresentations: {
list: () => string;
detail: (id: string) => string;
create: () => string;
};
flows: {
list: () => string;
create: () => string;
detail: (flowId: string) => string;
};
design: {
list: () => string;
themesCreate: () => string;
themeDetail: (themeId: string) => string;
layoutDetail: (layoutId: string) => string;
};
importExport: {
list: () => string;
};
export: {
page: () => string;
};
importConfiguration: {
upload: () => string;
validate: () => string;
summary: () => string;
};
welcome: {
root: () => string;
createProject: () => string;
Expand Down Expand Up @@ -112,6 +84,10 @@ export type RouteConfig = OrganizationUnitRoutePaths &
ConnectionRoutePaths &
ResourceServerRoutePaths &
TranslationRoutePaths &
VerifiableCredentialRoutePaths &
ImportExportRoutePaths &
DesignRoutePaths &
GroupRoutePaths &
ConsoleRoutePaths;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// Copyright 2025 The ThunderID Authors
// SPDX-License-Identifier: Apache-2.0

import {
LayoutPresetThumbnail,
LayoutThumbnail,
ThemeThumbnail,
type LayoutPresetVariant,
} from '@thunderid/configure-design';
import {useConfig} from '@thunderid/contexts';
import {
useGetThemes,
Expand Down Expand Up @@ -33,11 +39,6 @@ import {Palette, ExternalLink, Code, Lightbulb, LayoutTemplate} from '@wso2/oxyg
import type {JSX, ChangeEvent} from 'react';
import {useState, useEffect} from 'react';
import {useTranslation} from 'react-i18next';
import LayoutPresetThumbnail, {
type LayoutPresetVariant,
} from '../../../design/components/layouts/LayoutPresetThumbnail';
import LayoutThumbnail from '../../../design/components/layouts/LayoutThumbnail';
import ThemeThumbnail from '../../../design/components/themes/ThemeThumbnail';
import useApplicationCreateContext from '../../hooks/useApplicationCreateContext';
import {ApplicationCreateFlowSignInApproach, OrganizationUnitDefaultItem} from '../../models/application-create-flow';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2026 The ThunderID Authors
// SPDX-License-Identifier: Apache-2.0

import {isValidOrigin} from '@thunderid/configure-settings';
import {
Alert,
Box,
Expand All @@ -19,7 +20,6 @@ import type {JSX} from 'react';
import {useEffect, useState} from 'react';
import {useTranslation} from 'react-i18next';
import DevServerLogo from './DevServerLogo';
import {isValidOrigin} from '../../../settings/utils/origin';
import useApplicationCreate from '../../contexts/ApplicationCreate/useApplicationCreate';

/** Pure URI-format check, permissive of path/host wildcards (the backend enforces wildcard rules). */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import {
VueIcon,
} from '@thunderid/components';
import type {Application, OAuth2Config} from '@thunderid/configure-applications';
import {GatePreview} from '@thunderid/configure-design';
import {useConfig} from '@thunderid/contexts';
import {DefaultTheme, type Theme, useGetTheme} from '@thunderid/design';
import {useLogger} from '@thunderid/logger/react';
import {Box, Button, Chip, Link, Paper, Stack, Typography, useColorScheme} from '@wso2/oxygen-ui';
import {ArrowRight, ArrowUpRight, Check, Copy, Sparkles} from '@wso2/oxygen-ui-icons-react';
import {useState, type JSX, type ReactNode} from 'react';
import {Trans, useTranslation} from 'react-i18next';
import GatePreview from '../../../../../components/GatePreview/GatePreview';
import useGetFlowById from '../../../../flows/api/useGetFlowById';
import {getIntegrationGuideForTemplate} from '../../../utils/getIntegrationGuidesForTemplate';
import getPlaygroundsForTemplate from '../../../utils/getPlaygroundsForTemplate';
Expand Down
Loading
Loading