@parallelworks/tandem-web 0.141.2 → 0.143.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/_virtual/_virtual_i18n/en/common.js +162 -5
  2. package/_virtual/_virtual_i18n/es/common.js +162 -5
  3. package/_virtual/_virtual_i18n/ja/common.js +162 -5
  4. package/_virtual/_virtual_i18n/ko/common.js +162 -5
  5. package/_virtual/_virtual_i18n/zh/common.js +162 -5
  6. package/components/AccessGrants.js +6 -6
  7. package/components/ActivityTimeline.js +2 -0
  8. package/components/CodeHostSettings.js +25 -25
  9. package/components/CustomFields.js +349 -0
  10. package/components/DocProperties.js +320 -0
  11. package/components/DocTable.js +176 -0
  12. package/components/DocViewBlock.js +104 -0
  13. package/components/DocsTree.js +16 -6
  14. package/components/Editor.js +30 -28
  15. package/components/GitHub.js +22 -22
  16. package/components/IssueBoard.js +48 -43
  17. package/components/IssueEvent.js +2 -0
  18. package/components/IssueFilters.js +210 -122
  19. package/components/IssueImport.js +1 -1
  20. package/components/IssueRow.js +96 -79
  21. package/components/IssueTemplates.js +216 -156
  22. package/components/IssueTypes.js +318 -0
  23. package/components/NewIssueDialog.js +254 -216
  24. package/components/SettingsNav.js +40 -35
  25. package/components/SlashMenu.js +2 -0
  26. package/components/TeamForm.js +49 -35
  27. package/components/TeamRepositories.js +51 -51
  28. package/components/TeamWorkflow.js +8 -8
  29. package/components/Updates.js +8 -8
  30. package/lib/boardMove.js +69 -47
  31. package/lib/customFields.js +113 -0
  32. package/lib/docProperties.js +135 -0
  33. package/lib/issueDisplay.js +27 -12
  34. package/lib/issueList.js +166 -62
  35. package/lib/issueTypes.js +50 -0
  36. package/lib/teamTree.js +24 -0
  37. package/lib/views.js +13 -11
  38. package/package.json +1 -1
  39. package/pages/issues.js +331 -291
  40. package/routeTree.gen.js +174 -162
  41. package/routes/_workspace/agents/index2.js +9 -9
  42. package/routes/_workspace/docs/_doc2.js +147 -140
  43. package/routes/_workspace/docs/space._space.js +6 -0
  44. package/routes/_workspace/docs/space2._space.js +256 -0
  45. package/routes/_workspace/docs2.js +3 -3
  46. package/routes/_workspace/issues/_identifier2.js +433 -370
  47. package/routes/_workspace/projects/_projectId3.js +213 -201
  48. package/routes/_workspace/settings/audit-log3.js +2 -0
  49. package/routes/_workspace/settings/fields.js +6 -0
  50. package/routes/_workspace/settings/fields2.js +30 -0
  51. package/routes/_workspace/settings/fields3.js +5 -0
  52. package/routes/_workspace/settings/groups2.js +74 -74
  53. package/routes/_workspace/settings/labels2.js +33 -33
  54. package/routes/_workspace/settings/members2.js +35 -35
  55. package/routes/_workspace/settings/roles2.js +24 -24
  56. package/routes/_workspace/settings/runners2.js +18 -18
  57. package/routes/_workspace/settings/sessions2.js +9 -9
  58. package/routes/_workspace/settings/slack2.js +8 -8
  59. package/routes/_workspace/settings/sso2.js +50 -50
  60. package/routes/_workspace/settings/tokens2.js +15 -15
  61. package/routes/_workspace/settings/webhooks2.js +42 -42
  62. package/routes/_workspace/teams/_key/settings2.js +138 -76
  63. package/routes/_workspace2.js +321 -319
  64. package/styles.css +39 -0
