@webx-ui/module-audit 0.4.6 → 0.5.0

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.
@@ -0,0 +1,375 @@
1
+ import { defineComponent as L, ref as m, computed as $, watch as F, openBlock as r, createElementBlock as h, createVNode as p, unref as t, createBlock as g, withCtx as n, createTextVNode as c, toDisplayString as i, Fragment as B, renderList as K, createCommentVNode as _, onMounted as se, createElementVNode as re } from "vue";
2
+ import { useRoute as oe } from "vue-router";
3
+ import { useAdmin as j, useTranslate as G, useErrorText as H, WxDate as S } from "@webx-ui/module-admin";
4
+ import { WxSegmented as ue, WxText as z, WxSkeleton as ie, WxLink as ce, WxButton as de, confirm as pe, toast as N, WxCard as R, WxAlert as U, WxTable as q, WxBadge as E } from "@webx-ui/core";
5
+ import { c as J, u as O, e as me, _ as Q } from "./index-BFYHJYU_.js";
6
+ import { _ as ge } from "./AuditLayout.vue_vue_type_script_setup_true_lang-C8H5jlTe.js";
7
+ const fe = { class: "wx-audit-compare" }, ve = /* @__PURE__ */ L({
8
+ __name: "AuditCompareIssues",
9
+ props: {
10
+ from: {},
11
+ to: {},
12
+ row: {}
13
+ },
14
+ setup(I) {
15
+ const b = I, C = J(j());
16
+ O();
17
+ const k = G("webx-audit"), T = H(), e = ["new", "fixed", "persisting"], x = m(e.find((u) => b.row[u] > 0) ?? "new"), f = m(null), w = m(1), v = m(!1), s = m(null), A = $(
18
+ () => e.map((u) => ({
19
+ value: u,
20
+ label: `${k(`page.kind-${u}`)} · ${b.row[u]}`,
21
+ disabled: b.row[u] === 0
22
+ }))
23
+ );
24
+ async function W(u = 1) {
25
+ s.value = null;
26
+ try {
27
+ const o = await C.compareIssues({
28
+ from: b.from,
29
+ to: b.to,
30
+ kind: x.value,
31
+ check: b.row.check,
32
+ page: u,
33
+ per_page: 50
34
+ });
35
+ f.value = u === 1 ? o.data : [...f.value ?? [], ...o.data], w.value = o.current_page, v.value = o.current_page < o.last_page;
36
+ } catch (o) {
37
+ s.value = T(o);
38
+ }
39
+ }
40
+ return F(
41
+ x,
42
+ () => {
43
+ f.value = null, W();
44
+ },
45
+ { immediate: !0 }
46
+ ), (u, o) => (r(), h("div", fe, [
47
+ p(t(ue), {
48
+ modelValue: x.value,
49
+ "onUpdate:modelValue": o[0] || (o[0] = (y) => x.value = y),
50
+ options: A.value,
51
+ size: "sm",
52
+ "aria-label": t(k)("page.compare")
53
+ }, null, 8, ["modelValue", "options", "aria-label"]),
54
+ s.value ? (r(), g(t(z), {
55
+ key: 0,
56
+ size: "sm",
57
+ tone: "danger"
58
+ }, {
59
+ default: n(() => [
60
+ c(i(s.value), 1)
61
+ ]),
62
+ _: 1
63
+ })) : f.value ? (r(), h(B, { key: 2 }, [
64
+ (r(!0), h(B, null, K(f.value, (y) => (r(), h("div", {
65
+ key: y.id,
66
+ class: "wx-audit-compare__item"
67
+ }, [
68
+ y.url ? (r(), g(t(ce), {
69
+ key: 0,
70
+ href: y.url,
71
+ target: "_blank",
72
+ class: "wx-audit-compare__url"
73
+ }, {
74
+ default: n(() => [
75
+ c(i(y.url), 1)
76
+ ]),
77
+ _: 2
78
+ }, 1032, ["href"])) : _("", !0),
79
+ p(me, {
80
+ details: y.details
81
+ }, null, 8, ["details"])
82
+ ]))), 128)),
83
+ v.value ? (r(), g(t(de), {
84
+ key: 0,
85
+ size: "sm",
86
+ variant: "text",
87
+ onClick: o[1] || (o[1] = (y) => W(w.value + 1))
88
+ }, {
89
+ default: n(() => [...o[2] || (o[2] = [
90
+ c("…", -1)
91
+ ])]),
92
+ _: 1
93
+ })) : _("", !0)
94
+ ], 64)) : (r(), g(t(ie), {
95
+ key: 1,
96
+ rows: 2
97
+ }))
98
+ ]));
99
+ }
100
+ }), ye = /* @__PURE__ */ Q(ve, [["__scopeId", "data-v-02d42bdb"]]), _e = { class: "wx-audit-runs" }, be = {
101
+ key: 0,
102
+ class: "wx-audit-runs__counts"
103
+ }, xe = /* @__PURE__ */ L({
104
+ __name: "AuditRunsPage",
105
+ props: {
106
+ base: {}
107
+ },
108
+ setup(I) {
109
+ const b = I, C = j(), k = J(C), T = oe();
110
+ O();
111
+ const e = G("webx-audit"), x = H(), f = m(null), w = m(!1), v = m([]), s = m(null), A = m(!1), W = m([]), u = m(!1), o = C.can("audit.manage"), y = {
112
+ queued: "info",
113
+ running: "primary",
114
+ done: "success",
115
+ failed: "danger",
116
+ cancelled: "warning"
117
+ }, M = {
118
+ error: "danger",
119
+ warning: "warning",
120
+ notice: "info"
121
+ }, X = $(() => [
122
+ { key: "id", label: e("page.run-id"), width: 90 },
123
+ { key: "created_at", label: e("page.started-at"), minWidth: 160 },
124
+ { key: "scope", label: e("page.scope"), width: 120 },
125
+ { key: "status", label: e("page.status"), width: 130 },
126
+ { key: "health", label: e("page.health"), width: 100, align: "right" },
127
+ { key: "severity", label: e("page.severity"), minWidth: 170, hideBelow: 640 },
128
+ { key: "started_by", label: e("page.started-by"), minWidth: 130, hideBelow: 760 }
129
+ ]), Y = $(() => [
130
+ { key: "severity", label: e("page.severity"), width: 130 },
131
+ { key: "title", label: e("page.check") },
132
+ { key: "new", label: e("page.kind-new"), width: 90, align: "right" },
133
+ { key: "fixed", label: e("page.kind-fixed"), width: 100, align: "right" },
134
+ { key: "persisting", label: e("page.kind-persisting"), width: 120, align: "right" }
135
+ ]), V = $(() => {
136
+ const l = v.value.map(Number).sort((d, a) => d - a);
137
+ return l.length === 0 ? null : l.length === 1 ? { to: l[0], from: null } : { to: l[l.length - 1], from: l[0] };
138
+ }), Z = $(
139
+ () => s.value !== null && s.value.from.scope !== s.value.to.scope
140
+ );
141
+ function ee(l) {
142
+ return l.started_by === "schedule" ? e("page.by-schedule") : l.started_by === "mcp" ? e("page.by-mcp") : l.started_by === "console" ? e("page.by-console") : l.started_by ? e("page.by-person") : "";
143
+ }
144
+ async function P(l) {
145
+ w.value = !0;
146
+ try {
147
+ f.value = await k.runs({ page: l?.page ?? 1, per_page: l?.perPage ?? 20 });
148
+ } catch (d) {
149
+ N.danger(x(d));
150
+ } finally {
151
+ w.value = !1;
152
+ }
153
+ }
154
+ async function ae() {
155
+ const l = V.value;
156
+ if (s.value = null, W.value = [], !!l) {
157
+ A.value = !0;
158
+ try {
159
+ s.value = await k.compare(l.to, l.from);
160
+ } catch (d) {
161
+ N.danger(x(d));
162
+ } finally {
163
+ A.value = !1;
164
+ }
165
+ }
166
+ }
167
+ const te = $(
168
+ () => o && f.value?.total ? [
169
+ {
170
+ key: "clear",
171
+ label: e("page.clear"),
172
+ icon: "trash",
173
+ danger: !0,
174
+ disabled: u.value,
175
+ run: () => {
176
+ le();
177
+ }
178
+ }
179
+ ] : []
180
+ );
181
+ async function le() {
182
+ if (await pe({
183
+ title: e("page.clear-title"),
184
+ message: e("page.clear-text"),
185
+ confirmText: e("page.clear-confirm"),
186
+ cancelText: e("page.clear-cancel"),
187
+ tone: "danger"
188
+ })) {
189
+ u.value = !0;
190
+ try {
191
+ await k.clear(), v.value = [], N.success(e("page.cleared")), await P();
192
+ } catch (d) {
193
+ N.danger(x(d));
194
+ } finally {
195
+ u.value = !1;
196
+ }
197
+ }
198
+ }
199
+ return se(() => {
200
+ const l = Number(T.query.to);
201
+ Number.isInteger(l) && l > 0 && (v.value = [l]);
202
+ }), F(v, (l) => {
203
+ l.length > 2 ? v.value = l.slice(-2) : ae();
204
+ }), (l, d) => (r(), g(ge, {
205
+ base: b.base,
206
+ current: "runs",
207
+ card: !1,
208
+ actions: te.value
209
+ }, {
210
+ default: n(() => [
211
+ re("div", _e, [
212
+ p(t(R), null, {
213
+ default: n(() => [
214
+ !V.value && f.value?.total ? (r(), g(t(U), {
215
+ key: 0,
216
+ type: "info",
217
+ description: t(e)("page.compare-help"),
218
+ class: "wx-audit-runs__note"
219
+ }, null, 8, ["description"])) : _("", !0),
220
+ p(t(q), {
221
+ selected: v.value,
222
+ "onUpdate:selected": d[0] || (d[0] = (a) => v.value = a),
223
+ data: f.value,
224
+ columns: X.value,
225
+ "row-key": "id",
226
+ selectable: "",
227
+ "selectable-if": (a) => a.status === "done",
228
+ flush: "",
229
+ loading: w.value,
230
+ "empty-text": t(e)("page.runs-empty"),
231
+ onStateChange: P
232
+ }, {
233
+ "cell-created_at": n(({ row: a }) => [
234
+ p(t(S), {
235
+ value: a.created_at
236
+ }, null, 8, ["value"])
237
+ ]),
238
+ "cell-scope": n(({ row: a }) => [
239
+ c(i(t(e)(`page.scope-${a.scope}`)), 1)
240
+ ]),
241
+ "cell-status": n(({ row: a }) => [
242
+ p(t(E), {
243
+ type: y[a.status],
244
+ dot: ""
245
+ }, {
246
+ default: n(() => [
247
+ c(i(t(e)(`page.status-${a.status}`)), 1)
248
+ ]),
249
+ _: 2
250
+ }, 1032, ["type"])
251
+ ]),
252
+ "cell-health": n(({ row: a }) => [
253
+ c(i(a.counts ? `${a.counts.health}%` : ""), 1)
254
+ ]),
255
+ "cell-severity": n(({ row: a }) => [
256
+ a.counts ? (r(), h("span", be, [
257
+ (r(), h(B, null, K(M, (ne, D) => (r(), h(B, { key: D }, [
258
+ a.counts.severity[D] ? (r(), g(t(E), {
259
+ key: 0,
260
+ type: ne,
261
+ size: "sm"
262
+ }, {
263
+ default: n(() => [
264
+ c(i(a.counts.severity[D]), 1)
265
+ ]),
266
+ _: 2
267
+ }, 1032, ["type"])) : _("", !0)
268
+ ], 64))), 64))
269
+ ])) : _("", !0)
270
+ ]),
271
+ "cell-started_by": n(({ row: a }) => [
272
+ c(i(ee(a)), 1)
273
+ ]),
274
+ _: 1
275
+ }, 8, ["selected", "data", "columns", "selectable-if", "loading", "empty-text"])
276
+ ]),
277
+ _: 1
278
+ }),
279
+ V.value ? (r(), g(t(R), {
280
+ key: 0,
281
+ title: t(e)("page.compare")
282
+ }, {
283
+ default: n(() => [
284
+ s.value ? (r(), g(t(z), {
285
+ key: 0,
286
+ size: "sm",
287
+ tone: "muted",
288
+ class: "wx-audit-runs__pair"
289
+ }, {
290
+ default: n(() => [
291
+ c(i(t(e)("page.compare-from")) + " #" + i(s.value.from.id) + " · ", 1),
292
+ p(t(S), {
293
+ value: s.value.from.created_at
294
+ }, null, 8, ["value"]),
295
+ c(" → " + i(t(e)("page.compare-to")) + " #" + i(s.value.to.id) + " · ", 1),
296
+ p(t(S), {
297
+ value: s.value.to.created_at
298
+ }, null, 8, ["value"])
299
+ ]),
300
+ _: 1
301
+ })) : _("", !0),
302
+ Z.value ? (r(), g(t(U), {
303
+ key: 1,
304
+ type: "info",
305
+ description: t(e)("page.compare-scopes"),
306
+ class: "wx-audit-runs__note"
307
+ }, null, 8, ["description"])) : _("", !0),
308
+ p(t(q), {
309
+ expanded: W.value,
310
+ "onUpdate:expanded": d[1] || (d[1] = (a) => W.value = a),
311
+ data: s.value?.checks ?? [],
312
+ columns: Y.value,
313
+ "row-key": "check",
314
+ expandable: "",
315
+ flush: "",
316
+ pagination: !1,
317
+ loading: A.value,
318
+ "empty-text": t(e)("page.compare-none")
319
+ }, {
320
+ "cell-severity": n(({ row: a }) => [
321
+ p(t(E), {
322
+ type: M[a.severity],
323
+ dot: ""
324
+ }, {
325
+ default: n(() => [
326
+ c(i(t(e)(`page.severity-${a.severity}`)), 1)
327
+ ]),
328
+ _: 2
329
+ }, 1032, ["type"])
330
+ ]),
331
+ "cell-new": n(({ row: a }) => [
332
+ p(t(z), {
333
+ tone: a.new ? "danger" : "muted",
334
+ size: "sm"
335
+ }, {
336
+ default: n(() => [
337
+ c(i(a.new), 1)
338
+ ]),
339
+ _: 2
340
+ }, 1032, ["tone"])
341
+ ]),
342
+ "cell-fixed": n(({ row: a }) => [
343
+ p(t(z), {
344
+ tone: a.fixed ? "success" : "muted",
345
+ size: "sm"
346
+ }, {
347
+ default: n(() => [
348
+ c(i(a.fixed), 1)
349
+ ]),
350
+ _: 2
351
+ }, 1032, ["tone"])
352
+ ]),
353
+ expanded: n(({ row: a }) => [
354
+ s.value ? (r(), g(ye, {
355
+ key: 0,
356
+ from: s.value.from.id,
357
+ to: s.value.to.id,
358
+ row: a
359
+ }, null, 8, ["from", "to", "row"])) : _("", !0)
360
+ ]),
361
+ _: 1
362
+ }, 8, ["expanded", "data", "columns", "loading", "empty-text"])
363
+ ]),
364
+ _: 1
365
+ }, 8, ["title"])) : _("", !0)
366
+ ])
367
+ ]),
368
+ _: 1
369
+ }, 8, ["base", "actions"]));
370
+ }
371
+ }), Ce = /* @__PURE__ */ Q(xe, [["__scopeId", "data-v-bbf74c27"]]);
372
+ export {
373
+ Ce as default
374
+ };
375
+ //# sourceMappingURL=AuditRunsPage-BbWsuATw.js.map
@@ -0,0 +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":"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"}
@@ -0,0 +1,88 @@
1
+ import { defineComponent as N, ref as n, onMounted as W, openBlock as o, createBlock as r, withCtx as u, createElementVNode as M, unref as e, createVNode as T, createTextVNode as x, toDisplayString as b, createCommentVNode as k } from "vue";
2
+ import { useRouter as h } from "vue-router";
3
+ import { useAdmin as E, useTranslate as w, useErrorText as P, WxScreen as $ } from "@webx-ui/module-admin";
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";
7
+ const z = { class: "wx-audit-settings" }, F = /* @__PURE__ */ N({
8
+ __name: "AuditSettingsPage",
9
+ props: {
10
+ base: {}
11
+ },
12
+ setup(V) {
13
+ const m = V, f = E(), p = U(f);
14
+ j();
15
+ const v = w("webx-audit"), S = w("webx-admin"), C = h(), g = P(), a = n({}), l = n({}), i = n(!0), c = n(!1), _ = f.can("audit.manage");
16
+ W(async () => {
17
+ try {
18
+ a.value = await p.settings();
19
+ } catch (s) {
20
+ d.danger(g(s));
21
+ } finally {
22
+ i.value = !1;
23
+ }
24
+ });
25
+ async function B() {
26
+ c.value = !0, l.value = {};
27
+ try {
28
+ a.value = await p.saveSettings(a.value), d.success(v("page.saved"));
29
+ } catch (s) {
30
+ const t = s.body;
31
+ t?.errors && (l.value = t.errors), d.danger(g(s));
32
+ } finally {
33
+ c.value = !1;
34
+ }
35
+ }
36
+ return (s, t) => (o(), r(R, {
37
+ base: m.base,
38
+ current: "settings",
39
+ card: !1
40
+ }, {
41
+ default: u(() => [
42
+ M("div", z, [
43
+ i.value ? (o(), r(e(D), {
44
+ key: 0,
45
+ rows: 6
46
+ })) : (o(), r(e($), {
47
+ key: 1,
48
+ modelValue: a.value,
49
+ "onUpdate:modelValue": t[0] || (t[0] = (y) => a.value = y),
50
+ name: "audit.settings",
51
+ errors: l.value,
52
+ disabled: !e(_)
53
+ }, null, 8, ["modelValue", "errors", "disabled"])),
54
+ i.value ? k("", !0) : (o(), r(e(I), { key: 2 }, {
55
+ default: u(() => [
56
+ T(e(A), {
57
+ icon: "arrow-left",
58
+ onClick: t[1] || (t[1] = (y) => e(C).push(m.base))
59
+ }, {
60
+ default: u(() => [
61
+ x(b(e(S)("editor.back")), 1)
62
+ ]),
63
+ _: 1
64
+ }),
65
+ e(_) ? (o(), r(e(A), {
66
+ key: 0,
67
+ type: "primary",
68
+ loading: c.value,
69
+ onClick: B
70
+ }, {
71
+ default: u(() => [
72
+ x(b(e(v)("page.save")), 1)
73
+ ]),
74
+ _: 1
75
+ }, 8, ["loading"])) : k("", !0)
76
+ ]),
77
+ _: 1
78
+ }))
79
+ ])
80
+ ]),
81
+ _: 1
82
+ }, 8, ["base"]));
83
+ }
84
+ }), Q = /* @__PURE__ */ q(F, [["__scopeId", "data-v-37901757"]]);
85
+ export {
86
+ Q as default
87
+ };
88
+ //# sourceMappingURL=AuditSettingsPage-HwfdLU_s.js.map
@@ -0,0 +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;;;;;;;;;;;;"}