@webx-ui/module-team 0.1.16 → 0.2.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/TeamPage-ZI9lGyZ5.js +283 -0
- package/dist/TeamPage-ZI9lGyZ5.js.map +1 -0
- package/dist/index-Dq5upQx6.js +287 -0
- package/dist/index-Dq5upQx6.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +8 -553
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { defineComponent as X, ref as M, computed as n, watch as R, onBeforeUnmount as Y, openBlock as s, createBlock as f, unref as l, withCtx as i, createVNode as u, createCommentVNode as y, createElementVNode as z, createElementBlock as k, normalizeClass as A, createTextVNode as j, toDisplayString as q, Fragment as Z, resolveDynamicComponent as ee } from "vue";
|
|
2
|
+
import { useRoute as te, useRouter as ae } from "vue-router";
|
|
3
|
+
import { WxCard as le, WxListDetail as re, WxEmpty as D, WxInput as oe, WxIcon as L, WxSkeleton as ne, WxSortableList as se, WxAvatar as ie, WxBadge as ue, WxAlert as me, toast as w, confirm as de } from "@webx-ui/core";
|
|
4
|
+
import { useAdmin as ce, useTranslate as ve, useErrorText as pe, useItemOrder as be, WxListScreen as fe, WxRowMenu as we } from "@webx-ui/module-admin";
|
|
5
|
+
import { c as ye, u as _e, T as xe, M as he, _ as ge } from "./index-Dq5upQx6.js";
|
|
6
|
+
const ke = { class: "wx-team__bar" }, qe = { class: "wx-member-row__body" }, Te = { class: "wx-member-row__name" }, We = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "wx-member-row__job"
|
|
9
|
+
}, Ce = {
|
|
10
|
+
key: 1,
|
|
11
|
+
class: "wx-member-row__facts"
|
|
12
|
+
}, Ve = /* @__PURE__ */ X({
|
|
13
|
+
__name: "TeamPage",
|
|
14
|
+
props: {
|
|
15
|
+
base: { default: "/team" }
|
|
16
|
+
},
|
|
17
|
+
setup(Be) {
|
|
18
|
+
const T = ce(), W = ye(T), m = te(), _ = ae();
|
|
19
|
+
_e();
|
|
20
|
+
const a = ve("webx-team"), x = pe(), v = M([]), h = M(!0), p = n(() => T.can("team.manage")), F = n(
|
|
21
|
+
() => T.state.manifest?.modules.find((e) => e.id === "team")?.title ?? a("module.team")
|
|
22
|
+
), g = n({
|
|
23
|
+
get: () => m.query.view === "trashed" ? "trashed" : "",
|
|
24
|
+
set: (e) => {
|
|
25
|
+
const r = {
|
|
26
|
+
...m.query,
|
|
27
|
+
view: e === "" ? void 0 : String(e)
|
|
28
|
+
};
|
|
29
|
+
delete r.member, _.replace({ query: r });
|
|
30
|
+
}
|
|
31
|
+
}), o = n(() => g.value === "trashed"), b = n(() => typeof m.query.q == "string" ? m.query.q : ""), C = M(b.value), d = n(() => {
|
|
32
|
+
const e = m.query.member;
|
|
33
|
+
return e === "new" ? p.value ? "new" : null : typeof e == "string" && e !== "" && Number(e) || null;
|
|
34
|
+
}), E = n({
|
|
35
|
+
get: () => d.value !== null,
|
|
36
|
+
set: (e) => {
|
|
37
|
+
e || N();
|
|
38
|
+
}
|
|
39
|
+
}), $ = n(() => [
|
|
40
|
+
{ value: "", label: a("member.all") },
|
|
41
|
+
{ value: "trashed", label: a("member.trashed"), icon: "trash" }
|
|
42
|
+
]), V = be(xe, () => ({ q: b.value, filtered: o.value })), I = n(() => p.value && V.sortable.value), O = n(() => b.value !== "" ? a("member.empty-search") : o.value ? a("member.empty-bin") : a("member.empty"));
|
|
43
|
+
async function c() {
|
|
44
|
+
h.value = !0;
|
|
45
|
+
try {
|
|
46
|
+
const e = await W.list({ search: b.value, trashed: o.value });
|
|
47
|
+
v.value = e.data;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
w.danger(x(e));
|
|
50
|
+
} finally {
|
|
51
|
+
h.value = !1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
R(
|
|
55
|
+
() => [g.value, b.value],
|
|
56
|
+
() => {
|
|
57
|
+
c();
|
|
58
|
+
}
|
|
59
|
+
), c();
|
|
60
|
+
let B;
|
|
61
|
+
R(C, (e) => {
|
|
62
|
+
clearTimeout(B), B = setTimeout(() => {
|
|
63
|
+
_.replace({ query: { ...m.query, q: e.trim() === "" ? void 0 : e } });
|
|
64
|
+
}, 300);
|
|
65
|
+
}), Y(() => clearTimeout(B));
|
|
66
|
+
function S(e) {
|
|
67
|
+
_.replace({ query: { ...m.query, member: String(e) } });
|
|
68
|
+
}
|
|
69
|
+
function N() {
|
|
70
|
+
const e = { ...m.query };
|
|
71
|
+
delete e.member, _.replace({ query: e });
|
|
72
|
+
}
|
|
73
|
+
function G(e) {
|
|
74
|
+
S(e.id), c();
|
|
75
|
+
}
|
|
76
|
+
async function H() {
|
|
77
|
+
try {
|
|
78
|
+
await V.move(v.value.map((e) => e.id));
|
|
79
|
+
} catch (e) {
|
|
80
|
+
w.danger(x(e, a("member.reorder-failed"))), await c();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function J(e) {
|
|
84
|
+
return p.value ? o.value ? [
|
|
85
|
+
{
|
|
86
|
+
key: "restore",
|
|
87
|
+
icon: "refresh",
|
|
88
|
+
label: a("member.restore"),
|
|
89
|
+
run: () => {
|
|
90
|
+
Q(e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
] : [
|
|
94
|
+
{
|
|
95
|
+
key: "delete",
|
|
96
|
+
icon: "trash",
|
|
97
|
+
label: a("member.delete"),
|
|
98
|
+
danger: !0,
|
|
99
|
+
run: () => {
|
|
100
|
+
K(e);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
] : [];
|
|
104
|
+
}
|
|
105
|
+
async function K(e) {
|
|
106
|
+
if (await de({
|
|
107
|
+
title: a("member.delete-title", { name: e.name }),
|
|
108
|
+
message: a("member.delete-text"),
|
|
109
|
+
confirmText: a("member.delete"),
|
|
110
|
+
cancelText: a("member.cancel"),
|
|
111
|
+
tone: "danger"
|
|
112
|
+
}))
|
|
113
|
+
try {
|
|
114
|
+
await W.remove(e.id), w.success(a("member.deleted")), U(e.id);
|
|
115
|
+
} catch (t) {
|
|
116
|
+
w.danger(x(t));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function U(e) {
|
|
120
|
+
d.value === e && N(), c();
|
|
121
|
+
}
|
|
122
|
+
async function Q(e) {
|
|
123
|
+
try {
|
|
124
|
+
await W.restore(e.id), w.success(a("member.restored"));
|
|
125
|
+
} catch (r) {
|
|
126
|
+
w.danger(x(r));
|
|
127
|
+
} finally {
|
|
128
|
+
await c();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return (e, r) => (s(), f(l(fe), {
|
|
132
|
+
view: g.value,
|
|
133
|
+
"onUpdate:view": r[4] || (r[4] = (t) => g.value = t),
|
|
134
|
+
title: F.value,
|
|
135
|
+
views: $.value,
|
|
136
|
+
card: !1
|
|
137
|
+
}, {
|
|
138
|
+
default: i(() => [
|
|
139
|
+
u(l(le), {
|
|
140
|
+
class: "wx-team",
|
|
141
|
+
padding: "none"
|
|
142
|
+
}, {
|
|
143
|
+
default: i(() => [
|
|
144
|
+
u(l(re), {
|
|
145
|
+
open: E.value,
|
|
146
|
+
"onUpdate:open": r[3] || (r[3] = (t) => E.value = t),
|
|
147
|
+
class: "wx-team__panes",
|
|
148
|
+
"list-width": 360,
|
|
149
|
+
"detail-min": 460,
|
|
150
|
+
"detail-label": l(a)("module.team")
|
|
151
|
+
}, {
|
|
152
|
+
list: i(() => [
|
|
153
|
+
z("div", ke, [
|
|
154
|
+
u(l(oe), {
|
|
155
|
+
modelValue: C.value,
|
|
156
|
+
"onUpdate:modelValue": r[0] || (r[0] = (t) => C.value = t),
|
|
157
|
+
class: "wx-team__search",
|
|
158
|
+
size: "sm",
|
|
159
|
+
clearable: "",
|
|
160
|
+
placeholder: l(a)("member.search"),
|
|
161
|
+
"aria-label": l(a)("member.search")
|
|
162
|
+
}, {
|
|
163
|
+
prefix: i(() => [
|
|
164
|
+
u(l(L), {
|
|
165
|
+
name: "search",
|
|
166
|
+
size: "sm"
|
|
167
|
+
})
|
|
168
|
+
]),
|
|
169
|
+
_: 1
|
|
170
|
+
}, 8, ["modelValue", "placeholder", "aria-label"])
|
|
171
|
+
]),
|
|
172
|
+
p.value && !o.value ? (s(), k("button", {
|
|
173
|
+
key: 0,
|
|
174
|
+
type: "button",
|
|
175
|
+
class: A(["wx-team__new", { "is-current": d.value === "new" }]),
|
|
176
|
+
onClick: r[1] || (r[1] = (t) => S("new"))
|
|
177
|
+
}, [
|
|
178
|
+
u(l(L), {
|
|
179
|
+
name: "plus",
|
|
180
|
+
size: "sm"
|
|
181
|
+
}),
|
|
182
|
+
j(" " + q(l(a)("member.new")), 1)
|
|
183
|
+
], 2)) : y("", !0),
|
|
184
|
+
h.value && v.value.length === 0 ? (s(), f(l(ne), {
|
|
185
|
+
key: 1,
|
|
186
|
+
class: "wx-team__loading",
|
|
187
|
+
rows: 5
|
|
188
|
+
})) : v.value.length === 0 ? (s(), f(l(D), {
|
|
189
|
+
key: 2,
|
|
190
|
+
title: O.value,
|
|
191
|
+
description: !o.value && b.value === "" ? l(a)("member.empty-help") : void 0
|
|
192
|
+
}, null, 8, ["title", "description"])) : (s(), k(Z, { key: 3 }, [
|
|
193
|
+
u(l(se), {
|
|
194
|
+
modelValue: v.value,
|
|
195
|
+
"onUpdate:modelValue": r[2] || (r[2] = (t) => v.value = t),
|
|
196
|
+
class: A(["wx-team__list", { "is-loading": h.value }]),
|
|
197
|
+
hoverable: "",
|
|
198
|
+
plain: "",
|
|
199
|
+
"item-key": "id",
|
|
200
|
+
handle: I.value ? "grip" : "row",
|
|
201
|
+
"item-label": (t) => t.name,
|
|
202
|
+
disabled: !I.value,
|
|
203
|
+
onMove: H
|
|
204
|
+
}, {
|
|
205
|
+
default: i(({ item: t }) => [
|
|
206
|
+
(s(), f(ee(o.value ? "div" : "button"), {
|
|
207
|
+
type: o.value ? void 0 : "button",
|
|
208
|
+
class: A(["wx-member-row", { "is-current": d.value === t.id }]),
|
|
209
|
+
onClick: (P) => o.value ? void 0 : S(t.id)
|
|
210
|
+
}, {
|
|
211
|
+
default: i(() => [
|
|
212
|
+
u(l(ie), {
|
|
213
|
+
class: "wx-member-row__photo",
|
|
214
|
+
src: t.photo?.thumb ?? void 0,
|
|
215
|
+
name: t.name,
|
|
216
|
+
size: "md"
|
|
217
|
+
}, null, 8, ["src", "name"]),
|
|
218
|
+
z("span", qe, [
|
|
219
|
+
z("span", Te, q(t.name), 1),
|
|
220
|
+
t.job_title ? (s(), k("span", We, q(t.job_title), 1)) : y("", !0),
|
|
221
|
+
t.published ? y("", !0) : (s(), k("span", Ce, [
|
|
222
|
+
u(l(ue), {
|
|
223
|
+
dot: "",
|
|
224
|
+
size: "sm"
|
|
225
|
+
}, {
|
|
226
|
+
default: i(() => [
|
|
227
|
+
j(q(l(a)("member.not-published")), 1)
|
|
228
|
+
]),
|
|
229
|
+
_: 1
|
|
230
|
+
})
|
|
231
|
+
]))
|
|
232
|
+
])
|
|
233
|
+
]),
|
|
234
|
+
_: 2
|
|
235
|
+
}, 1032, ["type", "class", "onClick"]))
|
|
236
|
+
]),
|
|
237
|
+
actions: i(({ item: t }) => [
|
|
238
|
+
u(l(we), {
|
|
239
|
+
actions: J(t),
|
|
240
|
+
label: t.name
|
|
241
|
+
}, null, 8, ["actions", "label"])
|
|
242
|
+
]),
|
|
243
|
+
_: 1
|
|
244
|
+
}, 8, ["modelValue", "class", "handle", "item-label", "disabled"]),
|
|
245
|
+
p.value && !o.value ? (s(), f(l(me), {
|
|
246
|
+
key: 0,
|
|
247
|
+
class: "wx-team__note",
|
|
248
|
+
type: "info",
|
|
249
|
+
description: l(V).hint.value
|
|
250
|
+
}, null, 8, ["description"])) : y("", !0)
|
|
251
|
+
], 64))
|
|
252
|
+
]),
|
|
253
|
+
detail: i(({ inline: t, back: P }) => [
|
|
254
|
+
d.value !== null ? (s(), f(he, {
|
|
255
|
+
id: d.value === "new" ? null : d.value,
|
|
256
|
+
key: String(d.value),
|
|
257
|
+
inline: t,
|
|
258
|
+
onBack: P,
|
|
259
|
+
onSaved: c,
|
|
260
|
+
onCreated: G,
|
|
261
|
+
onRemoved: U
|
|
262
|
+
}, null, 8, ["id", "inline", "onBack"])) : y("", !0)
|
|
263
|
+
]),
|
|
264
|
+
empty: i(() => [
|
|
265
|
+
u(l(D), {
|
|
266
|
+
title: l(a)("member.choose"),
|
|
267
|
+
description: p.value ? l(a)("member.choose-help") : void 0
|
|
268
|
+
}, null, 8, ["title", "description"])
|
|
269
|
+
]),
|
|
270
|
+
_: 1
|
|
271
|
+
}, 8, ["open", "detail-label"])
|
|
272
|
+
]),
|
|
273
|
+
_: 1
|
|
274
|
+
})
|
|
275
|
+
]),
|
|
276
|
+
_: 1
|
|
277
|
+
}, 8, ["view", "title", "views"]));
|
|
278
|
+
}
|
|
279
|
+
}), Ie = /* @__PURE__ */ ge(Ve, [["__scopeId", "data-v-9de1c5bb"]]);
|
|
280
|
+
export {
|
|
281
|
+
Ie as default
|
|
282
|
+
};
|
|
283
|
+
//# sourceMappingURL=TeamPage-ZI9lGyZ5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamPage-ZI9lGyZ5.js","sources":["../src/TeamPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'\nimport {\n confirm,\n toast,\n WxAlert,\n WxAvatar,\n WxBadge,\n WxCard,\n WxEmpty,\n WxIcon,\n WxInput,\n WxListDetail,\n WxSkeleton,\n WxSortableList,\n type TabItem,\n type TabValue,\n} from '@webx-ui/core'\nimport {\n useAdmin,\n useErrorText,\n useItemOrder,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n} from '@webx-ui/module-admin'\nimport { createTeamApi, TEAM_API } from './api'\nimport { useTeamMessages } from './i18n'\nimport MemberPane from './MemberPane.vue'\nimport type { MemberRow, MemberSummary } from './types'\n\n/**\n * The team: everybody on the left, the person being written on the right (§5.6, decision 11).\n *\n * The shape of the reviews without their categories: a person is typed in from a list sent by\n * the client in a minute, and the next one is usually the one under it. On a phone the form is\n * the whole screen, in the drawer `WxListDetail` raises, and draws its own way back.\n *\n * One order, the general one (decision 5): a drag moves it; a search or the bin shows a\n * selection, so the grips go away and the line under the list says why.\n *\n * Everything the screen is looking at lives in the address — the view, the search and the open\n * person — so a link to a person is a link to them in their list.\n */\nwithDefaults(defineProps<{ base?: string }>(), { base: '/team' })\n\nconst context = useAdmin()\nconst api = createTeamApi(context)\nconst route = useRoute()\nconst router = useRouter()\nuseTeamMessages()\n\nconst t = useTranslate('webx-team')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst rows = ref<MemberRow[]>([])\nconst loading = ref(true)\n\nconst canManage = computed(() => context.can('team.manage'))\n\nconst title = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'team')?.title ??\n t('module.team'),\n)\n\nconst view = computed<TabValue>({\n get: () => (route.query.view === 'trashed' ? 'trashed' : ''),\n set: (value) => {\n const query: LocationQueryRaw = {\n ...route.query,\n view: value === '' ? undefined : String(value),\n }\n\n // A person from the list is not a person from the bin: the form closes with the view.\n delete query.member\n void router.replace({ query })\n },\n})\n\nconst inBin = computed(() => view.value === 'trashed')\n\nconst q = computed(() => (typeof route.query.q === 'string' ? route.query.q : ''))\n\n/* What is typed, ahead of the address: the address follows it after a pause. */\nconst typed = ref(q.value)\n\n/** The open person: a number, `'new'` for one not yet saved, or nothing. */\nconst selected = computed<number | 'new' | null>(() => {\n const raw = route.query.member\n\n if (raw === 'new') return canManage.value ? 'new' : null\n\n return typeof raw === 'string' && raw !== '' ? Number(raw) || null : null\n})\n\n/*\n * Open is \"a person is chosen\", and closing is un-choosing them — so the address, the list's\n * highlight and the drawer on a phone can never disagree about it.\n */\nconst open = computed({\n get: () => selected.value !== null,\n set: (value) => {\n if (!value) close()\n },\n})\n\nconst views = computed<TabItem[]>(() => [\n { value: '', label: t('member.all') },\n { value: 'trashed', label: t('member.trashed'), icon: 'trash' },\n])\n\nconst order = useItemOrder(TEAM_API, () => ({ q: q.value, filtered: inBin.value }))\n\n/* Dragged only by somebody who may write, and only in a list that is the whole order. */\nconst sortable = computed(() => canManage.value && order.sortable.value)\n\nconst emptyText = computed(() => {\n if (q.value !== '') return t('member.empty-search')\n\n return inBin.value ? t('member.empty-bin') : t('member.empty')\n})\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n const answer = await api.list({ search: q.value, trashed: inBin.value })\n\n rows.value = answer.data\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nwatch(\n () => [view.value, q.value] as const,\n () => void load(),\n)\nvoid load()\n\nlet pause: ReturnType<typeof setTimeout> | undefined\n\nwatch(typed, (value) => {\n clearTimeout(pause)\n pause = setTimeout(() => {\n void router.replace({ query: { ...route.query, q: value.trim() === '' ? undefined : value } })\n }, 300)\n})\n\nonBeforeUnmount(() => clearTimeout(pause))\n\n/* `replace` and not `push`: going through twenty people is not twenty steps of history. */\nfunction choose(id: number | 'new'): void {\n void router.replace({ query: { ...route.query, member: String(id) } })\n}\n\nfunction close(): void {\n const query = { ...route.query }\n\n delete query.member\n void router.replace({ query })\n}\n\n/** A new person was saved: they are a record now, and the list has them. */\nfunction created(member: MemberSummary): void {\n choose(member.id)\n void load()\n}\n\n/**\n * The order on screen, written as a whole. The list is already in its new order\n * (`WxSortableList` reorders the model before it says so), so a failure has to put it back\n * rather than leave the screen disagreeing with the database.\n */\nasync function reorder(): Promise<void> {\n try {\n await order.move(rows.value.map((row) => row.id))\n } catch (error) {\n toast.danger(message(error, t('member.reorder-failed')))\n await load()\n }\n}\n\nfunction actionsFor(row: MemberRow): RowAction[] {\n if (!canManage.value) return []\n\n if (inBin.value) {\n return [\n {\n key: 'restore',\n icon: 'refresh',\n label: t('member.restore'),\n run: () => void restore(row),\n },\n ]\n }\n\n return [\n {\n key: 'delete',\n icon: 'trash',\n label: t('member.delete'),\n danger: true,\n run: () => void remove(row),\n },\n ]\n}\n\nasync function remove(row: MemberRow): Promise<void> {\n const agreed = await confirm({\n title: t('member.delete-title', { name: row.name }),\n message: t('member.delete-text'),\n confirmText: t('member.delete'),\n cancelText: t('member.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.remove(row.id)\n toast.success(t('member.deleted'))\n removed(row.id)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/** Gone from the list; and if they were the open one, the form goes with them. */\nfunction removed(id: number): void {\n if (selected.value === id) close()\n\n void load()\n}\n\nasync function restore(row: MemberRow): Promise<void> {\n try {\n await api.restore(row.id)\n toast.success(t('member.restored'))\n } catch (error) {\n toast.danger(message(error))\n } finally {\n await load()\n }\n}\n</script>\n\n<template>\n <wx-list-screen v-model:view=\"view\" :title=\"title\" :views=\"views\" :card=\"false\">\n <wx-card class=\"wx-team\" padding=\"none\">\n <wx-list-detail\n v-model:open=\"open\"\n class=\"wx-team__panes\"\n :list-width=\"360\"\n :detail-min=\"460\"\n :detail-label=\"t('module.team')\"\n >\n <template #list>\n <div class=\"wx-team__bar\">\n <wx-input\n v-model=\"typed\"\n class=\"wx-team__search\"\n size=\"sm\"\n clearable\n :placeholder=\"t('member.search')\"\n :aria-label=\"t('member.search')\"\n >\n <template #prefix><wx-icon name=\"search\" size=\"sm\" /></template>\n </wx-input>\n </div>\n\n <!--\n A line of the list rather than a button in the head: the new person is written where\n they will stand, beside the ones they join — and the form opens the way any other does.\n -->\n <button\n v-if=\"canManage && !inBin\"\n type=\"button\"\n class=\"wx-team__new\"\n :class=\"{ 'is-current': selected === 'new' }\"\n @click=\"choose('new')\"\n >\n <wx-icon name=\"plus\" size=\"sm\" />\n {{ t('member.new') }}\n </button>\n\n <wx-skeleton v-if=\"loading && rows.length === 0\" class=\"wx-team__loading\" :rows=\"5\" />\n\n <wx-empty\n v-else-if=\"rows.length === 0\"\n :title=\"emptyText\"\n :description=\"!inBin && q === '' ? t('member.empty-help') : undefined\"\n />\n\n <template v-else>\n <!-- A grip and not the whole row: the row opens a person, and a row that both opens\n and drags is one where one of the two happens by accident. -->\n <wx-sortable-list\n v-model=\"rows\"\n class=\"wx-team__list\"\n hoverable\n :class=\"{ 'is-loading': loading }\"\n plain\n item-key=\"id\"\n :handle=\"sortable ? 'grip' : 'row'\"\n :item-label=\"(item: MemberRow) => item.name\"\n :disabled=\"!sortable\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <component\n :is=\"inBin ? 'div' : 'button'\"\n :type=\"inBin ? undefined : 'button'\"\n class=\"wx-member-row\"\n :class=\"{ 'is-current': selected === item.id }\"\n @click=\"inBin ? undefined : choose(item.id)\"\n >\n <wx-avatar\n class=\"wx-member-row__photo\"\n :src=\"item.photo?.thumb ?? undefined\"\n :name=\"item.name\"\n size=\"md\"\n />\n\n <span class=\"wx-member-row__body\">\n <span class=\"wx-member-row__name\">{{ item.name }}</span>\n\n <span v-if=\"item.job_title\" class=\"wx-member-row__job\">\n {{ item.job_title }}\n </span>\n\n <span v-if=\"!item.published\" class=\"wx-member-row__facts\">\n <wx-badge dot size=\"sm\">{{ t('member.not-published') }}</wx-badge>\n </span>\n </span>\n </component>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"item.name\" />\n </template>\n </wx-sortable-list>\n\n <!-- What a drag does here, or why there is nothing to drag. -->\n <wx-alert\n v-if=\"canManage && !inBin\"\n class=\"wx-team__note\"\n type=\"info\"\n :description=\"order.hint.value\"\n />\n </template>\n </template>\n\n <template #detail=\"{ inline, back }\">\n <member-pane\n v-if=\"selected !== null\"\n :id=\"selected === 'new' ? null : selected\"\n :key=\"String(selected)\"\n :inline=\"inline\"\n @back=\"back\"\n @saved=\"load\"\n @created=\"created\"\n @removed=\"removed\"\n />\n </template>\n\n <template #empty>\n <wx-empty\n :title=\"t('member.choose')\"\n :description=\"canManage ? t('member.choose-help') : undefined\"\n />\n </template>\n </wx-list-detail>\n </wx-card>\n </wx-list-screen>\n</template>\n\n<style>\n/*\n * What scrolls here is the page, the way it does on every other list of the panel. The card's\n * corners are the screen's, and the panes paint their own background to the edge: `clip`, not\n * `hidden`, which would make this a scroll container and pin everything sticky inside to a box\n * that never moves (CLAUDE.md §4).\n */\n.wx-team > .wx-card__body {\n display: flex;\n flex-direction: column;\n overflow: clip;\n border-radius: inherit;\n}\n</style>\n\n<style scoped>\n.wx-team__bar {\n display: flex;\n gap: var(--wx-space-8);\n padding: var(--wx-space-12) var(--wx-space-12) var(--wx-space-8);\n}\n\n.wx-team__search {\n flex: 1 1 180px;\n min-width: 0;\n}\n\n.wx-team__new {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n width: calc(100% - 2 * var(--wx-space-8));\n margin: 0 var(--wx-space-8) var(--wx-space-4);\n padding: var(--wx-space-8);\n border: 1px dashed var(--wx-border-default);\n border-radius: var(--wx-radius-sm);\n background: none;\n font: inherit;\n color: var(--wx-color-primary);\n text-align: start;\n cursor: pointer;\n}\n\n.wx-team__new:hover,\n.wx-team__new.is-current {\n background: var(--wx-bg-subtle);\n}\n\n.wx-team__loading {\n padding: var(--wx-space-12);\n}\n\n.wx-team__list {\n padding-inline: var(--wx-space-8);\n}\n\n.wx-team__list.is-loading {\n opacity: 0.6;\n}\n\n.wx-team__list :deep(.wx-sortable-list__row) {\n gap: var(--wx-space-4);\n padding-inline: var(--wx-space-4);\n}\n\n.wx-team__note {\n margin: var(--wx-space-8);\n}\n\n.wx-member-row {\n display: flex;\n align-items: flex-start;\n gap: var(--wx-space-10);\n /* The row is the target: a short name should not leave half the line dead — and a button,\n unlike a link, is only as wide as what is in it until it is told otherwise. */\n flex: 1 1 auto;\n width: 100%;\n min-width: 0;\n padding-block: var(--wx-space-8);\n padding-inline: 0;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n}\n\nbutton.wx-member-row {\n cursor: pointer;\n}\n\n.wx-member-row__photo {\n flex: none;\n}\n\n.wx-member-row__body {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--wx-space-2);\n min-width: 0;\n}\n\n.wx-member-row__name {\n min-width: 0;\n overflow: hidden;\n font-weight: var(--wx-font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wx-member-row.is-current .wx-member-row__name {\n color: var(--wx-color-primary);\n}\n\n.wx-member-row__job {\n overflow: hidden;\n color: var(--wx-text-muted);\n font-size: var(--wx-font-size-sm);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wx-member-row__facts {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wx-space-4);\n min-width: 0;\n margin-top: var(--wx-space-2);\n}\n</style>\n"],"names":["context","useAdmin","api","createTeamApi","route","useRoute","router","useRouter","useTeamMessages","t","useTranslate","message","useErrorText","rows","ref","loading","canManage","computed","title","module","view","value","query","inBin","q","typed","selected","raw","open","close","views","order","useItemOrder","TEAM_API","sortable","emptyText","load","answer","error","toast","watch","pause","onBeforeUnmount","choose","id","created","member","reorder","row","actionsFor","restore","remove","confirm","removed","_createBlock","_unref","WxListScreen","$event","_createVNode","WxCard","WxListDetail","_createElementVNode","_hoisted_1","WxInput","WxIcon","_createElementBlock","_normalizeClass","_createTextVNode","WxSkeleton","WxEmpty","_Fragment","WxSortableList","item","_withCtx","_openBlock","_resolveDynamicComponent","WxAvatar","_hoisted_2","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","WxBadge","WxRowMenu","WxAlert","inline","back","MemberPane"],"mappings":"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"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { defineComponent as q, ref as m, computed as v, onMounted as F, onBeforeUnmount as G, openBlock as x, createElementBlock as L, createBlock as M, unref as i, Fragment as H, createVNode as y, createSlots as Q, withCtx as g, createTextVNode as C, toDisplayString as R, createCommentVNode as X, defineAsyncComponent as Y } from "vue";
|
|
2
|
+
import { reorderItems as Z, useAdmin as j, useTranslate as ee, useErrorText as te, useBodyKeys as ae, WxScreenHead as ne, WxScreen as oe, WxSaveState as re } from "@webx-ui/module-admin";
|
|
3
|
+
import { onBeforeRouteUpdate as se, onBeforeRouteLeave as le } from "vue-router";
|
|
4
|
+
import { useLocales as ie, localizedValue as ce, WxSkeleton as ue, WxBadge as de, WxActionBar as me, WxButton as ve, toast as h, confirm as V } from "@webx-ui/core";
|
|
5
|
+
function Se(a = {}) {
|
|
6
|
+
const s = a.path ?? "/team";
|
|
7
|
+
return {
|
|
8
|
+
id: "team",
|
|
9
|
+
path: s,
|
|
10
|
+
// One route: the open person is in the address (`?member=`), beside the list they were
|
|
11
|
+
// opened from, so a link to them is a link to both.
|
|
12
|
+
routes: [
|
|
13
|
+
{ path: s, name: "webx.team", component: () => import("./TeamPage-ZI9lGyZ5.js"), props: { base: s } }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const D = "team";
|
|
18
|
+
function he(a) {
|
|
19
|
+
const s = `${a.apiPath}/${D}`, n = (t) => t.data;
|
|
20
|
+
return {
|
|
21
|
+
list: (t = {}) => {
|
|
22
|
+
const l = new URLSearchParams();
|
|
23
|
+
return t.search && l.set("search", t.search), t.trashed && l.set("trashed", "1"), a.http.get(l.size > 0 ? `${s}?${l}` : s);
|
|
24
|
+
},
|
|
25
|
+
get: (t) => a.http.get(`${s}/${t}`).then(n),
|
|
26
|
+
create: (t) => a.http.post(s, { values: t }).then(n),
|
|
27
|
+
save: (t, l) => a.http.put(`${s}/${t}`, { values: l }).then(n),
|
|
28
|
+
remove: (t) => a.http.delete(`${s}/${t}`).then(() => {
|
|
29
|
+
}),
|
|
30
|
+
// The resource of the list line, and not the form's pair: a restored person stays closed.
|
|
31
|
+
restore: (t) => a.http.post(`${s}/${t}/restore`, {}).then(n),
|
|
32
|
+
reorder: (t) => Z(a, D, t, null)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const pe = {
|
|
36
|
+
module: {
|
|
37
|
+
team: "Team"
|
|
38
|
+
},
|
|
39
|
+
member: {
|
|
40
|
+
new: "New person",
|
|
41
|
+
untitled: "Untitled",
|
|
42
|
+
search: "Search the team",
|
|
43
|
+
empty: "Nobody on the team yet.",
|
|
44
|
+
"empty-help": "A person reaches the site in a team block, on any page.",
|
|
45
|
+
"empty-search": "Nothing matches that.",
|
|
46
|
+
"empty-bin": "The bin is empty.",
|
|
47
|
+
all: "All",
|
|
48
|
+
trashed: "Bin",
|
|
49
|
+
"not-published": "Not published",
|
|
50
|
+
"no-job-title": "No job title",
|
|
51
|
+
order: "Drag to change the order on the site.",
|
|
52
|
+
choose: "Choose a person",
|
|
53
|
+
"choose-help": "Or add a new one: the first line of the list.",
|
|
54
|
+
save: "Save",
|
|
55
|
+
saved: "Saved.",
|
|
56
|
+
"save-failed": "Not saved.",
|
|
57
|
+
cancel: "Cancel",
|
|
58
|
+
delete: "Delete",
|
|
59
|
+
"delete-title": "Delete “:name” from the team?",
|
|
60
|
+
"delete-text": "They go to the bin and leave every block on the site. Restored, they come back to their place.",
|
|
61
|
+
deleted: "Moved to the bin.",
|
|
62
|
+
restore: "Restore",
|
|
63
|
+
restored: "Restored.",
|
|
64
|
+
"reorder-failed": "The new order was not saved.",
|
|
65
|
+
"leave-title": "Leave without saving?",
|
|
66
|
+
"leave-text": "What you wrote about this person is not on the server.",
|
|
67
|
+
leave: "Leave",
|
|
68
|
+
back: "Back to the list"
|
|
69
|
+
},
|
|
70
|
+
screen: {
|
|
71
|
+
person: "Person",
|
|
72
|
+
photo: "Photo",
|
|
73
|
+
"photo-help": "Without one, the site shows the initials of the name.",
|
|
74
|
+
name: "Name",
|
|
75
|
+
"name-help": "Required in the default language. Not written in another, the default one is shown.",
|
|
76
|
+
"job-title": "Job title",
|
|
77
|
+
"job-title-help": "Printed under the name. Not written in a language, the default one is shown.",
|
|
78
|
+
about: "About",
|
|
79
|
+
text: "Text",
|
|
80
|
+
"text-help": "Printed only in the language it is written in. The person is shown either way.",
|
|
81
|
+
links: "Links",
|
|
82
|
+
socials: "Social networks",
|
|
83
|
+
"socials-help": "In the order the site prints them. A row left empty is dropped when you save.",
|
|
84
|
+
"socials-add": "Add a link",
|
|
85
|
+
"socials-empty": "No links.",
|
|
86
|
+
network: "Network",
|
|
87
|
+
"network-placeholder": "Choose a network",
|
|
88
|
+
url: "Address",
|
|
89
|
+
services: "Services",
|
|
90
|
+
"services-help": "What the person provides: a team block on a service’s page can show only them.",
|
|
91
|
+
settings: "Settings",
|
|
92
|
+
published: "Published",
|
|
93
|
+
"published-help": "On the site in every team block, from the moment it is saved."
|
|
94
|
+
}
|
|
95
|
+
}, O = /* @__PURE__ */ new WeakSet();
|
|
96
|
+
function be() {
|
|
97
|
+
try {
|
|
98
|
+
const { i18n: a } = j();
|
|
99
|
+
O.has(a) || (a.defaults("webx-team", pe), O.add(a));
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const fe = /* @__PURE__ */ q({
|
|
104
|
+
name: "WxMemberPane",
|
|
105
|
+
__name: "MemberPane",
|
|
106
|
+
props: {
|
|
107
|
+
id: {},
|
|
108
|
+
inline: { type: Boolean, default: !0 }
|
|
109
|
+
},
|
|
110
|
+
emits: ["back", "saved", "created", "removed"],
|
|
111
|
+
setup(a, { emit: s }) {
|
|
112
|
+
const n = a, t = s, l = j(), w = he(l), E = ie();
|
|
113
|
+
be();
|
|
114
|
+
const o = ee("webx-team"), S = te(), u = m(null), c = m({}), p = m(""), T = m(n.id !== null), d = m(!1), N = m({}), b = v(() => l.can("team.manage")), _ = v(() => JSON.stringify(c.value)), f = v(() => p.value !== "" && _.value !== p.value), U = v(() => d.value ? "saving" : f.value || n.id === null ? "unsaved" : "saved"), I = v(() => {
|
|
115
|
+
const e = c.value.name, r = n.id === null ? o("member.new") : u.value?.name ?? "";
|
|
116
|
+
return ce(e, E.active.value, r) || o("member.untitled");
|
|
117
|
+
});
|
|
118
|
+
function B(e) {
|
|
119
|
+
u.value = e.member, c.value = e.values, p.value = JSON.stringify(e.values);
|
|
120
|
+
}
|
|
121
|
+
if (n.id === null) {
|
|
122
|
+
const e = {
|
|
123
|
+
name: {},
|
|
124
|
+
job_title: {},
|
|
125
|
+
text: {},
|
|
126
|
+
photo: null,
|
|
127
|
+
socials: [],
|
|
128
|
+
published: !1
|
|
129
|
+
};
|
|
130
|
+
c.value = e, p.value = JSON.stringify(e);
|
|
131
|
+
}
|
|
132
|
+
async function J() {
|
|
133
|
+
if (n.id !== null) {
|
|
134
|
+
T.value = !0;
|
|
135
|
+
try {
|
|
136
|
+
B(await w.get(n.id));
|
|
137
|
+
} catch (e) {
|
|
138
|
+
h.danger(S(e)), t("back");
|
|
139
|
+
} finally {
|
|
140
|
+
T.value = !1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function W() {
|
|
145
|
+
if (!(d.value || !b.value)) {
|
|
146
|
+
d.value = !0, N.value = {};
|
|
147
|
+
try {
|
|
148
|
+
const e = n.id === null, r = e ? await w.create(c.value) : await w.save(n.id, c.value);
|
|
149
|
+
B(r), h.success(o("member.saved")), t(e ? "created" : "saved", r.member);
|
|
150
|
+
} catch (e) {
|
|
151
|
+
const r = e.body;
|
|
152
|
+
r?.errors ? (N.value = r.errors, h.danger(o("member.save-failed"))) : h.danger(S(e));
|
|
153
|
+
} finally {
|
|
154
|
+
d.value = !1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function K() {
|
|
159
|
+
const e = u.value;
|
|
160
|
+
if (!(!e || !await V({
|
|
161
|
+
title: o("member.delete-title", { name: e.name }),
|
|
162
|
+
message: o("member.delete-text"),
|
|
163
|
+
confirmText: o("member.delete"),
|
|
164
|
+
cancelText: o("member.cancel"),
|
|
165
|
+
tone: "danger"
|
|
166
|
+
})))
|
|
167
|
+
try {
|
|
168
|
+
await w.remove(e.id), h.success(o("member.deleted")), p.value = _.value, t("removed", e.id);
|
|
169
|
+
} catch (k) {
|
|
170
|
+
h.danger(S(k));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function $(e) {
|
|
174
|
+
f.value && e.preventDefault();
|
|
175
|
+
}
|
|
176
|
+
function A(e) {
|
|
177
|
+
(e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s" && (e.preventDefault(), (f.value || n.id === null) && W());
|
|
178
|
+
}
|
|
179
|
+
ae(A), F(() => {
|
|
180
|
+
J(), window.addEventListener("beforeunload", $);
|
|
181
|
+
}), G(() => {
|
|
182
|
+
window.removeEventListener("beforeunload", $);
|
|
183
|
+
});
|
|
184
|
+
async function P() {
|
|
185
|
+
return !f.value || !b.value ? !0 : await V({
|
|
186
|
+
title: o("member.leave-title"),
|
|
187
|
+
message: o("member.leave-text"),
|
|
188
|
+
confirmText: o("member.leave"),
|
|
189
|
+
cancelText: o("member.cancel"),
|
|
190
|
+
tone: "danger"
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
se(
|
|
194
|
+
async (e, r) => e.query.member === r.query.member ? !0 : await P()
|
|
195
|
+
), le(P);
|
|
196
|
+
const z = v(
|
|
197
|
+
() => b.value && u.value !== null ? [
|
|
198
|
+
{
|
|
199
|
+
key: "delete",
|
|
200
|
+
label: o("member.delete"),
|
|
201
|
+
icon: "trash",
|
|
202
|
+
danger: !0,
|
|
203
|
+
menu: !0,
|
|
204
|
+
run: () => {
|
|
205
|
+
K();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
] : []
|
|
209
|
+
);
|
|
210
|
+
return (e, r) => (x(), L("div", {
|
|
211
|
+
class: "wx-member",
|
|
212
|
+
onKeydown: A
|
|
213
|
+
}, [
|
|
214
|
+
T.value ? (x(), M(i(ue), {
|
|
215
|
+
key: 0,
|
|
216
|
+
class: "wx-member__ghost",
|
|
217
|
+
title: "",
|
|
218
|
+
rows: 6
|
|
219
|
+
})) : (x(), L(H, { key: 1 }, [
|
|
220
|
+
y(i(ne), {
|
|
221
|
+
level: 3,
|
|
222
|
+
back: !n.inline,
|
|
223
|
+
"back-label": i(o)("member.back"),
|
|
224
|
+
title: I.value,
|
|
225
|
+
actions: z.value,
|
|
226
|
+
"collapse-below": 480,
|
|
227
|
+
onBack: r[0] || (r[0] = (k) => t("back"))
|
|
228
|
+
}, Q({ _: 2 }, [
|
|
229
|
+
u.value && !u.value.published ? {
|
|
230
|
+
name: "title-after",
|
|
231
|
+
fn: g(() => [
|
|
232
|
+
y(i(de), { dot: "" }, {
|
|
233
|
+
default: g(() => [
|
|
234
|
+
C(R(i(o)("member.not-published")), 1)
|
|
235
|
+
]),
|
|
236
|
+
_: 1
|
|
237
|
+
})
|
|
238
|
+
]),
|
|
239
|
+
key: "0"
|
|
240
|
+
} : void 0
|
|
241
|
+
]), 1032, ["back", "back-label", "title", "actions"]),
|
|
242
|
+
y(i(oe), {
|
|
243
|
+
modelValue: c.value,
|
|
244
|
+
"onUpdate:modelValue": r[1] || (r[1] = (k) => c.value = k),
|
|
245
|
+
name: "team.form",
|
|
246
|
+
errors: N.value,
|
|
247
|
+
disabled: !b.value || d.value
|
|
248
|
+
}, null, 8, ["modelValue", "errors", "disabled"]),
|
|
249
|
+
b.value ? (x(), M(i(me), { key: 0 }, {
|
|
250
|
+
state: g(() => [
|
|
251
|
+
y(i(re), { state: U.value }, null, 8, ["state"])
|
|
252
|
+
]),
|
|
253
|
+
default: g(() => [
|
|
254
|
+
y(i(ve), {
|
|
255
|
+
type: "primary",
|
|
256
|
+
loading: d.value,
|
|
257
|
+
disabled: !f.value && n.id !== null,
|
|
258
|
+
onClick: W
|
|
259
|
+
}, {
|
|
260
|
+
default: g(() => [
|
|
261
|
+
C(R(i(o)("member.save")), 1)
|
|
262
|
+
]),
|
|
263
|
+
_: 1
|
|
264
|
+
}, 8, ["loading", "disabled"])
|
|
265
|
+
]),
|
|
266
|
+
_: 1
|
|
267
|
+
})) : X("", !0)
|
|
268
|
+
], 64))
|
|
269
|
+
], 32));
|
|
270
|
+
}
|
|
271
|
+
}), ye = (a, s) => {
|
|
272
|
+
const n = a.__vccOpts || a;
|
|
273
|
+
for (const [t, l] of s)
|
|
274
|
+
n[t] = l;
|
|
275
|
+
return n;
|
|
276
|
+
}, Te = /* @__PURE__ */ ye(fe, [["__scopeId", "data-v-443f6ebd"]]), Ne = Y(() => import("./TeamPage-ZI9lGyZ5.js"));
|
|
277
|
+
export {
|
|
278
|
+
Te as M,
|
|
279
|
+
D as T,
|
|
280
|
+
Ne as W,
|
|
281
|
+
ye as _,
|
|
282
|
+
pe as a,
|
|
283
|
+
he as c,
|
|
284
|
+
Se as t,
|
|
285
|
+
be as u
|
|
286
|
+
};
|
|
287
|
+
//# sourceMappingURL=index-Dq5upQx6.js.map
|