@burdenoff/microfe-auth 2026.520.2 → 2026.521.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/AuthRoot.d.ts.map +1 -1
- package/dist/auth/AuthRoot.js +9 -8
- package/dist/auth/AuthRoot.js.map +1 -1
- package/dist/auth/AuthRoutes.d.ts +2 -1
- package/dist/auth/AuthRoutes.d.ts.map +1 -1
- package/dist/auth/AuthRoutes.js +11 -11
- package/dist/auth/AuthRoutes.js.map +1 -1
- package/dist/auth/pages/AuditLogPage.d.ts.map +1 -1
- package/dist/auth/pages/AuditLogPage.js +49 -48
- package/dist/auth/pages/AuditLogPage.js.map +1 -1
- package/dist/auth/pages/SessionsPage.d.ts.map +1 -1
- package/dist/auth/pages/SessionsPage.js +133 -185
- package/dist/auth/pages/SessionsPage.js.map +1 -1
- package/dist/auth/pages/SsoConfigPage.d.ts +10 -3
- package/dist/auth/pages/SsoConfigPage.d.ts.map +1 -1
- package/dist/auth/pages/SsoConfigPage.js +440 -396
- package/dist/auth/pages/SsoConfigPage.js.map +1 -1
- package/dist/auth/pages/UserProfilePage.d.ts.map +1 -1
- package/dist/auth/pages/UserProfilePage.js +148 -145
- package/dist/auth/pages/UserProfilePage.js.map +1 -1
- package/dist/auth/types/index.d.ts +7 -0
- package/dist/auth/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuditLogPage.js","names":[],"sources":["../../../src/auth/pages/AuditLogPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useFeatureFlagDetails } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { formatDateTime } from \"../utils\";\nimport { AlertIcon, SpinnerIcon } from \"../components/AuthIcons\";\nimport {\n useAuthAuditLogsQuery,\n type AuditLogEntry_AuthAuditLogFragment,\n} from \"../../generated/global-operations\";\nimport { useCreateAuthExportJobMutation } from \"../../generated/wspace-operations\";\n\nconst PAGE_SIZE = 20;\n\n/**\n * Security audit log page with pagination and export\n *\n * Fragment: AuditLogEntry_AuthAuditLog (graphql/operations/global/fragments/AuditLogEntry.fragment.graphql)\n * Query: AuthAuditLogs (graphql/operations/global/queries/auditLog.graphql)\n *\n * TODO: When authAuditLogs backend migrates to AuthAuditLogConnection type,\n * update this query to use: authAuditLogs { auditLogs: [...], totalCount, hasMore }\n * and remove the client-side hasMore approximation below.\n */\nexport function AuditLogPage() {\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 [page, setPage] = useState(1);\n const offset = (page - 1) * PAGE_SIZE;\n\n // Default-deny: only show when the flag is explicitly enabled in the system.\n // useFeatureFlag uses default-allow (returns true when not found), so we use\n // useFeatureFlagDetails + explicit value check instead.\n const auditLogFlag = useFeatureFlagDetails(\"auth.audit-log\");\n const showAuditLog = auditLogFlag?.value === true;\n\n const { data, loading, error } = useAuthAuditLogsQuery({\n skip: !showAuditLog,\n fetchPolicy: \"cache-and-network\",\n variables: { pagination: { limit: PAGE_SIZE, offset } },\n });\n\n const auditLogs = data?.authAuditLogs ?? [];\n // Approximate hasMore: if we received a full page there may be more\n const hasMore = auditLogs.length === PAGE_SIZE;\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: \"Audit Log Export\",\n // permission_audit_logs covers auth audit logs in the export system\n entityTypes: [\"permission_audit_logs\"],\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 getEventMarker = (eventType: string) => {\n switch (eventType) {\n case \"LOGIN_SUCCESS\":\n return \"OK\";\n case \"LOGIN_FAILURE\":\n return \"ER\";\n case \"LOGOUT\":\n return \"LO\";\n case \"PASSWORD_CHANGE\":\n return \"PW\";\n case \"MFA_ENABLED\":\n case \"MFA_VERIFIED\":\n return \"MF\";\n case \"ANOMALY_DETECTED\":\n return \"AL\";\n default:\n return \"AU\";\n }\n };\n\n if (!showAuditLog) {\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.auditLog.notAvailable\", \"Page Not Available\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.auditLog.notEnabled\",\n \"The Security Audit Log is not enabled for your account.\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.auditLog.title\", \"Security Audit Log\")}\n </h1>\n <button\n type=\"button\"\n onClick={() => void handleExport()}\n disabled={isExporting}\n aria-label={tr(\"auth.auditLog.exportAriaLabel\", \"Export audit log\")}\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.auditLog.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.auditLog.export\", \"Export\")}\n </>\n )}\n </button>\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 {loading ? (\n <div aria-live=\"polite\" aria-busy=\"true\" className=\"text-center py-12\">\n <SpinnerIcon\n className=\"w-8 h-8 mx-auto text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <p className=\"mt-3 text-text-secondary\">\n {tr(\"auth.auditLog.loading\", \"Loading audit events...\")}\n </p>\n </div>\n ) : error ? (\n <div\n role=\"alert\"\n className=\"text-center py-12 border border-status-error-border rounded-xl bg-status-error-bg-subtle\"\n >\n <p className=\"text-status-error-text\">\n {tr(\"auth.auditLog.error\", \"Unable to load audit events\")}\n </p>\n </div>\n ) : auditLogs.length === 0 ? (\n <div className=\"text-center py-12\" role=\"status\">\n <p className=\"text-text-secondary\">\n {tr(\"auth.auditLog.noEvents\", \"No security events recorded\")}\n </p>\n </div>\n ) : (\n <>\n <div className=\"space-y-4\" aria-live=\"polite\" aria-busy={loading}>\n {auditLogs.map((event: AuditLogEntry_AuthAuditLogFragment) => (\n <div\n key={event.id}\n className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-bg-muted text-xs font-semibold text-text-secondary\"\n aria-hidden=\"true\"\n >\n {getEventMarker(event.action)}\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-medium text-text-primary mb-1\">\n {event.action.replace(/_/g, \" \")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-2\">\n <time dateTime={event.createdAt}>\n {formatDateTime(event.createdAt)}\n </time>\n </p>\n <p className=\"text-sm text-text-secondary\">\n {event.description ??\n tr(\n \"auth.auditLog.defaultDescription\",\n \"Authentication event\",\n )}\n {event.ipAddress && ` • ${event.ipAddress}`}\n </p>\n </div>\n {event.action.includes(\"FAILURE\") && (\n <span\n role=\"status\"\n className=\"px-3 py-1 rounded-full bg-status-error-bg-subtle text-status-error-text text-sm font-medium\"\n >\n {tr(\"auth.auditLog.failed\", \"Failed\")}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <nav\n aria-label={tr(\n \"auth.auditLog.paginationAriaLabel\",\n \"Audit log pagination\",\n )}\n className=\"mt-6 flex items-center justify-between\"\n >\n <p className=\"text-sm text-text-secondary\">\n {tr(\"auth.auditLog.page\", \"Page\")} {page}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => setPage((prev) => Math.max(1, prev - 1))}\n disabled={page === 1}\n aria-label={tr(\n \"auth.auditLog.previousPageAriaLabel\",\n \"Go to previous page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.auditLog.previous\", \"Previous\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setPage((prev) => prev + 1)}\n disabled={!hasMore}\n aria-label={tr(\n \"auth.auditLog.nextPageAriaLabel\",\n \"Go to next page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.auditLog.next\", \"Next\")}\n </button>\n </div>\n </nav>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAWA,IAAM,IAAY;AAYlB,SAAgB,IAAe;CAC7B,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAGnC,CAAC,GAAM,KAAW,EAAS,EAAE,EAC7B,KAAU,IAAO,KAAK,GAMtB,IADe,EAAsB,iBAAiB,EACzB,UAAU,IAEvC,EAAE,SAAM,YAAS,aAAU,EAAsB;EACrD,MAAM,CAAC;EACP,aAAa;EACb,WAAW,EAAE,YAAY;GAAE,OAAO;GAAW;GAAQ,EAAE;EACxD,CAAC,EAEI,IAAY,GAAM,iBAAiB,EAAE,EAErC,IAAU,EAAU,WAAW,GAE/B,CAAC,GAAiB,EAAE,SAAS,OACjC,GAAgC,EAC5B,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAe,YAAY;AAC/B,IAAe,KAAK;AACpB,MAAI;AACF,SAAM,EAAgB,EACpB,WAAW,EACT,OAAO;IACL,MAAM;IAEN,aAAa,CAAC,wBAAwB;IACtC,QAAQ;IACR,aAAa;IACb,iBAAiB;IAClB,EACF,EACF,CAAC;WACK,GAAK;AACZ,KACE,aAAe,QAAQ,EAAI,UAAU,yBACtC;;IAIC,KAAkB,MAAsB;AAC5C,UAAQ,GAAR;GACE,KAAK,gBACH,QAAO;GACT,KAAK,gBACH,QAAO;GACT,KAAK,SACH,QAAO;GACT,KAAK,kBACH,QAAO;GACT,KAAK;GACL,KAAK,eACH,QAAO;GACT,KAAK,mBACH,QAAO;GACT,QACE,QAAO;;;AA4Bb,QAxBK,IAyBH,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,uBAAuB,qBAAqB;KAC7C,CAAA,EACL,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,KAAK,GAAc;KAClC,UAAU;KACV,cAAY,EAAG,iCAAiC,mBAAmB;KACnE,WAAU;eAET,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;MACE,WAAU;MACV,eAAY;MACZ,CAAA,EACD,EAAG,2BAA2B,eAAe,CAC7C,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;MACE,WAAU;MACV,MAAK;MACL,SAAQ;MACR,QAAO;MACP,eAAY;gBAEZ,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA,EACL,EAAG,wBAAwB,SAAS,CACpC,EAAA,CAAA;KAEE,CAAA,CACL;;GAGL,KACC,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;cAFZ,CAIE,kBAAC,GAAD;KACE,WAAU;KACV,eAAY;KACZ,CAAA,EACF,kBAAC,KAAD;KAAG,WAAU;eAAkC;KAAgB,CAAA,CAC3D;;GAGP,IACC,kBAAC,OAAD;IAAK,aAAU;IAAS,aAAU;IAAO,WAAU;cAAnD,CACE,kBAAC,GAAD;KACE,WAAU;KACV,eAAY;KACZ,CAAA,EACF,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,yBAAyB,0BAA0B;KACrD,CAAA,CACA;QACJ,IACF,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;cAEV,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,uBAAuB,8BAA8B;KACvD,CAAA;IACA,CAAA,GACJ,EAAU,WAAW,IACvB,kBAAC,OAAD;IAAK,WAAU;IAAoB,MAAK;cACtC,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,0BAA0B,8BAA8B;KAC1D,CAAA;IACA,CAAA,GAEN,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAY,aAAU;IAAS,aAAW;cACtD,EAAU,KAAK,MACd,kBAAC,OAAD;KAEE,WAAU;eAEV,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QACE,WAAU;QACV,eAAY;kBAEX,EAAe,EAAM,OAAO;QACzB,CAAA;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAM,OAAO,QAAQ,MAAM,IAAI;UAC7B,CAAA;SACL,kBAAC,KAAD;UAAG,WAAU;oBACX,kBAAC,QAAD;WAAM,UAAU,EAAM;qBACnB,EAAe,EAAM,UAAU;WAC3B,CAAA;UACL,CAAA;SACJ,kBAAC,KAAD;UAAG,WAAU;oBAAb,CACG,EAAM,eACL,EACE,oCACA,uBACD,EACF,EAAM,aAAa,MAAM,EAAM,YAC9B;;SACA;;OACL,EAAM,OAAO,SAAS,UAAU,IAC/B,kBAAC,QAAD;QACE,MAAK;QACL,WAAU;kBAET,EAAG,wBAAwB,SAAS;QAChC,CAAA;OAEL;;KACF,EArCC,EAAM,GAqCP,CACN;IACE,CAAA,EAGN,kBAAC,OAAD;IACE,cAAY,EACV,qCACA,uBACD;IACD,WAAU;cALZ,CAOE,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAG,sBAAsB,OAAO;MAAC;MAAE;MAClC;QACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAS,MAAS,KAAK,IAAI,GAAG,IAAO,EAAE,CAAC;MACvD,UAAU,MAAS;MACnB,cAAY,EACV,uCACA,sBACD;MACD,WAAU;gBAET,EAAG,0BAA0B,WAAW;MAClC,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAS,MAAS,IAAO,EAAE;MAC1C,UAAU,CAAC;MACX,cAAY,EACV,mCACA,kBACD;MACD,WAAU;gBAET,EAAG,sBAAsB,OAAO;MAC1B,CAAA,CACL;OACF;MACL,EAAA,CAAA;GAED;MA/LJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,WAAU;MACV,eAAY;MACZ,CAAA;KACE,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,8BAA8B,qBAAqB;KACpD,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,4BACA,0DACD;KACC,CAAA;IACA;;EACF,CAAA"}
|
|
1
|
+
{"version":3,"file":"AuditLogPage.js","names":[],"sources":["../../../src/auth/pages/AuditLogPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useGatewayClient } from \"@burdenoff/fe-libs/shared/graphql\";\nimport { useFeatureFlagDetails } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { formatDateTime } from \"../utils\";\nimport { AlertIcon, SpinnerIcon } from \"../components/AuthIcons\";\nimport {\n useAuthAuditLogsQuery,\n type AuditLogEntry_AuthAuditLogFragment,\n} from \"../../generated/global-operations\";\nimport { useCreateAuthExportJobMutation } from \"../../generated/wspace-operations\";\n\nconst PAGE_SIZE = 20;\n\n/**\n * Security audit log page with pagination and export\n *\n * Fragment: AuditLogEntry_AuthAuditLog (graphql/operations/global/fragments/AuditLogEntry.fragment.graphql)\n * Query: AuthAuditLogs (graphql/operations/global/queries/auditLog.graphql)\n *\n * TODO: When authAuditLogs backend migrates to AuthAuditLogConnection type,\n * update this query to use: authAuditLogs { auditLogs: [...], totalCount, hasMore }\n * and remove the client-side hasMore approximation below.\n */\nexport function AuditLogPage() {\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 [page, setPage] = useState(1);\n const offset = (page - 1) * PAGE_SIZE;\n\n // Default-deny: only show when the flag is explicitly enabled in the system.\n // useFeatureFlag uses default-allow (returns true when not found), so we use\n // useFeatureFlagDetails + explicit value check instead.\n const auditLogFlag = useFeatureFlagDetails(\"auth.audit-log\");\n const showAuditLog = auditLogFlag?.value === true;\n\n const { data, loading, error } = useAuthAuditLogsQuery({\n skip: !showAuditLog,\n fetchPolicy: \"cache-and-network\",\n variables: { pagination: { limit: PAGE_SIZE, offset } },\n });\n\n const auditLogs = data?.authAuditLogs ?? [];\n // Approximate hasMore: if we received a full page there may be more\n const hasMore = auditLogs.length === PAGE_SIZE;\n\n const wspaceClient = useGatewayClient(\"workspace\");\n const [createExportJob, { loading: isExporting }] =\n useCreateAuthExportJobMutation({ client: wspaceClient });\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: \"Audit Log Export\",\n // permission_audit_logs covers auth audit logs in the export system\n entityTypes: [\"permission_audit_logs\"],\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 getEventMarker = (eventType: string) => {\n switch (eventType) {\n case \"LOGIN_SUCCESS\":\n return \"OK\";\n case \"LOGIN_FAILURE\":\n return \"ER\";\n case \"LOGOUT\":\n return \"LO\";\n case \"PASSWORD_CHANGE\":\n return \"PW\";\n case \"MFA_ENABLED\":\n case \"MFA_VERIFIED\":\n return \"MF\";\n case \"ANOMALY_DETECTED\":\n return \"AL\";\n default:\n return \"AU\";\n }\n };\n\n if (!showAuditLog) {\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.auditLog.notAvailable\", \"Page Not Available\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.auditLog.notEnabled\",\n \"The Security Audit Log is not enabled for your account.\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.auditLog.title\", \"Security Audit Log\")}\n </h1>\n <button\n type=\"button\"\n onClick={() => void handleExport()}\n disabled={isExporting}\n aria-label={tr(\"auth.auditLog.exportAriaLabel\", \"Export audit log\")}\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.auditLog.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.auditLog.export\", \"Export\")}\n </>\n )}\n </button>\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 {loading ? (\n <div aria-live=\"polite\" aria-busy=\"true\" className=\"text-center py-12\">\n <SpinnerIcon\n className=\"w-8 h-8 mx-auto text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <p className=\"mt-3 text-text-secondary\">\n {tr(\"auth.auditLog.loading\", \"Loading audit events...\")}\n </p>\n </div>\n ) : error ? (\n <div\n role=\"alert\"\n className=\"text-center py-12 border border-status-error-border rounded-xl bg-status-error-bg-subtle\"\n >\n <p className=\"text-status-error-text\">\n {tr(\"auth.auditLog.error\", \"Unable to load audit events\")}\n </p>\n </div>\n ) : auditLogs.length === 0 ? (\n <div className=\"text-center py-12\" role=\"status\">\n <p className=\"text-text-secondary\">\n {tr(\"auth.auditLog.noEvents\", \"No security events recorded\")}\n </p>\n </div>\n ) : (\n <>\n <div className=\"space-y-4\" aria-live=\"polite\" aria-busy={loading}>\n {auditLogs.map((event: AuditLogEntry_AuthAuditLogFragment) => (\n <div\n key={event.id}\n className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-bg-muted text-xs font-semibold text-text-secondary\"\n aria-hidden=\"true\"\n >\n {getEventMarker(event.action)}\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-medium text-text-primary mb-1\">\n {event.action.replace(/_/g, \" \")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-2\">\n <time dateTime={event.createdAt}>\n {formatDateTime(event.createdAt)}\n </time>\n </p>\n <p className=\"text-sm text-text-secondary\">\n {event.description ??\n tr(\n \"auth.auditLog.defaultDescription\",\n \"Authentication event\",\n )}\n {event.ipAddress && ` • ${event.ipAddress}`}\n </p>\n </div>\n {event.action.includes(\"FAILURE\") && (\n <span\n role=\"status\"\n className=\"px-3 py-1 rounded-full bg-status-error-bg-subtle text-status-error-text text-sm font-medium\"\n >\n {tr(\"auth.auditLog.failed\", \"Failed\")}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n\n {/* Pagination */}\n <nav\n aria-label={tr(\n \"auth.auditLog.paginationAriaLabel\",\n \"Audit log pagination\",\n )}\n className=\"mt-6 flex items-center justify-between\"\n >\n <p className=\"text-sm text-text-secondary\">\n {tr(\"auth.auditLog.page\", \"Page\")} {page}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => setPage((prev) => Math.max(1, prev - 1))}\n disabled={page === 1}\n aria-label={tr(\n \"auth.auditLog.previousPageAriaLabel\",\n \"Go to previous page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.auditLog.previous\", \"Previous\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setPage((prev) => prev + 1)}\n disabled={!hasMore}\n aria-label={tr(\n \"auth.auditLog.nextPageAriaLabel\",\n \"Go to next page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.auditLog.next\", \"Next\")}\n </button>\n </div>\n </nav>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionsPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/SessionsPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SessionsPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/SessionsPage.tsx"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,wBAAgB,YAAY,4CAoe3B"}
|