@burdenoff/microfe-auth 2026.518.4 → 2026.519.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/hooks/usePasswordOperations.d.ts.map +1 -1
- package/dist/auth/hooks/usePasswordOperations.js +11 -4
- package/dist/auth/hooks/usePasswordOperations.js.map +1 -1
- package/dist/auth/hooks/useSessionOperations.d.ts +12 -1
- package/dist/auth/hooks/useSessionOperations.d.ts.map +1 -1
- package/dist/auth/hooks/useSessionOperations.js +62 -46
- package/dist/auth/hooks/useSessionOperations.js.map +1 -1
- package/dist/auth/pages/LoginPage.d.ts.map +1 -1
- package/dist/auth/pages/LoginPage.js +2 -0
- package/dist/auth/pages/LoginPage.js.map +1 -1
- package/dist/auth/pages/MfaSetupPage.d.ts.map +1 -1
- package/dist/auth/pages/MfaSetupPage.js +9 -4
- package/dist/auth/pages/MfaSetupPage.js.map +1 -1
- package/dist/auth/pages/PasswordResetPage.d.ts.map +1 -1
- package/dist/auth/pages/PasswordResetPage.js +9 -1
- package/dist/auth/pages/PasswordResetPage.js.map +1 -1
- package/dist/auth/pages/RegisterPage.d.ts.map +1 -1
- package/dist/auth/pages/RegisterPage.js +8 -0
- package/dist/auth/pages/RegisterPage.js.map +1 -1
- package/dist/auth/pages/SSODepositPage.d.ts.map +1 -1
- package/dist/auth/pages/SSODepositPage.js.map +1 -1
- package/dist/auth/pages/SecurityPage.d.ts.map +1 -1
- package/dist/auth/pages/SecurityPage.js +9 -0
- package/dist/auth/pages/SecurityPage.js.map +1 -1
- package/dist/auth/pages/SessionsPage.d.ts +2 -5
- package/dist/auth/pages/SessionsPage.d.ts.map +1 -1
- package/dist/auth/pages/SessionsPage.js +175 -152
- package/dist/auth/pages/SessionsPage.js.map +1 -1
- package/dist/auth/pages/SsoConfigPage.d.ts.map +1 -1
- package/dist/auth/pages/SsoConfigPage.js +39 -1
- package/dist/auth/pages/SsoConfigPage.js.map +1 -1
- package/dist/auth/pages/SsoLoginPage.d.ts.map +1 -1
- package/dist/auth/pages/SsoLoginPage.js +8 -5
- package/dist/auth/pages/SsoLoginPage.js.map +1 -1
- package/dist/auth/pages/UserDetailsPage.d.ts +1 -1
- package/dist/auth/pages/UserDetailsPage.d.ts.map +1 -1
- package/dist/auth/pages/UserDetailsPage.js +251 -174
- package/dist/auth/pages/UserDetailsPage.js.map +1 -1
- package/dist/generated/global-operations.d.ts +2 -1
- package/dist/generated/global-operations.d.ts.map +1 -1
- package/dist/generated/global-operations.js +55 -80
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/microfe-auth.css +1 -1
- package/dist/translations/en.d.ts +60 -0
- package/dist/translations/en.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionsPage.js","names":[],"sources":["../../../src/auth/pages/SessionsPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useSessionOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport { useCreateAuthExportJobMutation } from \"../../generated/wspace-operations\";\nimport {\n formatRelativeTime,\n parseDeviceName,\n parseBrowserName,\n} from \"../utils\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\n/**\n * Active sessions management page with professional UI\n *\n * Fragment: SessionCard_Session (graphql/operations/global/fragments/SessionCard.fragment.graphql)\n * Query: ActiveSessions (graphql/operations/global/queries/sessions.graphql)\n *\n * TODO: When activeSessions backend migrates to SessionConnection type,\n * update query to use: activeSessions { sessions: [...], totalCount, hasMore }\n */\nexport function SessionsPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const { activeSessions, revokeSession, revokeAllSessions, isLoading } =\n useSessionOperations({ disableTokenInfoQuery: true });\n const [error, setError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [pendingSessionId, setPendingSessionId] = useState<string | null>(null);\n const [showRevokeAllDialog, setShowRevokeAllDialog] = useState(false);\n\n const [createExportJob, { loading: isExporting }] =\n useCreateAuthExportJobMutation();\n const [exportError, setExportError] = useState<string | null>(null);\n\n const handleExport = async () => {\n setExportError(null);\n try {\n await createExportJob({\n variables: {\n input: {\n name: \"Sessions Export\",\n // vibecontrols_sessions is the closest session entity type in the export system\n // TODO: confirm correct entity type with export team when auth sessions are registered\n entityTypes: [\"vibecontrols_sessions\"],\n format: \"CSV\",\n exportScope: \"INDIVIDUAL\",\n includeMetadata: true,\n },\n },\n });\n } catch (err) {\n setExportError(\n err instanceof Error ? err.message : \"Failed to start export\",\n );\n }\n };\n\n const handleRevokeSession = async (sessionId: string) => {\n try {\n await revokeSession(sessionId);\n setSuccessMessage(\"Session revoked successfully\");\n setPendingSessionId(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to revoke session\");\n }\n };\n\n const handleRevokeAll = async () => {\n try {\n await revokeAllSessions();\n setSuccessMessage(\"All other sessions have been revoked\");\n setShowRevokeAllDialog(false);\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to revoke all sessions\",\n );\n }\n };\n\n if (!isAuthenticated) {\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center\">\n <AlertIcon\n className=\"w-8 h-8 text-status-warning-text\"\n aria-hidden=\"true\"\n />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.sessions.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.sessions.signInToView\",\n \"Please sign in to view your active sessions\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <ConfirmActionDialog\n open={pendingSessionId !== null}\n onOpenChange={(open) => {\n if (!open) {\n setPendingSessionId(null);\n }\n }}\n title=\"Revoke this session?\"\n description=\"The selected device will be signed out immediately and will need to authenticate again.\"\n confirmText=\"Revoke session\"\n variant=\"danger\"\n isPending={isLoading}\n onConfirm={async () => {\n if (pendingSessionId) {\n await handleRevokeSession(pendingSessionId);\n }\n }}\n />\n <ConfirmActionDialog\n open={showRevokeAllDialog}\n onOpenChange={setShowRevokeAllDialog}\n title=\"Revoke every other session?\"\n description=\"All devices except your current one will be signed out immediately.\"\n confirmText=\"Revoke all other sessions\"\n variant=\"warning\"\n isPending={isLoading}\n onConfirm={handleRevokeAll}\n />\n\n {/* Live regions for screen reader announcements */}\n <div aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {successMessage}\n </div>\n <div\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {error}\n </div>\n\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div>\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.sessions.title\", \"Active Sessions\")}\n </h1>\n <p className=\"text-text-secondary mt-2\">\n {tr(\"auth.sessions.sessionCount\", \"You have\")}{\" \"}\n {activeSessions.length}{\" \"}\n {tr(\n activeSessions.length !== 1\n ? \"auth.sessions.sessionsPlural\"\n : \"auth.sessions.sessionsSingular\",\n activeSessions.length !== 1\n ? \"active sessions\"\n : \"active session\",\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n {/* Export button */}\n <button\n type=\"button\"\n onClick={() => void handleExport()}\n disabled={isExporting}\n aria-label={tr(\n \"auth.sessions.exportAriaLabel\",\n \"Export sessions list\",\n )}\n className=\"flex items-center gap-2 px-4 py-2.5 rounded-xl border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {isExporting ? (\n <>\n <SpinnerIcon\n className=\"w-4 h-4 animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\"auth.sessions.exporting\", \"Exporting...\")}\n </>\n ) : (\n <>\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n {tr(\"auth.sessions.export\", \"Export\")}\n </>\n )}\n </button>\n {activeSessions.length > 1 && (\n <button\n type=\"button\"\n onClick={() => setShowRevokeAllDialog(true)}\n className=\"px-4 py-2.5 rounded-xl border border-status-error-border text-status-error-text font-medium hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n {tr(\"auth.sessions.revokeAll\", \"Revoke All Sessions\")}\n </button>\n )}\n </div>\n </div>\n\n {/* Export error */}\n {exportError && (\n <div\n role=\"alert\"\n className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\n <AlertIcon\n className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n />\n <p className=\"text-sm text-status-error-text\">{exportError}</p>\n </div>\n )}\n\n {/* Success Message */}\n {successMessage && (\n <div\n role=\"status\"\n className=\"mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\"\n >\n <p className=\"text-status-success-text\">{successMessage}</p>\n <button\n type=\"button\"\n onClick={() => setSuccessMessage(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline transition-colors duration-200\"\n >\n Dismiss\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div\n role=\"alert\"\n className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\n <AlertIcon\n className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline transition-colors duration-200\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {isLoading ? (\n <div\n aria-live=\"polite\"\n aria-busy=\"true\"\n className=\"flex items-center justify-center py-12\"\n >\n <SpinnerIcon\n className=\"w-8 h-8 text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.sessions.loading\", \"Loading sessions...\")}\n </span>\n </div>\n ) : activeSessions.length === 0 ? (\n <div\n className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\"\n role=\"status\"\n >\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-bg-muted flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n <p className=\"text-text-secondary\">\n {tr(\"auth.sessions.noSessions\", \"No active sessions found\")}\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\" aria-live=\"polite\" aria-busy={isLoading}>\n {activeSessions.map((session) => (\n <div\n key={session.id}\n className=\"p-6 rounded-xl border border-border-default bg-bg-surface shadow-sm hover:shadow-md transition-shadow\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-start gap-4\">\n {/* Device Icon */}\n <div\n className=\"w-12 h-12 rounded-xl bg-bg-accent flex items-center justify-center flex-shrink-0\"\n aria-hidden=\"true\"\n >\n <svg\n className=\"w-6 h-6 text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-3 mb-1\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {session.isCurrent &&\n parseDeviceName(session.userAgent) === \"Unknown Device\"\n ? tr(\"auth.sessions.thisDevice\", \"This Device\")\n : parseDeviceName(session.userAgent)}\n </h3>\n {session.isCurrent && (\n <span\n role=\"status\"\n className=\"px-2.5 py-1 rounded-full bg-status-success-bg-subtle text-status-success-text text-xs font-medium\"\n >\n {tr(\n \"auth.sessions.currentSession\",\n \"Current Session\",\n )}\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary mb-2\">\n {parseBrowserName(session.userAgent) ===\n \"Unknown Browser\" && session.isCurrent\n ? tr(\"auth.sessions.currentBrowser\", \"Current Browser\")\n : parseBrowserName(session.userAgent)}\n </p>\n <dl className=\"flex flex-wrap gap-4 text-sm text-text-secondary\">\n {session.ipAddress && session.ipAddress !== \"unknown\" && (\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9\"\n />\n </svg>\n <dt className=\"sr-only\">IP address</dt>\n <dd>{session.ipAddress}</dd>\n </div>\n )}\n {session.location && (\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <dt className=\"sr-only\">Location</dt>\n <dd>{session.location}</dd>\n </div>\n )}\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <dt className=\"sr-only\">Last active</dt>\n <dd>\n {tr(\"auth.sessions.lastActive\", \"Last active\")}{\" \"}\n {formatRelativeTime(session.lastActivityAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n {!session.isCurrent && (\n <button\n type=\"button\"\n onClick={() => setPendingSessionId(session.id)}\n aria-label={`${tr(\"auth.sessions.revoke\", \"Revoke\")} ${parseDeviceName(session.userAgent)} session`}\n className=\"ml-4 px-4 py-2 rounded-lg text-sm font-medium border border-status-error-border text-status-error-text bg-bg-surface hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n {tr(\"auth.sessions.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionsPage.js","names":[],"sources":["../../../src/auth/pages/SessionsPage.tsx"],"sourcesContent":["import { useState, useMemo } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useSessionOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport type { SessionCard_SessionFragment } from \"../../generated/global-operations\";\nimport {\n formatRelativeTime,\n parseDeviceName,\n parseBrowserName,\n} from \"../utils\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\n/**\n * Active sessions management page with professional UI\n *\n * Fragment: SessionCard_Session (src/operations/global/fragments/SessionCard.fragment.graphql)\n * Query: ActiveSessions (src/operations/global/queries/sessions.graphql)\n */\nexport function SessionsPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const {\n activeSessions,\n revokeSession,\n revokeAllSessions,\n isLoading,\n page,\n totalPages,\n totalCount,\n hasMore,\n goToNextPage,\n goToPrevPage,\n } = useSessionOperations({ disableTokenInfoQuery: true });\n const [error, setError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [pendingSessionId, setPendingSessionId] = useState<string | null>(null);\n const [showRevokeAllDialog, setShowRevokeAllDialog] = useState(false);\n\n // Deduplicate: keep newest session per device name\n const dedupedSessions = useMemo(() => {\n const byDevice = new Map<string, SessionCard_SessionFragment>();\n for (const s of activeSessions) {\n const device = parseDeviceName(s.userAgent ?? \"\");\n const existing = byDevice.get(device);\n if (\n !existing ||\n new Date(s.lastActivityAt) > new Date(existing.lastActivityAt)\n ) {\n byDevice.set(device, s);\n }\n }\n return [...byDevice.values()];\n }, [activeSessions]);\n\n const handleRevokeSession = async (sessionId: string) => {\n try {\n await revokeSession(sessionId);\n setSuccessMessage(\"Session revoked successfully\");\n setPendingSessionId(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to revoke session\");\n }\n };\n\n const handleRevokeAll = async () => {\n try {\n await revokeAllSessions();\n setSuccessMessage(\"All other sessions have been revoked\");\n setShowRevokeAllDialog(false);\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to revoke all sessions\",\n );\n }\n };\n\n if (!isAuthenticated) {\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center\">\n <AlertIcon\n className=\"w-8 h-8 text-status-warning-text\"\n aria-hidden=\"true\"\n />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.sessions.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.sessions.signInToView\",\n \"Please sign in to view your active sessions\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <ConfirmActionDialog\n open={pendingSessionId !== null}\n onOpenChange={(open) => {\n if (!open) {\n setPendingSessionId(null);\n }\n }}\n title=\"Revoke this session?\"\n description=\"The selected device will be signed out immediately and will need to authenticate again.\"\n confirmText=\"Revoke session\"\n variant=\"danger\"\n isPending={isLoading}\n onConfirm={async () => {\n if (pendingSessionId) {\n await handleRevokeSession(pendingSessionId);\n }\n }}\n />\n <ConfirmActionDialog\n open={showRevokeAllDialog}\n onOpenChange={setShowRevokeAllDialog}\n title=\"Revoke every other session?\"\n description=\"All devices except your current one will be signed out immediately.\"\n confirmText=\"Revoke all other sessions\"\n variant=\"warning\"\n isPending={isLoading}\n onConfirm={handleRevokeAll}\n />\n\n {/* Live regions for screen reader announcements */}\n <div aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {successMessage}\n </div>\n <div\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {error}\n </div>\n\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div>\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.sessions.title\", \"Active Sessions\")}\n </h1>\n <p className=\"text-text-secondary mt-2\">\n {tr(\"auth.sessions.sessionCount\", \"You have\")} {totalCount}{\" \"}\n {tr(\n totalCount !== 1\n ? \"auth.sessions.sessionsPlural\"\n : \"auth.sessions.sessionsSingular\",\n totalCount !== 1 ? \"active sessions\" : \"active session\",\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n {totalCount > 1 && (\n <button\n type=\"button\"\n onClick={() => setShowRevokeAllDialog(true)}\n className=\"px-4 py-2.5 rounded-xl border border-status-error-border text-status-error-text font-medium hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n {tr(\"auth.sessions.revokeAll\", \"Revoke All Sessions\")}\n </button>\n )}\n </div>\n </div>\n\n {/* Success Message */}\n {successMessage && (\n <div\n role=\"status\"\n className=\"mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\"\n >\n <p className=\"text-status-success-text\">{successMessage}</p>\n <button\n type=\"button\"\n onClick={() => setSuccessMessage(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline transition-colors duration-200\"\n >\n Dismiss\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div\n role=\"alert\"\n className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\n <AlertIcon\n className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline transition-colors duration-200\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {isLoading ? (\n <div\n aria-live=\"polite\"\n aria-busy=\"true\"\n className=\"flex items-center justify-center py-12\"\n >\n <SpinnerIcon\n className=\"w-8 h-8 text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.sessions.loading\", \"Loading sessions...\")}\n </span>\n </div>\n ) : dedupedSessions.length === 0 ? (\n <div\n className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\"\n role=\"status\"\n >\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-bg-muted flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n <p className=\"text-text-secondary\">\n {tr(\"auth.sessions.noSessions\", \"No active sessions found\")}\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\" aria-live=\"polite\" aria-busy={isLoading}>\n {dedupedSessions.map((session) => (\n <div\n key={session.id}\n className=\"p-6 rounded-xl border border-border-default bg-bg-surface shadow-sm hover:shadow-md transition-shadow\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-start gap-4\">\n {/* Device Icon */}\n <div\n className=\"w-12 h-12 rounded-xl bg-bg-accent flex items-center justify-center flex-shrink-0\"\n aria-hidden=\"true\"\n >\n <svg\n className=\"w-6 h-6 text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-3 mb-1\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {session.isCurrent &&\n parseDeviceName(session.userAgent) === \"Unknown Device\"\n ? tr(\"auth.sessions.thisDevice\", \"This Device\")\n : parseDeviceName(session.userAgent)}\n </h3>\n {session.isCurrent && (\n <span\n role=\"status\"\n className=\"px-2.5 py-1 rounded-full bg-status-success-bg-subtle text-status-success-text text-xs font-medium\"\n >\n {tr(\n \"auth.sessions.currentSession\",\n \"Current Session\",\n )}\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary mb-2\">\n {parseBrowserName(session.userAgent) ===\n \"Unknown Browser\" && session.isCurrent\n ? tr(\"auth.sessions.currentBrowser\", \"Current Browser\")\n : parseBrowserName(session.userAgent)}\n </p>\n <dl className=\"flex flex-wrap gap-4 text-sm text-text-secondary\">\n {session.ipAddress && session.ipAddress !== \"unknown\" && (\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9\"\n />\n </svg>\n <dt className=\"sr-only\">IP address</dt>\n <dd>{session.ipAddress}</dd>\n </div>\n )}\n {session.location && (\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <dt className=\"sr-only\">Location</dt>\n <dd>{session.location}</dd>\n </div>\n )}\n <div className=\"flex items-center gap-1.5\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <dt className=\"sr-only\">Last active</dt>\n <dd>\n {tr(\"auth.sessions.lastActive\", \"Last active\")}{\" \"}\n {formatRelativeTime(session.lastActivityAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n {!session.isCurrent && (\n <button\n type=\"button\"\n onClick={() => setPendingSessionId(session.id)}\n aria-label={`${tr(\"auth.sessions.revoke\", \"Revoke\")} ${parseDeviceName(session.userAgent)} session`}\n className=\"ml-4 px-4 py-2 rounded-lg text-sm font-medium border border-status-error-border text-status-error-text bg-bg-surface hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n {tr(\"auth.sessions.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Pagination controls */}\n {!isLoading && totalPages > 1 && (\n <div className=\"flex items-center justify-between mt-6 pt-4 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={goToPrevPage}\n disabled={page === 0}\n className=\"flex items-center gap-2 px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium text-sm\"\n aria-label={tr(\"auth.sessions.prevPage\", \"Previous page\")}\n >\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n {tr(\"auth.sessions.prev\", \"Previous\")}\n </button>\n\n <span className=\"text-sm text-text-secondary\">\n {tr(\"auth.sessions.pageOf\", \"Page\")}{\" \"}\n <span className=\"font-medium text-text-primary\">{page + 1}</span>{\" \"}\n {tr(\"auth.sessions.of\", \"of\")}{\" \"}\n <span className=\"font-medium text-text-primary\">{totalPages}</span>\n </span>\n\n <button\n type=\"button\"\n onClick={goToNextPage}\n disabled={!hasMore}\n className=\"flex items-center gap-2 px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium text-sm\"\n aria-label={tr(\"auth.sessions.nextPage\", \"Next page\")}\n >\n {tr(\"auth.sessions.next\", \"Next\")}\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SsoConfigPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/SsoConfigPage.tsx"],"names":[],"mappings":"AAgHA;;;GAGG;AACH,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"SsoConfigPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/SsoConfigPage.tsx"],"names":[],"mappings":"AAgHA;;;GAGG;AACH,wBAAgB,aAAa,4CAqgD5B"}
|
|
@@ -110,12 +110,14 @@ function y() {
|
|
|
110
110
|
className: "flex items-center gap-4",
|
|
111
111
|
children: [/* @__PURE__ */ h("button", {
|
|
112
112
|
onClick: () => a("/auth/security"),
|
|
113
|
+
"aria-label": k("auth.sso.backToSecurity", "Back to Security"),
|
|
113
114
|
className: "p-2 rounded-lg hover:bg-bg-sunken transition-colors",
|
|
114
115
|
children: /* @__PURE__ */ h("svg", {
|
|
115
116
|
className: "w-5 h-5 text-text-secondary",
|
|
116
117
|
fill: "none",
|
|
117
118
|
viewBox: "0 0 24 24",
|
|
118
119
|
stroke: "currentColor",
|
|
120
|
+
"aria-hidden": "true",
|
|
119
121
|
children: /* @__PURE__ */ h("path", {
|
|
120
122
|
strokeLinecap: "round",
|
|
121
123
|
strokeLinejoin: "round",
|
|
@@ -331,10 +333,12 @@ function y() {
|
|
|
331
333
|
}), /* @__PURE__ */ g("div", {
|
|
332
334
|
className: "flex gap-2",
|
|
333
335
|
children: [/* @__PURE__ */ h("input", {
|
|
336
|
+
id: "sso-metadata-url",
|
|
334
337
|
type: "url",
|
|
335
338
|
value: B,
|
|
336
339
|
onChange: (e) => V(e.target.value),
|
|
337
340
|
placeholder: "https://idp.example.com/metadata.xml",
|
|
341
|
+
"aria-label": k("auth.sso.fetchFromUrl", "Fetch from URL"),
|
|
338
342
|
className: "flex-1 px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all text-sm"
|
|
339
343
|
}), /* @__PURE__ */ g("button", {
|
|
340
344
|
type: "button",
|
|
@@ -354,7 +358,7 @@ function y() {
|
|
|
354
358
|
ssoUrl: t.ssoUrl,
|
|
355
359
|
sloUrl: t.sloUrl || "",
|
|
356
360
|
certificate: t.certificate
|
|
357
|
-
}), z("SAML metadata imported successfully! Review and save the configuration."), N(!0), V("")) : L(k("auth.sso.parseUrlError", "Failed to parse SAML metadata from URL."));
|
|
361
|
+
}), z(k("auth.sso.importSuccessFromUrl", "SAML metadata imported successfully! Review and save the configuration.")), N(!0), V("")) : L(k("auth.sso.parseUrlError", "Failed to parse SAML metadata from URL."));
|
|
358
362
|
} catch (e) {
|
|
359
363
|
L(e instanceof Error ? e.message : k("auth.sso.fetchError", "Failed to fetch metadata from URL"));
|
|
360
364
|
} finally {
|
|
@@ -452,17 +456,20 @@ function y() {
|
|
|
452
456
|
children: [
|
|
453
457
|
/* @__PURE__ */ g("div", { children: [
|
|
454
458
|
/* @__PURE__ */ g("label", {
|
|
459
|
+
htmlFor: "sso-entity-id",
|
|
455
460
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
456
461
|
children: [
|
|
457
462
|
k("auth.sso.idpEntityId", "IdP Entity ID / Issuer URL"),
|
|
458
463
|
" ",
|
|
459
464
|
/* @__PURE__ */ h("span", {
|
|
460
465
|
className: "text-status-error-text",
|
|
466
|
+
"aria-hidden": "true",
|
|
461
467
|
children: "*"
|
|
462
468
|
})
|
|
463
469
|
]
|
|
464
470
|
}),
|
|
465
471
|
/* @__PURE__ */ h("input", {
|
|
472
|
+
id: "sso-entity-id",
|
|
466
473
|
type: "url",
|
|
467
474
|
value: Q.entityId,
|
|
468
475
|
onChange: (e) => $({
|
|
@@ -472,26 +479,32 @@ function y() {
|
|
|
472
479
|
disabled: !M && !!x,
|
|
473
480
|
placeholder: k("auth.sso.idpEntityIdPlaceholder", "https://your-idp.example.com/saml/metadata"),
|
|
474
481
|
required: !0,
|
|
482
|
+
"aria-required": "true",
|
|
483
|
+
"aria-describedby": "sso-entity-id-hint",
|
|
475
484
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all"
|
|
476
485
|
}),
|
|
477
486
|
/* @__PURE__ */ h("p", {
|
|
487
|
+
id: "sso-entity-id-hint",
|
|
478
488
|
className: "mt-1 text-xs text-text-secondary",
|
|
479
489
|
children: k("auth.sso.idpEntityIdHelper", "The unique identifier of your Identity Provider")
|
|
480
490
|
})
|
|
481
491
|
] }),
|
|
482
492
|
/* @__PURE__ */ g("div", { children: [
|
|
483
493
|
/* @__PURE__ */ g("label", {
|
|
494
|
+
htmlFor: "sso-sso-url",
|
|
484
495
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
485
496
|
children: [
|
|
486
497
|
k("auth.sso.ssoUrl", "SSO URL (Login URL)"),
|
|
487
498
|
" ",
|
|
488
499
|
/* @__PURE__ */ h("span", {
|
|
489
500
|
className: "text-status-error-text",
|
|
501
|
+
"aria-hidden": "true",
|
|
490
502
|
children: "*"
|
|
491
503
|
})
|
|
492
504
|
]
|
|
493
505
|
}),
|
|
494
506
|
/* @__PURE__ */ h("input", {
|
|
507
|
+
id: "sso-sso-url",
|
|
495
508
|
type: "url",
|
|
496
509
|
value: Q.ssoUrl,
|
|
497
510
|
onChange: (e) => $({
|
|
@@ -501,19 +514,24 @@ function y() {
|
|
|
501
514
|
disabled: !M && !!x,
|
|
502
515
|
placeholder: k("auth.sso.ssoUrlPlaceholder", "https://your-idp.example.com/saml/sso"),
|
|
503
516
|
required: !0,
|
|
517
|
+
"aria-required": "true",
|
|
518
|
+
"aria-describedby": "sso-sso-url-hint",
|
|
504
519
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all"
|
|
505
520
|
}),
|
|
506
521
|
/* @__PURE__ */ h("p", {
|
|
522
|
+
id: "sso-sso-url-hint",
|
|
507
523
|
className: "mt-1 text-xs text-text-secondary",
|
|
508
524
|
children: k("auth.sso.ssoUrlHelper", "The URL where users are redirected to authenticate")
|
|
509
525
|
})
|
|
510
526
|
] }),
|
|
511
527
|
/* @__PURE__ */ g("div", { children: [
|
|
512
528
|
/* @__PURE__ */ h("label", {
|
|
529
|
+
htmlFor: "sso-slo-url",
|
|
513
530
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
514
531
|
children: k("auth.sso.sloUrl", "Single Logout (SLO) URL")
|
|
515
532
|
}),
|
|
516
533
|
/* @__PURE__ */ h("input", {
|
|
534
|
+
id: "sso-slo-url",
|
|
517
535
|
type: "url",
|
|
518
536
|
value: Q.sloUrl,
|
|
519
537
|
onChange: (e) => $({
|
|
@@ -522,26 +540,31 @@ function y() {
|
|
|
522
540
|
}),
|
|
523
541
|
disabled: !M && !!x,
|
|
524
542
|
placeholder: k("auth.sso.sloUrlPlaceholder", "https://your-idp.example.com/saml/slo"),
|
|
543
|
+
"aria-describedby": "sso-slo-url-hint",
|
|
525
544
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all"
|
|
526
545
|
}),
|
|
527
546
|
/* @__PURE__ */ h("p", {
|
|
547
|
+
id: "sso-slo-url-hint",
|
|
528
548
|
className: "mt-1 text-xs text-text-secondary",
|
|
529
549
|
children: k("auth.sso.sloUrlHelper", "Optional: URL for single logout across all applications")
|
|
530
550
|
})
|
|
531
551
|
] }),
|
|
532
552
|
/* @__PURE__ */ g("div", { children: [
|
|
533
553
|
/* @__PURE__ */ g("label", {
|
|
554
|
+
htmlFor: "sso-certificate",
|
|
534
555
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
535
556
|
children: [
|
|
536
557
|
k("auth.sso.certificate", "X.509 Certificate"),
|
|
537
558
|
" ",
|
|
538
559
|
/* @__PURE__ */ h("span", {
|
|
539
560
|
className: "text-status-error-text",
|
|
561
|
+
"aria-hidden": "true",
|
|
540
562
|
children: "*"
|
|
541
563
|
})
|
|
542
564
|
]
|
|
543
565
|
}),
|
|
544
566
|
/* @__PURE__ */ h("textarea", {
|
|
567
|
+
id: "sso-certificate",
|
|
545
568
|
value: Q.certificate,
|
|
546
569
|
onChange: (e) => $({
|
|
547
570
|
...Q,
|
|
@@ -550,10 +573,13 @@ function y() {
|
|
|
550
573
|
disabled: !M && !!x,
|
|
551
574
|
placeholder: k("auth.sso.certificatePlaceholder", "-----BEGIN CERTIFICATE-----\nMIIDpDCCAoygAwIBAgIGAX...\n-----END CERTIFICATE-----"),
|
|
552
575
|
required: !0,
|
|
576
|
+
"aria-required": "true",
|
|
577
|
+
"aria-describedby": "sso-certificate-hint",
|
|
553
578
|
rows: 6,
|
|
554
579
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all font-mono text-sm"
|
|
555
580
|
}),
|
|
556
581
|
/* @__PURE__ */ h("p", {
|
|
582
|
+
id: "sso-certificate-hint",
|
|
557
583
|
className: "mt-1 text-xs text-text-secondary",
|
|
558
584
|
children: k("auth.sso.certificateHelper", "The public X.509 certificate from your IdP for signature verification")
|
|
559
585
|
})
|
|
@@ -836,16 +862,19 @@ function y() {
|
|
|
836
862
|
className: "space-y-5",
|
|
837
863
|
children: [
|
|
838
864
|
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ g("label", {
|
|
865
|
+
htmlFor: "oidc-client-name",
|
|
839
866
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
840
867
|
children: [
|
|
841
868
|
k("auth.sso.clientName", "Client Name"),
|
|
842
869
|
" ",
|
|
843
870
|
/* @__PURE__ */ h("span", {
|
|
844
871
|
className: "text-status-error-text",
|
|
872
|
+
"aria-hidden": "true",
|
|
845
873
|
children: "*"
|
|
846
874
|
})
|
|
847
875
|
]
|
|
848
876
|
}), /* @__PURE__ */ h("input", {
|
|
877
|
+
id: "oidc-client-name",
|
|
849
878
|
type: "text",
|
|
850
879
|
value: K.client_name,
|
|
851
880
|
onChange: (e) => q({
|
|
@@ -853,21 +882,25 @@ function y() {
|
|
|
853
882
|
client_name: e.target.value
|
|
854
883
|
}),
|
|
855
884
|
placeholder: k("auth.sso.clientNamePlaceholder", "My Application"),
|
|
885
|
+
"aria-required": "true",
|
|
856
886
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all"
|
|
857
887
|
})] }),
|
|
858
888
|
/* @__PURE__ */ g("div", { children: [
|
|
859
889
|
/* @__PURE__ */ g("label", {
|
|
890
|
+
htmlFor: "oidc-redirect-uris",
|
|
860
891
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
861
892
|
children: [
|
|
862
893
|
k("auth.sso.redirectUris", "Redirect URIs"),
|
|
863
894
|
" ",
|
|
864
895
|
/* @__PURE__ */ h("span", {
|
|
865
896
|
className: "text-status-error-text",
|
|
897
|
+
"aria-hidden": "true",
|
|
866
898
|
children: "*"
|
|
867
899
|
})
|
|
868
900
|
]
|
|
869
901
|
}),
|
|
870
902
|
/* @__PURE__ */ h("input", {
|
|
903
|
+
id: "oidc-redirect-uris",
|
|
871
904
|
type: "text",
|
|
872
905
|
value: K.redirect_uris,
|
|
873
906
|
onChange: (e) => q({
|
|
@@ -875,9 +908,12 @@ function y() {
|
|
|
875
908
|
redirect_uris: e.target.value
|
|
876
909
|
}),
|
|
877
910
|
placeholder: k("auth.sso.redirectUrisPlaceholder", "http://localhost:3000/callback, https://app.example.com/callback"),
|
|
911
|
+
"aria-required": "true",
|
|
912
|
+
"aria-describedby": "oidc-redirect-uris-hint",
|
|
878
913
|
className: "block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all"
|
|
879
914
|
}),
|
|
880
915
|
/* @__PURE__ */ h("p", {
|
|
916
|
+
id: "oidc-redirect-uris-hint",
|
|
881
917
|
className: "mt-1 text-xs text-text-secondary",
|
|
882
918
|
children: k("auth.sso.redirectUrisHelper", "Separate multiple URIs with commas")
|
|
883
919
|
})
|
|
@@ -913,9 +949,11 @@ function y() {
|
|
|
913
949
|
}, e))
|
|
914
950
|
})] }),
|
|
915
951
|
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
952
|
+
htmlFor: "oidc-token-auth-method",
|
|
916
953
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
917
954
|
children: k("auth.sso.tokenEndpointAuth", "Token Endpoint Auth Method")
|
|
918
955
|
}), /* @__PURE__ */ g("select", {
|
|
956
|
+
id: "oidc-token-auth-method",
|
|
919
957
|
value: K.token_endpoint_auth_method,
|
|
920
958
|
onChange: (e) => q({
|
|
921
959
|
...K,
|