smart-admin-web 10.26.0 → 10.28.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.
Files changed (62) hide show
  1. package/dist/api/index.d.ts +163 -0
  2. package/dist/api/index.js +195 -108
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/schema.d.ts +1465 -109
  5. package/dist/assets/icons/ph-subset.json.js +1 -1
  6. package/dist/components/FilePathUpload/index.vue.d.ts +35 -0
  7. package/dist/components/FilePathUpload/index.vue.js +47 -0
  8. package/dist/components/FilePathUpload/index.vue.js.map +1 -0
  9. package/dist/components/FilePathUpload/index2.vue.js +5 -0
  10. package/dist/components/FilePathUpload/index2.vue.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +302 -294
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/runtime.js +1 -1
  15. package/dist/locales/en-US.d.ts +141 -0
  16. package/dist/locales/en-US.js +136 -0
  17. package/dist/locales/en-US.js.map +1 -1
  18. package/dist/locales/kernelMenuTitles.js +10 -0
  19. package/dist/locales/kernelMenuTitles.js.map +1 -1
  20. package/dist/locales/zh-CN.d.ts +141 -0
  21. package/dist/locales/zh-CN.js +136 -0
  22. package/dist/locales/zh-CN.js.map +1 -1
  23. package/dist/router/viewRegistry.js +8 -8
  24. package/dist/router/viewRegistry.js.map +1 -1
  25. package/dist/style.css +1 -1
  26. package/dist/utils/error.js +22 -18
  27. package/dist/utils/error.js.map +1 -1
  28. package/dist/utils/filePathUpload.d.ts +14 -0
  29. package/dist/utils/filePathUpload.js +84 -0
  30. package/dist/utils/filePathUpload.js.map +1 -0
  31. package/dist/views/system/file-path/access.d.ts +15 -0
  32. package/dist/views/system/file-path/access.js +49 -0
  33. package/dist/views/system/file-path/access.js.map +1 -0
  34. package/dist/views/system/file-path/components/PathForm.vue.d.ts +18 -0
  35. package/dist/views/system/file-path/components/PathForm.vue.js +8 -0
  36. package/dist/views/system/file-path/components/PathForm.vue.js.map +1 -0
  37. package/dist/views/system/file-path/components/PathForm2.vue.js +529 -0
  38. package/dist/views/system/file-path/components/PathForm2.vue.js.map +1 -0
  39. package/dist/views/system/file-path/components/PathTab.vue.d.ts +3 -0
  40. package/dist/views/system/file-path/components/PathTab.vue.js +8 -0
  41. package/dist/views/system/file-path/components/PathTab.vue.js.map +1 -0
  42. package/dist/views/system/file-path/components/PathTab2.vue.js +226 -0
  43. package/dist/views/system/file-path/components/PathTab2.vue.js.map +1 -0
  44. package/dist/views/system/file-path/components/ServerForm.vue.d.ts +20 -0
  45. package/dist/views/system/file-path/components/ServerForm.vue.js +8 -0
  46. package/dist/views/system/file-path/components/ServerForm.vue.js.map +1 -0
  47. package/dist/views/system/file-path/components/ServerForm2.vue.js +328 -0
  48. package/dist/views/system/file-path/components/ServerForm2.vue.js.map +1 -0
  49. package/dist/views/system/file-path/components/ServerTab.vue.d.ts +7 -0
  50. package/dist/views/system/file-path/components/ServerTab.vue.js +8 -0
  51. package/dist/views/system/file-path/components/ServerTab.vue.js.map +1 -0
  52. package/dist/views/system/file-path/components/ServerTab2.vue.js +181 -0
  53. package/dist/views/system/file-path/components/ServerTab2.vue.js.map +1 -0
  54. package/dist/views/system/file-path/index.vue.d.ts +3 -0
  55. package/dist/views/system/file-path/index.vue.js +8 -0
  56. package/dist/views/system/file-path/index.vue.js.map +1 -0
  57. package/dist/views/system/file-path/index2.vue.js +61 -0
  58. package/dist/views/system/file-path/index2.vue.js.map +1 -0
  59. package/dist/views/system/file-path/rules.d.ts +61 -0
  60. package/dist/views/system/file-path/rules.js +53 -0
  61. package/dist/views/system/file-path/rules.js.map +1 -0
  62. package/package.json +1 -1
