@webx-ui/module-tasks 0.0.0-stage → 0.1.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 ADDED
@@ -0,0 +1,1753 @@
1
+ import { defineComponent as Y, useId as Te, ref as S, reactive as Ee, openBlock as p, createBlock as $, unref as e, isRef as $e, withCtx as s, createElementVNode as L, withModifiers as Se, createVNode as n, createCommentVNode as A, createTextVNode as f, toDisplayString as v, computed as C, onMounted as fe, onBeforeUnmount as Le, createElementBlock as N, Fragment as G, renderList as de, useTemplateRef as Fe, nextTick as Oe, watch as We } from "vue";
2
+ import { useAdmin as ee, useTranslate as te, useErrorText as ae, WxListScreen as Ve, useBodyKeys as Ke, WxScreenHead as ge, WxScreen as Pe, WxSaveState as qe, renderMarkdown as Je, WxDate as Ce } from "@webx-ui/module-admin";
3
+ import { useModal as ze, WxDialog as Ae, WxFormItem as H, WxInput as ie, WxTextarea as ye, WxSwitch as He, WxSpace as Ne, WxButton as K, toast as M, createModal as Ie, WxTable as Ue, WxText as B, WxBadge as Q, confirm as pe, WxSkeleton as he, WxAlert as me, WxCard as ve, WxActionBar as Be, WxProse as Ge, WxAccordion as Qe, WxAccordionItem as Ye, WxTimeline as Xe, WxTimelineItem as Ze, WxSelect as et } from "@webx-ui/core";
4
+ import { useRoute as De, useRouter as be, onBeforeRouteLeave as tt } from "vue-router";
5
+ function se(h) {
6
+ const l = `${h.apiPath}/tasks`, d = (a) => a.data, k = (a, t = {}) => h.http.post(`${l}/${a}`, t).then(d);
7
+ return {
8
+ projects: () => h.http.get(`${l}/projects`).then(d),
9
+ createProject: (a) => h.http.post(`${l}/projects`, a).then(d),
10
+ saveProject: (a, t) => h.http.put(`${l}/projects/${a}`, t).then(d),
11
+ /* `undefined` drops a parameter; `null` and `''` would be sent as words. */
12
+ tasks: (a = {}) => h.http.get(`${l}/tasks`, {
13
+ query: {
14
+ view: a.view && a.view !== "all" ? a.view : void 0,
15
+ project: a.project ?? void 0,
16
+ q: a.q || void 0,
17
+ page: a.page,
18
+ per_page: a.per_page
19
+ }
20
+ }),
21
+ task: (a) => h.http.get(`${l}/tasks/${a}`).then(d),
22
+ create: (a) => h.http.post(`${l}/tasks`, a).then(d),
23
+ save: (a, t) => h.http.put(`${l}/tasks/${a}`, t).then(d),
24
+ ready: (a) => k(`tasks/${a}/ready`),
25
+ cancel: (a, t) => k(`tasks/${a}/cancel`, { reason: t }),
26
+ comment: (a, t, r) => k(`tasks/${a}/comments`, { body: t, stage_id: r }),
27
+ accept: (a, t) => k(`stages/${a}/accept`, { note: t }),
28
+ rework: (a, t) => k(`stages/${a}/rework`, { remarks: t }),
29
+ unblock: (a, t) => k(`stages/${a}/unblock`, { answer: t }),
30
+ release: (a, t) => k(`stages/${a}/release`, { reason: t }),
31
+ cancelStage: (a, t) => k(`stages/${a}/cancel`, { reason: t }),
32
+ settings: () => h.http.get(`${l}/settings`).then(d),
33
+ saveSettings: (a, t = !1) => h.http.put(`${l}/settings`, {
34
+ values: a,
35
+ forget_token: t || void 0
36
+ }).then(d),
37
+ testNotice: () => h.http.post(`${l}/settings/test`, {}).then((a) => a.message)
38
+ };
39
+ }
40
+ const at = {
41
+ module: {
42
+ title: "Tasks"
43
+ },
44
+ panel: {
45
+ new: "New task",
46
+ projects: "Projects",
47
+ "view-all": "All",
48
+ "view-waiting": "Waiting for me",
49
+ "view-active": "In work",
50
+ "view-draft": "Drafts",
51
+ "view-closed": "Closed",
52
+ "all-projects": "All projects",
53
+ search: "Search tasks",
54
+ empty: "No tasks here.",
55
+ "column-task": "Task",
56
+ "column-status": "Status",
57
+ "column-stage": "Stage",
58
+ "column-priority": "Priority",
59
+ "column-updated": "Updated",
60
+ "stage-of": "Stage :position/:count",
61
+ "status-draft": "Draft",
62
+ "status-ready": "Ready",
63
+ "status-in_progress": "In progress",
64
+ "status-review": "In review",
65
+ "status-done": "Done",
66
+ "status-cancelled": "Cancelled",
67
+ "stage-pending": "Waiting",
68
+ "stage-ready": "Ready",
69
+ "stage-in_progress": "In progress",
70
+ "stage-review": "In review",
71
+ "stage-rework": "Sent back",
72
+ "stage-blocked": "Asked a question",
73
+ "stage-done": "Done",
74
+ "stage-cancelled": "The stage is cancelled.",
75
+ "priority-low": "Low",
76
+ "priority-normal": "Normal",
77
+ "priority-high": "High",
78
+ spec: "Specification",
79
+ acceptance: "Acceptance criteria",
80
+ "no-spec": "No specification.",
81
+ branch: "Branch",
82
+ stages: "Stages",
83
+ journal: "Journal",
84
+ brief: "Assignment",
85
+ "stage-acceptance": "Criteria",
86
+ report: "Report",
87
+ result: "Result",
88
+ "no-report": "Not reported yet.",
89
+ agent: "Agent",
90
+ attempt: "Attempt :attempt",
91
+ "by-person": "Checked by a person",
92
+ "by-agent": "Checked by an agent",
93
+ question: "Question",
94
+ start: "Put to work",
95
+ started: "The task is in work: the first stage can be taken.",
96
+ edit: "Edit",
97
+ "cancel-task": "Cancel the task",
98
+ "cancel-task-title": "Cancel «:title»?",
99
+ "cancel-task-text": "Every stage that is not done is cancelled, and nothing of the task is handed out again.",
100
+ cancelled: "The task is cancelled.",
101
+ accept: "Accept",
102
+ "accept-title": "Accept «:stage»?",
103
+ "accept-text": "The next stage can be taken right after.",
104
+ accepted: "The stage is accepted.",
105
+ rework: "Send back",
106
+ "rework-title": "Send «:stage» back",
107
+ "rework-label": "What has to change",
108
+ reworked: "The stage is sent back.",
109
+ answer: "Answer",
110
+ "answer-title": "Answer the question",
111
+ "answer-label": "Your answer",
112
+ answered: "The answer is sent; the stage is back in the queue.",
113
+ release: "Release",
114
+ "release-title": "Release «:stage»?",
115
+ "release-text": "The stage goes back to the queue, and the agent that held it loses it.",
116
+ released: "The stage is released.",
117
+ "cancel-stage": "Cancel the stage",
118
+ "cancel-stage-title": "Cancel «:stage»?",
119
+ "cancel-stage-text": "The stage is skipped and the next one can start.",
120
+ note: "Note",
121
+ send: "Send",
122
+ keep: "Keep",
123
+ comment: "Comment",
124
+ "comment-placeholder": "Add a comment for people and agents",
125
+ commented: "The comment is added.",
126
+ "kind-status": "changed the status",
127
+ "kind-report": "reported",
128
+ "kind-rework": "sent back",
129
+ "kind-question": "asked",
130
+ "kind-answer": "answered",
131
+ "kind-edit": "edited the task",
132
+ "kind-comment": "commented",
133
+ system: "System",
134
+ "journal-empty": "Nothing has happened yet.",
135
+ "locked-stages": "Started stages",
136
+ "locked-help": "Stages already taken stay as they are. The others can be changed and reordered, and new ones go at the end.",
137
+ "locked-fields": "Work has started: of the task itself, only the priority can change.",
138
+ save: "Save",
139
+ saved: "Saved.",
140
+ created: "The task is written. It stays a draft until you put it to work.",
141
+ "save-failed": "The task is not saved: check the marked fields.",
142
+ "leave-title": "Leave without saving?",
143
+ "leave-text": "The changes made here will be lost.",
144
+ leave: "Leave",
145
+ back: "Back to tasks",
146
+ untitled: "Untitled task",
147
+ "need-project": "Add a project first: every task belongs to one.",
148
+ "project-new": "New project",
149
+ "project-edit": "Edit the project",
150
+ "project-title": "Name",
151
+ "project-slug": "Slug",
152
+ "project-slug-help": "Lowercase letters, digits and dashes. Tasks are named by it: shop#12.",
153
+ "project-workdir": "Working folder",
154
+ "project-workdir-help": "The folder an agent is started in.",
155
+ "project-repo": "Repository",
156
+ "project-branch": "Default branch",
157
+ "project-rules": "Rules for agents",
158
+ "project-rules-help": "Handed to every stage of the project: the gate to run, what never to touch.",
159
+ "project-archived": "Archived",
160
+ "project-archived-help": "An archived project takes no new tasks and hands nothing out.",
161
+ "project-tasks": "Tasks",
162
+ "project-saved": "The project is saved.",
163
+ "projects-empty": "No projects yet. A task belongs to a project — add one first.",
164
+ settings: "Settings",
165
+ "settings-saved": "The settings are saved.",
166
+ "send-test": "Send a test message",
167
+ "test-sent": "The test message is sent.",
168
+ "token-set": "A bot token is set.",
169
+ "token-not-set": "No bot token yet: nothing is sent.",
170
+ "forget-token": "Forget the token",
171
+ "token-forgotten": "The token is forgotten."
172
+ }
173
+ }, xe = /* @__PURE__ */ new WeakSet();
174
+ function le() {
175
+ try {
176
+ const { i18n: h } = ee();
177
+ xe.has(h) || (h.defaults("webx-tasks", at), xe.add(h));
178
+ } catch {
179
+ }
180
+ }
181
+ const st = ["id"], lt = /* @__PURE__ */ Y({
182
+ name: "WxTasksProjectDialog",
183
+ __name: "ProjectDialog",
184
+ props: {
185
+ project: { default: null }
186
+ },
187
+ setup(h) {
188
+ const l = h, { open: d, resolve: k, dismiss: a } = ze(), t = ee(), r = se(t);
189
+ le();
190
+ const i = te("webx-tasks"), j = ae(), V = Te(), y = S(!1), x = S({}), b = Ee({
191
+ slug: l.project?.slug ?? "",
192
+ title: l.project?.title ?? "",
193
+ workdir: l.project?.workdir ?? "",
194
+ repo_url: l.project?.repo_url ?? "",
195
+ default_branch: l.project?.default_branch ?? "main",
196
+ rules: l.project?.rules ?? "",
197
+ archived: l.project?.archived ?? !1
198
+ });
199
+ async function I() {
200
+ if (y.value) return;
201
+ y.value = !0, x.value = {};
202
+ const q = {
203
+ ...b,
204
+ workdir: b.workdir || null,
205
+ repo_url: b.repo_url || null,
206
+ default_branch: b.default_branch || null,
207
+ rules: b.rules || null
208
+ };
209
+ try {
210
+ k(
211
+ l.project ? await r.saveProject(l.project.id, q) : await r.createProject(q)
212
+ ), M.success(i("panel.project-saved"));
213
+ } catch (_) {
214
+ const g = _.body;
215
+ g?.errors ? x.value = g.errors : M.danger(j(_));
216
+ } finally {
217
+ y.value = !1;
218
+ }
219
+ }
220
+ return (q, _) => (p(), $(e(Ae), {
221
+ open: e(d),
222
+ "onUpdate:open": _[8] || (_[8] = (g) => $e(d) ? d.value = g : null),
223
+ title: l.project ? e(i)("panel.project-edit") : e(i)("panel.project-new"),
224
+ width: 560
225
+ }, {
226
+ footer: s(() => [
227
+ n(e(Ne), { size: "sm" }, {
228
+ default: s(() => [
229
+ n(e(K), {
230
+ variant: "outline",
231
+ onClick: _[7] || (_[7] = (g) => e(a)())
232
+ }, {
233
+ default: s(() => [
234
+ f(v(e(i)("panel.keep")), 1)
235
+ ]),
236
+ _: 1
237
+ }),
238
+ n(e(K), {
239
+ type: "primary",
240
+ "native-type": "submit",
241
+ form: e(V),
242
+ loading: y.value
243
+ }, {
244
+ default: s(() => [
245
+ f(v(e(i)("panel.save")), 1)
246
+ ]),
247
+ _: 1
248
+ }, 8, ["form", "loading"])
249
+ ]),
250
+ _: 1
251
+ })
252
+ ]),
253
+ default: s(() => [
254
+ L("form", {
255
+ id: e(V),
256
+ class: "wx-tasks-project",
257
+ onSubmit: Se(I, ["prevent"])
258
+ }, [
259
+ n(e(H), {
260
+ label: e(i)("panel.project-title"),
261
+ error: x.value.title,
262
+ required: ""
263
+ }, {
264
+ default: s(() => [
265
+ n(e(ie), {
266
+ modelValue: b.title,
267
+ "onUpdate:modelValue": _[0] || (_[0] = (g) => b.title = g),
268
+ maxlength: 255
269
+ }, null, 8, ["modelValue"])
270
+ ]),
271
+ _: 1
272
+ }, 8, ["label", "error"]),
273
+ n(e(H), {
274
+ label: e(i)("panel.project-slug"),
275
+ help: e(i)("panel.project-slug-help"),
276
+ error: x.value.slug,
277
+ required: ""
278
+ }, {
279
+ default: s(() => [
280
+ n(e(ie), {
281
+ modelValue: b.slug,
282
+ "onUpdate:modelValue": _[1] || (_[1] = (g) => b.slug = g),
283
+ maxlength: 64
284
+ }, null, 8, ["modelValue"])
285
+ ]),
286
+ _: 1
287
+ }, 8, ["label", "help", "error"]),
288
+ n(e(H), {
289
+ label: e(i)("panel.project-workdir"),
290
+ help: e(i)("panel.project-workdir-help"),
291
+ error: x.value.workdir
292
+ }, {
293
+ default: s(() => [
294
+ n(e(ie), {
295
+ modelValue: b.workdir,
296
+ "onUpdate:modelValue": _[2] || (_[2] = (g) => b.workdir = g)
297
+ }, null, 8, ["modelValue"])
298
+ ]),
299
+ _: 1
300
+ }, 8, ["label", "help", "error"]),
301
+ n(e(H), {
302
+ label: e(i)("panel.project-repo"),
303
+ error: x.value.repo_url
304
+ }, {
305
+ default: s(() => [
306
+ n(e(ie), {
307
+ modelValue: b.repo_url,
308
+ "onUpdate:modelValue": _[3] || (_[3] = (g) => b.repo_url = g)
309
+ }, null, 8, ["modelValue"])
310
+ ]),
311
+ _: 1
312
+ }, 8, ["label", "error"]),
313
+ n(e(H), {
314
+ label: e(i)("panel.project-branch"),
315
+ error: x.value.default_branch
316
+ }, {
317
+ default: s(() => [
318
+ n(e(ie), {
319
+ modelValue: b.default_branch,
320
+ "onUpdate:modelValue": _[4] || (_[4] = (g) => b.default_branch = g)
321
+ }, null, 8, ["modelValue"])
322
+ ]),
323
+ _: 1
324
+ }, 8, ["label", "error"]),
325
+ n(e(H), {
326
+ label: e(i)("panel.project-rules"),
327
+ help: e(i)("panel.project-rules-help"),
328
+ error: x.value.rules
329
+ }, {
330
+ default: s(() => [
331
+ n(e(ye), {
332
+ modelValue: b.rules,
333
+ "onUpdate:modelValue": _[5] || (_[5] = (g) => b.rules = g),
334
+ rows: 5
335
+ }, null, 8, ["modelValue"])
336
+ ]),
337
+ _: 1
338
+ }, 8, ["label", "help", "error"]),
339
+ l.project ? (p(), $(e(H), {
340
+ key: 0,
341
+ help: e(i)("panel.project-archived-help")
342
+ }, {
343
+ default: s(() => [
344
+ n(e(He), {
345
+ modelValue: b.archived,
346
+ "onUpdate:modelValue": _[6] || (_[6] = (g) => b.archived = g),
347
+ label: e(i)("panel.project-archived")
348
+ }, null, 8, ["modelValue", "label"])
349
+ ]),
350
+ _: 1
351
+ }, 8, ["help"])) : A("", !0)
352
+ ], 40, st)
353
+ ]),
354
+ _: 1
355
+ }, 8, ["open", "title"]));
356
+ }
357
+ }), X = (h, l) => {
358
+ const d = h.__vccOpts || h;
359
+ for (const [k, a] of l)
360
+ d[k] = a;
361
+ return d;
362
+ }, nt = /* @__PURE__ */ X(lt, [["__scopeId", "data-v-f2e7c250"]]), ot = { class: "wx-tasks-projects__title" }, rt = /* @__PURE__ */ Y({
363
+ name: "WxTasksProjectsPage",
364
+ __name: "ProjectsPage",
365
+ props: {
366
+ base: { default: "/tasks" }
367
+ },
368
+ setup(h) {
369
+ const l = h, d = ee(), k = se(d);
370
+ le();
371
+ const a = te("webx-tasks"), t = ae(), r = S([]), i = S(!0), j = d.can("tasks.manage"), V = Ie(nt), y = C(() => [
372
+ { key: "title", label: a("panel.project-title"), minWidth: 200 },
373
+ { key: "workdir", label: a("panel.project-workdir"), minWidth: 200, hideBelow: 640 },
374
+ { key: "tasks_count", label: a("panel.project-tasks"), width: 100, align: "right" },
375
+ { key: "actions", label: "", width: 120, align: "right" }
376
+ ]);
377
+ async function x() {
378
+ i.value = !0;
379
+ try {
380
+ r.value = await k.projects();
381
+ } catch (q) {
382
+ M.danger(t(q));
383
+ } finally {
384
+ i.value = !1;
385
+ }
386
+ }
387
+ x();
388
+ async function b(q) {
389
+ await V({ project: q }) && await x();
390
+ }
391
+ const I = C(
392
+ () => j ? [
393
+ {
394
+ key: "new",
395
+ label: a("panel.project-new"),
396
+ icon: "plus",
397
+ primary: !0,
398
+ run: () => {
399
+ b(null);
400
+ }
401
+ }
402
+ ] : []
403
+ );
404
+ return (q, _) => (p(), $(e(Ve), {
405
+ title: e(a)("panel.projects"),
406
+ back: l.base,
407
+ "back-label": e(a)("panel.back"),
408
+ actions: I.value
409
+ }, {
410
+ default: s(() => [
411
+ n(e(Ue), {
412
+ data: r.value,
413
+ columns: y.value,
414
+ "row-key": "id",
415
+ flush: "",
416
+ layout: "fixed",
417
+ loading: i.value,
418
+ "cards-below": 0,
419
+ "empty-text": r.value.length === 0 && !i.value ? e(a)("panel.projects-empty") : void 0,
420
+ "aria-label": e(a)("panel.projects")
421
+ }, {
422
+ "cell-title": s(({ row: g }) => [
423
+ L("div", ot, [
424
+ n(e(B), {
425
+ truncate: "",
426
+ weight: "medium"
427
+ }, {
428
+ default: s(() => [
429
+ f(v(g.title), 1)
430
+ ]),
431
+ _: 2
432
+ }, 1024),
433
+ n(e(B), {
434
+ size: "sm",
435
+ tone: "muted",
436
+ mono: ""
437
+ }, {
438
+ default: s(() => [
439
+ f(v(g.slug), 1)
440
+ ]),
441
+ _: 2
442
+ }, 1024),
443
+ g.archived ? (p(), $(e(Q), {
444
+ key: 0,
445
+ size: "sm"
446
+ }, {
447
+ default: s(() => [
448
+ f(v(e(a)("panel.project-archived")), 1)
449
+ ]),
450
+ _: 1
451
+ })) : A("", !0)
452
+ ])
453
+ ]),
454
+ "cell-workdir": s(({ row: g }) => [
455
+ n(e(B), {
456
+ size: "sm",
457
+ tone: "muted",
458
+ mono: "",
459
+ truncate: ""
460
+ }, {
461
+ default: s(() => [
462
+ f(v(g.workdir ?? "—"), 1)
463
+ ]),
464
+ _: 2
465
+ }, 1024)
466
+ ]),
467
+ "cell-actions": s(({ row: g }) => [
468
+ e(j) ? (p(), $(e(K), {
469
+ key: 0,
470
+ size: "sm",
471
+ variant: "outline",
472
+ onClick: (R) => b(g)
473
+ }, {
474
+ default: s(() => [
475
+ f(v(e(a)("panel.edit")), 1)
476
+ ]),
477
+ _: 1
478
+ }, 8, ["onClick"])) : A("", !0)
479
+ ]),
480
+ _: 1
481
+ }, 8, ["data", "columns", "loading", "empty-text", "aria-label"])
482
+ ]),
483
+ _: 1
484
+ }, 8, ["title", "back", "back-label", "actions"]));
485
+ }
486
+ }), it = /* @__PURE__ */ X(rt, [["__scopeId", "data-v-4e551660"]]), Me = {
487
+ draft: "default",
488
+ ready: "info",
489
+ in_progress: "primary",
490
+ review: "warning",
491
+ done: "success",
492
+ cancelled: "default"
493
+ }, _e = {
494
+ pending: "default",
495
+ ready: "info",
496
+ in_progress: "primary",
497
+ review: "warning",
498
+ rework: "danger",
499
+ blocked: "warning",
500
+ done: "success",
501
+ cancelled: "default"
502
+ }, Re = {
503
+ low: "default",
504
+ normal: "info",
505
+ high: "danger"
506
+ }, ct = { class: "wx-task-form__locked" }, ut = /* @__PURE__ */ Y({
507
+ name: "WxTaskFormPage",
508
+ __name: "TaskFormPage",
509
+ props: {
510
+ id: { default: null },
511
+ base: { default: "/tasks" }
512
+ },
513
+ setup(h) {
514
+ const l = h, d = ee(), k = se(d), a = De(), t = be();
515
+ le();
516
+ const r = te("webx-tasks"), i = ae(), j = S(null), V = S([]), y = S({}), x = S(""), b = S(!0), I = S(!1), q = S({}), _ = d.can("tasks.manage"), g = C(() => j.value === null || j.value.status === "draft"), R = C(
517
+ () => g.value ? [] : (j.value?.stages ?? []).filter(
518
+ (c) => c.status !== "pending" && c.status !== "ready"
519
+ )
520
+ ), J = C(() => JSON.stringify(y.value)), O = C(() => x.value !== "" && J.value !== x.value), U = C(() => I.value ? "saving" : O.value || l.id === null ? "unsaved" : "saved"), z = C(() => {
521
+ const c = [
522
+ {
523
+ op: "set",
524
+ target: "project",
525
+ props: {
526
+ options: V.value.filter((P) => !P.archived || P.id === y.value.project_id).map((P) => ({ label: P.title, value: P.id })),
527
+ // A task never moves between projects: its number is counted inside one.
528
+ disabled: l.id !== null
529
+ }
530
+ }
531
+ ];
532
+ if (!g.value)
533
+ for (const P of ["title", "branch", "spec", "acceptance"])
534
+ c.push({ op: "set", target: P, props: { disabled: !0 } });
535
+ return c;
536
+ });
537
+ function F(c) {
538
+ return {
539
+ id: c.id,
540
+ title: c.title,
541
+ brief: c.brief ?? "",
542
+ acceptance: c.acceptance ?? "",
543
+ review_mode: c.review_mode
544
+ };
545
+ }
546
+ function ne(c) {
547
+ j.value = c;
548
+ const P = c ? {
549
+ project_id: V.value.find((D) => D.slug === c.project)?.id ?? null,
550
+ title: c.title,
551
+ priority: c.priority,
552
+ branch: c.branch ?? "",
553
+ spec: c.spec ?? "",
554
+ acceptance: c.acceptance ?? "",
555
+ stages: c.stages.filter(
556
+ (D) => c.status === "draft" || ["pending", "ready"].includes(D.status)
557
+ ).map(F)
558
+ } : {
559
+ project_id: Number(a.query.project) || V.value.find((D) => !D.archived)?.id || null,
560
+ title: "",
561
+ priority: "normal",
562
+ branch: "",
563
+ spec: "",
564
+ acceptance: "",
565
+ stages: [{ title: "", brief: "", acceptance: "", review_mode: "auto" }]
566
+ };
567
+ y.value = P, x.value = JSON.stringify(P);
568
+ }
569
+ async function oe() {
570
+ b.value = !0;
571
+ try {
572
+ V.value = await k.projects(), ne(l.id === null ? null : await k.task(l.id));
573
+ } catch (c) {
574
+ M.danger(i(c)), t.push(l.base);
575
+ } finally {
576
+ b.value = !1;
577
+ }
578
+ }
579
+ function w() {
580
+ const c = Array.isArray(y.value.stages) ? y.value.stages : [], P = (T) => ({
581
+ ...T.id ? { id: T.id } : {},
582
+ title: T.title ?? "",
583
+ brief: T.brief || null,
584
+ acceptance: T.acceptance || null,
585
+ review_mode: T.review_mode ?? "auto"
586
+ });
587
+ if (g.value) return c.map(P);
588
+ const D = c.filter((T) => T.id), ke = c.filter((T) => !T.id), o = [];
589
+ for (const T of R.value) o[T.position - 1] = { id: T.id };
590
+ let u = 0;
591
+ const m = R.value.length + D.length;
592
+ for (let T = 0; T < m; T += 1)
593
+ o[T] === void 0 && (o[T] = P(D[u++]));
594
+ return [...o, ...ke.map(P)];
595
+ }
596
+ function E() {
597
+ const c = y.value;
598
+ return g.value ? {
599
+ project_id: typeof c.project_id == "number" ? c.project_id : void 0,
600
+ title: String(c.title ?? ""),
601
+ priority: c.priority,
602
+ branch: c.branch ? String(c.branch) : null,
603
+ spec: c.spec ? String(c.spec) : null,
604
+ acceptance: c.acceptance ? String(c.acceptance) : null,
605
+ stages: w()
606
+ } : { priority: c.priority, stages: w() };
607
+ }
608
+ async function W() {
609
+ if (!(I.value || !_)) {
610
+ I.value = !0, q.value = {};
611
+ try {
612
+ const c = l.id === null, P = c ? await k.create(E()) : await k.save(l.id, E());
613
+ x.value = J.value, M.success(r(c ? "panel.created" : "panel.saved")), await t.push(`${l.base}/${P.id}`);
614
+ } catch (c) {
615
+ const P = c.body;
616
+ P?.errors ? (q.value = P.errors, M.danger(r("panel.save-failed"))) : M.danger(i(c));
617
+ } finally {
618
+ I.value = !1;
619
+ }
620
+ }
621
+ }
622
+ function ce(c) {
623
+ O.value && c.preventDefault();
624
+ }
625
+ function ue(c) {
626
+ (c.ctrlKey || c.metaKey) && c.key.toLowerCase() === "s" && (c.preventDefault(), W());
627
+ }
628
+ Ke(ue), fe(() => {
629
+ oe(), window.addEventListener("beforeunload", ce);
630
+ }), Le(() => {
631
+ window.removeEventListener("beforeunload", ce);
632
+ }), tt(async () => !O.value || !_ ? !0 : await pe({
633
+ title: r("panel.leave-title"),
634
+ message: r("panel.leave-text"),
635
+ confirmText: r("panel.leave"),
636
+ cancelText: r("panel.keep"),
637
+ tone: "danger"
638
+ }));
639
+ const re = C(
640
+ () => l.id === null ? r("panel.new") : j.value?.title || r("panel.untitled")
641
+ );
642
+ return (c, P) => (p(), N("div", {
643
+ class: "wx-task-form",
644
+ onKeydown: ue
645
+ }, [
646
+ b.value ? (p(), $(e(he), {
647
+ key: 0,
648
+ title: "",
649
+ rows: 8
650
+ })) : (p(), N(G, { key: 1 }, [
651
+ n(e(ge), {
652
+ back: l.id === null ? l.base : `${l.base}/${l.id}`,
653
+ "back-label": e(r)("panel.back"),
654
+ title: re.value,
655
+ subtitle: j.value?.ref
656
+ }, null, 8, ["back", "back-label", "title", "subtitle"]),
657
+ l.id === null && V.value.length === 0 ? (p(), $(e(me), {
658
+ key: 0,
659
+ type: "info"
660
+ }, {
661
+ default: s(() => [
662
+ f(v(e(r)("panel.need-project")), 1)
663
+ ]),
664
+ _: 1
665
+ })) : A("", !0),
666
+ g.value ? A("", !0) : (p(), $(e(me), {
667
+ key: 1,
668
+ type: "info"
669
+ }, {
670
+ default: s(() => [
671
+ f(v(e(r)("panel.locked-fields")), 1)
672
+ ]),
673
+ _: 1
674
+ })),
675
+ R.value.length > 0 ? (p(), $(e(ve), {
676
+ key: 2,
677
+ title: e(r)("panel.locked-stages")
678
+ }, {
679
+ default: s(() => [
680
+ n(e(B), {
681
+ size: "sm",
682
+ tone: "muted"
683
+ }, {
684
+ default: s(() => [
685
+ f(v(e(r)("panel.locked-help")), 1)
686
+ ]),
687
+ _: 1
688
+ }),
689
+ L("ol", ct, [
690
+ (p(!0), N(G, null, de(R.value, (D) => (p(), N("li", {
691
+ key: D.id
692
+ }, [
693
+ n(e(B), { truncate: "" }, {
694
+ default: s(() => [
695
+ f(v(D.position) + ". " + v(D.title), 1)
696
+ ]),
697
+ _: 2
698
+ }, 1024),
699
+ n(e(Q), {
700
+ size: "sm",
701
+ type: e(_e)[D.status]
702
+ }, {
703
+ default: s(() => [
704
+ f(v(e(r)(`panel.stage-${D.status}`)), 1)
705
+ ]),
706
+ _: 2
707
+ }, 1032, ["type"])
708
+ ]))), 128))
709
+ ])
710
+ ]),
711
+ _: 1
712
+ }, 8, ["title"])) : A("", !0),
713
+ n(e(Pe), {
714
+ modelValue: y.value,
715
+ "onUpdate:modelValue": P[0] || (P[0] = (D) => y.value = D),
716
+ name: "tasks.form",
717
+ patch: z.value,
718
+ errors: q.value,
719
+ disabled: !e(_) || I.value
720
+ }, null, 8, ["modelValue", "patch", "errors", "disabled"]),
721
+ e(_) ? (p(), $(e(Be), { key: 3 }, {
722
+ state: s(() => [
723
+ n(e(qe), { state: U.value }, null, 8, ["state"])
724
+ ]),
725
+ default: s(() => [
726
+ n(e(K), {
727
+ type: "primary",
728
+ loading: I.value,
729
+ disabled: !O.value && l.id !== null || V.value.length === 0,
730
+ onClick: W
731
+ }, {
732
+ default: s(() => [
733
+ f(v(e(r)("panel.save")), 1)
734
+ ]),
735
+ _: 1
736
+ }, 8, ["loading", "disabled"])
737
+ ]),
738
+ _: 1
739
+ })) : A("", !0)
740
+ ], 64))
741
+ ], 32));
742
+ }
743
+ }), je = /* @__PURE__ */ X(ut, [["__scopeId", "data-v-76e175ee"]]), dt = {
744
+ key: 1,
745
+ class: "wx-tasks-markdown is-empty"
746
+ }, pt = /* @__PURE__ */ Y({
747
+ name: "WxTasksMarkdown",
748
+ __name: "TasksMarkdown",
749
+ props: {
750
+ source: {},
751
+ empty: {}
752
+ },
753
+ setup(h) {
754
+ const l = h, d = C(() => l.source ? Je(l.source) : "");
755
+ return (k, a) => d.value ? (p(), $(e(Ge), {
756
+ key: 0,
757
+ class: "wx-tasks-markdown",
758
+ html: d.value,
759
+ size: "sm"
760
+ }, null, 8, ["html"])) : h.empty ? (p(), N("p", dt, v(h.empty), 1)) : A("", !0);
761
+ }
762
+ }), Z = /* @__PURE__ */ X(pt, [["__scopeId", "data-v-4ea92199"]]), vt = {
763
+ key: 0,
764
+ class: "wx-tasks-text-dialog__message"
765
+ }, mt = ["id"], kt = /* @__PURE__ */ Y({
766
+ name: "WxTasksTextDialog",
767
+ __name: "TasksTextDialog",
768
+ props: {
769
+ title: {},
770
+ label: {},
771
+ confirmText: {},
772
+ cancelText: {},
773
+ message: { default: void 0 },
774
+ required: { type: Boolean, default: !1 },
775
+ danger: { type: Boolean, default: !1 }
776
+ },
777
+ setup(h) {
778
+ const l = h, { open: d, resolve: k, dismiss: a } = ze(), t = Te(), r = S(""), i = Fe("form");
779
+ fe(async () => {
780
+ await Oe(), i.value?.querySelector("textarea")?.focus();
781
+ });
782
+ function j() {
783
+ l.required && r.value.trim() === "" || k(r.value.trim());
784
+ }
785
+ return (V, y) => (p(), $(e(Ae), {
786
+ open: e(d),
787
+ "onUpdate:open": y[2] || (y[2] = (x) => $e(d) ? d.value = x : null),
788
+ title: l.title,
789
+ width: 520
790
+ }, {
791
+ footer: s(() => [
792
+ n(e(Ne), { size: "sm" }, {
793
+ default: s(() => [
794
+ n(e(K), {
795
+ variant: "outline",
796
+ onClick: y[1] || (y[1] = (x) => e(a)())
797
+ }, {
798
+ default: s(() => [
799
+ f(v(l.cancelText), 1)
800
+ ]),
801
+ _: 1
802
+ }),
803
+ n(e(K), {
804
+ type: l.danger ? "danger" : "primary",
805
+ "native-type": "submit",
806
+ form: e(t),
807
+ disabled: l.required && r.value.trim() === ""
808
+ }, {
809
+ default: s(() => [
810
+ f(v(l.confirmText), 1)
811
+ ]),
812
+ _: 1
813
+ }, 8, ["type", "form", "disabled"])
814
+ ]),
815
+ _: 1
816
+ })
817
+ ]),
818
+ default: s(() => [
819
+ l.message ? (p(), N("p", vt, v(l.message), 1)) : A("", !0),
820
+ L("form", {
821
+ id: e(t),
822
+ ref_key: "form",
823
+ ref: i,
824
+ onSubmit: Se(j, ["prevent"])
825
+ }, [
826
+ n(e(H), {
827
+ label: l.label,
828
+ required: l.required
829
+ }, {
830
+ default: s(() => [
831
+ n(e(ye), {
832
+ modelValue: r.value,
833
+ "onUpdate:modelValue": y[0] || (y[0] = (x) => r.value = x),
834
+ rows: 5,
835
+ "aria-label": l.label
836
+ }, null, 8, ["modelValue", "aria-label"])
837
+ ]),
838
+ _: 1
839
+ }, 8, ["label", "required"])
840
+ ], 40, mt)
841
+ ]),
842
+ _: 1
843
+ }, 8, ["open", "title"]));
844
+ }
845
+ }), ft = /* @__PURE__ */ X(kt, [["__scopeId", "data-v-9648ad86"]]), gt = { class: "wx-task" }, yt = { class: "wx-task__about" }, ht = { class: "wx-task__facts" }, bt = { class: "wx-task__section" }, _t = {
846
+ key: 0,
847
+ class: "wx-task__section"
848
+ }, wt = { class: "wx-task__stage" }, xt = { class: "wx-task__section" }, jt = {
849
+ key: 1,
850
+ class: "wx-task__section"
851
+ }, Tt = { class: "wx-task__section" }, $t = {
852
+ key: 2,
853
+ class: "wx-task__moves"
854
+ }, St = {
855
+ key: 0,
856
+ class: "wx-task__comment"
857
+ }, Wt = { class: "wx-task__entry" }, Vt = { class: "wx-task__entry-head" }, Pt = /* @__PURE__ */ Y({
858
+ name: "WxTaskPage",
859
+ __name: "TaskPage",
860
+ props: {
861
+ id: {},
862
+ base: { default: "/tasks" }
863
+ },
864
+ setup(h) {
865
+ const l = h, d = ee(), k = se(d), a = be();
866
+ le();
867
+ const t = te("webx-tasks"), r = ae(), i = S(null), j = S(!0), V = S(!1), y = S([]), x = S(""), b = d.can("tasks.manage"), I = d.can("tasks.review"), q = d.can("tasks.work"), _ = b || I || q, g = Ie(ft), R = C(() => i.value?.status === "done" || i.value?.status === "cancelled");
868
+ function J(o) {
869
+ return o.stages.find((u) => u.status === "review" || u.status === "blocked") ?? o.stages.find((u) => !["done", "cancelled", "pending"].includes(u.status));
870
+ }
871
+ function O(o) {
872
+ if (i.value = o, y.value.length === 0) {
873
+ const u = J(o);
874
+ y.value = u ? [String(u.id)] : [];
875
+ }
876
+ }
877
+ async function U() {
878
+ j.value = !0;
879
+ try {
880
+ O(await k.task(l.id));
881
+ } catch (o) {
882
+ M.danger(r(o)), a.push(l.base);
883
+ } finally {
884
+ j.value = !1;
885
+ }
886
+ }
887
+ We(() => l.id, U, { immediate: !0 });
888
+ async function z(o, u) {
889
+ if (!V.value) {
890
+ V.value = !0;
891
+ try {
892
+ O(await o()), M.success(u), d.refreshManifest();
893
+ } catch (m) {
894
+ M.danger(r(m)), await U();
895
+ } finally {
896
+ V.value = !1;
897
+ }
898
+ }
899
+ }
900
+ async function F() {
901
+ const o = i.value;
902
+ o && await z(() => k.ready(o.id), t("panel.started"));
903
+ }
904
+ async function ne() {
905
+ const o = i.value;
906
+ if (!o) return;
907
+ const u = await g({
908
+ title: t("panel.cancel-task-title", { title: o.title }),
909
+ message: t("panel.cancel-task-text"),
910
+ label: t("panel.note"),
911
+ confirmText: t("panel.cancel-task"),
912
+ cancelText: t("panel.keep"),
913
+ danger: !0
914
+ });
915
+ u != null && await z(() => k.cancel(o.id, u), t("panel.cancelled"));
916
+ }
917
+ async function oe(o) {
918
+ await pe({
919
+ title: t("panel.accept-title", { stage: o.title }),
920
+ message: t("panel.accept-text"),
921
+ confirmText: t("panel.accept"),
922
+ cancelText: t("panel.keep")
923
+ }) && await z(() => k.accept(o.id), t("panel.accepted"));
924
+ }
925
+ async function w(o) {
926
+ const u = await g({
927
+ title: t("panel.rework-title", { stage: o.title }),
928
+ label: t("panel.rework-label"),
929
+ confirmText: t("panel.rework"),
930
+ cancelText: t("panel.keep"),
931
+ required: !0
932
+ });
933
+ u && await z(() => k.rework(o.id, u), t("panel.reworked"));
934
+ }
935
+ async function E(o) {
936
+ const u = await g({
937
+ title: t("panel.answer-title"),
938
+ message: re(o)?.body ?? void 0,
939
+ label: t("panel.answer-label"),
940
+ confirmText: t("panel.send"),
941
+ cancelText: t("panel.keep"),
942
+ required: !0
943
+ });
944
+ u && await z(() => k.unblock(o.id, u), t("panel.answered"));
945
+ }
946
+ async function W(o) {
947
+ await pe({
948
+ title: t("panel.release-title", { stage: o.title }),
949
+ message: t("panel.release-text"),
950
+ confirmText: t("panel.release"),
951
+ cancelText: t("panel.keep"),
952
+ tone: "danger"
953
+ }) && await z(() => k.release(o.id), t("panel.released"));
954
+ }
955
+ async function ce(o) {
956
+ await pe({
957
+ title: t("panel.cancel-stage-title", { stage: o.title }),
958
+ message: t("panel.cancel-stage-text"),
959
+ confirmText: t("panel.cancel-stage"),
960
+ cancelText: t("panel.keep"),
961
+ tone: "danger"
962
+ }) && await z(() => k.cancelStage(o.id), t("panel.stage-cancelled"));
963
+ }
964
+ async function ue() {
965
+ const o = i.value, u = x.value.trim();
966
+ !o || u === "" || (await z(() => k.comment(o.id, u), t("panel.commented")), x.value = "");
967
+ }
968
+ function re(o) {
969
+ return [...i.value?.journal ?? []].reverse().find((u) => u.stage_id === o.id && u.kind === "question");
970
+ }
971
+ function c(o) {
972
+ if (R.value) return [];
973
+ const u = [];
974
+ return o.status === "review" && I && (u.push({
975
+ key: "accept",
976
+ label: t("panel.accept"),
977
+ primary: !0,
978
+ run: () => {
979
+ oe(o);
980
+ }
981
+ }), u.push({ key: "rework", label: t("panel.rework"), run: () => {
982
+ w(o);
983
+ } })), o.status === "blocked" && b && u.push({
984
+ key: "answer",
985
+ label: t("panel.answer"),
986
+ primary: !0,
987
+ run: () => {
988
+ E(o);
989
+ }
990
+ }), o.status === "in_progress" && (b || q) && u.push({ key: "release", label: t("panel.release"), run: () => {
991
+ W(o);
992
+ } }), b && !["done", "cancelled"].includes(o.status) && u.push({ key: "cancel", label: t("panel.cancel-stage"), run: () => {
993
+ ce(o);
994
+ } }), u;
995
+ }
996
+ function P(o) {
997
+ return i.value?.stages.find((u) => u.id === o.stage_id)?.position ?? null;
998
+ }
999
+ function D(o) {
1000
+ const u = typeof o.meta?.from == "string" ? o.meta.from : null, m = typeof o.meta?.to == "string" ? o.meta.to : null;
1001
+ if (o.kind === "status" && m !== null) {
1002
+ const T = (we) => o.stage_id === null ? t(`panel.status-${we}`) : t(`panel.stage-${we}`);
1003
+ return u === null ? T(m) : `${T(u)} → ${T(m)}`;
1004
+ }
1005
+ return t(`panel.kind-${o.kind}`);
1006
+ }
1007
+ const ke = C(() => {
1008
+ const o = i.value;
1009
+ if (!o || !b) return [];
1010
+ const u = [];
1011
+ return o.status === "draft" && u.push({
1012
+ key: "start",
1013
+ label: t("panel.start"),
1014
+ icon: "play",
1015
+ primary: !0,
1016
+ run: () => {
1017
+ F();
1018
+ }
1019
+ }), R.value || (u.push({
1020
+ key: "edit",
1021
+ label: t("panel.edit"),
1022
+ icon: "edit",
1023
+ run: () => {
1024
+ a.push(`${l.base}/${o.id}/edit`);
1025
+ }
1026
+ }), u.push({
1027
+ key: "cancel",
1028
+ label: t("panel.cancel-task"),
1029
+ icon: "close",
1030
+ danger: !0,
1031
+ menu: !0,
1032
+ run: () => {
1033
+ ne();
1034
+ }
1035
+ })), u;
1036
+ });
1037
+ return (o, u) => (p(), N("div", gt, [
1038
+ j.value && !i.value ? (p(), $(e(he), {
1039
+ key: 0,
1040
+ title: "",
1041
+ rows: 8
1042
+ })) : i.value ? (p(), N(G, { key: 1 }, [
1043
+ n(e(ge), {
1044
+ back: l.base,
1045
+ "back-label": e(t)("panel.back"),
1046
+ title: i.value.title || e(t)("panel.untitled"),
1047
+ subtitle: i.value.ref,
1048
+ actions: ke.value
1049
+ }, {
1050
+ "title-after": s(() => [
1051
+ n(e(Q), {
1052
+ type: e(Me)[i.value.status]
1053
+ }, {
1054
+ default: s(() => [
1055
+ f(v(e(t)(`panel.status-${i.value.status}`)), 1)
1056
+ ]),
1057
+ _: 1
1058
+ }, 8, ["type"])
1059
+ ]),
1060
+ _: 1
1061
+ }, 8, ["back", "back-label", "title", "subtitle", "actions"]),
1062
+ n(e(ve), null, {
1063
+ default: s(() => [
1064
+ L("div", yt, [
1065
+ L("div", ht, [
1066
+ n(e(Q), {
1067
+ variant: "outline",
1068
+ type: e(Re)[i.value.priority]
1069
+ }, {
1070
+ default: s(() => [
1071
+ f(v(e(t)(`panel.priority-${i.value.priority}`)), 1)
1072
+ ]),
1073
+ _: 1
1074
+ }, 8, ["type"]),
1075
+ i.value.branch ? (p(), $(e(B), {
1076
+ key: 0,
1077
+ size: "sm",
1078
+ tone: "muted",
1079
+ mono: ""
1080
+ }, {
1081
+ default: s(() => [
1082
+ f(v(e(t)("panel.branch")) + ": " + v(i.value.branch), 1)
1083
+ ]),
1084
+ _: 1
1085
+ })) : A("", !0)
1086
+ ]),
1087
+ L("section", bt, [
1088
+ n(e(B), {
1089
+ as: "h3",
1090
+ weight: "semibold"
1091
+ }, {
1092
+ default: s(() => [
1093
+ f(v(e(t)("panel.spec")), 1)
1094
+ ]),
1095
+ _: 1
1096
+ }),
1097
+ n(Z, {
1098
+ source: i.value.spec,
1099
+ empty: e(t)("panel.no-spec")
1100
+ }, null, 8, ["source", "empty"])
1101
+ ]),
1102
+ i.value.acceptance ? (p(), N("section", _t, [
1103
+ n(e(B), {
1104
+ as: "h3",
1105
+ weight: "semibold"
1106
+ }, {
1107
+ default: s(() => [
1108
+ f(v(e(t)("panel.acceptance")), 1)
1109
+ ]),
1110
+ _: 1
1111
+ }),
1112
+ n(Z, {
1113
+ source: i.value.acceptance
1114
+ }, null, 8, ["source"])
1115
+ ])) : A("", !0)
1116
+ ])
1117
+ ]),
1118
+ _: 1
1119
+ }),
1120
+ n(e(ve), {
1121
+ title: e(t)("panel.stages")
1122
+ }, {
1123
+ default: s(() => [
1124
+ n(e(Qe), {
1125
+ modelValue: y.value,
1126
+ "onUpdate:modelValue": u[0] || (u[0] = (m) => y.value = m),
1127
+ multiple: ""
1128
+ }, {
1129
+ default: s(() => [
1130
+ (p(!0), N(G, null, de(i.value.stages, (m) => (p(), $(e(Ye), {
1131
+ key: m.id,
1132
+ value: String(m.id),
1133
+ title: `${m.position}. ${m.title}`,
1134
+ subtitle: [
1135
+ m.assignee,
1136
+ m.attempt > 1 ? e(t)("panel.attempt", { attempt: m.attempt }) : null,
1137
+ m.review_mode === "human" ? e(t)("panel.by-person") : null
1138
+ ].filter(Boolean).join(" · ")
1139
+ }, {
1140
+ extra: s(() => [
1141
+ n(e(Q), {
1142
+ size: "sm",
1143
+ type: e(_e)[m.status]
1144
+ }, {
1145
+ default: s(() => [
1146
+ f(v(e(t)(`panel.stage-${m.status}`)), 1)
1147
+ ]),
1148
+ _: 2
1149
+ }, 1032, ["type"])
1150
+ ]),
1151
+ default: s(() => [
1152
+ L("div", wt, [
1153
+ m.status === "blocked" && re(m) ? (p(), $(e(me), {
1154
+ key: 0,
1155
+ type: "warning",
1156
+ title: e(t)("panel.question")
1157
+ }, {
1158
+ default: s(() => [
1159
+ n(Z, {
1160
+ source: re(m)?.body
1161
+ }, null, 8, ["source"])
1162
+ ]),
1163
+ _: 2
1164
+ }, 1032, ["title"])) : A("", !0),
1165
+ L("section", xt, [
1166
+ n(e(B), {
1167
+ as: "h4",
1168
+ size: "sm",
1169
+ weight: "semibold"
1170
+ }, {
1171
+ default: s(() => [
1172
+ f(v(e(t)("panel.brief")), 1)
1173
+ ]),
1174
+ _: 1
1175
+ }),
1176
+ n(Z, {
1177
+ source: m.brief,
1178
+ empty: "—"
1179
+ }, null, 8, ["source"])
1180
+ ]),
1181
+ m.acceptance ? (p(), N("section", jt, [
1182
+ n(e(B), {
1183
+ as: "h4",
1184
+ size: "sm",
1185
+ weight: "semibold"
1186
+ }, {
1187
+ default: s(() => [
1188
+ f(v(e(t)("panel.stage-acceptance")), 1)
1189
+ ]),
1190
+ _: 1
1191
+ }),
1192
+ n(Z, {
1193
+ source: m.acceptance
1194
+ }, null, 8, ["source"])
1195
+ ])) : A("", !0),
1196
+ L("section", Tt, [
1197
+ n(e(B), {
1198
+ as: "h4",
1199
+ size: "sm",
1200
+ weight: "semibold"
1201
+ }, {
1202
+ default: s(() => [
1203
+ f(v(e(t)("panel.report")), 1)
1204
+ ]),
1205
+ _: 1
1206
+ }),
1207
+ n(Z, {
1208
+ source: m.report,
1209
+ empty: e(t)("panel.no-report")
1210
+ }, null, 8, ["source", "empty"]),
1211
+ m.result_ref ? (p(), $(e(B), {
1212
+ key: 0,
1213
+ size: "sm",
1214
+ mono: "",
1215
+ class: "wx-task__result"
1216
+ }, {
1217
+ default: s(() => [
1218
+ f(v(e(t)("panel.result")) + ": " + v(m.result_ref), 1)
1219
+ ]),
1220
+ _: 2
1221
+ }, 1024)) : A("", !0)
1222
+ ]),
1223
+ c(m).length > 0 ? (p(), N("div", $t, [
1224
+ (p(!0), N(G, null, de(c(m), (T) => (p(), $(e(K), {
1225
+ key: T.key,
1226
+ size: "sm",
1227
+ type: T.primary ? "primary" : "default",
1228
+ variant: T.primary ? void 0 : "outline",
1229
+ disabled: V.value,
1230
+ onClick: T.run
1231
+ }, {
1232
+ default: s(() => [
1233
+ f(v(T.label), 1)
1234
+ ]),
1235
+ _: 2
1236
+ }, 1032, ["type", "variant", "disabled", "onClick"]))), 128))
1237
+ ])) : A("", !0)
1238
+ ])
1239
+ ]),
1240
+ _: 2
1241
+ }, 1032, ["value", "title", "subtitle"]))), 128))
1242
+ ]),
1243
+ _: 1
1244
+ }, 8, ["modelValue"])
1245
+ ]),
1246
+ _: 1
1247
+ }, 8, ["title"]),
1248
+ n(e(ve), {
1249
+ title: e(t)("panel.journal")
1250
+ }, {
1251
+ default: s(() => [
1252
+ e(_) && !R.value ? (p(), N("div", St, [
1253
+ n(e(ye), {
1254
+ modelValue: x.value,
1255
+ "onUpdate:modelValue": u[1] || (u[1] = (m) => x.value = m),
1256
+ rows: 2,
1257
+ placeholder: e(t)("panel.comment-placeholder"),
1258
+ "aria-label": e(t)("panel.comment")
1259
+ }, null, 8, ["modelValue", "placeholder", "aria-label"]),
1260
+ n(e(K), {
1261
+ size: "sm",
1262
+ disabled: V.value || x.value.trim() === "",
1263
+ onClick: ue
1264
+ }, {
1265
+ default: s(() => [
1266
+ f(v(e(t)("panel.comment")), 1)
1267
+ ]),
1268
+ _: 1
1269
+ }, 8, ["disabled"])
1270
+ ])) : A("", !0),
1271
+ i.value.journal.length === 0 ? (p(), $(e(B), {
1272
+ key: 1,
1273
+ tone: "muted"
1274
+ }, {
1275
+ default: s(() => [
1276
+ f(v(e(t)("panel.journal-empty")), 1)
1277
+ ]),
1278
+ _: 1
1279
+ })) : (p(), $(e(Xe), {
1280
+ key: 2,
1281
+ size: "sm"
1282
+ }, {
1283
+ default: s(() => [
1284
+ (p(!0), N(G, null, de([...i.value.journal].reverse(), (m) => (p(), $(e(Ze), {
1285
+ key: m.id,
1286
+ type: m.actor_type === "agent" ? "primary" : void 0,
1287
+ hollow: m.actor_type === "system"
1288
+ }, {
1289
+ default: s(() => [
1290
+ L("div", Wt, [
1291
+ L("div", Vt, [
1292
+ n(e(B), {
1293
+ size: "sm",
1294
+ weight: "medium"
1295
+ }, {
1296
+ default: s(() => [
1297
+ f(v(m.actor_type === "system" ? e(t)("panel.system") : m.actor_name), 1)
1298
+ ]),
1299
+ _: 2
1300
+ }, 1024),
1301
+ n(e(B), {
1302
+ size: "sm",
1303
+ tone: "muted"
1304
+ }, {
1305
+ default: s(() => [
1306
+ f(v(D(m)) + " ", 1),
1307
+ P(m) !== null ? (p(), N(G, { key: 0 }, [
1308
+ f("· #" + v(P(m)), 1)
1309
+ ], 64)) : A("", !0)
1310
+ ]),
1311
+ _: 2
1312
+ }, 1024),
1313
+ n(e(Ce), {
1314
+ value: m.created_at,
1315
+ compact: "",
1316
+ size: "sm",
1317
+ tone: "muted"
1318
+ }, null, 8, ["value"])
1319
+ ]),
1320
+ m.body && m.kind !== "report" ? (p(), $(Z, {
1321
+ key: 0,
1322
+ source: m.body
1323
+ }, null, 8, ["source"])) : A("", !0)
1324
+ ])
1325
+ ]),
1326
+ _: 2
1327
+ }, 1032, ["type", "hollow"]))), 128))
1328
+ ]),
1329
+ _: 1
1330
+ }))
1331
+ ]),
1332
+ _: 1
1333
+ }, 8, ["title"])
1334
+ ], 64)) : A("", !0)
1335
+ ]));
1336
+ }
1337
+ }), qt = /* @__PURE__ */ X(Pt, [["__scopeId", "data-v-51fc8473"]]), Ct = { class: "wx-tasks-list" }, zt = { class: "wx-tasks-list__task" }, At = {
1338
+ key: 0,
1339
+ class: "wx-tasks-list__stage"
1340
+ }, Nt = /* @__PURE__ */ Y({
1341
+ name: "WxTasksPage",
1342
+ __name: "TasksPage",
1343
+ props: {
1344
+ base: { default: "/tasks" }
1345
+ },
1346
+ setup(h) {
1347
+ const l = h, d = ee(), k = se(d), a = De(), t = be();
1348
+ le();
1349
+ const r = te("webx-tasks"), i = ae(), j = S(null), V = S([]), y = S(!0), x = d.can("tasks.manage"), b = ["all", "waiting", "active", "draft", "closed"], I = C(
1350
+ () => d.state.manifest?.modules.find((w) => w.id === "tasks")?.title ?? r("module.title")
1351
+ ), q = C({
1352
+ get: () => typeof a.query.view == "string" && b.includes(a.query.view) ? a.query.view : "all",
1353
+ set: (w) => {
1354
+ t.replace({
1355
+ query: { ...a.query, view: w === "all" ? void 0 : String(w), page: void 0 }
1356
+ });
1357
+ }
1358
+ }), _ = C({
1359
+ get: () => typeof a.query.project == "string" ? Number(a.query.project) : null,
1360
+ set: (w) => {
1361
+ t.replace({
1362
+ query: {
1363
+ ...a.query,
1364
+ project: w === null || w === "" ? void 0 : String(w),
1365
+ page: void 0
1366
+ }
1367
+ });
1368
+ }
1369
+ }), g = C(
1370
+ () => b.map((w) => ({
1371
+ value: w,
1372
+ label: r(`panel.view-${w}`),
1373
+ badge: j.value?.counts[w] ?? void 0
1374
+ }))
1375
+ ), R = C(
1376
+ () => V.value.map((w) => ({ label: w.title, value: w.id }))
1377
+ ), J = C(() => j.value?.data ?? []), O = C(() => [
1378
+ { key: "title", label: r("panel.column-task"), minWidth: 220 },
1379
+ { key: "status", label: r("panel.column-status"), width: 140 },
1380
+ { key: "current_stage", label: r("panel.column-stage"), minWidth: 180, hideBelow: 640 },
1381
+ { key: "priority", label: r("panel.column-priority"), width: 120, hideBelow: 760 },
1382
+ { key: "updated_at", label: r("panel.column-updated"), width: 120, hideBelow: 900 }
1383
+ ]);
1384
+ async function U(w) {
1385
+ y.value = !0;
1386
+ try {
1387
+ j.value = await k.tasks({
1388
+ view: q.value,
1389
+ project: typeof _.value == "number" ? _.value : null,
1390
+ q: w?.search ?? (typeof a.query.q == "string" ? a.query.q : ""),
1391
+ page: w?.page ?? (Number(a.query.page ?? 1) || 1),
1392
+ per_page: w?.perPage
1393
+ });
1394
+ } catch (E) {
1395
+ M.danger(i(E));
1396
+ } finally {
1397
+ y.value = !1;
1398
+ }
1399
+ }
1400
+ function z(w) {
1401
+ t.replace({
1402
+ query: {
1403
+ ...a.query,
1404
+ q: w.search === "" ? void 0 : w.search,
1405
+ page: w.page === 1 ? void 0 : String(w.page)
1406
+ }
1407
+ }), U(w);
1408
+ }
1409
+ async function F() {
1410
+ try {
1411
+ V.value = await k.projects();
1412
+ } catch (w) {
1413
+ M.danger(i(w));
1414
+ }
1415
+ }
1416
+ We([q, _], () => {
1417
+ U();
1418
+ }), U(), F();
1419
+ function ne(w) {
1420
+ t.push(`${l.base}/${w.id}`);
1421
+ }
1422
+ const oe = C(() => [
1423
+ {
1424
+ key: "projects",
1425
+ label: r("panel.projects"),
1426
+ icon: "folder",
1427
+ run: () => {
1428
+ t.push(`${l.base}/projects`);
1429
+ }
1430
+ },
1431
+ ...x ? [
1432
+ {
1433
+ key: "settings",
1434
+ label: r("panel.settings"),
1435
+ icon: "settings",
1436
+ menu: !0,
1437
+ run: () => {
1438
+ t.push(`${l.base}/settings`);
1439
+ }
1440
+ },
1441
+ {
1442
+ key: "new",
1443
+ label: r("panel.new"),
1444
+ icon: "plus",
1445
+ primary: !0,
1446
+ run: () => {
1447
+ t.push(`${l.base}/new`);
1448
+ }
1449
+ }
1450
+ ] : []
1451
+ ]);
1452
+ return (w, E) => (p(), N("div", Ct, [
1453
+ n(e(Ve), {
1454
+ view: q.value,
1455
+ "onUpdate:view": E[1] || (E[1] = (W) => q.value = W),
1456
+ title: I.value,
1457
+ views: g.value,
1458
+ actions: oe.value
1459
+ }, {
1460
+ actions: s(() => [
1461
+ V.value.length > 1 ? (p(), $(e(et), {
1462
+ key: 0,
1463
+ modelValue: _.value,
1464
+ "onUpdate:modelValue": E[0] || (E[0] = (W) => _.value = W),
1465
+ class: "wx-tasks-list__project",
1466
+ options: R.value,
1467
+ placeholder: e(r)("panel.all-projects"),
1468
+ "aria-label": e(r)("panel.all-projects"),
1469
+ clearable: "",
1470
+ size: "sm"
1471
+ }, null, 8, ["modelValue", "options", "placeholder", "aria-label"])) : A("", !0)
1472
+ ]),
1473
+ default: s(() => [
1474
+ n(e(Ue), {
1475
+ data: j.value,
1476
+ columns: O.value,
1477
+ "row-key": "id",
1478
+ searchable: "",
1479
+ hover: "",
1480
+ flush: "",
1481
+ layout: "fixed",
1482
+ loading: y.value,
1483
+ "cards-below": 0,
1484
+ "search-placeholder": e(r)("panel.search"),
1485
+ "empty-text": J.value.length === 0 && !y.value ? e(r)("panel.empty") : void 0,
1486
+ "aria-label": I.value,
1487
+ onStateChange: z,
1488
+ onRowClick: ne
1489
+ }, {
1490
+ "cell-title": s(({ row: W }) => [
1491
+ L("div", zt, [
1492
+ n(e(B), {
1493
+ size: "sm",
1494
+ tone: "muted",
1495
+ mono: ""
1496
+ }, {
1497
+ default: s(() => [
1498
+ f(v(W.ref), 1)
1499
+ ]),
1500
+ _: 2
1501
+ }, 1024),
1502
+ n(e(B), {
1503
+ truncate: "",
1504
+ weight: "medium"
1505
+ }, {
1506
+ default: s(() => [
1507
+ f(v(W.title), 1)
1508
+ ]),
1509
+ _: 2
1510
+ }, 1024)
1511
+ ])
1512
+ ]),
1513
+ "cell-status": s(({ row: W }) => [
1514
+ n(e(Q), {
1515
+ type: e(Me)[W.status]
1516
+ }, {
1517
+ default: s(() => [
1518
+ f(v(e(r)(`panel.status-${W.status}`)), 1)
1519
+ ]),
1520
+ _: 2
1521
+ }, 1032, ["type"])
1522
+ ]),
1523
+ "cell-current_stage": s(({ row: W }) => [
1524
+ W.current_stage ? (p(), N("div", At, [
1525
+ n(e(B), {
1526
+ size: "sm",
1527
+ truncate: ""
1528
+ }, {
1529
+ default: s(() => [
1530
+ f(v(e(r)("panel.stage-of", { position: W.current_stage.position, count: W.stages })) + " · " + v(W.current_stage.title), 1)
1531
+ ]),
1532
+ _: 2
1533
+ }, 1024),
1534
+ n(e(Q), {
1535
+ size: "sm",
1536
+ type: e(_e)[W.current_stage.status]
1537
+ }, {
1538
+ default: s(() => [
1539
+ f(v(e(r)(`panel.stage-${W.current_stage.status}`)), 1)
1540
+ ]),
1541
+ _: 2
1542
+ }, 1032, ["type"])
1543
+ ])) : (p(), $(e(B), {
1544
+ key: 1,
1545
+ size: "sm",
1546
+ tone: "muted"
1547
+ }, {
1548
+ default: s(() => [...E[2] || (E[2] = [
1549
+ f("—", -1)
1550
+ ])]),
1551
+ _: 1
1552
+ }))
1553
+ ]),
1554
+ "cell-priority": s(({ row: W }) => [
1555
+ n(e(Q), {
1556
+ variant: "outline",
1557
+ type: e(Re)[W.priority]
1558
+ }, {
1559
+ default: s(() => [
1560
+ f(v(e(r)(`panel.priority-${W.priority}`)), 1)
1561
+ ]),
1562
+ _: 2
1563
+ }, 1032, ["type"])
1564
+ ]),
1565
+ "cell-updated_at": s(({ row: W }) => [
1566
+ n(e(Ce), {
1567
+ value: W.updated_at,
1568
+ compact: "",
1569
+ size: "sm",
1570
+ tone: "muted"
1571
+ }, null, 8, ["value"])
1572
+ ]),
1573
+ _: 1
1574
+ }, 8, ["data", "columns", "loading", "search-placeholder", "empty-text", "aria-label"])
1575
+ ]),
1576
+ _: 1
1577
+ }, 8, ["view", "title", "views", "actions"])
1578
+ ]));
1579
+ }
1580
+ }), It = /* @__PURE__ */ X(Nt, [["__scopeId", "data-v-97e58bc7"]]), Ut = { class: "wx-tasks-settings" }, Bt = "tasks.telegram.token", Dt = /* @__PURE__ */ Y({
1581
+ name: "WxTasksSettingsPage",
1582
+ __name: "TasksSettingsPage",
1583
+ props: {
1584
+ base: { default: "/tasks" }
1585
+ },
1586
+ setup(h) {
1587
+ const l = h, d = ee(), k = se(d);
1588
+ le();
1589
+ const a = te("webx-tasks"), t = ae(), r = S({}), i = S(""), j = S(!1), V = S(!0), y = S(!1), x = S(!1), b = S({}), I = d.can("tasks.manage"), q = C(
1590
+ () => i.value !== "" && JSON.stringify(r.value) !== i.value
1591
+ ), _ = C(
1592
+ () => y.value ? "saving" : q.value ? "unsaved" : "saved"
1593
+ ), g = C(() => [
1594
+ { op: "set", target: "token", props: { placeholder: j.value ? "••••••••" : "" } }
1595
+ ]);
1596
+ function R(U) {
1597
+ r.value = { ...U.values, [Bt]: "" }, i.value = JSON.stringify(r.value), j.value = U.token_set;
1598
+ }
1599
+ fe(async () => {
1600
+ try {
1601
+ R(await k.settings());
1602
+ } catch (U) {
1603
+ M.danger(t(U));
1604
+ } finally {
1605
+ V.value = !1;
1606
+ }
1607
+ });
1608
+ async function J(U = !1) {
1609
+ if (!y.value) {
1610
+ y.value = !0, b.value = {};
1611
+ try {
1612
+ R(await k.saveSettings(r.value, U)), M.success(a(U ? "panel.token-forgotten" : "panel.settings-saved"));
1613
+ } catch (z) {
1614
+ const F = z.body;
1615
+ F?.errors ? b.value = F.errors : M.danger(t(z));
1616
+ } finally {
1617
+ y.value = !1;
1618
+ }
1619
+ }
1620
+ }
1621
+ async function O() {
1622
+ x.value = !0;
1623
+ try {
1624
+ M.success(await k.testNotice());
1625
+ } catch (U) {
1626
+ M.danger(t(U));
1627
+ } finally {
1628
+ x.value = !1;
1629
+ }
1630
+ }
1631
+ return (U, z) => (p(), N("div", Ut, [
1632
+ n(e(ge), {
1633
+ back: l.base,
1634
+ "back-label": e(a)("panel.back"),
1635
+ title: e(a)("panel.settings")
1636
+ }, null, 8, ["back", "back-label", "title"]),
1637
+ V.value ? (p(), $(e(he), {
1638
+ key: 0,
1639
+ title: "",
1640
+ rows: 6
1641
+ })) : (p(), N(G, { key: 1 }, [
1642
+ n(e(me), {
1643
+ type: j.value ? "success" : "info"
1644
+ }, {
1645
+ default: s(() => [
1646
+ f(v(j.value ? e(a)("panel.token-set") : e(a)("panel.token-not-set")), 1)
1647
+ ]),
1648
+ _: 1
1649
+ }, 8, ["type"]),
1650
+ n(e(Pe), {
1651
+ modelValue: r.value,
1652
+ "onUpdate:modelValue": z[0] || (z[0] = (F) => r.value = F),
1653
+ name: "tasks.settings",
1654
+ patch: g.value,
1655
+ errors: b.value,
1656
+ disabled: !e(I) || y.value
1657
+ }, null, 8, ["modelValue", "patch", "errors", "disabled"]),
1658
+ e(I) ? (p(), $(e(Be), { key: 0 }, {
1659
+ state: s(() => [
1660
+ n(e(qe), { state: _.value }, null, 8, ["state"])
1661
+ ]),
1662
+ default: s(() => [
1663
+ j.value ? (p(), $(e(K), {
1664
+ key: 0,
1665
+ variant: "outline",
1666
+ disabled: y.value,
1667
+ onClick: z[1] || (z[1] = (F) => J(!0))
1668
+ }, {
1669
+ default: s(() => [
1670
+ f(v(e(a)("panel.forget-token")), 1)
1671
+ ]),
1672
+ _: 1
1673
+ }, 8, ["disabled"])) : A("", !0),
1674
+ n(e(K), {
1675
+ variant: "outline",
1676
+ loading: x.value,
1677
+ disabled: q.value,
1678
+ onClick: O
1679
+ }, {
1680
+ default: s(() => [
1681
+ f(v(e(a)("panel.send-test")), 1)
1682
+ ]),
1683
+ _: 1
1684
+ }, 8, ["loading", "disabled"]),
1685
+ n(e(K), {
1686
+ type: "primary",
1687
+ loading: y.value,
1688
+ disabled: !q.value,
1689
+ onClick: z[2] || (z[2] = (F) => J())
1690
+ }, {
1691
+ default: s(() => [
1692
+ f(v(e(a)("panel.save")), 1)
1693
+ ]),
1694
+ _: 1
1695
+ }, 8, ["loading", "disabled"])
1696
+ ]),
1697
+ _: 1
1698
+ })) : A("", !0)
1699
+ ], 64))
1700
+ ]));
1701
+ }
1702
+ }), Mt = /* @__PURE__ */ X(Dt, [["__scopeId", "data-v-99484e93"]]);
1703
+ function Ot(h = {}) {
1704
+ const l = h.path ?? "/tasks", d = { base: l }, k = (a) => Number(Array.isArray(a) ? a[0] : a);
1705
+ return {
1706
+ id: "tasks",
1707
+ path: l,
1708
+ routes: [
1709
+ { path: l, name: "webx.tasks", component: It, props: d },
1710
+ {
1711
+ path: `${l}/projects`,
1712
+ name: "webx.tasks.projects",
1713
+ component: it,
1714
+ props: d
1715
+ },
1716
+ {
1717
+ path: `${l}/settings`,
1718
+ name: "webx.tasks.settings",
1719
+ component: Mt,
1720
+ props: d
1721
+ },
1722
+ {
1723
+ path: `${l}/new`,
1724
+ name: "webx.tasks.new",
1725
+ component: je,
1726
+ props: { ...d, id: null }
1727
+ },
1728
+ {
1729
+ path: `${l}/:id(\\d+)`,
1730
+ name: "webx.tasks.task",
1731
+ component: qt,
1732
+ props: (a) => ({ ...d, id: k(a.params.id) })
1733
+ },
1734
+ {
1735
+ path: `${l}/:id(\\d+)/edit`,
1736
+ name: "webx.tasks.edit",
1737
+ component: je,
1738
+ props: (a) => ({ ...d, id: k(a.params.id) })
1739
+ }
1740
+ ]
1741
+ };
1742
+ }
1743
+ export {
1744
+ je as WxTaskFormPage,
1745
+ qt as WxTaskPage,
1746
+ It as WxTasksPage,
1747
+ it as WxTasksProjectsPage,
1748
+ Mt as WxTasksSettingsPage,
1749
+ se as createTasksApi,
1750
+ Ot as tasks,
1751
+ at as tasksMessages
1752
+ };
1753
+ //# sourceMappingURL=index.js.map