@webx-ui/module-audit 0.5.1 → 0.5.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.
Files changed (21) hide show
  1. package/dist/{AuditHostsPage-YFRORYHZ.js → AuditHostsPage-CSAlf3jK.js} +3 -3
  2. package/dist/{AuditHostsPage-YFRORYHZ.js.map → AuditHostsPage-CSAlf3jK.js.map} +1 -1
  3. package/dist/AuditIssuesPage-DtEJ9Sgq.js +718 -0
  4. package/dist/AuditIssuesPage-DtEJ9Sgq.js.map +1 -0
  5. package/dist/{AuditLayout.vue_vue_type_script_setup_true_lang-C8H5jlTe.js → AuditLayout.vue_vue_type_script_setup_true_lang-C39k6JNr.js} +2 -2
  6. package/dist/{AuditLayout.vue_vue_type_script_setup_true_lang-C8H5jlTe.js.map → AuditLayout.vue_vue_type_script_setup_true_lang-C39k6JNr.js.map} +1 -1
  7. package/dist/{AuditOverviewPage-gVpdBOAY.js → AuditOverviewPage-B5mexNDW.js} +3 -3
  8. package/dist/{AuditOverviewPage-gVpdBOAY.js.map → AuditOverviewPage-B5mexNDW.js.map} +1 -1
  9. package/dist/{AuditPagesPage-DNgZo-K-.js → AuditPagesPage-C1Akv4Ql.js} +3 -3
  10. package/dist/{AuditPagesPage-DNgZo-K-.js.map → AuditPagesPage-C1Akv4Ql.js.map} +1 -1
  11. package/dist/{AuditRunsPage-BbWsuATw.js → AuditRunsPage-SlBisvcG.js} +3 -3
  12. package/dist/{AuditRunsPage-BbWsuATw.js.map → AuditRunsPage-SlBisvcG.js.map} +1 -1
  13. package/dist/{AuditSettingsPage-HwfdLU_s.js → AuditSettingsPage-ADutjdIO.js} +3 -3
  14. package/dist/{AuditSettingsPage-HwfdLU_s.js.map → AuditSettingsPage-ADutjdIO.js.map} +1 -1
  15. package/dist/{index-BFYHJYU_.js → index-_DgRf2O6.js} +8 -8
  16. package/dist/{index-BFYHJYU_.js.map → index-_DgRf2O6.js.map} +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/style.css +1 -1
  19. package/package.json +4 -4
  20. package/dist/AuditIssuesPage-BjTPgAnD.js +0 -693
  21. package/dist/AuditIssuesPage-BjTPgAnD.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AuditRunsPage-BbWsuATw.js","sources":["../src/AuditCompareIssues.vue","../src/AuditRunsPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport { WxButton, WxLink, WxSegmented, WxSkeleton, WxText } from '@webx-ui/core'\nimport AuditDetails from './AuditDetails.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\nimport type { AuditComparisonKind, AuditComparisonRow, AuditIssue } from './types'\n\n/**\n * One check of a comparison opened: its new, fixed or persisting findings, fifty at a time —\n * fixed ones as the earlier run stored them, the others from the later run.\n */\nconst props = defineProps<{ from: number; to: number; row: AuditComparisonRow }>()\n\nconst api = createAuditApi(useAdmin())\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst message = useErrorText()\n\nconst KINDS: AuditComparisonKind[] = ['new', 'fixed', 'persisting']\n\n/* Open on what changed: new first, then fixed — persisting only when nothing else is there. */\nconst kind = ref<AuditComparisonKind>(KINDS.find((one) => props.row[one] > 0) ?? 'new')\nconst issues = ref<AuditIssue[] | null>(null)\nconst page = ref(1)\nconst more = ref(false)\nconst failure = ref<string | null>(null)\n\nconst options = computed(() =>\n KINDS.map((value) => ({\n value,\n label: `${t(`page.kind-${value}`)} · ${props.row[value]}`,\n disabled: props.row[value] === 0,\n })),\n)\n\nasync function load(next = 1): Promise<void> {\n failure.value = null\n\n try {\n const answer = await api.compareIssues({\n from: props.from,\n to: props.to,\n kind: kind.value,\n check: props.row.check,\n page: next,\n per_page: 50,\n })\n\n issues.value = next === 1 ? answer.data : [...(issues.value ?? []), ...answer.data]\n page.value = answer.current_page\n more.value = answer.current_page < answer.last_page\n } catch (error) {\n failure.value = message(error)\n }\n}\n\nwatch(\n kind,\n () => {\n issues.value = null\n void load()\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <div class=\"wx-audit-compare\">\n <wx-segmented v-model=\"kind\" :options=\"options\" size=\"sm\" :aria-label=\"t('page.compare')\" />\n\n <wx-text v-if=\"failure\" size=\"sm\" tone=\"danger\">{{ failure }}</wx-text>\n <wx-skeleton v-else-if=\"!issues\" :rows=\"2\" />\n\n <template v-else>\n <div v-for=\"issue in issues\" :key=\"issue.id\" class=\"wx-audit-compare__item\">\n <wx-link v-if=\"issue.url\" :href=\"issue.url\" target=\"_blank\" class=\"wx-audit-compare__url\">{{\n issue.url\n }}</wx-link>\n <audit-details :details=\"issue.details\" />\n </div>\n\n <wx-button v-if=\"more\" size=\"sm\" variant=\"text\" @click=\"load(page + 1)\">…</wx-button>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-audit-compare {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n min-width: 0;\n}\n\n.wx-audit-compare__item {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n\n.wx-audit-compare__url {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n toast,\n WxAlert,\n WxBadge,\n WxCard,\n WxTable,\n WxText,\n type BadgeType,\n type RowKey,\n type TableColumn,\n type TableState,\n} from '@webx-ui/core'\nimport AuditCompareIssues from './AuditCompareIssues.vue'\nimport AuditLayout from './AuditLayout.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\nimport type {\n AuditComparison,\n AuditComparisonRow,\n AuditPage,\n AuditRun,\n AuditRunStatus,\n AuditSeverity,\n} from './types'\n\n/**\n * The history (§8 «Runs»): every run kept, newest first, with its health and counts. Ticking a\n * run compares it with the one it was analysed against; ticking two compares those two — by\n * fingerprint (decision 8): what is new in the later one, what both have, what is gone. `?to=`\n * opens on one run already ticked — the way the page card's recheck leads here. In the head, for\n * whoever manages the section, the way to clear every run at once, behind a warning.\n */\nconst props = defineProps<{ base: string }>()\n\nconst context = useAdmin()\nconst api = createAuditApi(context)\nconst route = useRoute()\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst message = useErrorText()\n\nconst runs = ref<AuditPage<AuditRun> | null>(null)\nconst loading = ref(false)\nconst selected = ref<RowKey[]>([])\nconst comparison = ref<AuditComparison | null>(null)\nconst comparing = ref(false)\nconst expanded = ref<RowKey[]>([])\nconst clearing = ref(false)\n\n// A boolean, not a computed: the permissions do not change while the screen is open.\nconst canManage = context.can('audit.manage')\n\nconst statuses: Record<AuditRunStatus, BadgeType> = {\n queued: 'info',\n running: 'primary',\n done: 'success',\n failed: 'danger',\n cancelled: 'warning',\n}\n\nconst severities: Record<AuditSeverity, BadgeType> = {\n error: 'danger',\n warning: 'warning',\n notice: 'info',\n}\n\nconst columns = computed<TableColumn<AuditRun>[]>(() => [\n { key: 'id', label: t('page.run-id'), width: 90 },\n { key: 'created_at', label: t('page.started-at'), minWidth: 160 },\n { key: 'scope', label: t('page.scope'), width: 120 },\n { key: 'status', label: t('page.status'), width: 130 },\n { key: 'health', label: t('page.health'), width: 100, align: 'right' },\n { key: 'severity', label: t('page.severity'), minWidth: 170, hideBelow: 640 },\n { key: 'started_by', label: t('page.started-by'), minWidth: 130, hideBelow: 760 },\n])\n\nconst compareColumns = computed<TableColumn<AuditComparisonRow>[]>(() => [\n { key: 'severity', label: t('page.severity'), width: 130 },\n { key: 'title', label: t('page.check') },\n { key: 'new', label: t('page.kind-new'), width: 90, align: 'right' },\n { key: 'fixed', label: t('page.kind-fixed'), width: 100, align: 'right' },\n { key: 'persisting', label: t('page.kind-persisting'), width: 120, align: 'right' },\n])\n\n/* What the selection means: one run against its own previous, or two against each other. */\nconst pair = computed<{ to: number; from: number | null } | null>(() => {\n const ids = selected.value.map(Number).sort((a, b) => a - b)\n\n if (ids.length === 0) return null\n\n return ids.length === 1\n ? { to: ids[0]!, from: null }\n : { to: ids[ids.length - 1]!, from: ids[0]! }\n})\n\nconst scopesDiffer = computed(\n () => comparison.value !== null && comparison.value.from.scope !== comparison.value.to.scope,\n)\n\nfunction who(run: AuditRun): string {\n if (run.started_by === 'schedule') return t('page.by-schedule')\n if (run.started_by === 'mcp') return t('page.by-mcp')\n if (run.started_by === 'console') return t('page.by-console')\n\n return run.started_by ? t('page.by-person') : ''\n}\n\nasync function load(state?: TableState): Promise<void> {\n loading.value = true\n\n try {\n runs.value = await api.runs({ page: state?.page ?? 1, per_page: state?.perPage ?? 20 })\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nasync function compare(): Promise<void> {\n const current = pair.value\n\n comparison.value = null\n expanded.value = []\n\n if (!current) return\n\n comparing.value = true\n\n try {\n comparison.value = await api.compare(current.to, current.from)\n } catch (error) {\n toast.danger(message(error))\n } finally {\n comparing.value = false\n }\n}\n\n// Danger, so the head puts it in its `···`: never a red button beside the section's name.\nconst actions = computed<ScreenAction[]>(() =>\n canManage && runs.value?.total\n ? [\n {\n key: 'clear',\n label: t('page.clear'),\n icon: 'trash',\n danger: true,\n disabled: clearing.value,\n run: () => void clear(),\n },\n ]\n : [],\n)\n\nasync function clear(): Promise<void> {\n const agreed = await confirm({\n title: t('page.clear-title'),\n message: t('page.clear-text'),\n confirmText: t('page.clear-confirm'),\n cancelText: t('page.clear-cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n clearing.value = true\n\n try {\n await api.clear()\n selected.value = []\n toast.success(t('page.cleared'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n clearing.value = false\n }\n}\n\nonMounted(() => {\n const to = Number(route.query.to)\n\n if (Number.isInteger(to) && to > 0) selected.value = [to]\n})\n\nwatch(selected, (keys) => {\n /* Two at most: a third tick replaces the oldest one. */\n if (keys.length > 2) selected.value = keys.slice(-2)\n else void compare()\n})\n</script>\n\n<template>\n <audit-layout :base=\"props.base\" current=\"runs\" :card=\"false\" :actions=\"actions\">\n <div class=\"wx-audit-runs\">\n <wx-card>\n <!-- Above the table, not under it: read before ticking, not found after scrolling. -->\n <wx-alert\n v-if=\"!pair && runs?.total\"\n type=\"info\"\n :description=\"t('page.compare-help')\"\n class=\"wx-audit-runs__note\"\n />\n\n <wx-table\n v-model:selected=\"selected\"\n :data=\"runs\"\n :columns=\"columns\"\n row-key=\"id\"\n selectable\n :selectable-if=\"(row: AuditRun) => row.status === 'done'\"\n flush\n :loading=\"loading\"\n :empty-text=\"t('page.runs-empty')\"\n @state-change=\"load\"\n >\n <template #cell-created_at=\"{ row }\"><wx-date :value=\"row.created_at\" /></template>\n <template #cell-scope=\"{ row }\">{{ t(`page.scope-${row.scope}`) }}</template>\n <template #cell-status=\"{ row }\">\n <wx-badge :type=\"statuses[row.status]\" dot>{{\n t(`page.status-${row.status}`)\n }}</wx-badge>\n </template>\n <template #cell-health=\"{ row }\">{{\n row.counts ? `${row.counts.health}%` : ''\n }}</template>\n <template #cell-severity=\"{ row }\">\n <span v-if=\"row.counts\" class=\"wx-audit-runs__counts\">\n <template v-for=\"(type, key) in severities\" :key=\"key\">\n <wx-badge v-if=\"row.counts.severity[key]\" :type=\"type\" size=\"sm\">{{\n row.counts.severity[key]\n }}</wx-badge>\n </template>\n </span>\n </template>\n <template #cell-started_by=\"{ row }\">{{ who(row) }}</template>\n </wx-table>\n </wx-card>\n\n <wx-card v-if=\"pair\" :title=\"t('page.compare')\">\n <wx-text v-if=\"comparison\" size=\"sm\" tone=\"muted\" class=\"wx-audit-runs__pair\">\n {{ t('page.compare-from') }} #{{ comparison.from.id }} ·\n <wx-date :value=\"comparison.from.created_at\" /> → {{ t('page.compare-to') }} #{{\n comparison.to.id\n }}\n · <wx-date :value=\"comparison.to.created_at\" />\n </wx-text>\n\n <wx-alert\n v-if=\"scopesDiffer\"\n type=\"info\"\n :description=\"t('page.compare-scopes')\"\n class=\"wx-audit-runs__note\"\n />\n\n <wx-table\n v-model:expanded=\"expanded\"\n :data=\"comparison?.checks ?? []\"\n :columns=\"compareColumns\"\n row-key=\"check\"\n expandable\n flush\n :pagination=\"false\"\n :loading=\"comparing\"\n :empty-text=\"t('page.compare-none')\"\n >\n <template #cell-severity=\"{ row }\">\n <wx-badge :type=\"severities[row.severity]\" dot>{{\n t(`page.severity-${row.severity}`)\n }}</wx-badge>\n </template>\n <template #cell-new=\"{ row }\">\n <wx-text :tone=\"row.new ? 'danger' : 'muted'\" size=\"sm\">{{ row.new }}</wx-text>\n </template>\n <template #cell-fixed=\"{ row }\">\n <wx-text :tone=\"row.fixed ? 'success' : 'muted'\" size=\"sm\">{{ row.fixed }}</wx-text>\n </template>\n <template #expanded=\"{ row }\">\n <audit-compare-issues\n v-if=\"comparison\"\n :from=\"comparison.from.id\"\n :to=\"comparison.to.id\"\n :row=\"row\"\n />\n </template>\n </wx-table>\n </wx-card>\n </div>\n </audit-layout>\n</template>\n\n<style scoped>\n.wx-audit-runs {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n min-width: 0;\n}\n\n.wx-audit-runs__counts {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--wx-space-4);\n}\n\n.wx-audit-runs__pair {\n display: block;\n margin-bottom: var(--wx-space-12);\n}\n\n.wx-audit-runs__note {\n margin-bottom: var(--wx-space-12);\n}\n</style>\n"],"names":["props","__props","api","createAuditApi","useAdmin","useAuditMessages","t","useTranslate","message","useErrorText","KINDS","kind","ref","one","issues","page","more","failure","options","computed","value","load","next","answer","error","watch","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxSegmented","$event","_createBlock","WxText","_Fragment","_renderList","issue","WxLink","_createTextVNode","_toDisplayString","AuditDetails","WxButton","_cache","WxSkeleton","context","route","useRoute","runs","loading","selected","comparison","comparing","expanded","clearing","canManage","statuses","severities","columns","compareColumns","pair","ids","a","b","scopesDiffer","who","run","state","toast","compare","current","actions","clear","confirm","onMounted","to","keys","AuditLayout","_createElementVNode","WxCard","WxAlert","WxTable","row","_withCtx","WxDate","WxBadge","_hoisted_2","type","key","AuditCompareIssues"],"mappings":";;;;;;;;;;;;;;AAaA,UAAMA,IAAQC,GAERC,IAAMC,EAAeC,GAAU;AACrC,IAAAC,EAAA;AAEA,UAAMC,IAAIC,EAAa,YAAY,GAC7BC,IAAUC,EAAA,GAEVC,IAA+B,CAAC,OAAO,SAAS,YAAY,GAG5DC,IAAOC,EAAyBF,EAAM,KAAK,CAACG,MAAQb,EAAM,IAAIa,CAAG,IAAI,CAAC,KAAK,KAAK,GAChFC,IAASF,EAAyB,IAAI,GACtCG,IAAOH,EAAI,CAAC,GACZI,IAAOJ,EAAI,EAAK,GAChBK,IAAUL,EAAmB,IAAI,GAEjCM,IAAUC;AAAA,MAAS,MACvBT,EAAM,IAAI,CAACU,OAAW;AAAA,QACpB,OAAAA;AAAA,QACA,OAAO,GAAGd,EAAE,aAAac,CAAK,EAAE,CAAC,MAAMpB,EAAM,IAAIoB,CAAK,CAAC;AAAA,QACvD,UAAUpB,EAAM,IAAIoB,CAAK,MAAM;AAAA,MAAA,EAC/B;AAAA,IAAA;AAGJ,mBAAeC,EAAKC,IAAO,GAAkB;AAC3C,MAAAL,EAAQ,QAAQ;AAEhB,UAAI;AACF,cAAMM,IAAS,MAAMrB,EAAI,cAAc;AAAA,UACrC,MAAMF,EAAM;AAAA,UACZ,IAAIA,EAAM;AAAA,UACV,MAAMW,EAAK;AAAA,UACX,OAAOX,EAAM,IAAI;AAAA,UACjB,MAAMsB;AAAA,UACN,UAAU;AAAA,QAAA,CACX;AAED,QAAAR,EAAO,QAAQQ,MAAS,IAAIC,EAAO,OAAO,CAAC,GAAIT,EAAO,SAAS,CAAA,GAAK,GAAGS,EAAO,IAAI,GAClFR,EAAK,QAAQQ,EAAO,cACpBP,EAAK,QAAQO,EAAO,eAAeA,EAAO;AAAA,MAC5C,SAASC,GAAO;AACd,QAAAP,EAAQ,QAAQT,EAAQgB,CAAK;AAAA,MAC/B;AAAA,IACF;AAEA,WAAAC;AAAA,MACEd;AAAA,MACA,MAAM;AACJ,QAAAG,EAAO,QAAQ,MACVO,EAAA;AAAA,MACP;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK,cAKlBK,EAAA,GAAAC,EAgBM,OAhBNC,IAgBM;AAAA,MAfJC,EAA4FC,EAAAC,EAAA,GAAA;AAAA,oBAArEpB,EAAA;AAAA,sDAAAA,EAAI,QAAAqB;AAAA,QAAG,SAASd,EAAA;AAAA,QAAS,MAAK;AAAA,QAAM,cAAYY,EAAAxB,CAAA,EAAC,cAAA;AAAA,MAAA;MAEzDW,EAAA,cAAfgB,EAAuEH,EAAAI,CAAA,GAAA;AAAA;QAA/C,MAAK;AAAA,QAAK,MAAK;AAAA,MAAA;mBAAS,MAAa;AAAA,cAAVjB,EAAA,KAAO,GAAA,CAAA;AAAA,QAAA;;YACjCH,EAAA,cAEzBa,EASWQ,GAAA,EAAA,KAAA,KAAA;AAAA,gBARTR,EAKMQ,GAAA,MAAAC,EALetB,EAAA,OAAM,CAAfuB,YAAZV,EAKM,OAAA;AAAA,UALwB,KAAKU,EAAM;AAAA,UAAI,OAAM;AAAA,QAAA;UAClCA,EAAM,YAArBJ,EAEYH,EAAAQ,EAAA,GAAA;AAAA;YAFe,MAAMD,EAAM;AAAA,YAAK,QAAO;AAAA,YAAS,OAAM;AAAA,UAAA;uBAAwB,MAExF;AAAA,cADAE,EAAAC,EAAAH,EAAM,GAAG,GAAA,CAAA;AAAA,YAAA;;;UAEXR,EAA0CY,IAAA;AAAA,YAA1B,SAASJ,EAAM;AAAA,UAAA;;QAGhBrB,EAAA,cAAjBiB,EAAqFH,EAAAY,EAAA,GAAA;AAAA;UAA9D,MAAK;AAAA,UAAK,SAAQ;AAAA,UAAQ,SAAKC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAX,MAAEX,EAAKN,EAAA,QAAI,CAAA;AAAA,QAAA;qBAAO,MAAC,CAAA,GAAA4B,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,cAAD,KAAC,EAAA;AAAA,UAAA;;;sBAV3EV,EAA6CH,EAAAc,EAAA,GAAA;AAAA;QAAX,MAAM;AAAA,MAAA;;;;;;;;;;;;AC/B5C,UAAM5C,IAAQC,GAER4C,IAAUzC,EAAA,GACVF,IAAMC,EAAe0C,CAAO,GAC5BC,IAAQC,GAAA;AACd,IAAA1C,EAAA;AAEA,UAAMC,IAAIC,EAAa,YAAY,GAC7BC,IAAUC,EAAA,GAEVuC,IAAOpC,EAAgC,IAAI,GAC3CqC,IAAUrC,EAAI,EAAK,GACnBsC,IAAWtC,EAAc,EAAE,GAC3BuC,IAAavC,EAA4B,IAAI,GAC7CwC,IAAYxC,EAAI,EAAK,GACrByC,IAAWzC,EAAc,EAAE,GAC3B0C,IAAW1C,EAAI,EAAK,GAGpB2C,IAAYV,EAAQ,IAAI,cAAc,GAEtCW,IAA8C;AAAA,MAClD,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,WAAW;AAAA,IAAA,GAGPC,IAA+C;AAAA,MACnD,OAAO;AAAA,MACP,SAAS;AAAA,MACT,QAAQ;AAAA,IAAA,GAGJC,IAAUvC,EAAkC,MAAM;AAAA,MACtD,EAAE,KAAK,MAAM,OAAOb,EAAE,aAAa,GAAG,OAAO,GAAA;AAAA,MAC7C,EAAE,KAAK,cAAc,OAAOA,EAAE,iBAAiB,GAAG,UAAU,IAAA;AAAA,MAC5D,EAAE,KAAK,SAAS,OAAOA,EAAE,YAAY,GAAG,OAAO,IAAA;AAAA,MAC/C,EAAE,KAAK,UAAU,OAAOA,EAAE,aAAa,GAAG,OAAO,IAAA;AAAA,MACjD,EAAE,KAAK,UAAU,OAAOA,EAAE,aAAa,GAAG,OAAO,KAAK,OAAO,QAAA;AAAA,MAC7D,EAAE,KAAK,YAAY,OAAOA,EAAE,eAAe,GAAG,UAAU,KAAK,WAAW,IAAA;AAAA,MACxE,EAAE,KAAK,cAAc,OAAOA,EAAE,iBAAiB,GAAG,UAAU,KAAK,WAAW,IAAA;AAAA,IAAI,CACjF,GAEKqD,IAAiBxC,EAA4C,MAAM;AAAA,MACvE,EAAE,KAAK,YAAY,OAAOb,EAAE,eAAe,GAAG,OAAO,IAAA;AAAA,MACrD,EAAE,KAAK,SAAS,OAAOA,EAAE,YAAY,EAAA;AAAA,MACrC,EAAE,KAAK,OAAO,OAAOA,EAAE,eAAe,GAAG,OAAO,IAAI,OAAO,QAAA;AAAA,MAC3D,EAAE,KAAK,SAAS,OAAOA,EAAE,iBAAiB,GAAG,OAAO,KAAK,OAAO,QAAA;AAAA,MAChE,EAAE,KAAK,cAAc,OAAOA,EAAE,sBAAsB,GAAG,OAAO,KAAK,OAAO,QAAA;AAAA,IAAQ,CACnF,GAGKsD,IAAOzC,EAAqD,MAAM;AACtE,YAAM0C,IAAMX,EAAS,MAAM,IAAI,MAAM,EAAE,KAAK,CAACY,GAAGC,MAAMD,IAAIC,CAAC;AAE3D,aAAIF,EAAI,WAAW,IAAU,OAEtBA,EAAI,WAAW,IAClB,EAAE,IAAIA,EAAI,CAAC,GAAI,MAAM,KAAA,IACrB,EAAE,IAAIA,EAAIA,EAAI,SAAS,CAAC,GAAI,MAAMA,EAAI,CAAC,EAAA;AAAA,IAC7C,CAAC,GAEKG,IAAe7C;AAAA,MACnB,MAAMgC,EAAW,UAAU,QAAQA,EAAW,MAAM,KAAK,UAAUA,EAAW,MAAM,GAAG;AAAA,IAAA;AAGzF,aAASc,GAAIC,GAAuB;AAClC,aAAIA,EAAI,eAAe,aAAmB5D,EAAE,kBAAkB,IAC1D4D,EAAI,eAAe,QAAc5D,EAAE,aAAa,IAChD4D,EAAI,eAAe,YAAkB5D,EAAE,iBAAiB,IAErD4D,EAAI,aAAa5D,EAAE,gBAAgB,IAAI;AAAA,IAChD;AAEA,mBAAee,EAAK8C,GAAmC;AACrD,MAAAlB,EAAQ,QAAQ;AAEhB,UAAI;AACF,QAAAD,EAAK,QAAQ,MAAM9C,EAAI,KAAK,EAAE,MAAMiE,GAAO,QAAQ,GAAG,UAAUA,GAAO,WAAW,IAAI;AAAA,MACxF,SAAS3C,GAAO;AACd,QAAA4C,EAAM,OAAO5D,EAAQgB,CAAK,CAAC;AAAA,MAC7B,UAAA;AACE,QAAAyB,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAEA,mBAAeoB,KAAyB;AACtC,YAAMC,IAAUV,EAAK;AAKrB,UAHAT,EAAW,QAAQ,MACnBE,EAAS,QAAQ,CAAA,GAEb,EAACiB,GAEL;AAAA,QAAAlB,EAAU,QAAQ;AAElB,YAAI;AACF,UAAAD,EAAW,QAAQ,MAAMjD,EAAI,QAAQoE,EAAQ,IAAIA,EAAQ,IAAI;AAAA,QAC/D,SAAS9C,GAAO;AACd,UAAA4C,EAAM,OAAO5D,EAAQgB,CAAK,CAAC;AAAA,QAC7B,UAAA;AACE,UAAA4B,EAAU,QAAQ;AAAA,QACpB;AAAA;AAAA,IACF;AAGA,UAAMmB,KAAUpD;AAAA,MAAyB,MACvCoC,KAAaP,EAAK,OAAO,QACrB;AAAA,QACE;AAAA,UACE,KAAK;AAAA,UACL,OAAO1C,EAAE,YAAY;AAAA,UACrB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,UAAUgD,EAAS;AAAA,UACnB,KAAK,MAAA;AAAM,YAAKkB,GAAA;AAAA;AAAA,QAAM;AAAA,MACxB,IAEF,CAAA;AAAA,IAAC;AAGP,mBAAeA,KAAuB;AASpC,UARe,MAAMC,GAAQ;AAAA,QAC3B,OAAOnE,EAAE,kBAAkB;AAAA,QAC3B,SAASA,EAAE,iBAAiB;AAAA,QAC5B,aAAaA,EAAE,oBAAoB;AAAA,QACnC,YAAYA,EAAE,mBAAmB;AAAA,QACjC,MAAM;AAAA,MAAA,CACP,GAID;AAAA,QAAAgD,EAAS,QAAQ;AAEjB,YAAI;AACF,gBAAMpD,EAAI,MAAA,GACVgD,EAAS,QAAQ,CAAA,GACjBkB,EAAM,QAAQ9D,EAAE,cAAc,CAAC,GAC/B,MAAMe,EAAA;AAAA,QACR,SAASG,GAAO;AACd,UAAA4C,EAAM,OAAO5D,EAAQgB,CAAK,CAAC;AAAA,QAC7B,UAAA;AACE,UAAA8B,EAAS,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAEA,WAAAoB,GAAU,MAAM;AACd,YAAMC,IAAK,OAAO7B,EAAM,MAAM,EAAE;AAEhC,MAAI,OAAO,UAAU6B,CAAE,KAAKA,IAAK,MAAGzB,EAAS,QAAQ,CAACyB,CAAE;AAAA,IAC1D,CAAC,GAEDlD,EAAMyB,GAAU,CAAC0B,MAAS;AAExB,MAAIA,EAAK,SAAS,MAAY,QAAQA,EAAK,MAAM,EAAE,IACzCP,GAAA;AAAA,IACZ,CAAC,mBAICpC,EA+Fe4C,IAAA;AAAA,MA/FA,MAAM7E,EAAM;AAAA,MAAM,SAAQ;AAAA,MAAQ,MAAM;AAAA,MAAQ,SAASuE,GAAA;AAAA,IAAA;iBACtE,MA6FM;AAAA,QA7FNO,GA6FM,OA7FNlD,IA6FM;AAAA,UA5FJC,EA0CUC,EAAAiD,CAAA,GAAA,MAAA;AAAA,uBAxCR,MAKE;AAAA,eAJOnB,EAAA,SAAQZ,EAAA,OAAM,cADvBf,EAKEH,EAAAkD,CAAA,GAAA;AAAA;gBAHA,MAAK;AAAA,gBACJ,aAAalD,EAAAxB,CAAA,EAAC,mBAAA;AAAA,gBACf,OAAM;AAAA,cAAA;cAGRuB,EAgCWC,EAAAmD,CAAA,GAAA;AAAA,gBA/BD,UAAU/B,EAAA;AAAA,4DAAAA,EAAQ,QAAAlB;AAAA,gBACzB,MAAMgB,EAAA;AAAA,gBACN,SAASU,EAAA;AAAA,gBACV,WAAQ;AAAA,gBACR,YAAA;AAAA,gBACC,iBAAa,CAAGwB,MAAkBA,EAAI,WAAM;AAAA,gBAC7C,OAAA;AAAA,gBACC,SAASjC,EAAA;AAAA,gBACT,cAAYnB,EAAAxB,CAAA,EAAC,iBAAA;AAAA,gBACb,eAAce;AAAA,cAAA;gBAEJ,mBAAe8D,EAAW,CAAmC,EAA1C,KAAAD,QAAG;AAAA,kBAAIrD,EAAmCC,EAAAsD,CAAA,GAAA;AAAA,oBAAzB,OAAOF,EAAI;AAAA,kBAAA;;gBAC/C,cAAUC,EAAW,CAAkC,EAAzC,KAAAD,QAAG;AAAA,sBAAOpD,EAAAxB,CAAA,EAAC,cAAe4E,EAAI,KAAK,EAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;gBACjD,eAAWC,EACpB,CAEa,EAHW,KAAAD,QAAG;AAAA,kBAC3BrD,EAEaC,EAAAuD,CAAA,GAAA;AAAA,oBAFF,MAAM7B,EAAS0B,EAAI,MAAM;AAAA,oBAAG,KAAA;AAAA,kBAAA;+BAAI,MAEzC;AAAA,0BADApD,EAAAxB,CAAA,EAAC,eAAgB4E,EAAI,MAAM,EAAA,CAAA,GAAA,CAAA;AAAA,oBAAA;;;;gBAGpB,eAAWC,EAAW,CAE/B,EAFwB,KAAAD,QAAG;AAAA,kBAC3B3C,EAAAC,EAAA0C,EAAI,SAAM,GAAMA,EAAI,OAAO,MAAM,MAAA,EAAA,GAAA,CAAA;AAAA,gBAAA;gBAExB,iBAAaC,EACtB,CAMO,EAPmB,KAAAD,QAAG;AAAA,kBACjBA,EAAI,UAAhBxD,EAAA,GAAAC,EAMO,QANP2D,IAMO;AAAA,qBALL5D,EAAA,GAAAC,EAIWQ,GAAA,MAAAC,EAJqBqB,GAAU,CAAxB8B,IAAMC,6BAA6B;AAAA,sBACnCN,EAAI,OAAO,SAASM,CAAG,UAAvCvD,EAEaH,EAAAuD,CAAA,GAAA;AAAA;wBAF8B,MAAAE;AAAA,wBAAY,MAAK;AAAA,sBAAA;mCAAK,MAE/D;AAAA,0BADAhD,EAAAC,EAAA0C,EAAI,OAAO,SAASM,CAAG,CAAA,GAAA,CAAA;AAAA,wBAAA;;;;;;gBAKpB,mBAAeL,EAAW,CAAc,EAArB,KAAAD,QAAG;AAAA,kBAAO3C,EAAAC,EAAAyB,GAAIiB,CAAG,CAAA,GAAA,CAAA;AAAA,gBAAA;;;;;;UAIpCtB,EAAA,cAAf3B,EA+CUH,EAAAiD,CAAA,GAAA;AAAA;YA/CY,OAAOjD,EAAAxB,CAAA,EAAC,cAAA;AAAA,UAAA;uBAC5B,MAMU;AAAA,cANK6C,EAAA,cAAflB,EAMUH,EAAAI,CAAA,GAAA;AAAA;gBANiB,MAAK;AAAA,gBAAK,MAAK;AAAA,gBAAQ,OAAM;AAAA,cAAA;2BACtD,MAA4B;AAAA,sBAAzBJ,EAAAxB,CAAA,EAAC,mBAAA,CAAA,IAAwB,OAAEkC,EAAGW,EAAA,MAAW,KAAK,EAAE,IAAG,OACtD,CAAA;AAAA,kBAAAtB,EAA+CC,EAAAsD,CAAA,GAAA;AAAA,oBAArC,OAAOjC,EAAA,MAAW,KAAK;AAAA,kBAAA;oBAAc,QAAGX,EAAGV,EAAAxB,CAAA,EAAC,iBAAA,CAAA,IAAsB,OAAEkC,EAC5EW,EAAA,MAAW,GAAG,EAAE,IAChB,OACA,CAAA;AAAA,kBAAAtB,EAA6CC,EAAAsD,CAAA,GAAA;AAAA,oBAAnC,OAAOjC,EAAA,MAAW,GAAG;AAAA,kBAAA;;;;cAI3Ba,EAAA,cADR/B,EAKEH,EAAAkD,CAAA,GAAA;AAAA;gBAHA,MAAK;AAAA,gBACJ,aAAalD,EAAAxB,CAAA,EAAC,qBAAA;AAAA,gBACf,OAAM;AAAA,cAAA;cAGRuB,EA8BWC,EAAAmD,CAAA,GAAA;AAAA,gBA7BD,UAAU5B,EAAA;AAAA,4DAAAA,EAAQ,QAAArB;AAAA,gBACzB,MAAMmB,EAAA,OAAY,UAAM,CAAA;AAAA,gBACxB,SAASQ,EAAA;AAAA,gBACV,WAAQ;AAAA,gBACR,YAAA;AAAA,gBACA,OAAA;AAAA,gBACC,YAAY;AAAA,gBACZ,SAASP,EAAA;AAAA,gBACT,cAAYtB,EAAAxB,CAAA,EAAC,mBAAA;AAAA,cAAA;gBAEH,iBAAa6E,EACtB,CAEa,EAHa,KAAAD,QAAG;AAAA,kBAC7BrD,EAEaC,EAAAuD,CAAA,GAAA;AAAA,oBAFF,MAAM5B,EAAWyB,EAAI,QAAQ;AAAA,oBAAG,KAAA;AAAA,kBAAA;+BAAI,MAE7C;AAAA,0BADApD,EAAAxB,CAAA,EAAC,iBAAkB4E,EAAI,QAAQ,EAAA,CAAA,GAAA,CAAA;AAAA,oBAAA;;;;gBAGxB,YAAQC,EACjB,CAA+E,EAD1D,KAAAD,QAAG;AAAA,kBACxBrD,EAA+EC,EAAAI,CAAA,GAAA;AAAA,oBAArE,MAAMgD,EAAI,MAAG,WAAA;AAAA,oBAAuB,MAAK;AAAA,kBAAA;+BAAK,MAAa;AAAA,sBAAV3C,EAAAC,EAAA0C,EAAI,GAAG,GAAA,CAAA;AAAA,oBAAA;;;;gBAEzD,cAAUC,EACnB,CAAoF,EAD7D,KAAAD,QAAG;AAAA,kBAC1BrD,EAAoFC,EAAAI,CAAA,GAAA;AAAA,oBAA1E,MAAMgD,EAAI,QAAK,YAAA;AAAA,oBAAwB,MAAK;AAAA,kBAAA;+BAAK,MAAe;AAAA,sBAAZ3C,EAAAC,EAAA0C,EAAI,KAAK,GAAA,CAAA;AAAA,oBAAA;;;;gBAE9D,UAAQC,EACjB,CAKE,EANmB,KAAAD,QAAG;AAAA,kBAEhB/B,EAAA,cADRlB,EAKEwD,IAAA;AAAA;oBAHC,MAAMtC,EAAA,MAAW,KAAK;AAAA,oBACtB,IAAIA,EAAA,MAAW,GAAG;AAAA,oBAClB,KAAA+B;AAAA,kBAAA;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"AuditRunsPage-SlBisvcG.js","sources":["../src/AuditCompareIssues.vue","../src/AuditRunsPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport { WxButton, WxLink, WxSegmented, WxSkeleton, WxText } from '@webx-ui/core'\nimport AuditDetails from './AuditDetails.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\nimport type { AuditComparisonKind, AuditComparisonRow, AuditIssue } from './types'\n\n/**\n * One check of a comparison opened: its new, fixed or persisting findings, fifty at a time —\n * fixed ones as the earlier run stored them, the others from the later run.\n */\nconst props = defineProps<{ from: number; to: number; row: AuditComparisonRow }>()\n\nconst api = createAuditApi(useAdmin())\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst message = useErrorText()\n\nconst KINDS: AuditComparisonKind[] = ['new', 'fixed', 'persisting']\n\n/* Open on what changed: new first, then fixed — persisting only when nothing else is there. */\nconst kind = ref<AuditComparisonKind>(KINDS.find((one) => props.row[one] > 0) ?? 'new')\nconst issues = ref<AuditIssue[] | null>(null)\nconst page = ref(1)\nconst more = ref(false)\nconst failure = ref<string | null>(null)\n\nconst options = computed(() =>\n KINDS.map((value) => ({\n value,\n label: `${t(`page.kind-${value}`)} · ${props.row[value]}`,\n disabled: props.row[value] === 0,\n })),\n)\n\nasync function load(next = 1): Promise<void> {\n failure.value = null\n\n try {\n const answer = await api.compareIssues({\n from: props.from,\n to: props.to,\n kind: kind.value,\n check: props.row.check,\n page: next,\n per_page: 50,\n })\n\n issues.value = next === 1 ? answer.data : [...(issues.value ?? []), ...answer.data]\n page.value = answer.current_page\n more.value = answer.current_page < answer.last_page\n } catch (error) {\n failure.value = message(error)\n }\n}\n\nwatch(\n kind,\n () => {\n issues.value = null\n void load()\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <div class=\"wx-audit-compare\">\n <wx-segmented v-model=\"kind\" :options=\"options\" size=\"sm\" :aria-label=\"t('page.compare')\" />\n\n <wx-text v-if=\"failure\" size=\"sm\" tone=\"danger\">{{ failure }}</wx-text>\n <wx-skeleton v-else-if=\"!issues\" :rows=\"2\" />\n\n <template v-else>\n <div v-for=\"issue in issues\" :key=\"issue.id\" class=\"wx-audit-compare__item\">\n <wx-link v-if=\"issue.url\" :href=\"issue.url\" target=\"_blank\" class=\"wx-audit-compare__url\">{{\n issue.url\n }}</wx-link>\n <audit-details :details=\"issue.details\" />\n </div>\n\n <wx-button v-if=\"more\" size=\"sm\" variant=\"text\" @click=\"load(page + 1)\">…</wx-button>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-audit-compare {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n min-width: 0;\n}\n\n.wx-audit-compare__item {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n\n.wx-audit-compare__url {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n toast,\n WxAlert,\n WxBadge,\n WxCard,\n WxTable,\n WxText,\n type BadgeType,\n type RowKey,\n type TableColumn,\n type TableState,\n} from '@webx-ui/core'\nimport AuditCompareIssues from './AuditCompareIssues.vue'\nimport AuditLayout from './AuditLayout.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\nimport type {\n AuditComparison,\n AuditComparisonRow,\n AuditPage,\n AuditRun,\n AuditRunStatus,\n AuditSeverity,\n} from './types'\n\n/**\n * The history (§8 «Runs»): every run kept, newest first, with its health and counts. Ticking a\n * run compares it with the one it was analysed against; ticking two compares those two — by\n * fingerprint (decision 8): what is new in the later one, what both have, what is gone. `?to=`\n * opens on one run already ticked — the way the page card's recheck leads here. In the head, for\n * whoever manages the section, the way to clear every run at once, behind a warning.\n */\nconst props = defineProps<{ base: string }>()\n\nconst context = useAdmin()\nconst api = createAuditApi(context)\nconst route = useRoute()\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst message = useErrorText()\n\nconst runs = ref<AuditPage<AuditRun> | null>(null)\nconst loading = ref(false)\nconst selected = ref<RowKey[]>([])\nconst comparison = ref<AuditComparison | null>(null)\nconst comparing = ref(false)\nconst expanded = ref<RowKey[]>([])\nconst clearing = ref(false)\n\n// A boolean, not a computed: the permissions do not change while the screen is open.\nconst canManage = context.can('audit.manage')\n\nconst statuses: Record<AuditRunStatus, BadgeType> = {\n queued: 'info',\n running: 'primary',\n done: 'success',\n failed: 'danger',\n cancelled: 'warning',\n}\n\nconst severities: Record<AuditSeverity, BadgeType> = {\n error: 'danger',\n warning: 'warning',\n notice: 'info',\n}\n\nconst columns = computed<TableColumn<AuditRun>[]>(() => [\n { key: 'id', label: t('page.run-id'), width: 90 },\n { key: 'created_at', label: t('page.started-at'), minWidth: 160 },\n { key: 'scope', label: t('page.scope'), width: 120 },\n { key: 'status', label: t('page.status'), width: 130 },\n { key: 'health', label: t('page.health'), width: 100, align: 'right' },\n { key: 'severity', label: t('page.severity'), minWidth: 170, hideBelow: 640 },\n { key: 'started_by', label: t('page.started-by'), minWidth: 130, hideBelow: 760 },\n])\n\nconst compareColumns = computed<TableColumn<AuditComparisonRow>[]>(() => [\n { key: 'severity', label: t('page.severity'), width: 130 },\n { key: 'title', label: t('page.check') },\n { key: 'new', label: t('page.kind-new'), width: 90, align: 'right' },\n { key: 'fixed', label: t('page.kind-fixed'), width: 100, align: 'right' },\n { key: 'persisting', label: t('page.kind-persisting'), width: 120, align: 'right' },\n])\n\n/* What the selection means: one run against its own previous, or two against each other. */\nconst pair = computed<{ to: number; from: number | null } | null>(() => {\n const ids = selected.value.map(Number).sort((a, b) => a - b)\n\n if (ids.length === 0) return null\n\n return ids.length === 1\n ? { to: ids[0]!, from: null }\n : { to: ids[ids.length - 1]!, from: ids[0]! }\n})\n\nconst scopesDiffer = computed(\n () => comparison.value !== null && comparison.value.from.scope !== comparison.value.to.scope,\n)\n\nfunction who(run: AuditRun): string {\n if (run.started_by === 'schedule') return t('page.by-schedule')\n if (run.started_by === 'mcp') return t('page.by-mcp')\n if (run.started_by === 'console') return t('page.by-console')\n\n return run.started_by ? t('page.by-person') : ''\n}\n\nasync function load(state?: TableState): Promise<void> {\n loading.value = true\n\n try {\n runs.value = await api.runs({ page: state?.page ?? 1, per_page: state?.perPage ?? 20 })\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nasync function compare(): Promise<void> {\n const current = pair.value\n\n comparison.value = null\n expanded.value = []\n\n if (!current) return\n\n comparing.value = true\n\n try {\n comparison.value = await api.compare(current.to, current.from)\n } catch (error) {\n toast.danger(message(error))\n } finally {\n comparing.value = false\n }\n}\n\n// Danger, so the head puts it in its `···`: never a red button beside the section's name.\nconst actions = computed<ScreenAction[]>(() =>\n canManage && runs.value?.total\n ? [\n {\n key: 'clear',\n label: t('page.clear'),\n icon: 'trash',\n danger: true,\n disabled: clearing.value,\n run: () => void clear(),\n },\n ]\n : [],\n)\n\nasync function clear(): Promise<void> {\n const agreed = await confirm({\n title: t('page.clear-title'),\n message: t('page.clear-text'),\n confirmText: t('page.clear-confirm'),\n cancelText: t('page.clear-cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n clearing.value = true\n\n try {\n await api.clear()\n selected.value = []\n toast.success(t('page.cleared'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n clearing.value = false\n }\n}\n\nonMounted(() => {\n const to = Number(route.query.to)\n\n if (Number.isInteger(to) && to > 0) selected.value = [to]\n})\n\nwatch(selected, (keys) => {\n /* Two at most: a third tick replaces the oldest one. */\n if (keys.length > 2) selected.value = keys.slice(-2)\n else void compare()\n})\n</script>\n\n<template>\n <audit-layout :base=\"props.base\" current=\"runs\" :card=\"false\" :actions=\"actions\">\n <div class=\"wx-audit-runs\">\n <wx-card>\n <!-- Above the table, not under it: read before ticking, not found after scrolling. -->\n <wx-alert\n v-if=\"!pair && runs?.total\"\n type=\"info\"\n :description=\"t('page.compare-help')\"\n class=\"wx-audit-runs__note\"\n />\n\n <wx-table\n v-model:selected=\"selected\"\n :data=\"runs\"\n :columns=\"columns\"\n row-key=\"id\"\n selectable\n :selectable-if=\"(row: AuditRun) => row.status === 'done'\"\n flush\n :loading=\"loading\"\n :empty-text=\"t('page.runs-empty')\"\n @state-change=\"load\"\n >\n <template #cell-created_at=\"{ row }\"><wx-date :value=\"row.created_at\" /></template>\n <template #cell-scope=\"{ row }\">{{ t(`page.scope-${row.scope}`) }}</template>\n <template #cell-status=\"{ row }\">\n <wx-badge :type=\"statuses[row.status]\" dot>{{\n t(`page.status-${row.status}`)\n }}</wx-badge>\n </template>\n <template #cell-health=\"{ row }\">{{\n row.counts ? `${row.counts.health}%` : ''\n }}</template>\n <template #cell-severity=\"{ row }\">\n <span v-if=\"row.counts\" class=\"wx-audit-runs__counts\">\n <template v-for=\"(type, key) in severities\" :key=\"key\">\n <wx-badge v-if=\"row.counts.severity[key]\" :type=\"type\" size=\"sm\">{{\n row.counts.severity[key]\n }}</wx-badge>\n </template>\n </span>\n </template>\n <template #cell-started_by=\"{ row }\">{{ who(row) }}</template>\n </wx-table>\n </wx-card>\n\n <wx-card v-if=\"pair\" :title=\"t('page.compare')\">\n <wx-text v-if=\"comparison\" size=\"sm\" tone=\"muted\" class=\"wx-audit-runs__pair\">\n {{ t('page.compare-from') }} #{{ comparison.from.id }} ·\n <wx-date :value=\"comparison.from.created_at\" /> → {{ t('page.compare-to') }} #{{\n comparison.to.id\n }}\n · <wx-date :value=\"comparison.to.created_at\" />\n </wx-text>\n\n <wx-alert\n v-if=\"scopesDiffer\"\n type=\"info\"\n :description=\"t('page.compare-scopes')\"\n class=\"wx-audit-runs__note\"\n />\n\n <wx-table\n v-model:expanded=\"expanded\"\n :data=\"comparison?.checks ?? []\"\n :columns=\"compareColumns\"\n row-key=\"check\"\n expandable\n flush\n :pagination=\"false\"\n :loading=\"comparing\"\n :empty-text=\"t('page.compare-none')\"\n >\n <template #cell-severity=\"{ row }\">\n <wx-badge :type=\"severities[row.severity]\" dot>{{\n t(`page.severity-${row.severity}`)\n }}</wx-badge>\n </template>\n <template #cell-new=\"{ row }\">\n <wx-text :tone=\"row.new ? 'danger' : 'muted'\" size=\"sm\">{{ row.new }}</wx-text>\n </template>\n <template #cell-fixed=\"{ row }\">\n <wx-text :tone=\"row.fixed ? 'success' : 'muted'\" size=\"sm\">{{ row.fixed }}</wx-text>\n </template>\n <template #expanded=\"{ row }\">\n <audit-compare-issues\n v-if=\"comparison\"\n :from=\"comparison.from.id\"\n :to=\"comparison.to.id\"\n :row=\"row\"\n />\n </template>\n </wx-table>\n </wx-card>\n </div>\n </audit-layout>\n</template>\n\n<style scoped>\n.wx-audit-runs {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n min-width: 0;\n}\n\n.wx-audit-runs__counts {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--wx-space-4);\n}\n\n.wx-audit-runs__pair {\n display: block;\n margin-bottom: var(--wx-space-12);\n}\n\n.wx-audit-runs__note {\n margin-bottom: var(--wx-space-12);\n}\n</style>\n"],"names":["props","__props","api","createAuditApi","useAdmin","useAuditMessages","t","useTranslate","message","useErrorText","KINDS","kind","ref","one","issues","page","more","failure","options","computed","value","load","next","answer","error","watch","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxSegmented","$event","_createBlock","WxText","_Fragment","_renderList","issue","WxLink","_createTextVNode","_toDisplayString","AuditDetails","WxButton","_cache","WxSkeleton","context","route","useRoute","runs","loading","selected","comparison","comparing","expanded","clearing","canManage","statuses","severities","columns","compareColumns","pair","ids","a","b","scopesDiffer","who","run","state","toast","compare","current","actions","clear","confirm","onMounted","to","keys","AuditLayout","_createElementVNode","WxCard","WxAlert","WxTable","row","_withCtx","WxDate","WxBadge","_hoisted_2","type","key","AuditCompareIssues"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { defineComponent as N, ref as n, onMounted as W, openBlock as o, createB
