@webx-ui/module-settings 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,50 +1,50 @@
1
- import { defineComponent as E, ref as v, computed as x, onMounted as P, openBlock as m, createElementBlock as C, createVNode as h, unref as l, createBlock as w, withCtx as S, createTextVNode as M, toDisplayString as O, createCommentVNode as T } from "vue";
2
- import { useAdmin as B, useTranslate as $, useErrorText as j, WxScreenHead as I, WxScreen as L, WxBackupNote as R } from "@webx-ui/module-admin";
3
- import { toast as y, WxSkeleton as D, WxActionBar as H, WxButton as K } from "@webx-ui/core";
4
- function U(e) {
5
- const n = `${e.apiPath}/settings`;
1
+ import { defineComponent as P, ref as m, computed as b, onMounted as M, openBlock as x, createElementBlock as O, createVNode as f, unref as o, createBlock as w, withCtx as y, createTextVNode as T, toDisplayString as $, createCommentVNode as j } from "vue";
2
+ import { useAdmin as V, useTranslate as I, useErrorText as L, WxScreenHead as R, WxScreen as D, WxBackupNote as H } from "@webx-ui/module-admin";
3
+ import { toast as h, WxCard as S, WxSkeleton as W, WxActionBar as K, WxButton as U } from "@webx-ui/core";
4
+ function Y(e) {
5
+ const a = `${e.apiPath}/settings`;
6
6
  return {
7
7
  async load() {
8
- return (await e.http.get(n)).data.values;
8
+ return (await e.http.get(a)).data.values;
9
9
  },
10
- async save(a) {
11
- return (await e.http.put(n, { values: a })).data.values;
10
+ async save(n) {
11
+ return (await e.http.put(a, { values: n })).data.values;
12
12
  }
13
13
  };
14
14
  }
15
- const Y = /* @__PURE__ */ new Set(["wx-input", "wx-textarea", "wx-input-number", "wx-autocomplete"]), q = "shortcodes.data", _ = 40;
16
- function z(e, n, a) {
17
- const s = [], r = (o, u) => {
18
- for (const t of o) {
19
- if (t.type === "wx-repeater") continue;
15
+ const q = /* @__PURE__ */ new Set(["wx-input", "wx-textarea", "wx-input-number", "wx-autocomplete"]), z = "shortcodes.data", B = 40;
16
+ function F(e, a, n) {
17
+ const s = [], i = (r, u) => {
18
+ for (const t of r) {
19
+ if (t.visible === !1 || t.type === "wx-repeater") continue;
20
20
  if (t.name !== void 0) {
21
- if (Y.has(t.type) && t.name !== q) {
22
- const f = [...u, t.label ?? t.name].join(" → "), p = F(n[t.name], a);
21
+ if (q.has(t.type) && t.name !== z) {
22
+ const v = [...u, t.label ?? t.name].join(" → "), p = G(a[t.name], n);
23
23
  s.push({
24
24
  value: t.name,
25
- label: f,
25
+ label: v,
26
26
  description: p === "" ? t.name : `${t.name} · ${p}`
27
27
  });
28
28
  }
29
29
  continue;
30
30
  }
31
31
  const d = (t.type === "wx-tab" || t.type === "wx-card") && t.label;
32
- r(t.children ?? [], d ? [...u, t.label] : u);
32
+ i(t.children ?? [], d ? [...u, t.label] : u);
33
33
  }
34
34
  };
35
- return r(e, []), s;
35
+ return i(e, []), s;
36
36
  }
37
- function F(e, n) {
38
- let a = e;
37
+ function G(e, a) {
38
+ let n = e;
39
39
  if (e !== null && typeof e == "object" && !Array.isArray(e)) {
40
- const r = e;
41
- a = r[n] || Object.values(r).find((o) => typeof o == "string" && o !== "");
40
+ const i = e;
41
+ n = i[a] || Object.values(i).find((r) => typeof r == "string" && r !== "");
42
42
  }
43
- if (typeof a == "number" && (a = String(a)), typeof a != "string") return "";
44
- const s = a.replace(/\s+/g, " ").trim();
45
- return s.length > _ ? `${s.slice(0, _ - 1)}…` : s;
43
+ if (typeof n == "number" && (n = String(n)), typeof n != "string") return "";
44
+ const s = n.replace(/\s+/g, " ").trim();
45
+ return s.length > B ? `${s.slice(0, B - 1)}…` : s;
46
46
  }
47
- const G = {
47
+ const J = {
48
48
  module: {
49
49
  title: "Settings"
50
50
  },
@@ -53,39 +53,39 @@ const G = {
53
53
  saved: "Settings saved.",
54
54
  failed: "Some values were not accepted. Check the highlighted fields."
55
55
  }
56
- }, W = /* @__PURE__ */ new WeakSet();
57
- function J() {
56
+ }, N = /* @__PURE__ */ new WeakSet();
57
+ function Q() {
58
58
  try {
59
- const { i18n: e } = B();
60
- W.has(e) || (e.defaults("webx-settings", G), W.add(e));
59
+ const { i18n: e } = V();
60
+ N.has(e) || (e.defaults("webx-settings", J), N.add(e));
61
61
  } catch {
62
62
  }
63
63
  }
64
- const Q = { class: "wx-settings" }, X = /* @__PURE__ */ E({
64
+ const X = { class: "wx-settings" }, Z = /* @__PURE__ */ P({
65
65
  __name: "SettingsPage",
66
66
  setup(e) {
67
- const n = B(), a = U(n);
68
- J();
69
- const s = $("webx-settings"), r = j(), o = v({}), u = v({}), t = v(!0), d = v(!1), f = n.can("settings.manage"), p = v([]), N = x(
70
- () => b(p.value, "shortcode-key") ? [
67
+ const a = V(), n = Y(a);
68
+ Q();
69
+ const s = I("webx-settings"), i = L(), r = m({}), u = m({}), t = m(!0), d = m(!1), v = a.can("settings.manage"), p = m([]), A = b(
70
+ () => _(p.value, "shortcode-key") ? [
71
71
  {
72
72
  op: "set",
73
73
  target: "shortcode-key",
74
- props: { options: z(p.value, o.value, n.i18n.state.locale) }
74
+ props: { options: F(p.value, r.value, a.i18n.state.locale) }
75
75
  }
76
76
  ] : []
77
77
  );
78
- function b(c, i) {
79
- return c.some((g) => g.id === i || b(g.children ?? [], i));
78
+ function _(c, l) {
79
+ return c.some((g) => g.id === l || _(g.children ?? [], l));
80
80
  }
81
- const V = x(
82
- () => n.state.manifest?.modules.find((c) => c.id === "settings")?.title ?? s("module.title")
81
+ const C = b(
82
+ () => a.state.manifest?.modules.find((c) => c.id === "settings")?.title ?? s("module.title")
83
83
  );
84
- P(async () => {
84
+ M(async () => {
85
85
  try {
86
- o.value = await a.load();
86
+ r.value = await n.load();
87
87
  } catch (c) {
88
- y.danger(r(c));
88
+ h.danger(i(c));
89
89
  } finally {
90
90
  t.value = !1;
91
91
  }
@@ -93,16 +93,16 @@ const Q = { class: "wx-settings" }, X = /* @__PURE__ */ E({
93
93
  async function k() {
94
94
  d.value = !0, u.value = {};
95
95
  try {
96
- o.value = await a.save(o.value), y.success(s("page.saved")), n.refreshManifest();
96
+ r.value = await n.save(r.value), h.success(s("page.saved")), a.refreshManifest();
97
97
  } catch (c) {
98
- const i = c.body;
99
- i?.errors ? (u.value = i.errors, y.danger(s("page.failed"))) : y.danger(r(c, s("page.failed")));
98
+ const l = c.body;
99
+ l?.errors ? (u.value = l.errors, h.danger(s("page.failed"))) : h.danger(i(c, s("page.failed")));
100
100
  } finally {
101
101
  d.value = !1;
102
102
  }
103
103
  }
104
- const A = x(
105
- () => f ? [
104
+ const E = b(
105
+ () => v ? [
106
106
  {
107
107
  key: "save",
108
108
  label: s("page.save"),
@@ -114,60 +114,72 @@ const Q = { class: "wx-settings" }, X = /* @__PURE__ */ E({
114
114
  }
115
115
  ] : []
116
116
  );
117
- return (c, i) => (m(), C("div", Q, [
118
- h(l(I), {
119
- title: V.value,
120
- actions: A.value
117
+ return (c, l) => (x(), O("div", X, [
118
+ f(o(R), {
119
+ title: C.value,
120
+ actions: E.value
121
121
  }, null, 8, ["title", "actions"]),
122
- t.value ? (m(), w(l(D), {
123
- key: 0,
124
- rows: 4
125
- })) : (m(), w(l(L), {
122
+ t.value ? (x(), w(o(S), { key: 0 }, {
123
+ default: y(() => [
124
+ f(o(W), { rows: 6 })
125
+ ]),
126
+ _: 1
127
+ })) : (x(), w(o(D), {
126
128
  key: 1,
127
- modelValue: o.value,
128
- "onUpdate:modelValue": i[0] || (i[0] = (g) => o.value = g),
129
+ modelValue: r.value,
130
+ "onUpdate:modelValue": l[0] || (l[0] = (g) => r.value = g),
129
131
  name: "settings.index",
130
- patch: N.value,
132
+ patch: A.value,
131
133
  errors: u.value,
132
- disabled: !l(f),
133
- onLoaded: i[1] || (i[1] = (g) => p.value = g)
134
- }, null, 8, ["modelValue", "patch", "errors", "disabled"])),
135
- h(l(R)),
136
- l(f) && !t.value ? (m(), w(l(H), { key: 2 }, {
137
- default: S(() => [
138
- h(l(K), {
134
+ disabled: !o(v),
135
+ onLoaded: l[1] || (l[1] = (g) => p.value = g)
136
+ }, {
137
+ loading: y(() => [
138
+ f(o(S), null, {
139
+ default: y(() => [
140
+ f(o(W), { rows: 6 })
141
+ ]),
142
+ _: 1
143
+ })
144
+ ]),
145
+ _: 1
146
+ }, 8, ["modelValue", "patch", "errors", "disabled"])),
147
+ f(o(H)),
148
+ o(v) && !t.value ? (x(), w(o(K), { key: 2 }, {
149
+ default: y(() => [
150
+ f(o(U), {
139
151
  type: "primary",
140
152
  loading: d.value,
141
153
  onClick: k
142
154
  }, {
143
- default: S(() => [
144
- M(O(l(s)("page.save")), 1)
155
+ default: y(() => [
156
+ T($(o(s)("page.save")), 1)
145
157
  ]),
146
158
  _: 1
147
159
  }, 8, ["loading"])
148
160
  ]),
149
161
  _: 1
150
- })) : T("", !0)
162
+ })) : j("", !0)
151
163
  ]));
152
164
  }
153
- }), Z = (e, n) => {
154
- const a = e.__vccOpts || e;
155
- for (const [s, r] of n)
156
- a[s] = r;
157
- return a;
158
- }, ee = /* @__PURE__ */ Z(X, [["__scopeId", "data-v-75a3a47c"]]);
159
- function se(e = {}) {
160
- const n = e.path ?? "/settings";
165
+ }), ee = (e, a) => {
166
+ const n = e.__vccOpts || e;
167
+ for (const [s, i] of a)
168
+ n[s] = i;
169
+ return n;
170
+ }, te = /* @__PURE__ */ ee(Z, [["__scopeId", "data-v-3e5b5a71"]]);
171
+ function oe(e = {}) {
172
+ const a = e.path ?? "/settings";
161
173
  return {
162
174
  id: "settings",
163
- path: n,
164
- routes: [{ path: n, name: "webx.settings", component: ee }]
175
+ path: a,
176
+ routes: [{ path: a, name: "webx.settings", component: te }]
165
177
  };
166
178
  }
167
179
  export {
168
- ee as WxSettingsPage,
169
- U as createSettingsApi,
170
- se as settings,
171
- G as settingsMessages
180
+ te as WxSettingsPage,
181
+ Y as createSettingsApi,
182
+ oe as settings,
183
+ J as settingsMessages
172
184
  };
173
185
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/api.ts","../src/settingOptions.ts","../src/messages.ts","../src/i18n.ts","../src/SettingsPage.vue","../src/module.ts"],"sourcesContent":["import type { AdminContext } from '@webx-ui/module-admin'\nimport type { SettingsValues } from './types'\n\nexport interface SettingsApi {\n /** Every value the screen describes, as stored. */\n load(): Promise<SettingsValues>\n /** Sends the values back; answers with what the server kept. A 422 lands as `HttpError`. */\n save(values: SettingsValues): Promise<SettingsValues>\n}\n\n/** `GET` and `PUT` on `/settings`, under the panel's API path. */\nexport function createSettingsApi(admin: AdminContext): SettingsApi {\n const base = `${admin.apiPath}/settings`\n\n return {\n async load() {\n const body = await admin.http.get<{ data: { values: SettingsValues } }>(base)\n\n return body.data.values\n },\n async save(values) {\n const body = await admin.http.put<{ data: { values: SettingsValues } }>(base, { values })\n\n return body.data.values\n },\n }\n}\n","import type { AutocompleteOption } from '@webx-ui/core'\nimport type { ScreenModel, ScreenNode } from '@webx-ui/schema'\n\n/**\n * The types whose value a shortcode can print as it is: a line of text or a number. A picture, a\n * list or a switch would print as nothing, so they are not offered.\n */\nconst PRINTABLE = new Set(['wx-input', 'wx-textarea', 'wx-input-number', 'wx-autocomplete'])\n\n/** The list the shortcodes keep themselves in — reading it would print nothing. */\nconst OWN_KEY = 'shortcodes.data'\n\n/** Long enough to recognise an address by, short enough for one line of the dropdown. */\nconst PREVIEW = 40\n\n/**\n * The settings a shortcode can read, for the autocomplete of its key: labelled the way the form\n * shows them («Contacts → Phone»), with the key and what the setting holds now underneath, so the\n * one being picked is the one meant.\n */\nexport function settingOptions(\n root: ScreenNode[],\n values: ScreenModel,\n locale: string,\n): AutocompleteOption[] {\n const options: AutocompleteOption[] = []\n\n const walk = (nodes: ScreenNode[], trail: string[]): void => {\n for (const node of nodes) {\n // A repeater's children are fields of its rows, not settings.\n if (node.type === 'wx-repeater') continue\n\n if (node.name !== undefined) {\n if (PRINTABLE.has(node.type) && node.name !== OWN_KEY) {\n const label = [...trail, node.label ?? node.name].join(' → ')\n const now = preview(values[node.name], locale)\n\n options.push({\n value: node.name,\n label,\n description: now === '' ? node.name : `${node.name} · ${now}`,\n })\n }\n continue\n }\n\n // Tabs and cards name a group; the rest of the layout does not.\n const named = (node.type === 'wx-tab' || node.type === 'wx-card') && node.label\n walk(node.children ?? [], named ? [...trail, node.label as string] : trail)\n }\n }\n\n walk(root, [])\n\n return options\n}\n\n/** A value as a line: the panel's language of a translated one, or the first language filled. */\nfunction preview(value: unknown, locale: string): string {\n let text = value\n\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const languages = value as Record<string, unknown>\n text =\n languages[locale] ||\n Object.values(languages).find((one) => typeof one === 'string' && one !== '')\n }\n\n if (typeof text === 'number') text = String(text)\n if (typeof text !== 'string') return ''\n\n const line = text.replace(/\\s+/g, ' ').trim()\n\n return line.length > PREVIEW ? `${line.slice(0, PREVIEW - 1)}…` : line\n}\n","import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * What this package says, in English — the same keys `webx-ui/module-settings` ships as\n * `lang/en/*.php`, so a key never reaches the screen when a translation is missing.\n */\nexport const settingsMessages: Record<string, Messages> = {\n module: {\n title: 'Settings',\n },\n page: {\n save: 'Save',\n saved: 'Settings saved.',\n failed: 'Some values were not accepted. Check the highlighted fields.',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { settingsMessages } from './messages'\n\nconst seeded = new WeakSet<object>()\n\n/** Puts this package's English under the panel's dictionary, once per panel. */\nexport function useSettingsMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-settings', settingsMessages)\n seeded.add(i18n)\n }\n } catch {\n // Outside a panel there is no dictionary to seed, and `useTranslate` falls back on its own.\n }\n}\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxBackupNote,\n WxScreen,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport { toast, WxActionBar, WxButton, WxSkeleton } from '@webx-ui/core'\nimport type { Patch, ScreenModel, ScreenNode } from '@webx-ui/schema'\nimport { createSettingsApi } from './api'\nimport { settingOptions } from './settingOptions'\nimport { useSettingsMessages } from './i18n'\n\n/**\n * The settings section: the screen the server describes, and the saving that is the page's own\n * — in the head, and again in the bar along the bottom, because the form is taller than a\n * window and the head goes with the scroll. The screen does not know how it is saved; this does.\n */\nconst context = useAdmin()\nconst api = createSettingsApi(context)\nuseSettingsMessages()\n\nconst t = useTranslate('webx-settings')\n/* Not the server's `message`: the panel says how a request failed in its own words (§13.3). */\nconst message = useErrorText()\n\nconst values = ref<ScreenModel>({})\nconst errors = ref<Record<string, string[]>>({})\nconst loading = ref(true)\nconst saving = ref(false)\n\nconst canManage = context.can('settings.manage')\n\n/** The tree as drawn, for what the shortcodes can read; it arrives with the screen. */\nconst tree = ref<ScreenNode[]>([])\n\n/*\n * A shortcode that reads a setting names it by key, and nobody remembers keys: the list to pick\n * from is every text setting on this screen, with where it lives and what it holds right now.\n * Built here because only the page has both the tree and the values.\n */\nconst patch = computed<Patch>(() =>\n hasNode(tree.value, 'shortcode-key')\n ? [\n {\n op: 'set',\n target: 'shortcode-key',\n props: { options: settingOptions(tree.value, values.value, context.i18n.state.locale) },\n },\n ]\n : [],\n)\n\nfunction hasNode(nodes: ScreenNode[], id: string): boolean {\n return nodes.some((node) => node.id === id || hasNode(node.children ?? [], id))\n}\n\n/** The section's name, as the server translated it; the built-in English until it arrives. */\nconst title = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'settings')?.title ??\n t('module.title'),\n)\n\nonMounted(async () => {\n try {\n values.value = await api.load()\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.save(values.value)\n toast.success(t('page.saved'))\n\n // Some of what this screen holds is also what the panel is wearing — the logo in the\n // corner, the mark on the rail, the name of the site. The manifest is where the shell\n // reads those, so saving them here has to hand the shell a new one; otherwise the logo\n // somebody has just replaced goes on being the old one until the page is reloaded.\n void context.refreshManifest()\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]>; message?: string } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('page.failed'))\n } else {\n toast.danger(message(error, t('page.failed')))\n }\n } finally {\n saving.value = false\n }\n}\n/* Saving, and again in the bar below: the head goes with the scroll on a form this long (§3.3). */\nconst actions = computed<ScreenAction[]>(() =>\n canManage\n ? [\n {\n key: 'save',\n label: t('page.save'),\n primary: true,\n loading: saving.value,\n run: () => void save(),\n },\n ]\n : [],\n)\n</script>\n\n<template>\n <div class=\"wx-settings\">\n <wx-screen-head :title=\"title\" :actions=\"actions\" />\n\n <wx-skeleton v-if=\"loading\" :rows=\"4\" />\n <wx-screen\n v-else\n v-model=\"values\"\n name=\"settings.index\"\n :patch=\"patch\"\n :errors=\"errors\"\n :disabled=\"!canManage\"\n @loaded=\"tree = $event\"\n />\n\n <!--\n Where the panel says when the database was last dumped (§6 of the backups spec). It is\n the section this belongs in — System is Settings and Administrators, and of those two\n this is the one somebody opens to ask how the installation is doing — and `settings.view`\n is the right the line itself asks for. A footnote under the form rather than a field in\n it: the form is what the site is, and this is what the server did last night.\n -->\n <wx-backup-note />\n\n <!-- The settings are longer than a window, and the button in the head is off the top of it\n by the second group of fields. This is the same button, where the eye already is. -->\n <wx-action-bar v-if=\"canManage && !loading\">\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('page.save') }}</wx-button>\n </wx-action-bar>\n </div>\n</template>\n\n<style scoped>\n/* A column, because the bar along the bottom is pushed there by an auto margin — and it is\n `WxMain` that gives a screen carrying one the height to push it down through. */\n.wx-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport SettingsPage from './SettingsPage.vue'\n\nexport interface SettingsOptions {\n /** Where the section lives inside the panel. */\n path?: string\n}\n\n/**\n * The settings, as a section of the panel.\n *\n * The id matches the module the server reports, which is what makes the entry appear in the\n * navigation: a section shows up when both halves are installed.\n */\nexport function settings(options: SettingsOptions = {}): AdminModule {\n const path = options.path ?? '/settings'\n\n return {\n id: 'settings',\n path,\n routes: [{ path, name: 'webx.settings', component: SettingsPage }],\n }\n}\n"],"names":["createSettingsApi","admin","base","values","PRINTABLE","OWN_KEY","PREVIEW","settingOptions","root","locale","options","walk","nodes","trail","node","label","now","preview","named","value","text","languages","one","line","settingsMessages","seeded","useSettingsMessages","i18n","useAdmin","context","api","t","useTranslate","message","useErrorText","ref","errors","loading","saving","canManage","tree","patch","computed","hasNode","id","title","module","onMounted","error","toast","save","body","actions","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxScreenHead","_createBlock","WxSkeleton","WxScreen","$event","_cache","WxBackupNote","WxActionBar","WxButton","settings","path","SettingsPage"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/api.ts","../src/settingOptions.ts","../src/messages.ts","../src/i18n.ts","../src/SettingsPage.vue","../src/module.ts"],"sourcesContent":["import type { AdminContext } from '@webx-ui/module-admin'\nimport type { SettingsValues } from './types'\n\nexport interface SettingsApi {\n /** Every value the screen describes, as stored. */\n load(): Promise<SettingsValues>\n /** Sends the values back; answers with what the server kept. A 422 lands as `HttpError`. */\n save(values: SettingsValues): Promise<SettingsValues>\n}\n\n/** `GET` and `PUT` on `/settings`, under the panel's API path. */\nexport function createSettingsApi(admin: AdminContext): SettingsApi {\n const base = `${admin.apiPath}/settings`\n\n return {\n async load() {\n const body = await admin.http.get<{ data: { values: SettingsValues } }>(base)\n\n return body.data.values\n },\n async save(values) {\n const body = await admin.http.put<{ data: { values: SettingsValues } }>(base, { values })\n\n return body.data.values\n },\n }\n}\n","import type { AutocompleteOption } from '@webx-ui/core'\nimport type { ScreenModel, ScreenNode } from '@webx-ui/schema'\n\n/**\n * The types whose value a shortcode can print as it is: a line of text or a number. A picture, a\n * list or a switch would print as nothing, so they are not offered.\n */\nconst PRINTABLE = new Set(['wx-input', 'wx-textarea', 'wx-input-number', 'wx-autocomplete'])\n\n/** The list the shortcodes keep themselves in — reading it would print nothing. */\nconst OWN_KEY = 'shortcodes.data'\n\n/** Long enough to recognise an address by, short enough for one line of the dropdown. */\nconst PREVIEW = 40\n\n/**\n * The settings a shortcode can read, for the autocomplete of its key: labelled the way the form\n * shows them («Contacts → Phone»), with the key and what the setting holds now underneath, so the\n * one being picked is the one meant.\n */\nexport function settingOptions(\n root: ScreenNode[],\n values: ScreenModel,\n locale: string,\n): AutocompleteOption[] {\n const options: AutocompleteOption[] = []\n\n const walk = (nodes: ScreenNode[], trail: string[]): void => {\n for (const node of nodes) {\n // Hidden for good — a Contacts section the site does not draw — so not a setting to offer.\n if (node.visible === false) continue\n // A repeater's children are fields of its rows, not settings.\n if (node.type === 'wx-repeater') continue\n\n if (node.name !== undefined) {\n if (PRINTABLE.has(node.type) && node.name !== OWN_KEY) {\n const label = [...trail, node.label ?? node.name].join(' → ')\n const now = preview(values[node.name], locale)\n\n options.push({\n value: node.name,\n label,\n description: now === '' ? node.name : `${node.name} · ${now}`,\n })\n }\n continue\n }\n\n // Tabs and cards name a group; the rest of the layout does not.\n const named = (node.type === 'wx-tab' || node.type === 'wx-card') && node.label\n walk(node.children ?? [], named ? [...trail, node.label as string] : trail)\n }\n }\n\n walk(root, [])\n\n return options\n}\n\n/** A value as a line: the panel's language of a translated one, or the first language filled. */\nfunction preview(value: unknown, locale: string): string {\n let text = value\n\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const languages = value as Record<string, unknown>\n text =\n languages[locale] ||\n Object.values(languages).find((one) => typeof one === 'string' && one !== '')\n }\n\n if (typeof text === 'number') text = String(text)\n if (typeof text !== 'string') return ''\n\n const line = text.replace(/\\s+/g, ' ').trim()\n\n return line.length > PREVIEW ? `${line.slice(0, PREVIEW - 1)}…` : line\n}\n","import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * What this package says, in English — the same keys `webx-ui/module-settings` ships as\n * `lang/en/*.php`, so a key never reaches the screen when a translation is missing.\n */\nexport const settingsMessages: Record<string, Messages> = {\n module: {\n title: 'Settings',\n },\n page: {\n save: 'Save',\n saved: 'Settings saved.',\n failed: 'Some values were not accepted. Check the highlighted fields.',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { settingsMessages } from './messages'\n\nconst seeded = new WeakSet<object>()\n\n/** Puts this package's English under the panel's dictionary, once per panel. */\nexport function useSettingsMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-settings', settingsMessages)\n seeded.add(i18n)\n }\n } catch {\n // Outside a panel there is no dictionary to seed, and `useTranslate` falls back on its own.\n }\n}\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxBackupNote,\n WxScreen,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport { toast, WxActionBar, WxButton, WxCard, WxSkeleton } from '@webx-ui/core'\nimport type { Patch, ScreenModel, ScreenNode } from '@webx-ui/schema'\nimport { createSettingsApi } from './api'\nimport { settingOptions } from './settingOptions'\nimport { useSettingsMessages } from './i18n'\n\n/**\n * The settings section: the screen the server describes, and the saving that is the page's own\n * — in the head, and again in the bar along the bottom, because the form is taller than a\n * window and the head goes with the scroll. The screen does not know how it is saved; this does.\n */\nconst context = useAdmin()\nconst api = createSettingsApi(context)\nuseSettingsMessages()\n\nconst t = useTranslate('webx-settings')\n/* Not the server's `message`: the panel says how a request failed in its own words (§13.3). */\nconst message = useErrorText()\n\nconst values = ref<ScreenModel>({})\nconst errors = ref<Record<string, string[]>>({})\nconst loading = ref(true)\nconst saving = ref(false)\n\nconst canManage = context.can('settings.manage')\n\n/** The tree as drawn, for what the shortcodes can read; it arrives with the screen. */\nconst tree = ref<ScreenNode[]>([])\n\n/*\n * A shortcode that reads a setting names it by key, and nobody remembers keys: the list to pick\n * from is every text setting on this screen, with where it lives and what it holds right now.\n * Built here because only the page has both the tree and the values.\n */\nconst patch = computed<Patch>(() =>\n hasNode(tree.value, 'shortcode-key')\n ? [\n {\n op: 'set',\n target: 'shortcode-key',\n props: { options: settingOptions(tree.value, values.value, context.i18n.state.locale) },\n },\n ]\n : [],\n)\n\nfunction hasNode(nodes: ScreenNode[], id: string): boolean {\n return nodes.some((node) => node.id === id || hasNode(node.children ?? [], id))\n}\n\n/** The section's name, as the server translated it; the built-in English until it arrives. */\nconst title = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'settings')?.title ??\n t('module.title'),\n)\n\nonMounted(async () => {\n try {\n values.value = await api.load()\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.save(values.value)\n toast.success(t('page.saved'))\n\n // Some of what this screen holds is also what the panel is wearing — the logo in the\n // corner, the mark on the rail, the name of the site. The manifest is where the shell\n // reads those, so saving them here has to hand the shell a new one; otherwise the logo\n // somebody has just replaced goes on being the old one until the page is reloaded.\n void context.refreshManifest()\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]>; message?: string } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('page.failed'))\n } else {\n toast.danger(message(error, t('page.failed')))\n }\n } finally {\n saving.value = false\n }\n}\n/* Saving, and again in the bar below: the head goes with the scroll on a form this long (§3.3). */\nconst actions = computed<ScreenAction[]>(() =>\n canManage\n ? [\n {\n key: 'save',\n label: t('page.save'),\n primary: true,\n loading: saving.value,\n run: () => void save(),\n },\n ]\n : [],\n)\n</script>\n\n<template>\n <div class=\"wx-settings\">\n <wx-screen-head :title=\"title\" :actions=\"actions\" />\n\n <!-- The wait looks like what comes: the fields sit in cards. Twice — while the values load,\n then while the screen does — so the shape does not change between the two. -->\n <wx-card v-if=\"loading\"><wx-skeleton :rows=\"6\" /></wx-card>\n <wx-screen\n v-else\n v-model=\"values\"\n name=\"settings.index\"\n :patch=\"patch\"\n :errors=\"errors\"\n :disabled=\"!canManage\"\n @loaded=\"tree = $event\"\n >\n <template #loading>\n <wx-card><wx-skeleton :rows=\"6\" /></wx-card>\n </template>\n </wx-screen>\n\n <!--\n Where the panel says when the database was last dumped (§6 of the backups spec). It is\n the section this belongs in — System is Settings and Administrators, and of those two\n this is the one somebody opens to ask how the installation is doing — and `settings.view`\n is the right the line itself asks for. A footnote under the form rather than a field in\n it: the form is what the site is, and this is what the server did last night.\n -->\n <wx-backup-note />\n\n <!-- The settings are longer than a window, and the button in the head is off the top of it\n by the second group of fields. This is the same button, where the eye already is. -->\n <wx-action-bar v-if=\"canManage && !loading\">\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('page.save') }}</wx-button>\n </wx-action-bar>\n </div>\n</template>\n\n<style scoped>\n/* A column, because the bar along the bottom is pushed there by an auto margin — and it is\n `WxMain` that gives a screen carrying one the height to push it down through. */\n.wx-settings {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport SettingsPage from './SettingsPage.vue'\n\nexport interface SettingsOptions {\n /** Where the section lives inside the panel. */\n path?: string\n}\n\n/**\n * The settings, as a section of the panel.\n *\n * The id matches the module the server reports, which is what makes the entry appear in the\n * navigation: a section shows up when both halves are installed.\n */\nexport function settings(options: SettingsOptions = {}): AdminModule {\n const path = options.path ?? '/settings'\n\n return {\n id: 'settings',\n path,\n routes: [{ path, name: 'webx.settings', component: SettingsPage }],\n }\n}\n"],"names":["createSettingsApi","admin","base","values","PRINTABLE","OWN_KEY","PREVIEW","settingOptions","root","locale","options","walk","nodes","trail","node","label","now","preview","named","value","text","languages","one","line","settingsMessages","seeded","useSettingsMessages","i18n","useAdmin","context","api","t","useTranslate","message","useErrorText","ref","errors","loading","saving","canManage","tree","patch","computed","hasNode","id","title","module","onMounted","error","toast","save","body","actions","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxScreenHead","_createBlock","WxCard","WxSkeleton","WxScreen","$event","_cache","WxBackupNote","WxActionBar","WxButton","settings","path","SettingsPage"],"mappings":"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"}
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .wx-settings[data-v-75a3a47c]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16))}
1
+ .wx-settings[data-v-3e5b5a71]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16))}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webx-ui/module-settings",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Site settings for the WebX UI admin panel: the section that draws the settings screen and saves it.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -42,8 +42,8 @@
42
42
  "vue-router": "^4.5.0"
43
43
  },
44
44
  "dependencies": {
45
- "@webx-ui/core": "^0.40.0",
46
- "@webx-ui/module-admin": "^0.25.0",
45
+ "@webx-ui/core": "^0.40.1",
46
+ "@webx-ui/module-admin": "^0.25.1",
47
47
  "@webx-ui/schema": "^0.9.0"
48
48
  },
49
49
  "devDependencies": {