@@ -0,0 +1,226 @@
1
+ import { defineComponent as T, ref as d, onMounted as _, h as l, resolveDirective as N, openBlock as k, createElementBlock as z, Fragment as A, createVNode as m, unref as a, withCtx as p, withDirectives as C, createBlock as M, createTextVNode as O, toDisplayString as B } from "vue";
2
+ import { useMessage as L, NTag as U, NSpace as $, NButton as y, NPopconfirm as D } from "naive-ui";
3
+ import { useI18n as H } from "vue-i18n";
4
+ import { SmartTable as j } from "smart-naive-table";
5
+ import q from "../../../../components/AppIcon.vue.js";
6
+ import F from "../../../../components/StatusSwitch/index.vue.js";
7
+ import G from "../../../../components/TableTotal/index.vue.js";
8
+ import { useConfirm as V } from "../../../../composables/useConfirm.js";
9
+ import { filePathApi as u, roleApi as K } from "../../../../api/index.js";
10
+ import { useAuthStore as W } from "../../../../stores/auth.js";
11
+ import { translateError as Y } from "../../../../utils/error.js";
12
+ import { SEARCH_ACTIONS as J, deriveHeaderFilters as Q } from "../../../../utils/tableFilter.js";
13
+ import { TABLE_MIN_ROW_HEIGHT as X, TABLE_TOOLBAR as Z } from "../../../../utils/tableToolbar.js";
14
+ import { useAccessStatus as ee } from "../access.js";
15
+ import { NAMING_RULE_LABEL_KEYS as te } from "../rules.js";
16
+ import oe from "./PathForm.vue.js";
17
+ const Pe = /* @__PURE__ */ T({
18
+ __name: "PathTab",
19
+ setup(le) {
20
+ const { t } = H(), R = L(), { run: S } = V(), h = W(), f = d(), w = ee(u.status), g = d({});
21
+ _(async () => {
22
+ try {
23
+ g.value = Object.fromEntries((await K.options()).map((e) => [String(e.id), e.name]));
24
+ } catch {
25
+ }
26
+ });
27
+ function v(e) {
28
+ return e.length === 0 ? t("filePath.path.allLoggedIn") : e.map((o) => g.value[String(o)] ?? `#${o}`).join(t("filePath.path.roleSeparator"));
29
+ }
30
+ const x = (e) => ({
31
+ name: e.name,
32
+ serverId: e.serverId,
33
+ folder: e.folder,
34
+ namingRule: e.namingRule,
35
+ onConflict: e.onConflict,
36
+ readOnly: e.readOnly,
37
+ allowedExtensions: e.allowedExtensions,
38
+ maxSizeMb: e.maxSizeMb,
39
+ uploadRoleIds: e.uploadRoleIds,
40
+ downloadRoleIds: e.downloadRoleIds,
41
+ enabled: e.enabled,
42
+ remark: e.remark
43
+ }), n = () => l("span", { style: { color: "var(--text-3)" } }, "—"), P = [
44
+ { type: "index", title: () => t("common.rowNo"), width: 64, align: "center" },
45
+ // 只作搜索项,不进表格:后端的 keyword 同时匹配编码和名称
46
+ {
47
+ key: "keyword",
48
+ title: () => t("filePath.path.keyword"),
49
+ hideInTable: !0,
50
+ search: { actions: J.fuzzy }
51
+ },
52
+ {
53
+ key: "code",
54
+ width: 130,
55
+ ellipsis: { tooltip: !0 },
56
+ title: () => t("filePath.path.code"),
57
+ render: (e) => l("span", { class: "mono muted" }, e.code)
58
+ },
59
+ { key: "name", width: 100, ellipsis: { tooltip: !0 }, title: () => t("filePath.path.name") },
60
+ {
61
+ key: "serverName",
62
+ width: 100,
63
+ ellipsis: { tooltip: !0 },
64
+ title: () => t("filePath.path.server"),
65
+ render: (e) => e.serverName ?? n()
66
+ },
67
+ {
68
+ key: "folder",
69
+ width: 100,
70
+ ellipsis: { tooltip: !0 },
71
+ title: () => t("filePath.path.folder"),
72
+ render: (e) => e.folder ? l("span", { class: "mono muted" }, e.folder) : n()
73
+ },
74
+ {
75
+ key: "namingRule",
76
+ width: 124,
77
+ ellipsis: { tooltip: !0 },
78
+ title: () => t("filePath.path.namingRule"),
79
+ render: (e) => t(te[e.namingRule] ?? "filePath.path.unknownRule")
80
+ },
81
+ {
82
+ // 只读的路径不设后缀和上限,在这一格标出「只读」
83
+ key: "allowedExtensions",
84
+ width: 120,
85
+ ellipsis: { tooltip: !0 },
86
+ title: () => t("filePath.path.extensions"),
87
+ render: (e) => e.readOnly ? l(U, { size: "small", bordered: !1 }, () => t("filePath.path.readOnly")) : e.allowedExtensions ? l("span", { class: "mono muted" }, e.allowedExtensions) : n()
88
+ },
89
+ {
90
+ key: "maxSizeMb",
91
+ width: 80,
92
+ title: () => t("filePath.path.maxSize"),
93
+ render: (e) => e.maxSizeMb == null ? n() : l("span", { class: "num muted" }, `${e.maxSizeMb} MB`)
94
+ },
95
+ {
96
+ key: "status",
97
+ width: 90,
98
+ title: () => t("filePath.status.column"),
99
+ render: (e) => w.render(e.id)
100
+ },
101
+ {
102
+ key: "enabled",
103
+ title: () => t("common.status"),
104
+ width: 70,
105
+ render: (e) => l(F, {
106
+ value: e.enabled,
107
+ disabled: !h.hasPerm("PUT:/api/v1/sys/file-path/{id}"),
108
+ request: (o) => u.update(Number(e.id), { ...x(e), enabled: o }),
109
+ "onUpdate:value": (o) => {
110
+ e.enabled = o;
111
+ }
112
+ })
113
+ },
114
+ {
115
+ key: "uploadRoleIds",
116
+ width: 112,
117
+ ellipsis: { tooltip: !0 },
118
+ title: () => t("filePath.path.uploadRoles"),
119
+ render: (e) => v(e.uploadRoleIds)
120
+ },
121
+ {
122
+ key: "downloadRoleIds",
123
+ width: 112,
124
+ ellipsis: { tooltip: !0 },
125
+ title: () => t("filePath.path.downloadRoles"),
126
+ render: (e) => v(e.downloadRoleIds)
127
+ },
128
+ {
129
+ key: "op",
130
+ title: () => t("common.operation"),
131
+ width: 110,
132
+ align: "right",
133
+ fixed: "right",
134
+ hideInSetting: !0,
135
+ render: (e) => l($, { size: 2, wrapItem: !1, justify: "end" }, () => [
136
+ h.hasPerm("PUT:/api/v1/sys/file-path/{id}") ? l(
137
+ y,
138
+ { size: "small", quaternary: !0, type: "primary", onClick: () => I(e) },
139
+ () => t("common.edit")
140
+ ) : null,
141
+ h.hasPerm("DELETE:/api/v1/sys/file-path/{id}") ? l(
142
+ D,
143
+ {
144
+ onPositiveClick: () => S(() => u.remove(Number(e.id)), t("filePath.deleted")).then((o) => {
145
+ var s;
146
+ o && ((s = f.value) == null || s.refresh());
147
+ })
148
+ },
149
+ {
150
+ trigger: () => l(
151
+ y,
152
+ { size: "small", quaternary: !0, type: "error" },
153
+ () => t("common.delete")
154
+ ),
155
+ default: () => t("filePath.path.deleteConfirm", { name: e.name })
156
+ }
157
+ ) : null
158
+ ])
159
+ }
160
+ ];
161
+ Q(P);
162
+ const r = d(!1), c = d(null);
163
+ function E() {
164
+ c.value = null, r.value = !0;
165
+ }
166
+ function I(e) {
167
+ c.value = e, r.value = !0;
168
+ }
169
+ return (e, o) => {
170
+ const s = N("auth");
171
+ return k(), z(A, null, [
172
+ m(a(j), {
173
+ ref_key: "tableRef",
174
+ ref: f,
175
+ toolbar: a(Z),
176
+ columns: P,
177
+ fetcher: a(u).page,
178
+ search: { container: "table" },
179
+ "fill-height": "",
180
+ "min-row-height": a(X),
181
+ "card-on-narrow": "",
182
+ "storage-key": "sys-file-path",
183
+ onLoaded: o[0] || (o[0] = (i) => a(w).load(i)),
184
+ onError: o[1] || (o[1] = (i) => a(R).error(a(Y)(i)))
185
+ }, {
186
+ "pagination-prefix": p(({ itemCount: i }) => [
187
+ m(G, { count: i }, null, 8, ["count"])
188
+ ]),
189
+ "toolbar-right": p(() => [
190
+ C((k(), M(a(y), {
191
+ type: "primary",
192
+ onClick: E
193
+ }, {
194
+ icon: p(() => [
195
+ m(q, {
196
+ icon: "ph:plus",
197
+ size: 16
198
+ })
199
+ ]),
200
+ default: p(() => [
201
+ O(" " + B(a(t)("common.add")), 1)
202
+ ]),
203
+ _: 1
204
+ })), [
205
+ [s, "POST:/api/v1/sys/file-path/add"]
206
+ ])
207
+ ]),
208
+ _: 1
209
+ }, 8, ["toolbar", "fetcher", "min-row-height"]),
210
+ m(oe, {
211
+ show: r.value,
212
+ "onUpdate:show": o[2] || (o[2] = (i) => r.value = i),
213
+ editing: c.value,
214
+ onSaved: o[3] || (o[3] = (i) => {
215
+ var b;
216
+ return (b = f.value) == null ? void 0 : b.refresh();
217
+ })
218
+ }, null, 8, ["show", "editing"])
219
+ ], 64);
220
+ };
221
+ }
222
+ });
223
+ export {
224
+ Pe as default
225
+ };
226
+ //# sourceMappingURL=PathTab2.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PathTab2.vue.js","sources":["../../../../../src/views/system/file-path/components/PathTab.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 「文件路径」页签:列表 + 新增/编辑抽屉。在线状态在一页取完后另外问一次,见 access.ts。\nimport { h, onMounted, ref } from 'vue'\nimport { NButton, NPopconfirm, NSpace, NTag, useMessage } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport AppIcon from '#/components/AppIcon.vue'\nimport StatusSwitch from '#/components/StatusSwitch/index.vue'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { filePathApi, roleApi, type FilePathUpdateInput, type FilePathView } from '#/api'\nimport { useAuthStore } from '#/stores/auth'\nimport { translateError } from '#/utils/error'\nimport { SEARCH_ACTIONS, deriveHeaderFilters } from '#/utils/tableFilter'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport { useAccessStatus } from '../access'\nimport { NAMING_RULE_LABEL_KEYS } from '../rules'\nimport PathForm from './PathForm.vue'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { run } = useConfirm()\nconst authStore = useAuthStore()\nconst tableRef = ref<SmartTableInst<FilePathView>>()\nconst status = useAccessStatus(filePathApi.status)\n\n// 角色列只存 Id,名称取启用角色的下拉数据(登录即可调用);查不到的(已停用)显示 #Id\nconst roleNames = ref<Record<string, string>>({})\nonMounted(async () => {\n try {\n roleNames.value = Object.fromEntries((await roleApi.options()).map(r => [String(r.id), r.name]))\n } catch {\n // 拿不到名称只是退化成显示 Id,不打断页面\n }\n})\nfunction rolesText(ids: (number | string)[]) {\n return ids.length === 0\n ? t('filePath.path.allLoggedIn')\n : ids.map(id => roleNames.value[String(id)] ?? `#${id}`).join(t('filePath.path.roleSeparator'))\n}\n\n// 行数据 → 更新入参:只给行内启停用(后端没有独立启停端点,走全量 update);编辑抽屉按行数据自己回填\nconst toInput = (r: FilePathView): FilePathUpdateInput => ({\n name: r.name,\n serverId: r.serverId,\n folder: r.folder,\n namingRule: r.namingRule,\n onConflict: r.onConflict,\n readOnly: r.readOnly,\n allowedExtensions: r.allowedExtensions,\n maxSizeMb: r.maxSizeMb,\n uploadRoleIds: r.uploadRoleIds,\n downloadRoleIds: r.downloadRoleIds,\n enabled: r.enabled,\n remark: r.remark,\n})\n\nconst dash = () => h('span', { style: { color: 'var(--text-3)' } }, '—')\n\nconst columns: SmartTableColumn<FilePathView>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n // 只作搜索项,不进表格:后端的 keyword 同时匹配编码和名称\n {\n key: 'keyword',\n title: () => t('filePath.path.keyword'),\n hideInTable: true,\n search: { actions: SEARCH_ACTIONS.fuzzy },\n },\n {\n key: 'code',\n width: 130,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.code'),\n render: r => h('span', { class: 'mono muted' }, r.code),\n },\n { key: 'name', width: 100, ellipsis: { tooltip: true }, title: () => t('filePath.path.name') },\n {\n key: 'serverName',\n width: 100,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.server'),\n render: r => r.serverName ?? dash(),\n },\n {\n key: 'folder',\n width: 100,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.folder'),\n render: r => (r.folder ? h('span', { class: 'mono muted' }, r.folder) : dash()),\n },\n {\n key: 'namingRule',\n width: 124,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.namingRule'),\n render: r => t(NAMING_RULE_LABEL_KEYS[r.namingRule] ?? 'filePath.path.unknownRule'),\n },\n {\n // 只读的路径不设后缀和上限,在这一格标出「只读」\n key: 'allowedExtensions',\n width: 120,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.extensions'),\n render: r =>\n r.readOnly\n ? h(NTag, { size: 'small', bordered: false }, () => t('filePath.path.readOnly'))\n : r.allowedExtensions\n ? h('span', { class: 'mono muted' }, r.allowedExtensions)\n : dash(),\n },\n {\n key: 'maxSizeMb',\n width: 80,\n title: () => t('filePath.path.maxSize'),\n render: r =>\n r.maxSizeMb == null ? dash() : h('span', { class: 'num muted' }, `${r.maxSizeMb} MB`),\n },\n {\n key: 'status',\n width: 90,\n title: () => t('filePath.status.column'),\n render: r => status.render(r.id),\n },\n {\n key: 'enabled',\n title: () => t('common.status'),\n width: 70,\n render: r =>\n h(StatusSwitch, {\n value: r.enabled,\n disabled: !authStore.hasPerm('PUT:/api/v1/sys/file-path/{id}'),\n request: (next: boolean) =>\n filePathApi.update(Number(r.id), { ...toInput(r), enabled: next }),\n 'onUpdate:value': (v: boolean) => {\n r.enabled = v\n },\n }),\n },\n {\n key: 'uploadRoleIds',\n width: 112,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.uploadRoles'),\n render: r => rolesText(r.uploadRoleIds),\n },\n {\n key: 'downloadRoleIds',\n width: 112,\n ellipsis: { tooltip: true },\n title: () => t('filePath.path.downloadRoles'),\n render: r => rolesText(r.downloadRoleIds),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 110,\n align: 'right',\n fixed: 'right',\n hideInSetting: true,\n render: r =>\n h(NSpace, { size: 2, wrapItem: false, justify: 'end' }, () => [\n authStore.hasPerm('PUT:/api/v1/sys/file-path/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'primary', onClick: () => openEdit(r) },\n () => t('common.edit'),\n )\n : null,\n authStore.hasPerm('DELETE:/api/v1/sys/file-path/{id}')\n ? h(\n NPopconfirm,\n {\n onPositiveClick: () =>\n run(() => filePathApi.remove(Number(r.id)), t('filePath.deleted')).then(ok => {\n if (ok) tableRef.value?.refresh()\n }),\n },\n {\n trigger: () =>\n h(NButton, { size: 'small', quaternary: true, type: 'error' }, () =>\n t('common.delete'),\n ),\n default: () => t('filePath.path.deleteConfirm', { name: r.name }),\n },\n )\n : null,\n ]),\n },\n]\nderiveHeaderFilters(columns)\n\n// ── 新增/编辑抽屉 ──\nconst formShow = ref(false)\nconst editing = ref<FilePathView | null>(null)\nfunction openAdd() {\n editing.value = null\n formShow.value = true\n}\nfunction openEdit(r: FilePathView) {\n editing.value = r\n formShow.value = true\n}\n</script>\n\n<template>\n <SmartTable\n ref=\"tableRef\"\n :toolbar=\"TABLE_TOOLBAR\"\n :columns=\"columns\"\n :fetcher=\"filePathApi.page\"\n :search=\"{ container: 'table' }\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-file-path\"\n @loaded=\"rows => status.load(rows)\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n <template #toolbar-right>\n <n-button v-auth=\"'POST:/api/v1/sys/file-path/add'\" type=\"primary\" @click=\"openAdd\">\n <template #icon><AppIcon icon=\"ph:plus\" :size=\"16\" /></template>\n {{ t('common.add') }}\n </n-button>\n </template>\n </SmartTable>\n\n <PathForm v-model:show=\"formShow\" :editing=\"editing\" @saved=\"tableRef?.refresh()\" />\n</template>\n\n<style scoped>\n/* 表格单元格由库渲染,要 :deep */\n:deep(.mono) {\n font-family: var(--font-mono);\n font-size: 13.5px;\n letter-spacing: 0;\n}\n:deep(.muted) {\n color: var(--text-2);\n}\n</style>\n"],"names":["useI18n","message","useMessage","run","useConfirm","authStore","useAuthStore","tableRef","ref","status","useAccessStatus","filePathApi","roleNames","onMounted","roleApi","r","rolesText","ids","id","toInput","dash","h","columns","SEARCH_ACTIONS","NAMING_RULE_LABEL_KEYS","NTag","StatusSwitch","next","v","NSpace","NButton","openEdit","NPopconfirm","ok","_a","deriveHeaderFilters","formShow","editing","openAdd","_createVNode","_unref","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","rows","_cache","e","translateError","_withCtx","itemCount","TableTotal","_createBlock","AppIcon","_createTextVNode","PathForm","$event"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { FilePathEnvironment, FileServerView } from '../../../../api';
2
+ type __VLS_Props = {
3
+ editing: FileServerView | null;
4
+ /** 白名单根目录与平台能力;拿不到时(没有查询权限)按「能用账号」、没有候选处理。 */
5
+ environment: FilePathEnvironment | null;
6
+ };
7
+ type __VLS_ModelProps = {
8
+ 'show'?: boolean;
9
+ };
10
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
11
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
12
+ "update:show": (value: boolean) => any;
13
+ } & {
14
+ saved: () => any;
15
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
16
+ onSaved?: (() => any) | undefined;
17
+ "onUpdate:show"?: ((value: boolean) => any) | undefined;
18
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
19
+ declare const _default: typeof __VLS_export;
20
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import o from "./ServerForm2.vue.js";
2
+ /* empty css */
3
+ import r from "../../../../_virtual/_plugin-vue_export-helper.js";
4
+ const c = /* @__PURE__ */ r(o, [["__scopeId", "data-v-bdcbb4ca"]]);
5
+ export {
6
+ c as default
7
+ };
8
+ //# sourceMappingURL=ServerForm.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerForm.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,328 @@
1
+ import { defineComponent as $, useModel as j, ref as _, computed as v, reactive as L, watch as C, resolveDirective as Q, openBlock as m, createBlock as h, unref as e, withCtx as o, createTextVNode as w, toDisplayString as p, createCommentVNode as P, createVNode as s, mergeProps as G, createElementVNode as J, createElementBlock as M, withDirectives as K, normalizeClass as X, mergeModels as q } from "vue";
2
+ import { useMessage as Y, NAlert as Z, NForm as ee, NFormItem as d, NInput as b, NAutoComplete as ae, NSpace as R, NTag as te, NButton as le, NSwitch as re } from "naive-ui";
3
+ import { useMediaQuery as se } from "@vueuse/core";
4
+ import { useI18n as oe } from "vue-i18n";
5
+ import ie from "../../../../components/AppIcon.vue.js";
6
+ import ne from "../../../../components/FormContainer/index.vue.js";
7
+ /* empty css */
8
+ import { fileServerApi as z } from "../../../../api/index.js";
9
+ import { translateError as B } from "../../../../utils/error.js";
10
+ import { reasonText as ue } from "../access.js";
11
+ import { passwordReentryRequired as de, credentialCascade as me } from "../rules.js";
12
+ const pe = { class: "hint" }, fe = {
13
+ key: 0,
14
+ class: "hint cascade"
15
+ }, _e = /* @__PURE__ */ $({
16
+ __name: "ServerForm",
17
+ props: /* @__PURE__ */ q({
18
+ editing: {},
19
+ environment: {}
20
+ }, {
21
+ show: { type: Boolean, default: !1 },
22
+ showModifiers: {}
23
+ }),
24
+ emits: /* @__PURE__ */ q(["saved"], ["update:show"]),
25
+ setup(c, { emit: E }) {
26
+ const g = j(c, "show"), n = c, F = E, { t: l } = oe(), N = Y(), k = _(null), V = se("(max-width: 640px)"), A = v(
27
+ () => V.value ? { labelPlacement: "top", labelWidth: void 0 } : { labelPlacement: "left", labelWidth: 100 }
28
+ ), f = v(() => {
29
+ var r;
30
+ return ((r = n.environment) == null ? void 0 : r.supportsCredentials) ?? !0;
31
+ }), D = v(
32
+ () => {
33
+ var r;
34
+ return (((r = n.environment) == null ? void 0 : r.allowedRoots) ?? []).map((t) => ({ label: t, value: t }));
35
+ }
36
+ ), U = () => ({
37
+ name: "",
38
+ rootPath: "",
39
+ userName: "",
40
+ password: "",
41
+ enabled: !0,
42
+ remark: ""
43
+ }), a = L(U()), S = v(
44
+ () => n.editing !== null && f.value && de(n.editing, a.rootPath, a.userName)
45
+ ), T = v(() => {
46
+ if (n.editing === null || !f.value) return null;
47
+ const r = me(n.editing, a.rootPath, a.userName, a.password);
48
+ return r && l(r === "clear" ? "filePath.server.cascadeClear" : "filePath.server.cascadeChange");
49
+ }), I = {
50
+ name: {
51
+ required: !0,
52
+ whitespace: !0,
53
+ message: () => l("filePath.server.nameRequired"),
54
+ trigger: ["input", "blur"]
55
+ },
56
+ rootPath: {
57
+ required: !0,
58
+ whitespace: !0,
59
+ message: () => l("filePath.server.rootPathRequired"),
60
+ trigger: ["input", "blur"]
61
+ },
62
+ password: {
63
+ validator: () => S.value && !a.password ? new Error(l("filePath.server.passwordReentry")) : !0,
64
+ trigger: ["input", "blur"]
65
+ }
66
+ };
67
+ C(g, (r) => {
68
+ if (!r) return;
69
+ u.value = null;
70
+ const t = n.editing;
71
+ Object.assign(
72
+ a,
73
+ t ? {
74
+ name: t.name,
75
+ rootPath: t.rootPath,
76
+ userName: t.userName ?? "",
77
+ password: "",
78
+ enabled: t.enabled,
79
+ remark: t.remark ?? ""
80
+ } : U()
81
+ );
82
+ }), C(S, () => {
83
+ var r;
84
+ (r = k.value) == null || r.validate(void 0, ["password"]).catch(() => {
85
+ });
86
+ });
87
+ const y = _(!1), u = _(null);
88
+ C(
89
+ () => [a.rootPath, a.userName, a.password],
90
+ () => {
91
+ u.value = null;
92
+ }
93
+ );
94
+ async function O() {
95
+ y.value = !0, u.value = null;
96
+ try {
97
+ u.value = await z.test({
98
+ id: n.editing ? Number(n.editing.id) : null,
99
+ rootPath: a.rootPath.trim(),
100
+ userName: a.userName.trim() || null,
101
+ password: a.password || null
102
+ });
103
+ } catch (r) {
104
+ N.error(B(r));
105
+ } finally {
106
+ y.value = !1;
107
+ }
108
+ }
109
+ async function H() {
110
+ var t;
111
+ await ((t = k.value) == null ? void 0 : t.validate());
112
+ const r = {
113
+ name: a.name.trim(),
114
+ rootPath: a.rootPath.trim(),
115
+ userName: a.userName.trim() || null,
116
+ password: a.password || null,
117
+ enabled: a.enabled,
118
+ remark: a.remark.trim() || null
119
+ };
120
+ try {
121
+ n.editing === null ? await z.add(r) : await z.update(Number(n.editing.id), r), N.success(l("filePath.saved")), F("saved");
122
+ } catch (x) {
123
+ return N.error(B(x)), !1;
124
+ }
125
+ }
126
+ return (r, t) => {
127
+ const x = Q("auth");
128
+ return m(), h(ne, {
129
+ show: g.value,
130
+ "onUpdate:show": t[6] || (t[6] = (i) => g.value = i),
131
+ variant: "drawer",
132
+ width: 640,
133
+ title: c.editing === null ? e(l)("filePath.server.addTitle") : e(l)("filePath.server.editTitle"),
134
+ "on-confirm": H,
135
+ "confirm-text": e(l)("common.save")
136
+ }, {
137
+ default: o(() => [
138
+ f.value ? P("", !0) : (m(), h(e(Z), {
139
+ key: 0,
140
+ type: "info",
141
+ bordered: !1,
142
+ class: "tip"
143
+ }, {
144
+ default: o(() => [
145
+ w(p(e(l)("filePath.server.credentialsUnsupported")), 1)
146
+ ]),
147
+ _: 1
148
+ })),
149
+ s(e(ee), G({
150
+ ref_key: "formRef",
151
+ ref: k,
152
+ model: a,
153
+ rules: I
154
+ }, A.value), {
155
+ default: o(() => [
156
+ s(e(d), {
157
+ label: e(l)("filePath.server.name"),
158
+ path: "name"
159
+ }, {
160
+ default: o(() => [
161
+ s(e(b), {
162
+ value: a.name,
163
+ "onUpdate:value": t[0] || (t[0] = (i) => a.name = i),
164
+ maxlength: "64",
165
+ placeholder: e(l)("filePath.server.name")
166
+ }, null, 8, ["value", "placeholder"])
167
+ ]),
168
+ _: 1
169
+ }, 8, ["label"]),
170
+ s(e(d), {
171
+ label: e(l)("filePath.server.rootPath"),
172
+ path: "rootPath"
173
+ }, {
174
+ default: o(() => [
175
+ s(e(ae), {
176
+ value: a.rootPath,
177
+ "onUpdate:value": t[1] || (t[1] = (i) => a.rootPath = i),
178
+ options: D.value,
179
+ "get-show": () => !0,
180
+ "input-props": { maxlength: 260 },
181
+ placeholder: e(l)("filePath.server.rootPathPlaceholder")
182
+ }, null, 8, ["value", "options", "placeholder"])
183
+ ]),
184
+ _: 1
185
+ }, 8, ["label"]),
186
+ s(e(d), {
187
+ label: e(l)("filePath.server.userName")
188
+ }, {
189
+ default: o(() => [
190
+ s(e(b), {
191
+ value: a.userName,
192
+ "onUpdate:value": t[2] || (t[2] = (i) => a.userName = i),
193
+ maxlength: "128",
194
+ disabled: !f.value,
195
+ placeholder: e(l)("filePath.server.userNamePlaceholder"),
196
+ "input-props": { autocomplete: "off" }
197
+ }, null, 8, ["value", "disabled", "placeholder"])
198
+ ]),
199
+ _: 1
200
+ }, 8, ["label"]),
201
+ s(e(d), {
202
+ label: e(l)("filePath.server.password"),
203
+ path: "password"
204
+ }, {
205
+ default: o(() => [
206
+ s(e(R), {
207
+ vertical: "",
208
+ size: 2,
209
+ style: { width: "100%" }
210
+ }, {
211
+ default: o(() => [
212
+ s(e(R), {
213
+ size: 8,
214
+ align: "center",
215
+ wrap: !1
216
+ }, {
217
+ default: o(() => {
218
+ var i;
219
+ return [
220
+ s(e(b), {
221
+ value: a.password,
222
+ "onUpdate:value": t[3] || (t[3] = (W) => a.password = W),
223
+ type: "password",
224
+ "show-password-on": "click",
225
+ disabled: !f.value,
226
+ placeholder: e(l)("filePath.server.passwordPlaceholder"),
227
+ "input-props": { autocomplete: "new-password" },
228
+ style: { "min-width": "220px" }
229
+ }, null, 8, ["value", "disabled", "placeholder"]),
230
+ (i = c.editing) != null && i.hasPassword ? (m(), h(e(te), {
231
+ key: 0,
232
+ size: "small",
233
+ type: "success",
234
+ bordered: !1
235
+ }, {
236
+ default: o(() => [
237
+ w(p(e(l)("filePath.server.passwordSet")), 1)
238
+ ]),
239
+ _: 1
240
+ })) : P("", !0)
241
+ ];
242
+ }),
243
+ _: 1
244
+ }),
245
+ J("span", pe, p(e(l)("filePath.server.passwordHint")), 1),
246
+ T.value ? (m(), M("span", fe, p(T.value), 1)) : P("", !0)
247
+ ]),
248
+ _: 1
249
+ })
250
+ ]),
251
+ _: 1
252
+ }, 8, ["label"]),
253
+ s(e(d), {
254
+ label: e(l)("filePath.test.action")
255
+ }, {
256
+ default: o(() => [
257
+ s(e(R), {
258
+ size: 12,
259
+ align: "center"
260
+ }, {
261
+ default: o(() => [
262
+ K((m(), h(e(le), {
263
+ size: "small",
264
+ loading: y.value,
265
+ disabled: !a.rootPath.trim(),
266
+ onClick: O
267
+ }, {
268
+ default: o(() => [
269
+ w(p(e(l)("filePath.test.action")), 1)
270
+ ]),
271
+ _: 1
272
+ }, 8, ["loading", "disabled"])), [
273
+ [x, "POST:/api/v1/sys/file-server/test"]
274
+ ]),
275
+ u.value ? (m(), M("span", {
276
+ key: 0,
277
+ class: X(["test-result", u.value.ok ? "ok" : "fail"])
278
+ }, [
279
+ s(ie, {
280
+ icon: u.value.ok ? "ph:check-circle" : "ph:x-circle",
281
+ size: 16
282
+ }, null, 8, ["icon"]),
283
+ w(" " + p(u.value.ok ? e(l)("filePath.test.ok", { ms: u.value.latencyMs }) : e(l)("filePath.test.failed", { reason: e(ue)(u.value.reason) })), 1)
284
+ ], 2)) : P("", !0)
285
+ ]),
286
+ _: 1
287
+ })
288
+ ]),
289
+ _: 1
290
+ }, 8, ["label"]),
291
+ s(e(d), {
292
+ label: e(l)("common.enabled")
293
+ }, {
294
+ default: o(() => [
295
+ s(e(re), {
296
+ value: a.enabled,
297
+ "onUpdate:value": t[4] || (t[4] = (i) => a.enabled = i)
298
+ }, null, 8, ["value"])
299
+ ]),
300
+ _: 1
301
+ }, 8, ["label"]),
302
+ s(e(d), {
303
+ label: e(l)("filePath.remark")
304
+ }, {
305
+ default: o(() => [
306
+ s(e(b), {
307
+ value: a.remark,
308
+ "onUpdate:value": t[5] || (t[5] = (i) => a.remark = i),
309
+ type: "textarea",
310
+ maxlength: "512",
311
+ autosize: { minRows: 2 }
312
+ }, null, 8, ["value"])
313
+ ]),
314
+ _: 1
315
+ }, 8, ["label"])
316
+ ]),
317
+ _: 1
318
+ }, 16, ["model"])
319
+ ]),
320
+ _: 1
321
+ }, 8, ["show", "title", "confirm-text"]);
322
+ };
323
+ }
324
+ });
325
+ export {
326
+ _e as default
327
+ };
328
+ //# sourceMappingURL=ServerForm2.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerForm2.vue.js","sources":["../../../../../src/views/system/file-path/components/ServerForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 文件服务器新增/编辑抽屉。show/editing 走 v-model + prop(null = 新增),与 AI 厂商的 ProviderForm 同一协议。\n// 密码留空表示不改;换了主机或账号而密码仍留空,后端拒绝保存(44157),表单先挡住。\n// 同一主机的文件服务器共用一套账号和密码:改了账号或密码,保存后同主机的其他行一起改,表单在密码框下提示。\nimport { computed, reactive, ref, watch } from 'vue'\nimport {\n NAlert,\n NAutoComplete,\n NButton,\n NForm,\n NFormItem,\n NInput,\n NSpace,\n NSwitch,\n NTag,\n useMessage,\n type FormInst,\n type FormRules,\n} from 'naive-ui'\nimport { useMediaQuery } from '@vueuse/core'\nimport { useI18n } from 'vue-i18n'\nimport AppIcon from '#/components/AppIcon.vue'\nimport FormContainer from '#/components/FormContainer/index.vue'\nimport {\n fileServerApi,\n type FileAccessTestResult,\n type FilePathEnvironment,\n type FileServerSaveInput,\n type FileServerView,\n} from '#/api'\nimport { translateError } from '#/utils/error'\nimport { reasonText } from '../access'\nimport { credentialCascade, passwordReentryRequired } from '../rules'\n\nconst show = defineModel<boolean>('show', { default: false })\nconst props = defineProps<{\n editing: FileServerView | null\n /** 白名单根目录与平台能力;拿不到时(没有查询权限)按「能用账号」、没有候选处理。 */\n environment: FilePathEnvironment | null\n}>()\nconst emit = defineEmits<{ (e: 'saved'): void }>()\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst formRef = ref<FormInst | null>(null)\n\n// 窄屏标签放上方,底部抽屉里横排标签太挤\nconst narrowForm = useMediaQuery('(max-width: 640px)')\nconst formLayout = computed(() =>\n narrowForm.value\n ? { labelPlacement: 'top' as const, labelWidth: undefined }\n : { labelPlacement: 'left' as const, labelWidth: 100 },\n)\n\nconst supportsCredentials = computed(() => props.environment?.supportsCredentials ?? true)\nconst rootOptions = computed(() =>\n (props.environment?.allowedRoots ?? []).map(r => ({ label: r, value: r })),\n)\n\ninterface ServerFormState {\n name: string\n rootPath: string\n userName: string\n password: string\n enabled: boolean\n remark: string\n}\nconst blank = (): ServerFormState => ({\n name: '',\n rootPath: '',\n userName: '',\n password: '',\n enabled: true,\n remark: '',\n})\nconst form = reactive<ServerFormState>(blank())\n\n// 换主机或账号时必须重填(原来有没有密码都一样)。不支持账号密码的平台(Linux)上不要求:那里换主机同样会让这条判断成立,\n// 但后端不用账号密码连接,密码框也是置灰的,所以由 supportsCredentials 直接挡掉。\nconst reentry = computed(\n () =>\n props.editing !== null &&\n supportsCredentials.value &&\n passwordReentryRequired(props.editing, form.rootPath, form.userName),\n)\n\n// 同主机级联的提示;只在编辑、平台支持账号时出现\nconst cascadeHint = computed(() => {\n if (props.editing === null || !supportsCredentials.value) return null\n const kind = credentialCascade(props.editing, form.rootPath, form.userName, form.password)\n return (\n kind && t(kind === 'clear' ? 'filePath.server.cascadeClear' : 'filePath.server.cascadeChange')\n )\n})\n\nconst rules: FormRules = {\n name: {\n required: true,\n whitespace: true,\n message: () => t('filePath.server.nameRequired'),\n trigger: ['input', 'blur'],\n },\n rootPath: {\n required: true,\n whitespace: true,\n message: () => t('filePath.server.rootPathRequired'),\n trigger: ['input', 'blur'],\n },\n password: {\n validator: () =>\n reentry.value && !form.password ? new Error(t('filePath.server.passwordReentry')) : true,\n trigger: ['input', 'blur'],\n },\n}\n\n// 回填/重置:组件随父页常驻,每次打开都按 editing 重置,不能指望重新挂载清空。\nwatch(show, v => {\n if (!v) return\n testResult.value = null\n const e = props.editing\n Object.assign(\n form,\n e\n ? {\n name: e.name,\n rootPath: e.rootPath,\n userName: e.userName ?? '',\n password: '',\n enabled: e.enabled,\n remark: e.remark ?? '',\n }\n : blank(),\n )\n})\n\n// 放在回填之后注册:打开抽屉时先按 editing 回填,再判断要不要重填,不拿上一次的表单值去校验。\n// 主机或账号改过之后要不要重填密码可能变了:重新校验密码框,改回原值时过时的「请重新填写密码」随之消失\nwatch(reentry, () => {\n formRef.value?.validate(undefined, ['password']).catch(() => undefined)\n})\n\n// ── 测试连接:用表单里当前填的值,结果在返回体里(ok=false 不代表接口失败) ──\nconst testing = ref(false)\nconst testResult = ref<FileAccessTestResult | null>(null)\nwatch(\n () => [form.rootPath, form.userName, form.password],\n () => {\n testResult.value = null\n },\n)\nasync function onTest() {\n testing.value = true\n testResult.value = null\n try {\n testResult.value = await fileServerApi.test({\n id: props.editing ? Number(props.editing.id) : null,\n rootPath: form.rootPath.trim(),\n userName: form.userName.trim() || null,\n password: form.password || null,\n })\n } catch (e) {\n message.error(translateError(e))\n } finally {\n testing.value = false\n }\n}\n\nasync function save() {\n await formRef.value?.validate()\n const body: FileServerSaveInput = {\n name: form.name.trim(),\n rootPath: form.rootPath.trim(),\n userName: form.userName.trim() || null,\n password: form.password || null,\n enabled: form.enabled,\n remark: form.remark.trim() || null,\n }\n try {\n if (props.editing === null) await fileServerApi.add(body)\n else await fileServerApi.update(Number(props.editing.id), body)\n message.success(t('filePath.saved'))\n emit('saved')\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n</script>\n\n<template>\n <FormContainer\n v-model:show=\"show\"\n variant=\"drawer\"\n :width=\"640\"\n :title=\"editing === null ? t('filePath.server.addTitle') : t('filePath.server.editTitle')\"\n :on-confirm=\"save\"\n :confirm-text=\"t('common.save')\"\n >\n <n-alert v-if=\"!supportsCredentials\" type=\"info\" :bordered=\"false\" class=\"tip\">\n {{ t('filePath.server.credentialsUnsupported') }}\n </n-alert>\n <n-form ref=\"formRef\" :model=\"form\" :rules=\"rules\" v-bind=\"formLayout\">\n <n-form-item :label=\"t('filePath.server.name')\" path=\"name\">\n <n-input\n v-model:value=\"form.name\"\n maxlength=\"64\"\n :placeholder=\"t('filePath.server.name')\"\n />\n </n-form-item>\n <n-form-item :label=\"t('filePath.server.rootPath')\" path=\"rootPath\">\n <n-auto-complete\n v-model:value=\"form.rootPath\"\n :options=\"rootOptions\"\n :get-show=\"() => true\"\n :input-props=\"{ maxlength: 260 }\"\n :placeholder=\"t('filePath.server.rootPathPlaceholder')\"\n />\n </n-form-item>\n <n-form-item :label=\"t('filePath.server.userName')\">\n <n-input\n v-model:value=\"form.userName\"\n maxlength=\"128\"\n :disabled=\"!supportsCredentials\"\n :placeholder=\"t('filePath.server.userNamePlaceholder')\"\n :input-props=\"{ autocomplete: 'off' }\"\n />\n </n-form-item>\n <n-form-item :label=\"t('filePath.server.password')\" path=\"password\">\n <n-space vertical :size=\"2\" style=\"width: 100%\">\n <n-space :size=\"8\" align=\"center\" :wrap=\"false\">\n <n-input\n v-model:value=\"form.password\"\n type=\"password\"\n show-password-on=\"click\"\n :disabled=\"!supportsCredentials\"\n :placeholder=\"t('filePath.server.passwordPlaceholder')\"\n :input-props=\"{ autocomplete: 'new-password' }\"\n style=\"min-width: 220px\"\n />\n <n-tag v-if=\"editing?.hasPassword\" size=\"small\" type=\"success\" :bordered=\"false\">\n {{ t('filePath.server.passwordSet') }}\n </n-tag>\n </n-space>\n <span class=\"hint\">{{ t('filePath.server.passwordHint') }}</span>\n <span v-if=\"cascadeHint\" class=\"hint cascade\">{{ cascadeHint }}</span>\n </n-space>\n </n-form-item>\n <n-form-item :label=\"t('filePath.test.action')\">\n <n-space :size=\"12\" align=\"center\">\n <n-button\n v-auth=\"'POST:/api/v1/sys/file-server/test'\"\n size=\"small\"\n :loading=\"testing\"\n :disabled=\"!form.rootPath.trim()\"\n @click=\"onTest\"\n >\n {{ t('filePath.test.action') }}\n </n-button>\n <span v-if=\"testResult\" class=\"test-result\" :class=\"testResult.ok ? 'ok' : 'fail'\">\n <AppIcon :icon=\"testResult.ok ? 'ph:check-circle' : 'ph:x-circle'\" :size=\"16\" />\n {{\n testResult.ok\n ? t('filePath.test.ok', { ms: testResult.latencyMs })\n : t('filePath.test.failed', { reason: reasonText(testResult.reason) })\n }}\n </span>\n </n-space>\n </n-form-item>\n <n-form-item :label=\"t('common.enabled')\">\n <n-switch v-model:value=\"form.enabled\" />\n </n-form-item>\n <n-form-item :label=\"t('filePath.remark')\">\n <n-input\n v-model:value=\"form.remark\"\n type=\"textarea\"\n maxlength=\"512\"\n :autosize=\"{ minRows: 2 }\"\n />\n </n-form-item>\n </n-form>\n </FormContainer>\n</template>\n\n<style scoped>\n.tip {\n margin-bottom: 12px;\n}\n.hint {\n font-size: 13px;\n color: var(--text-3);\n}\n.cascade {\n color: var(--warn);\n}\n.test-result {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n}\n.test-result.ok {\n color: var(--ok);\n}\n.test-result.fail {\n color: var(--err);\n}\n</style>\n"],"names":["show","_useModel","__props","props","emit","__emit","t","useI18n","message","useMessage","formRef","ref","narrowForm","useMediaQuery","formLayout","computed","supportsCredentials","_a","rootOptions","r","blank","form","reactive","reentry","passwordReentryRequired","cascadeHint","kind","credentialCascade","rules","watch","v","testResult","e","testing","onTest","fileServerApi","translateError","save","body","_createBlock","FormContainer","$event","_unref","NAlert","_createVNode","_mergeProps","NFormItem","NInput","_cache","NAutoComplete","NSpace","NTag","_createElementVNode","_hoisted_1","_toDisplayString","_createElementBlock","_hoisted_2","NButton","_normalizeClass","AppIcon","reasonText","NSwitch"],"mappings":"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"}