2
2
  import { useRouter as h } from "vue-router";
3
3
  import { useAdmin as E, useTranslate as w, useErrorText as P, WxScreen as $ } from "@webx-ui/module-admin";
4
4
  import { toast as d, WxSkeleton as D, WxActionBar as I, WxButton as A } from "@webx-ui/core";
5
- import { _ as R } from "./AuditLayout.vue_vue_type_script_setup_true_lang-C8H5jlTe.js";
6
- import { c as U, u as j, _ as q } from "./index-BFYHJYU_.js";
5
+ import { _ as R } from "./AuditLayout.vue_vue_type_script_setup_true_lang-C39k6JNr.js";
6
+ import { c as U, u as j, _ as q } from "./index-_DgRf2O6.js";
7
7
  const z = { class: "wx-audit-settings" }, F = /* @__PURE__ */ N({
8
8
  __name: "AuditSettingsPage",
9
9
  props: {
@@ -85,4 +85,4 @@ const z = { class: "wx-audit-settings" }, F = /* @__PURE__ */ N({
85
85
  export {
86
86
  Q as default
87
87
  };
88
- //# sourceMappingURL=AuditSettingsPage-HwfdLU_s.js.map
88
+ //# sourceMappingURL=AuditSettingsPage-ADutjdIO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuditSettingsPage-HwfdLU_s.js","sources":["../src/AuditSettingsPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onMounted, ref } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { useAdmin, useErrorText, useTranslate, WxScreen } from '@webx-ui/module-admin'\nimport { toast, WxActionBar, WxButton, WxSkeleton } from '@webx-ui/core'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport AuditLayout from './AuditLayout.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\n\n/**\n * The section's settings (§8): where the site is and which hosts are its stands, the limits of\n * the crawl and the paths it leaves out, the thresholds, the nightly run and how much history\n * to keep. The form is the screen the server describes (`audit.settings`), so a project patches\n * a field in the way it does everywhere else; saving is this page's own. «Back» beside «Save» returns\n * to the overview — the tabs above cannot, their «Overview» is already the lit one.\n */\nconst props = defineProps<{ base: string }>()\n\nconst context = useAdmin()\nconst api = createAuditApi(context)\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst panel = useTranslate('webx-admin')\nconst router = useRouter()\nconst message = useErrorText()\n\nconst values = ref<ScreenModel>({})\nconst errors = ref<Record<string, string[]>>({})\nconst loading = ref(true)\nconst saving = ref(false)\n\n// A boolean, not a computed: the permissions do not change while the screen is open.\nconst canManage = context.can('audit.manage')\n\nonMounted(async () => {\n try {\n values.value = (await api.settings()) as ScreenModel\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n})\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n values.value = (await api.saveSettings(values.value)) as ScreenModel\n toast.success(t('page.saved'))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) errors.value = body.errors\n\n toast.danger(message(error))\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <audit-layout :base=\"props.base\" current=\"settings\" :card=\"false\">\n <div class=\"wx-audit-settings\">\n <wx-skeleton v-if=\"loading\" :rows=\"6\" />\n <wx-screen\n v-else\n v-model=\"values\"\n name=\"audit.settings\"\n :errors=\"errors\"\n :disabled=\"!canManage\"\n />\n\n <wx-action-bar v-if=\"!loading\">\n <wx-button icon=\"arrow-left\" @click=\"router.push(props.base)\">{{\n panel('editor.back')\n }}</wx-button>\n <wx-button v-if=\"canManage\" type=\"primary\" :loading=\"saving\" @click=\"save\">{{\n t('page.save')\n }}</wx-button>\n </wx-action-bar>\n </div>\n </audit-layout>\n</template>\n\n<style scoped>\n.wx-audit-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n</style>\n"],"names":["props","__props","context","useAdmin","api","createAuditApi","useAuditMessages","t","useTranslate","panel","router","useRouter","message","useErrorText","values","ref","errors","loading","saving","canManage","onMounted","error","toast","save","body","_createBlock","AuditLayout","_createElementVNode","_hoisted_1","_unref","WxSkeleton","WxScreen","$event","WxActionBar","_createVNode","WxButton"],"mappings":";;;;;;;;;;;;AAiBA,UAAMA,IAAQC,GAERC,IAAUC,EAAA,GACVC,IAAMC,EAAeH,CAAO;AAClC,IAAAI,EAAA;AAEA,UAAMC,IAAIC,EAAa,YAAY,GAC7BC,IAAQD,EAAa,YAAY,GACjCE,IAASC,EAAA,GACTC,IAAUC,EAAA,GAEVC,IAASC,EAAiB,EAAE,GAC5BC,IAASD,EAA8B,EAAE,GACzCE,IAAUF,EAAI,EAAI,GAClBG,IAASH,EAAI,EAAK,GAGlBI,IAAYjB,EAAQ,IAAI,cAAc;AAE5C,IAAAkB,EAAU,YAAY;AACpB,UAAI;AACF,QAAAN,EAAO,QAAS,MAAMV,EAAI,SAAA;AAAA,MAC5B,SAASiB,GAAO;AACd,QAAAC,EAAM,OAAOV,EAAQS,CAAK,CAAC;AAAA,MAC7B,UAAA;AACE,QAAAJ,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AAED,mBAAeM,IAAsB;AACnC,MAAAL,EAAO,QAAQ,IACfF,EAAO,QAAQ,CAAA;AAEf,UAAI;AACF,QAAAF,EAAO,QAAS,MAAMV,EAAI,aAAaU,EAAO,KAAK,GACnDQ,EAAM,QAAQf,EAAE,YAAY,CAAC;AAAA,MAC/B,SAASc,GAAO;AACd,cAAMG,IAAQH,EAA2D;AAEzE,QAAIG,GAAM,WAAQR,EAAO,QAAQQ,EAAK,SAEtCF,EAAM,OAAOV,EAAQS,CAAK,CAAC;AAAA,MAC7B,UAAA;AACE,QAAAH,EAAO,QAAQ;AAAA,MACjB;AAAA,IACF;2BAIEO,EAoBeC,GAAA;AAAA,MApBA,MAAM1B,EAAM;AAAA,MAAM,SAAQ;AAAA,MAAY,MAAM;AAAA,IAAA;iBACzD,MAkBM;AAAA,QAlBN2B,EAkBM,OAlBNC,GAkBM;AAAA,UAjBeX,EAAA,cAAnBQ,EAAwCI,EAAAC,CAAA,GAAA;AAAA;YAAX,MAAM;AAAA,UAAA,YACnCL,EAMEI,EAAAE,CAAA,GAAA;AAAA;wBAJSjB,EAAA;AAAA,0DAAAA,EAAM,QAAAkB;AAAA,YACf,MAAK;AAAA,YACJ,QAAQhB,EAAA;AAAA,YACR,WAAWa,EAAAV,CAAA;AAAA,UAAA;UAGQF,EAAA,0BAAtBQ,EAOgBI,EAAAI,CAAA,GAAA,EAAA,KAAA,KAAA;AAAA,uBANd,MAEc;AAAA,cAFdC,EAEcL,EAAAM,CAAA,GAAA;AAAA,gBAFH,MAAK;AAAA,gBAAc,gCAAON,EAAAnB,CAAA,EAAO,KAAKV,EAAM,IAAI;AAAA,cAAA;2BAAG,MAE5D;AAAA,sBADA6B,EAAApB,CAAA,EAAK,aAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;;cAEUoB,EAAAV,CAAA,UAAjBM,EAEcI,EAAAM,CAAA,GAAA;AAAA;gBAFc,MAAK;AAAA,gBAAW,SAASjB,EAAA;AAAA,gBAAS,SAAOK;AAAA,cAAA;2BAAM,MAEzE;AAAA,sBADAM,EAAAtB,CAAA,EAAC,WAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;;;;;;;;;;;"}
1
+ {"version":3,"file":"AuditSettingsPage-ADutjdIO.js","sources":["../src/AuditSettingsPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onMounted, ref } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { useAdmin, useErrorText, useTranslate, WxScreen } from '@webx-ui/module-admin'\nimport { toast, WxActionBar, WxButton, WxSkeleton } from '@webx-ui/core'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport AuditLayout from './AuditLayout.vue'\nimport { createAuditApi } from './api'\nimport { useAuditMessages } from './i18n'\n\n/**\n * The section's settings (§8): where the site is and which hosts are its stands, the limits of\n * the crawl and the paths it leaves out, the thresholds, the nightly run and how much history\n * to keep. The form is the screen the server describes (`audit.settings`), so a project patches\n * a field in the way it does everywhere else; saving is this page's own. «Back» beside «Save» returns\n * to the overview — the tabs above cannot, their «Overview» is already the lit one.\n */\nconst props = defineProps<{ base: string }>()\n\nconst context = useAdmin()\nconst api = createAuditApi(context)\nuseAuditMessages()\n\nconst t = useTranslate('webx-audit')\nconst panel = useTranslate('webx-admin')\nconst router = useRouter()\nconst message = useErrorText()\n\nconst values = ref<ScreenModel>({})\nconst errors = ref<Record<string, string[]>>({})\nconst loading = ref(true)\nconst saving = ref(false)\n\n// A boolean, not a computed: the permissions do not change while the screen is open.\nconst canManage = context.can('audit.manage')\n\nonMounted(async () => {\n try {\n values.value = (await api.settings()) as ScreenModel\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n})\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n values.value = (await api.saveSettings(values.value)) as ScreenModel\n toast.success(t('page.saved'))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) errors.value = body.errors\n\n toast.danger(message(error))\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <audit-layout :base=\"props.base\" current=\"settings\" :card=\"false\">\n <div class=\"wx-audit-settings\">\n <wx-skeleton v-if=\"loading\" :rows=\"6\" />\n <wx-screen\n v-else\n v-model=\"values\"\n name=\"audit.settings\"\n :errors=\"errors\"\n :disabled=\"!canManage\"\n />\n\n <wx-action-bar v-if=\"!loading\">\n <wx-button icon=\"arrow-left\" @click=\"router.push(props.base)\">{{\n panel('editor.back')\n }}</wx-button>\n <wx-button v-if=\"canManage\" type=\"primary\" :loading=\"saving\" @click=\"save\">{{\n t('page.save')\n }}</wx-button>\n </wx-action-bar>\n </div>\n </audit-layout>\n</template>\n\n<style scoped>\n.wx-audit-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n</style>\n"],"names":["props","__props","context","useAdmin","api","createAuditApi","useAuditMessages","t","useTranslate","panel","router","useRouter","message","useErrorText","values","ref","errors","loading","saving","canManage","onMounted","error","toast","save","body","_createBlock","AuditLayout","_createElementVNode","_hoisted_1","_unref","WxSkeleton","WxScreen","$event","WxActionBar","_createVNode","WxButton"],"mappings":";;;;;;;;;;;;AAiBA,UAAMA,IAAQC,GAERC,IAAUC,EAAA,GACVC,IAAMC,EAAeH,CAAO;AAClC,IAAAI,EAAA;AAEA,UAAMC,IAAIC,EAAa,YAAY,GAC7BC,IAAQD,EAAa,YAAY,GACjCE,IAASC,EAAA,GACTC,IAAUC,EAAA,GAEVC,IAASC,EAAiB,EAAE,GAC5BC,IAASD,EAA8B,EAAE,GACzCE,IAAUF,EAAI,EAAI,GAClBG,IAASH,EAAI,EAAK,GAGlBI,IAAYjB,EAAQ,IAAI,cAAc;AAE5C,IAAAkB,EAAU,YAAY;AACpB,UAAI;AACF,QAAAN,EAAO,QAAS,MAAMV,EAAI,SAAA;AAAA,MAC5B,SAASiB,GAAO;AACd,QAAAC,EAAM,OAAOV,EAAQS,CAAK,CAAC;AAAA,MAC7B,UAAA;AACE,QAAAJ,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AAED,mBAAeM,IAAsB;AACnC,MAAAL,EAAO,QAAQ,IACfF,EAAO,QAAQ,CAAA;AAEf,UAAI;AACF,QAAAF,EAAO,QAAS,MAAMV,EAAI,aAAaU,EAAO,KAAK,GACnDQ,EAAM,QAAQf,EAAE,YAAY,CAAC;AAAA,MAC/B,SAASc,GAAO;AACd,cAAMG,IAAQH,EAA2D;AAEzE,QAAIG,GAAM,WAAQR,EAAO,QAAQQ,EAAK,SAEtCF,EAAM,OAAOV,EAAQS,CAAK,CAAC;AAAA,MAC7B,UAAA;AACE,QAAAH,EAAO,QAAQ;AAAA,MACjB;AAAA,IACF;2BAIEO,EAoBeC,GAAA;AAAA,MApBA,MAAM1B,EAAM;AAAA,MAAM,SAAQ;AAAA,MAAY,MAAM;AAAA,IAAA;iBACzD,MAkBM;AAAA,QAlBN2B,EAkBM,OAlBNC,GAkBM;AAAA,UAjBeX,EAAA,cAAnBQ,EAAwCI,EAAAC,CAAA,GAAA;AAAA;YAAX,MAAM;AAAA,UAAA,YACnCL,EAMEI,EAAAE,CAAA,GAAA;AAAA;wBAJSjB,EAAA;AAAA,0DAAAA,EAAM,QAAAkB;AAAA,YACf,MAAK;AAAA,YACJ,QAAQhB,EAAA;AAAA,YACR,WAAWa,EAAAV,CAAA;AAAA,UAAA;UAGQF,EAAA,0BAAtBQ,EAOgBI,EAAAI,CAAA,GAAA,EAAA,KAAA,KAAA;AAAA,uBANd,MAEc;AAAA,cAFdC,EAEcL,EAAAM,CAAA,GAAA;AAAA,gBAFH,MAAK;AAAA,gBAAc,gCAAON,EAAAnB,CAAA,EAAO,KAAKV,EAAM,IAAI;AAAA,cAAA;2BAAG,MAE5D;AAAA,sBADA6B,EAAApB,CAAA,EAAK,aAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;;cAEUoB,EAAAV,CAAA,UAAjBM,EAEcI,EAAAM,CAAA,GAAA;AAAA;gBAFc,MAAK;AAAA,gBAAW,SAASjB,EAAA;AAAA,gBAAS,SAAOK;AAAA,cAAA;2BAAM,MAEzE;AAAA,sBADAM,EAAAtB,CAAA,EAAC,WAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;;;;;;;;;;;"}
@@ -8,35 +8,35 @@ function rs(i = {}) {
8
8
  id: "audit",
9
9
  path: n,
10
10
  routes: [
11
- { path: n, name: "webx.audit", component: () => import("./AuditOverviewPage-gVpdBOAY.js"), props: o },
11
+ { path: n, name: "webx.audit", component: () => import("./AuditOverviewPage-B5mexNDW.js"), props: o },
12
12
  {
13
13
  path: `${n}/issues`,
14
14
  name: "webx.audit.issues",
15
- component: () => import("./AuditIssuesPage-BjTPgAnD.js"),
15
+ component: () => import("./AuditIssuesPage-DtEJ9Sgq.js"),
16
16
  props: o
17
17
  },
18
18
  {
19
19
  path: `${n}/pages`,
20
20
  name: "webx.audit.pages",
21
- component: () => import("./AuditPagesPage-DNgZo-K-.js"),
21
+ component: () => import("./AuditPagesPage-C1Akv4Ql.js"),
22
22
  props: o
23
23
  },
24
24
  {
25
25
  path: `${n}/hosts`,
26
26
  name: "webx.audit.hosts",
27
- component: () => import("./AuditHostsPage-YFRORYHZ.js"),
27
+ component: () => import("./AuditHostsPage-CSAlf3jK.js"),
28
28
  props: o
29
29
  },
30
30
  {
31
31
  path: `${n}/runs`,
32
32
  name: "webx.audit.runs",
33
- component: () => import("./AuditRunsPage-BbWsuATw.js"),
33
+ component: () => import("./AuditRunsPage-SlBisvcG.js"),
34
34
  props: o
35
35
  },
36
36
  {
37
37
  path: `${n}/settings`,
38
38
  name: "webx.audit.settings",
39
- component: () => import("./AuditSettingsPage-HwfdLU_s.js"),
39
+ component: () => import("./AuditSettingsPage-ADutjdIO.js"),
40
40
  props: o
41
41
  }
42
42
  ]
@@ -1849,7 +1849,7 @@ const bt = { class: "wx-audit-card__title" }, wt = { class: "wx-audit-card__url"
1849
1849
  status: ["eq", "gt", "lt", "empty"],
1850
1850
  bool: ["yes", "no"],
1851
1851
  source: ["eq"]
1852
- }, ps = ["contains", "eq", "gt", "lt"], gs = ["home", "sitemap", "registry", "link"], fs = D(() => import("./AuditOverviewPage-gVpdBOAY.js")), _s = D(() => import("./AuditIssuesPage-BjTPgAnD.js")), ms = D(() => import("./AuditPagesPage-DNgZo-K-.js")), ys = D(() => import("./AuditHostsPage-YFRORYHZ.js")), vs = D(() => import("./AuditRunsPage-BbWsuATw.js")), ks = D(() => import("./AuditSettingsPage-HwfdLU_s.js"));
1852
+ }, ps = ["contains", "eq", "gt", "lt"], gs = ["home", "sitemap", "registry", "link"], fs = D(() => import("./AuditOverviewPage-B5mexNDW.js")), _s = D(() => import("./AuditIssuesPage-DtEJ9Sgq.js")), ms = D(() => import("./AuditPagesPage-C1Akv4Ql.js")), ys = D(() => import("./AuditHostsPage-CSAlf3jK.js")), vs = D(() => import("./AuditRunsPage-SlBisvcG.js")), ks = D(() => import("./AuditSettingsPage-ADutjdIO.js"));
1853
1853
  export {
1854
1854
  fe as A,
1855
1855
  cs as C,
@@ -1877,4 +1877,4 @@ export {
1877
1877
  ge as p,
1878
1878
  G as u
1879
1879
  };
1880
- //# sourceMappingURL=index-BFYHJYU_.js.map
1880
+ //# sourceMappingURL=index-_DgRf2O6.js.map