@@ -0,0 +1,349 @@
1
+ import { issueQuery as e } from "../api/queries.js";
2
+ import { useConfirm as t } from "../lib/confirm.js";
3
+ import { customFieldsQuery as n, fieldKinds as r, fieldsFor as i, hasValue as a, setIssueFields as o, setProjectFields as s, useCustomFieldActions as c } from "../lib/customFields.js";
4
+ import { issueTypesQuery as l, typeShows as u } from "../lib/issueTypes.js";
5
+ import { AddIcon as d } from "./icons.js";
6
+ import { invalidateIssueViews as f } from "../api/mutations.js";
7
+ import { PropertyField as p, usePropertyText as m } from "./DocProperties.js";
8
+ import { Button as h, Checkbox as g, ErrorText as _, IconButton as v, Input as y, Select as b, SettingsCard as x, Textarea as S, menuDivider as C, useOpenMenu as w } from "@parallelworks/ui";
9
+ import { useId as T, useState as E } from "react";
10
+ import { useErrorMessage as D } from "@parallelworks/problem/react";
11
+ import { useTranslations as O } from "use-intl";
12
+ import { Fragment as k, jsx as A, jsxs as j } from "react/jsx-runtime";
13
+ import { useMutation as M, useQuery as N, useQueryClient as P } from "@tanstack/react-query";
14
+ // src/components/CustomFields.tsx
15
+ function F(e) {
16
+ let t = m(e);
17
+ return (e, n) => t(e, n);
18
+ }
19
+ function I({ workspace: t, issue: r, label: a }) {
20
+ let s = D(), c = P(), { data: d } = N(n(t)), { data: m } = N(l(t)), h = m?.find((e) => e.id === r.type?.id), g = i(d, "issue", r.teamId).filter((e) => u(h, e.id)), v = e(t, r.identifier).queryKey, y = M({
21
+ mutationFn: (e) => o(t, r.identifier, e),
22
+ onMutate: async (e) => {
23
+ await c.cancelQueries({ queryKey: v });
24
+ let t = c.getQueryData(v);
25
+ return t && c.setQueryData(v, {
26
+ ...t,
27
+ fields: {
28
+ ...t.fields,
29
+ ...e
30
+ }
31
+ }), { previous: t };
32
+ },
33
+ onError: (e, t, n) => {
34
+ n?.previous && c.setQueryData(v, n.previous);
35
+ },
36
+ onSuccess: (e) => c.setQueryData(v, e),
37
+ onSettled: () => f(c, t, r.identifier)
38
+ });
39
+ return g.length === 0 ? null : /* @__PURE__ */ j(k, { children: [g.map((e) => a(e.name, /* @__PURE__ */ A("div", {
40
+ className: "px-2",
41
+ children: /* @__PURE__ */ A(p, {
42
+ workspace: t,
43
+ property: e,
44
+ value: r.fields[e.id],
45
+ editable: !0,
46
+ onChange: (t) => y.mutate({ [e.id]: t })
47
+ })
48
+ }), e.id)), y.error && /* @__PURE__ */ A(_, {
49
+ className: "px-2",
50
+ children: s(y.error)
51
+ })] });
52
+ }
53
+ function L({ workspace: e, project: t, editable: r, onChange: a }) {
54
+ let o = O("customFields"), c = D(), { data: l } = N(n(e)), u = i(l, "project"), d = M({
55
+ mutationFn: (n) => s(e, t.id, n),
56
+ onSuccess: a
57
+ });
58
+ return u.length === 0 ? null : /* @__PURE__ */ j("section", {
59
+ "aria-label": o("title"),
60
+ className: "max-w-xl space-y-0.5 text-sm",
61
+ children: [u.map((n) => /* @__PURE__ */ j("div", {
62
+ className: "flex min-h-8 items-center gap-2",
63
+ children: [/* @__PURE__ */ A("span", {
64
+ className: "w-36 shrink-0 truncate text-muted-foreground",
65
+ children: n.name
66
+ }), /* @__PURE__ */ A("div", {
67
+ className: "min-w-0 flex-1",
68
+ children: /* @__PURE__ */ A(p, {
69
+ workspace: e,
70
+ property: n,
71
+ value: t.fields[n.id],
72
+ editable: r,
73
+ onChange: (e) => d.mutate({ [n.id]: e })
74
+ })
75
+ })]
76
+ }, n.id)), d.error && /* @__PURE__ */ A(_, { children: c(d.error) })]
77
+ });
78
+ }
79
+ function R({ workspace: e, teamId: t, typeId: r, values: o, onChange: s }) {
80
+ let c = O("customFields"), { data: d } = N(n(e)), { data: f } = N(l(e)), m = f?.find((e) => e.id === r), h = i(d, "issue", t).filter((e) => u(m, e.id)).map((e) => m?.requiredFieldIds.includes(e.id) ? {
81
+ ...e,
82
+ required: !0
83
+ } : e).filter((e) => e.required || a(o[e.id]));
84
+ return h.length === 0 ? null : /* @__PURE__ */ j("fieldset", {
85
+ className: "space-y-0.5 text-sm",
86
+ children: [/* @__PURE__ */ A("legend", {
87
+ className: "sr-only",
88
+ children: c("title")
89
+ }), h.map((t) => /* @__PURE__ */ j("div", {
90
+ className: "flex min-h-8 items-center gap-2",
91
+ children: [/* @__PURE__ */ j("span", {
92
+ className: "w-36 shrink-0 truncate text-muted-foreground",
93
+ children: [t.name, t.required && /* @__PURE__ */ j(k, { children: [/* @__PURE__ */ j("span", {
94
+ "aria-hidden": !0,
95
+ className: "text-destructive",
96
+ children: [" ", "*"]
97
+ }), /* @__PURE__ */ A("span", {
98
+ className: "sr-only",
99
+ children: c("required")
100
+ })] })]
101
+ }), /* @__PURE__ */ A("div", {
102
+ className: "min-w-0 flex-1",
103
+ children: /* @__PURE__ */ A(p, {
104
+ workspace: e,
105
+ property: t,
106
+ value: o[t.id],
107
+ editable: !0,
108
+ onChange: (e) => s({
109
+ ...o,
110
+ [t.id]: e
111
+ })
112
+ })
113
+ })]
114
+ }, t.id))]
115
+ });
116
+ }
117
+ function z({ workspace: e, target: t, team: r }) {
118
+ let i = O("customFields"), { data: a } = N(n(e)), o = (a ?? []).filter((e) => e.target === t && (r ? e.teamId === r.id : !e.teamId)).sort((e, t) => e.position - t.position), [s, c] = E(!1);
119
+ return /* @__PURE__ */ j(x, {
120
+ title: i(t === "issue" ? "issueFields" : "projectFields"),
121
+ description: i(r ? "teamFieldsHelp" : t === "issue" ? "issueFieldsHelp" : "projectFieldsHelp"),
122
+ action: /* @__PURE__ */ A(h, {
123
+ size: "sm",
124
+ icon: /* @__PURE__ */ A(d, {}),
125
+ onClick: () => c(!0),
126
+ children: i("add")
127
+ }),
128
+ children: [s && /* @__PURE__ */ A(V, {
129
+ workspace: e,
130
+ target: t,
131
+ team: r?.key,
132
+ onDone: () => c(!1)
133
+ }), o.length === 0 && !s ? /* @__PURE__ */ A("p", {
134
+ className: "px-3 py-3 text-sm text-muted-foreground",
135
+ children: i("none")
136
+ }) : /* @__PURE__ */ A("ul", {
137
+ className: "divide-y divide-border",
138
+ children: o.map((t, n) => /* @__PURE__ */ A(B, {
139
+ workspace: e,
140
+ field: t,
141
+ before: o[n - 1],
142
+ after: o[n + 1]
143
+ }, t.id))
144
+ })]
145
+ });
146
+ }
147
+ function B({ workspace: e, field: n, before: r, after: i }) {
148
+ let a = O("customFields"), o = c(e), s = w(), { confirm: l, dialog: u } = t(), [d, f] = E(!1), p = (e, t) => e && o.update.mutate({
149
+ id: n.id,
150
+ position: t ? (e.position + t.position) / 2 : e.position + (e === i ? 1 : -1)
151
+ }), m = () => l({
152
+ title: a("deleteTitle", { name: n.name }),
153
+ description: a("deleteDescription", { count: n.values }),
154
+ confirmLabel: a("delete"),
155
+ destructive: !0,
156
+ onConfirm: () => o.remove.mutateAsync(n.id)
157
+ }), h = () => [
158
+ {
159
+ label: a("edit"),
160
+ onClick: () => f(!0)
161
+ },
162
+ ...r ? [{
163
+ label: a("moveUp"),
164
+ onClick: () => p(r, void 0)
165
+ }] : [],
166
+ ...i ? [{
167
+ label: a("moveDown"),
168
+ onClick: () => p(i, void 0)
169
+ }] : [],
170
+ {
171
+ label: n.archivedAt ? a("restore") : a("archive"),
172
+ onClick: () => o.update.mutate({
173
+ id: n.id,
174
+ archived: !n.archivedAt
175
+ })
176
+ },
177
+ C,
178
+ {
179
+ label: a("delete"),
180
+ destructive: !0,
181
+ onClick: m
182
+ }
183
+ ];
184
+ return d ? /* @__PURE__ */ A("li", {
185
+ className: "p-2",
186
+ children: /* @__PURE__ */ A(V, {
187
+ workspace: e,
188
+ target: n.target,
189
+ field: n,
190
+ onDone: () => f(!1)
191
+ })
192
+ }) : /* @__PURE__ */ j("li", {
193
+ className: "flex min-h-10 items-center gap-3 px-3 py-1.5",
194
+ onContextMenu: (e) => s(e, h()),
195
+ children: [
196
+ /* @__PURE__ */ j("div", {
197
+ className: "min-w-0 flex-1",
198
+ children: [/* @__PURE__ */ j("p", {
199
+ className: `truncate text-sm ${n.archivedAt ? "text-muted-foreground" : ""}`,
200
+ children: [n.name, n.required && /* @__PURE__ */ A("span", {
201
+ className: "ml-2 text-xs text-muted-foreground",
202
+ children: a("required")
203
+ })]
204
+ }), n.description && /* @__PURE__ */ A("p", {
205
+ className: "truncate text-xs text-muted-foreground",
206
+ children: n.description
207
+ })]
208
+ }),
209
+ n.archivedAt && /* @__PURE__ */ A("span", {
210
+ className: "shrink-0 text-xs text-muted-foreground",
211
+ children: a("archived")
212
+ }),
213
+ /* @__PURE__ */ A("span", {
214
+ className: "shrink-0 text-xs text-muted-foreground",
215
+ children: a(`kinds.${n.kind}`)
216
+ }),
217
+ /* @__PURE__ */ A("span", {
218
+ className: "w-20 shrink-0 text-right text-xs tabular-nums text-muted-foreground",
219
+ children: a("values", { count: n.values })
220
+ }),
221
+ /* @__PURE__ */ A(v, {
222
+ variant: "ghost",
223
+ size: "sm",
224
+ label: a("actions", { name: n.name }),
225
+ icon: /* @__PURE__ */ A("span", {
226
+ "aria-hidden": !0,
227
+ children: "⋯"
228
+ }),
229
+ onClick: (e) => s(e, h())
230
+ }),
231
+ u
232
+ ]
233
+ });
234
+ }
235
+ function V({ workspace: e, target: t, team: n, field: i, onDone: a }) {
236
+ let o = O("customFields"), s = D(), l = c(e), [u, d] = E(i?.name ?? ""), [f, p] = E(i?.description ?? ""), [m, v] = E(i?.kind ?? "text"), [x, C] = E(i?.required ?? !1), w = T(), [k, M] = E((i?.options ?? []).map((e) => e.name).join("\n")), N = m === "select" || m === "multi_select", P = () => k.split("\n").map((e) => e.trim()).filter(Boolean).map((e) => {
237
+ let t = i?.options.find((t) => t.name === e)?.id;
238
+ return {
239
+ name: e,
240
+ ...t && { id: t }
241
+ };
242
+ }), F = i ? l.update : l.create;
243
+ return /* @__PURE__ */ j("form", {
244
+ onSubmit: (e) => {
245
+ e.preventDefault(), i ? l.update.mutate({
246
+ id: i.id,
247
+ name: u,
248
+ description: f,
249
+ ...t === "issue" && { required: x },
250
+ ...N && { options: P() }
251
+ }, { onSuccess: a }) : l.create.mutate({
252
+ target: t,
253
+ ...n && { team: n },
254
+ name: u,
255
+ description: f,
256
+ kind: m,
257
+ ...t === "issue" && { required: x },
258
+ ...N && { options: P() }
259
+ }, { onSuccess: a });
260
+ },
261
+ className: "space-y-3 rounded-md border border-border p-3 text-sm",
262
+ children: [
263
+ /* @__PURE__ */ j("div", {
264
+ className: "grid gap-3 sm:grid-cols-2",
265
+ children: [/* @__PURE__ */ j("label", {
266
+ className: "block text-xs font-medium text-muted-foreground",
267
+ children: [o("name"), /* @__PURE__ */ A(y, {
268
+ value: u,
269
+ onChange: (e) => d(e.target.value),
270
+ required: !0,
271
+ maxLength: 60,
272
+ className: "mt-1",
273
+ autoFocus: !0
274
+ })]
275
+ }), /* @__PURE__ */ j("div", {
276
+ className: "text-xs font-medium text-muted-foreground",
277
+ children: [o("kind"), /* @__PURE__ */ A("div", {
278
+ className: "mt-1",
279
+ children: /* @__PURE__ */ A(b, {
280
+ value: m,
281
+ items: r.map((e) => ({
282
+ value: e,
283
+ label: o(`kinds.${e}`)
284
+ })),
285
+ onValueChange: v,
286
+ "aria-label": o("kind"),
287
+ width: "fill",
288
+ disabled: !!i
289
+ })
290
+ })]
291
+ })]
292
+ }),
293
+ /* @__PURE__ */ j("label", {
294
+ className: "block text-xs font-medium text-muted-foreground",
295
+ children: [o("description"), /* @__PURE__ */ A(y, {
296
+ value: f,
297
+ onChange: (e) => p(e.target.value),
298
+ maxLength: 500,
299
+ className: "mt-1"
300
+ })]
301
+ }),
302
+ N && /* @__PURE__ */ j("label", {
303
+ className: "block text-xs font-medium text-muted-foreground",
304
+ children: [
305
+ o("options"),
306
+ /* @__PURE__ */ A(S, {
307
+ value: k,
308
+ onChange: (e) => M(e.target.value),
309
+ rows: 4,
310
+ className: "mt-1"
311
+ }),
312
+ /* @__PURE__ */ A("span", {
313
+ className: "mt-1 block font-normal",
314
+ children: o("optionsHint")
315
+ })
316
+ ]
317
+ }),
318
+ t === "issue" && /* @__PURE__ */ j("div", {
319
+ className: "flex items-center gap-2 text-sm",
320
+ children: [/* @__PURE__ */ A(g, {
321
+ id: w,
322
+ checked: x,
323
+ onCheckedChange: (e) => C(e === !0)
324
+ }), /* @__PURE__ */ A("label", {
325
+ htmlFor: w,
326
+ children: o("requiredLabel")
327
+ })]
328
+ }),
329
+ F.error && /* @__PURE__ */ A(_, { children: s(F.error) }),
330
+ /* @__PURE__ */ j("div", {
331
+ className: "flex justify-end gap-2",
332
+ children: [/* @__PURE__ */ A(h, {
333
+ size: "sm",
334
+ variant: "ghost",
335
+ onClick: a,
336
+ children: o("cancel")
337
+ }), /* @__PURE__ */ A(h, {
338
+ type: "submit",
339
+ size: "sm",
340
+ variant: "primary",
341
+ loading: F.isPending,
342
+ disabled: !u.trim(),
343
+ children: o(i ? "save" : "add")
344
+ })]
345
+ })
346
+ ]
347
+ });
348
+ }
349
+ export { z as FieldSettings, I as IssueFields, R as NewIssueFields, L as ProjectFields, F as useFieldText };
@@ -0,0 +1,320 @@
1
+ import { AddIcon as e } from "./icons.js";
2
+ import { usePeople as t } from "../lib/people.js";
3
+ import { useCan as n } from "../lib/roles.js";
4
+ import { docPropertiesQuery as r, propertyKinds as i, spaceScope as a, useDocPropertyActions as o } from "../lib/docProperties.js";
5
+ import { Button as s, Checkbox as c, ErrorText as l, IconButton as u, Input as d, Popover as f, Select as p, Textarea as m, menuDivider as h, useOpenMenu as g } from "@parallelworks/ui";
6
+ import { Link as _ } from "@tanstack/react-router";
7
+ import { useEffect as v, useState as y } from "react";
8
+ import { useErrorMessage as b } from "@parallelworks/problem/react";
9
+ import { useTranslations as x } from "use-intl";
10
+ import { jsx as S, jsxs as C } from "react/jsx-runtime";
11
+ import { useQuery as w } from "@tanstack/react-query";
12
+ // src/components/DocProperties.tsx
13
+ function T(e) {
14
+ let { nameOf: n } = t(e), r = x("docProperties");
15
+ return (e, t) => {
16
+ if (t == null) return "";
17
+ let i = (t) => e.options.find((e) => e.id === t)?.name ?? String(t);
18
+ switch (e.kind) {
19
+ case "select": return i(t);
20
+ case "multi_select": return Array.isArray(t) ? t.map(i).join(", ") : "";
21
+ case "person": return n("user", String(t));
22
+ case "checkbox": return t === !0 ? r("yes") : "";
23
+ default: return String(t);
24
+ }
25
+ };
26
+ }
27
+ function E({ workspace: e, doc: t, space: i, editable: s }) {
28
+ let c = x("docProperties"), u = b(), { data: d = [] } = w(r(e, i)), f = n(e, "manage_labels", a(i)), p = o(e), m = t.properties ?? {};
29
+ if (d.length === 0 && !(s && f)) return null;
30
+ let h = (e, n) => p.setValues.mutate({
31
+ doc: t.key,
32
+ values: { [e]: n }
33
+ });
34
+ return /* @__PURE__ */ C("section", {
35
+ "aria-label": c("title"),
36
+ className: "mt-3 space-y-0.5 text-sm",
37
+ children: [
38
+ d.map((t) => /* @__PURE__ */ C("div", {
39
+ className: "flex min-h-8 items-center gap-2",
40
+ children: [/* @__PURE__ */ S(D, {
41
+ workspace: e,
42
+ property: t,
43
+ admin: s && f
44
+ }), /* @__PURE__ */ S("div", {
45
+ className: "min-w-0 flex-1",
46
+ children: /* @__PURE__ */ S(O, {
47
+ workspace: e,
48
+ property: t,
49
+ value: m[t.id],
50
+ editable: s,
51
+ onChange: (e) => h(t.id, e)
52
+ })
53
+ })]
54
+ }, t.id)),
55
+ s && f && /* @__PURE__ */ S(A, {
56
+ workspace: e,
57
+ space: i
58
+ }),
59
+ p.setValues.error && /* @__PURE__ */ S(l, { children: u(p.setValues.error) })
60
+ ]
61
+ });
62
+ }
63
+ function D({ workspace: e, property: t, admin: n }) {
64
+ let r = x("docProperties"), i = g(), a = o(e), [s, c] = y(!1), l = /* @__PURE__ */ S("span", {
65
+ className: "truncate",
66
+ children: t.name
67
+ });
68
+ if (!n) return /* @__PURE__ */ S("span", {
69
+ className: "flex w-36 shrink-0 text-muted-foreground",
70
+ children: l
71
+ });
72
+ let u = () => [
73
+ {
74
+ label: r("edit"),
75
+ onClick: () => c(!0)
76
+ },
77
+ h,
78
+ {
79
+ label: r("remove"),
80
+ destructive: !0,
81
+ onClick: () => a.remove.mutate(t.id)
82
+ }
83
+ ];
84
+ return /* @__PURE__ */ S(f, {
85
+ open: s,
86
+ onOpenChange: c,
87
+ trigger: /* @__PURE__ */ S("button", {
88
+ type: "button",
89
+ onContextMenu: (e) => i(e, u()),
90
+ className: "flex h-7 w-36 shrink-0 items-center rounded-md px-1.5 text-left text-muted-foreground hover:bg-muted",
91
+ children: l
92
+ }),
93
+ align: "start",
94
+ className: "w-72",
95
+ initialFocus: "first-control",
96
+ "aria-label": r("edit"),
97
+ children: /* @__PURE__ */ S(j, {
98
+ workspace: e,
99
+ property: t,
100
+ onDone: () => c(!1),
101
+ onRemove: () => {
102
+ a.remove.mutate(t.id), c(!1);
103
+ }
104
+ })
105
+ });
106
+ }
107
+ function O({ workspace: e, property: n, value: r, editable: i, onChange: a }) {
108
+ let o = x("docProperties"), { members: s } = t(e), l = T(e), u = o("empty");
109
+ if (!i) {
110
+ let t = l(n, r);
111
+ return n.kind === "issue" && t ? /* @__PURE__ */ S(_, {
112
+ to: "/$workspace/issues/$identifier",
113
+ params: {
114
+ workspace: e,
115
+ identifier: t
116
+ },
117
+ className: "text-primary hover:underline",
118
+ children: t
119
+ }) : n.kind === "url" && t ? /* @__PURE__ */ S("a", {
120
+ href: t,
121
+ target: "_blank",
122
+ rel: "noopener noreferrer",
123
+ className: "truncate text-primary hover:underline",
124
+ children: t
125
+ }) : /* @__PURE__ */ S("span", {
126
+ className: t ? "" : "text-muted-foreground",
127
+ children: t || u
128
+ });
129
+ }
130
+ switch (n.kind) {
131
+ case "select": return /* @__PURE__ */ S(p, {
132
+ value: typeof r == "string" ? r : "",
133
+ items: [{
134
+ value: "",
135
+ label: u
136
+ }, ...n.options.map((e) => ({
137
+ value: e.id ?? "",
138
+ label: e.name
139
+ }))],
140
+ onValueChange: (e) => a(e || null),
141
+ "aria-label": n.name,
142
+ size: "sm",
143
+ width: "content"
144
+ });
145
+ case "multi_select": return /* @__PURE__ */ S(p, {
146
+ multiple: !0,
147
+ value: Array.isArray(r) ? r : [],
148
+ items: n.options.map((e) => ({
149
+ value: e.id ?? "",
150
+ label: e.name
151
+ })),
152
+ onValueChange: (e) => a(e),
153
+ placeholder: u,
154
+ "aria-label": n.name,
155
+ size: "sm",
156
+ width: "content"
157
+ });
158
+ case "person": return /* @__PURE__ */ S(p, {
159
+ value: typeof r == "string" ? r : "",
160
+ items: [{
161
+ value: "",
162
+ label: u
163
+ }, ...s.map((e) => ({
164
+ value: e.user.username,
165
+ label: e.user.name
166
+ }))],
167
+ onValueChange: (e) => a(e || null),
168
+ "aria-label": n.name,
169
+ size: "sm",
170
+ width: "content"
171
+ });
172
+ case "checkbox": return /* @__PURE__ */ S(c, {
173
+ checked: r === !0,
174
+ onCheckedChange: (e) => a(e === !0),
175
+ "aria-label": n.name
176
+ });
177
+ case "date": return /* @__PURE__ */ S(d, {
178
+ type: "date",
179
+ value: typeof r == "string" ? r : "",
180
+ onChange: (e) => a(e.target.value || null),
181
+ "aria-label": n.name,
182
+ className: "h-7 px-1.5 w-40"
183
+ });
184
+ default: return /* @__PURE__ */ S(k, {
185
+ property: n,
186
+ value: r,
187
+ onChange: a
188
+ });
189
+ }
190
+ }
191
+ function k({ property: e, value: t, onChange: n }) {
192
+ let r = x("docProperties"), i = t == null ? "" : String(t), [a, o] = y(i);
193
+ v(() => o(i), [i]);
194
+ let s = () => {
195
+ a !== i && (a.trim() ? n(e.kind === "number" ? Number(a) : a) : n(null));
196
+ };
197
+ return /* @__PURE__ */ S(d, {
198
+ type: e.kind === "number" ? "number" : e.kind === "url" ? "url" : "text",
199
+ value: a,
200
+ onChange: (e) => o(e.target.value),
201
+ onBlur: s,
202
+ onKeyDown: (e) => e.key === "Enter" && s(),
203
+ placeholder: r(e.kind === "issue" ? "issueExample" : e.kind === "url" ? "urlExample" : "empty"),
204
+ "aria-label": e.name,
205
+ className: "h-7 border-transparent px-1.5 shadow-none hover:border-border"
206
+ });
207
+ }
208
+ function A({ workspace: t, space: n }) {
209
+ let r = x("docProperties"), [i, a] = y(!1);
210
+ return /* @__PURE__ */ S(f, {
211
+ open: i,
212
+ onOpenChange: a,
213
+ trigger: /* @__PURE__ */ S(s, {
214
+ size: "xs",
215
+ variant: "ghost",
216
+ icon: /* @__PURE__ */ S(e, {}),
217
+ className: "mt-1 text-muted-foreground",
218
+ children: r("add")
219
+ }),
220
+ align: "start",
221
+ className: "w-72",
222
+ initialFocus: "first-control",
223
+ "aria-label": r("add"),
224
+ children: /* @__PURE__ */ S(j, {
225
+ workspace: t,
226
+ space: n,
227
+ onDone: () => a(!1)
228
+ })
229
+ });
230
+ }
231
+ function j({ workspace: e, space: t, property: n, onDone: r, onRemove: a }) {
232
+ let c = x("docProperties"), f = b(), h = o(e), [g, _] = y(n?.name ?? ""), [v, w] = y(n?.kind ?? "text"), [T, E] = y((n?.options ?? []).map((e) => e.name).join("\n")), D = v === "select" || v === "multi_select", O = () => T.split("\n").map((e) => e.trim()).filter(Boolean).map((e) => {
233
+ let t = n?.options.find((t) => t.name === e)?.id;
234
+ return {
235
+ name: e,
236
+ ...t && { id: t }
237
+ };
238
+ }), k = n ? h.update : h.create;
239
+ return /* @__PURE__ */ C("form", {
240
+ onSubmit: (e) => {
241
+ e.preventDefault(), n ? h.update.mutate({
242
+ id: n.id,
243
+ name: g,
244
+ ...D && { options: O() }
245
+ }, { onSuccess: r }) : h.create.mutate({
246
+ ...t && { space: t },
247
+ name: g,
248
+ kind: v,
249
+ ...D && { options: O() }
250
+ }, { onSuccess: r });
251
+ },
252
+ className: "space-y-3 text-sm",
253
+ children: [
254
+ /* @__PURE__ */ C("label", {
255
+ className: "block text-xs font-medium text-muted-foreground",
256
+ children: [c("name"), /* @__PURE__ */ S(d, {
257
+ value: g,
258
+ onChange: (e) => _(e.target.value),
259
+ required: !0,
260
+ maxLength: 60,
261
+ className: "mt-1"
262
+ })]
263
+ }),
264
+ !n && /* @__PURE__ */ C("div", {
265
+ className: "text-xs font-medium text-muted-foreground",
266
+ children: [c("kind"), /* @__PURE__ */ S("div", {
267
+ className: "mt-1",
268
+ children: /* @__PURE__ */ S(p, {
269
+ value: v,
270
+ items: i.map((e) => ({
271
+ value: e,
272
+ label: c(`kinds.${e}`)
273
+ })),
274
+ onValueChange: w,
275
+ "aria-label": c("kind"),
276
+ width: "fill"
277
+ })
278
+ })]
279
+ }),
280
+ D && /* @__PURE__ */ C("label", {
281
+ className: "block text-xs font-medium text-muted-foreground",
282
+ children: [
283
+ c("options"),
284
+ /* @__PURE__ */ S(m, {
285
+ value: T,
286
+ onChange: (e) => E(e.target.value),
287
+ rows: 4,
288
+ className: "mt-1"
289
+ }),
290
+ /* @__PURE__ */ S("span", {
291
+ className: "mt-1 block font-normal",
292
+ children: c("optionsHint")
293
+ })
294
+ ]
295
+ }),
296
+ k.error && /* @__PURE__ */ S(l, { children: f(k.error) }),
297
+ /* @__PURE__ */ C("div", {
298
+ className: "flex justify-between gap-2",
299
+ children: [a ? /* @__PURE__ */ S(u, {
300
+ variant: "ghost",
301
+ size: "sm",
302
+ label: c("remove"),
303
+ icon: /* @__PURE__ */ S("span", {
304
+ "aria-hidden": !0,
305
+ children: "×"
306
+ }),
307
+ onClick: a
308
+ }) : /* @__PURE__ */ S("span", {}), /* @__PURE__ */ S(s, {
309
+ type: "submit",
310
+ size: "sm",
311
+ variant: "primary",
312
+ loading: k.isPending,
313
+ disabled: !g.trim(),
314
+ children: c(n ? "save" : "add")
315
+ })]
316
+ })
317
+ ]
318
+ });
319
+ }
320
+ export { E as DocProperties, O as PropertyField, T as usePropertyText };