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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@thunderid/components';
import type {Application, OAuth2Config} from '@thunderid/configure-applications';
import {GatePreview} from '@thunderid/configure-design';
import {useGetOrganizationUnit} from '@thunderid/configure-organization-units';
import {useConfig} from '@thunderid/contexts';
import {DefaultTheme, type Theme, useGetTheme} from '@thunderid/design';
import {useLogger} from '@thunderid/logger/react';
Expand Down Expand Up @@ -197,6 +198,7 @@ export default function IntegrationGuides({
Boolean(application.isRecoveryFlowEnabled && application.recoveryFlowId),
);
const {data: signOutFlowDetails} = useGetFlowById(application.signOutFlowId);
const {data: organizationUnit} = useGetOrganizationUnit(application.ouId);
const {mode, systemMode} = useColorScheme();
const productName = config.brand.product_name;
const [promptCopied, setPromptCopied] = useState(false);
Expand Down Expand Up @@ -407,6 +409,18 @@ export default function IntegrationGuides({
{oauth2Config?.clientId && (
<CopyableField label={t('applications:edit.general.labels.clientId')} value={oauth2Config.clientId} />
)}
{application.ouId && (
<CopyableField
label={t('applications:edit.overview.appDetails.organizationUnitId', 'Organization Unit ID')}
value={application.ouId}
/>
)}
{organizationUnit?.handle && (
<CopyableField
label={t('applications:edit.overview.appDetails.organizationUnitHandle', 'Organization Unit Handle')}
value={organizationUnit.handle}
/>
)}
</Box>
</OverviewCard>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ vi.mock('@thunderid/configure-design', async (importOriginal) => ({
GatePreview: () => <div data-testid="gate-preview" />,
}));

const mockUseGetOrganizationUnit = vi.fn(() => ({data: undefined}) as unknown);

vi.mock('@thunderid/configure-organization-units', () => ({
useGetOrganizationUnit: (...args: unknown[]): unknown => mockUseGetOrganizationUnit(...(args as [])),
}));

const mockWriteText = vi.fn();
const mockFetch = vi.fn();

Expand Down Expand Up @@ -87,6 +93,7 @@ describe('IntegrationGuides', () => {

beforeEach(() => {
vi.useFakeTimers({shouldAdvanceTime: true});
mockUseGetOrganizationUnit.mockReset().mockReturnValue({data: undefined});
mockWriteText.mockReset().mockResolvedValue(undefined);
mockGetDocumentationLink.mockImplementation((key: string) => documentationLinks[key]);
mockFetch.mockReset().mockImplementation((url: string) =>
Expand Down Expand Up @@ -119,6 +126,31 @@ describe('IntegrationGuides', () => {
expect(screen.queryByRole('link', {name: /Open on StackBlitz/i})).not.toBeInTheDocument();
});

it('shows the organization unit ID and handle in the application details card', () => {
mockUseGetOrganizationUnit.mockReturnValue({data: {id: 'ou-1', handle: 'engineering'}});

renderWithProviders(<IntegrationGuides application={{...reactApplication, ouId: 'ou-1'}} />);

expect(screen.getByText('Organization Unit ID')).toBeInTheDocument();
expect(screen.getByText('ou-1')).toBeInTheDocument();
expect(screen.getByText('Organization Unit Handle')).toBeInTheDocument();
expect(screen.getByText('engineering')).toBeInTheDocument();
});

it('hides the organization unit rows when the application has no ouId', () => {
renderWithProviders(<IntegrationGuides application={reactApplication} />);

expect(screen.queryByText('Organization Unit ID')).not.toBeInTheDocument();
expect(screen.queryByText('Organization Unit Handle')).not.toBeInTheDocument();
});

it('shows the organization unit ID alone when the handle has not resolved yet', () => {
renderWithProviders(<IntegrationGuides application={{...reactApplication, ouId: 'ou-1'}} />);

expect(screen.getByText('Organization Unit ID')).toBeInTheDocument();
expect(screen.queryByText('Organization Unit Handle')).not.toBeInTheDocument();
});

it('shows the OIDC endpoints and sign-in preview from the canonical type before the OAuth2 config resolves', () => {
// oauth2Config isn't always resolved on first paint; the canonical application type (always
// present) is enough to know a 'browser' app is OAuth2-based and user-facing.
Expand Down
Loading