feat: replace tenant OIDC page with Enterprise SSO connector management
All checks were successful
CI / build (push) Successful in 1m3s
CI / docker (push) Successful in 46s

- Add LogtoManagementClient methods for SSO connector CRUD + org JIT
- Add TenantSsoService with tenant isolation (validates connector-org link)
- Add TenantSsoController at /api/tenant/sso with test endpoint
- Create SsoPage with provider selection, dynamic config form, test button
- Remove old OIDC config endpoints from tenant portal (server OIDC is
  now platform-managed, set during provisioning)
- Sidebar: OIDC -> SSO with Shield icon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-10 15:48:51 +02:00
parent 4341656a5e
commit e559267f1e
11 changed files with 682 additions and 232 deletions

View File

@@ -1,6 +1,6 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { api } from './client';
import type { DashboardData, TenantLicenseData, TenantSettings, AuditLogPage, AuditLogFilters } from '../types/api';
import type { DashboardData, TenantLicenseData, TenantSettings, AuditLogPage, AuditLogFilters, SsoConnector, CreateSsoConnectorRequest, SsoTestResult } from '../types/api';
export function useTenantDashboard() {
return useQuery<DashboardData>({
@@ -17,18 +17,49 @@ export function useTenantLicense() {
});
}
export function useTenantOidc() {
return useQuery<Record<string, unknown>>({
queryKey: ['tenant', 'oidc'],
queryFn: () => api.get('/tenant/oidc'),
// SSO connector hooks
export function useSsoConnectors() {
return useQuery<SsoConnector[]>({
queryKey: ['tenant', 'sso'],
queryFn: () => api.get('/tenant/sso'),
});
}
export function useUpdateOidc() {
export function useSsoConnector(id: string | null) {
return useQuery<SsoConnector>({
queryKey: ['tenant', 'sso', id],
queryFn: () => api.get(`/tenant/sso/${id}`),
enabled: !!id,
});
}
export function useCreateSsoConnector() {
const qc = useQueryClient();
return useMutation<void, Error, Record<string, unknown>>({
mutationFn: (config) => api.post('/tenant/oidc', config),
onSuccess: () => qc.invalidateQueries({ queryKey: ['tenant', 'oidc'] }),
return useMutation<SsoConnector, Error, CreateSsoConnectorRequest>({
mutationFn: (req) => api.post('/tenant/sso', req),
onSuccess: () => qc.invalidateQueries({ queryKey: ['tenant', 'sso'] }),
});
}
export function useUpdateSsoConnector() {
const qc = useQueryClient();
return useMutation<SsoConnector, Error, { id: string; updates: Record<string, unknown> }>({
mutationFn: ({ id, updates }) => api.patch(`/tenant/sso/${id}`, updates),
onSuccess: () => qc.invalidateQueries({ queryKey: ['tenant', 'sso'] }),
});
}
export function useDeleteSsoConnector() {
const qc = useQueryClient();
return useMutation<void, Error, string>({
mutationFn: (id) => api.delete(`/tenant/sso/${id}`),
onSuccess: () => qc.invalidateQueries({ queryKey: ['tenant', 'sso'] }),
});
}
export function useTestSsoConnector() {
return useMutation<SsoTestResult, Error, string>({
mutationFn: (id) => api.post(`/tenant/sso/${id}/test`),
});
}