@parallelworks/tandem-web 0.142.0 → 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 (53) hide show
  1. package/_virtual/_virtual_i18n/en/common.js +105 -6
  2. package/_virtual/_virtual_i18n/es/common.js +105 -6
  3. package/_virtual/_virtual_i18n/ja/common.js +105 -6
  4. package/_virtual/_virtual_i18n/ko/common.js +105 -6
  5. package/_virtual/_virtual_i18n/zh/common.js +105 -6
  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 +8 -2
  11. package/components/GitHub.js +22 -22
  12. package/components/IssueBoard.js +48 -43
  13. package/components/IssueEvent.js +2 -0
  14. package/components/IssueFilters.js +210 -122
  15. package/components/IssueImport.js +1 -1
  16. package/components/IssueRow.js +96 -79
  17. package/components/IssueTemplates.js +216 -156
  18. package/components/IssueTypes.js +318 -0
  19. package/components/NewIssueDialog.js +254 -216
  20. package/components/SettingsNav.js +40 -35
  21. package/components/TeamForm.js +49 -35
  22. package/components/TeamRepositories.js +51 -51
  23. package/components/TeamWorkflow.js +8 -8
  24. package/components/Updates.js +8 -8
  25. package/lib/boardMove.js +69 -47
  26. package/lib/customFields.js +113 -0
  27. package/lib/issueDisplay.js +27 -12
  28. package/lib/issueList.js +166 -62
  29. package/lib/issueTypes.js +50 -0
  30. package/lib/teamTree.js +24 -0
  31. package/lib/views.js +13 -11
  32. package/package.json +1 -1
  33. package/pages/issues.js +331 -291
  34. package/routeTree.gen.js +151 -145
  35. package/routes/_workspace/agents/index2.js +9 -9
  36. package/routes/_workspace/issues/_identifier2.js +433 -370
  37. package/routes/_workspace/projects/_projectId3.js +213 -201
  38. package/routes/_workspace/settings/audit-log3.js +2 -0
  39. package/routes/_workspace/settings/fields.js +6 -0
  40. package/routes/_workspace/settings/fields2.js +30 -0
  41. package/routes/_workspace/settings/fields3.js +5 -0
  42. package/routes/_workspace/settings/groups2.js +74 -74
  43. package/routes/_workspace/settings/labels2.js +33 -33
  44. package/routes/_workspace/settings/members2.js +35 -35
  45. package/routes/_workspace/settings/roles2.js +24 -24
  46. package/routes/_workspace/settings/runners2.js +18 -18
  47. package/routes/_workspace/settings/sessions2.js +9 -9
  48. package/routes/_workspace/settings/slack2.js +8 -8
  49. package/routes/_workspace/settings/sso2.js +50 -50
  50. package/routes/_workspace/settings/tokens2.js +15 -15
  51. package/routes/_workspace/settings/webhooks2.js +42 -42
  52. package/routes/_workspace/teams/_key/settings2.js +138 -76
  53. package/routes/_workspace2.js +320 -318
@@ -115,7 +115,8 @@ var e = {
115
115
  webhooks: "Webhook",
116
116
  sso: "单点登录",
117
117
  slack: "Slack",
118
- roles: "角色"
118
+ roles: "角色",
119
+ fields: "字段"
119
120
  },
120
121
  account: {
121
122
  connectionsDescription: "你在其他服务上的账户。关联后,你在那里的操作会以你的身份显示在这里。",
@@ -859,7 +860,8 @@ var e = {
859
860
  priority: "优先级",
860
861
  project: "项目",
861
862
  label: "标签",
862
- none: "不分组"
863
+ none: "不分组",
864
+ type: "类型"
863
865
  },
864
866
  foldGroup: "折叠 {group}",
865
867
  unfoldGroup: "展开 {group}",
@@ -974,7 +976,10 @@ var e = {
974
976
  dueDateCleared: "<actor>{name}</actor> 移除了截止日期",
975
977
  attachmentAdded: "<actor>{name}</actor> 附加了 {file}",
976
978
  archivedBy: "<actor>{name}</actor> 归档了此问题",
977
- restored: "<actor>{name}</actor> 恢复了此问题"
979
+ restored: "<actor>{name}</actor> 恢复了此问题",
980
+ fieldsChanged: "<actor>{name}</actor> 更改了{fields}",
981
+ typeChanged: "<actor>{name}</actor> 将类型改为{type}",
982
+ typeCleared: "<actor>{name}</actor> 移除了类型"
978
983
  },
979
984
  activity: {
980
985
  title: "活动",
@@ -1244,6 +1249,13 @@ var e = {
1244
1249
  selectAll: "全选",
1245
1250
  clear: "清除"
1246
1251
  },
1252
+ teamParent: {
1253
+ title: "上级团队",
1254
+ description: "位于其他团队之下的团队,其问题会出现在上级团队的问题列表中。新的子团队沿用上级的工作流;标签在整个工作区共享。",
1255
+ parent: "上级",
1256
+ none: "无上级团队",
1257
+ subTeams: "子团队"
1258
+ },
1247
1259
  intakeForm: {
1248
1260
  heading: "提交请求",
1249
1261
  title: "向 {team} 提交请求",
@@ -1301,7 +1313,8 @@ var e = {
1301
1313
  date: "日期",
1302
1314
  checkbox: "复选框",
1303
1315
  issue: "问题"
1304
- }
1316
+ },
1317
+ urlExample: "https://…"
1305
1318
  },
1306
1319
  docViews: {
1307
1320
  title: "文档表格",
@@ -2226,7 +2239,10 @@ var e = {
2226
2239
  memberRoleChanged: "<actor>{name}</actor> 授予 {person} 角色 {role}",
2227
2240
  workspaceAccessChanged: "<actor>{name}</actor> 修改了整个工作区的角色",
2228
2241
  teamAccessChanged: "<actor>{name}</actor> 修改了可访问 <link>{target}</link> 的人员",
2229
- projectAccessChanged: "<actor>{name}</actor> 修改了项目 <link>{target}</link> 的角色"
2242
+ projectAccessChanged: "<actor>{name}</actor> 修改了项目 <link>{target}</link> 的角色",
2243
+ issueFieldsChanged: "<actor>{name}</actor> 更改了 <link>{target}</link> 的{fields}",
2244
+ issueTypeChanged: "<actor>{name}</actor> 将 <link>{target}</link> 的类型改为{type}",
2245
+ issueTypeCleared: "<actor>{name}</actor> 移除了 <link>{target}</link> 的类型"
2230
2246
  }
2231
2247
  },
2232
2248
  oneTimeSecret: {
@@ -3202,7 +3218,9 @@ var e = {
3202
3218
  label: "标签",
3203
3219
  project: "项目",
3204
3220
  estimate: "估算",
3205
- dueDate: "截止日期"
3221
+ dueDate: "截止日期",
3222
+ field: "字段",
3223
+ type: "类型"
3206
3224
  }
3207
3225
  },
3208
3226
  follow: {
@@ -3417,6 +3435,87 @@ var e = {
3417
3435
  projectAccess: {
3418
3436
  title: "{name} 的访问权限",
3419
3437
  description: "在此授予的角色适用于该项目及其议题,叠加在成员的工作区和团队角色之上。可用于让某人在不担任团队管理员的情况下负责一个项目。"
3438
+ },
3439
+ customFields: {
3440
+ title: "字段",
3441
+ pageDescription: "管理员为问题和项目添加的字段,例如严重程度或预算。成员填写字段值,列表可按字段筛选、排序和分组。",
3442
+ issueFields: "问题字段",
3443
+ projectFields: "项目字段",
3444
+ issueFieldsHelp: "所有团队的问题都有这些字段。",
3445
+ teamFieldsHelp: "仅此团队的问题有这些字段,排在工作区字段之后。",
3446
+ projectFieldsHelp: "所有项目都有这些字段。",
3447
+ add: "添加字段",
3448
+ none: "还没有字段。",
3449
+ edit: "编辑",
3450
+ moveUp: "上移",
3451
+ moveDown: "下移",
3452
+ archive: "归档",
3453
+ restore: "恢复",
3454
+ archived: "已归档",
3455
+ delete: "删除",
3456
+ deleteTitle: "删除 {name}?",
3457
+ deleteDescription: "{count, plural, =0 {没有问题或项目填写了此字段。} other {# 个问题和项目上的值将一并删除。}}",
3458
+ required: "必填",
3459
+ requiredLabel: "创建问题时必填",
3460
+ values: "{count, plural, =0 {没有值} other {# 个值}}",
3461
+ actions: "{name} 的操作",
3462
+ name: "名称",
3463
+ kind: "类型",
3464
+ description: "描述",
3465
+ options: "选项",
3466
+ optionsHint: "每行一个。",
3467
+ cancel: "取消",
3468
+ save: "保存",
3469
+ noValue: "无值",
3470
+ noField: "无{name}",
3471
+ yes: "是",
3472
+ kinds: {
3473
+ text: "文本",
3474
+ number: "数字",
3475
+ select: "单选",
3476
+ multi_select: "多选",
3477
+ person: "人员",
3478
+ date: "日期",
3479
+ checkbox: "复选框",
3480
+ url: "URL"
3481
+ },
3482
+ onRows: "行上显示的字段",
3483
+ noneOnRows: "无"
3484
+ },
3485
+ issueTypes: {
3486
+ title: "问题类型",
3487
+ description: "团队分开跟踪的问题种类,例如缺陷或风险。每种类型可以只显示部分字段、要求自己的必填字段,并用模板开始。没有类型的团队不会看到这个选项。",
3488
+ add: "添加类型",
3489
+ none: "没有类型;所有问题都是同一种。",
3490
+ edit: "编辑",
3491
+ moveUp: "上移",
3492
+ moveDown: "下移",
3493
+ archive: "归档",
3494
+ restore: "恢复",
3495
+ archived: "已归档",
3496
+ delete: "删除",
3497
+ deleteTitle: "删除 {name}?",
3498
+ deleteDescription: "{count, plural, =0 {没有问题是这个类型。} other {# 个问题将变为无类型。}}",
3499
+ everyTeam: "所有团队",
3500
+ issues: "{count, plural, =0 {没有问题} other {# 个问题}}",
3501
+ actions: "{name} 的操作",
3502
+ name: "名称",
3503
+ icon: "表情",
3504
+ iconHint: "可选",
3505
+ color: "颜色",
3506
+ descriptionLabel: "描述",
3507
+ teams: "团队",
3508
+ fields: "显示的字段",
3509
+ allFields: "所有字段",
3510
+ required: "必填字段",
3511
+ noneRequired: "无",
3512
+ template: "描述模板",
3513
+ templateHint: "此类型新问题开头的 Markdown",
3514
+ type: "类型",
3515
+ noType: "无类型",
3516
+ hiddenTitle: "更改类型?",
3517
+ hidden: "{type}不显示{fields}。它们的值会隐藏保留,类型改回后会再次显示。",
3518
+ change: "更改类型"
3420
3519
  }
3421
3520
  };
3422
3521
  export { e as default };
@@ -1,6 +1,6 @@
1
1
  import { groupsQuery as e, membersQuery as t, peopleQuery as n, rolesQuery as r } from "../api/queries.js";
2
- import { isBuiltIn as i, permissionGroups as a } from "../lib/roles.js";
3
- import { useConfirm as o } from "../lib/confirm.js";
2
+ import { useConfirm as i } from "../lib/confirm.js";
3
+ import { isBuiltIn as a, permissionGroups as o } from "../lib/roles.js";
4
4
  import { useMemo as s } from "react";
5
5
  import { useErrorMessage as c } from "@parallelworks/problem/react";
6
6
  import { useTranslations as l } from "use-intl";
@@ -10,13 +10,13 @@ import { AccessPanel as h } from "@parallelworks/ui/access";
10
10
  // src/components/AccessGrants.tsx
11
11
  var g = (e) => `${e.kind}:${e.handle}`;
12
12
  function _({ workspace: _, resourceName: v, access: y, openLabel: b, rules: x, readOnly: S = !1, footer: C, save: w }) {
13
- let { data: T } = m(e(_)), { data: E } = m(n(_)), { data: D = [] } = p(t(_)), O = l("access"), k = l("roles"), A = l("permissions"), { data: j = [] } = p(r(_)), M = c(), { confirm: N, dialog: P } = o(), F = s(() => j.map((e) => ({
13
+ let { data: T } = m(e(_)), { data: E } = m(n(_)), { data: D = [] } = p(t(_)), O = l("access"), k = l("roles"), A = l("permissions"), { data: j = [] } = p(r(_)), M = c(), { confirm: N, dialog: P } = i(), F = s(() => j.map((e) => ({
14
14
  id: e.id,
15
- name: i(e.id) ? k(`${e.id}.name`) : e.name,
16
- ...i(e.id) ? { description: k(`${e.id}.description`) } : e.description && { description: e.description },
15
+ name: a(e.id) ? k(`${e.id}.name`) : e.name,
16
+ ...a(e.id) ? { description: k(`${e.id}.description`) } : e.description && { description: e.description },
17
17
  permissions: e.permissions,
18
18
  privileged: e.permissions.includes("manage_members")
19
- })), [j, k]), I = s(() => a.flatMap((e) => e.permissions).map((e) => ({
19
+ })), [j, k]), I = s(() => o.flatMap((e) => e.permissions).map((e) => ({
20
20
  id: e,
21
21
  label: A(`${e}.name`)
22
22
  })), [A]), L = s(() => {
@@ -78,6 +78,8 @@ function H(F, I) {
78
78
  case "cycle.updated": return /* @__PURE__ */ B(u, {});
79
79
  case "issue.estimate_changed": return /* @__PURE__ */ B(f, {});
80
80
  case "issue.due_date_changed": return /* @__PURE__ */ B(s, {});
81
+ case "issue.fields_changed":
82
+ case "issue.type_changed": return /* @__PURE__ */ B(d, {});
81
83
  case "issue.area_changed":
82
84
  case "doc.area_changed":
83
85
  case "area.updated":
@@ -1,9 +1,9 @@
1
1
  import { api as e, unwrap as t } from "../api/client.js";
2
2
  import { codeHostAccountsQuery as n, codeHostQuery as r, meQuery as i } from "../api/queries.js";
3
- import { CodeHostIcon as a } from "./icons.js";
4
- import { usePeople as o } from "../lib/people.js";
5
- import { useFormError as s } from "./settings.js";
6
- import { useConfirm as c } from "../lib/confirm.js";
3
+ import { useConfirm as a } from "../lib/confirm.js";
4
+ import { CodeHostIcon as o } from "./icons.js";
5
+ import { usePeople as s } from "../lib/people.js";
6
+ import { useFormError as c } from "./settings.js";
7
7
  import { externalUrl as l } from "../lib/externalUrl.js";
8
8
  import { ConnectionCard as u, ConnectionPanel as d } from "./ConnectionCard.js";
9
9
  import { Avatar as f, Button as p, Card as m, ErrorText as h, Section as g, Select as _, SettingsCard as v, StatusLabel as y } from "@parallelworks/ui";
@@ -13,7 +13,7 @@ import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
13
13
  import { useMutation as T, useQueryClient as E, useSuspenseQuery as D } from "@tanstack/react-query";
14
14
  // src/components/CodeHostSettings.tsx
15
15
  function O({ workspace: n }) {
16
- let a = x("code"), { data: o } = D(i), { data: l } = D(r(n)), u = E(), d = s(), { confirm: f, dialog: m } = c(), v = T({
16
+ let o = x("code"), { data: s } = D(i), { data: l } = D(r(n)), u = E(), d = c(), { confirm: f, dialog: m } = a(), v = T({
17
17
  mutationFn: async (r) => t(await e.DELETE("/api/v1/workspaces/{workspace}/code-host/connections/{account}", { params: { path: {
18
18
  workspace: n,
19
19
  account: r
@@ -27,11 +27,11 @@ function O({ workspace: n }) {
27
27
  ] });
28
28
  }
29
29
  }), y = (e) => f({
30
- title: a("disconnectConfirm", { account: e }),
31
- description: a("disconnectDetail"),
32
- confirmLabel: a("disconnect"),
30
+ title: o("disconnectConfirm", { account: e }),
31
+ description: o("disconnectDetail"),
32
+ confirmLabel: o("disconnect"),
33
33
  onConfirm: () => v.mutateAsync(e)
34
- }), [S, O] = b(""), k = l.connections.filter((e) => e.connectedBy === o?.user.username), A = k[0];
34
+ }), [S, O] = b(""), k = l.connections.filter((e) => e.connectedBy === s?.user.username), A = k[0];
35
35
  if (!A) return null;
36
36
  let j = k.some((e) => e.account === S) ? S : A.account;
37
37
  return /* @__PURE__ */ w(g, {
@@ -39,8 +39,8 @@ function O({ workspace: n }) {
39
39
  tone: "error",
40
40
  collapsible: !1,
41
41
  headingLevel: 2,
42
- title: a("dangerZone"),
43
- description: a("disconnectDetail"),
42
+ title: o("dangerZone"),
43
+ description: o("disconnectDetail"),
44
44
  className: "mt-10",
45
45
  children: [
46
46
  /* @__PURE__ */ w("div", {
@@ -48,7 +48,7 @@ function O({ workspace: n }) {
48
48
  children: [/* @__PURE__ */ C("div", {
49
49
  className: "w-56 max-w-full",
50
50
  children: /* @__PURE__ */ C(_, {
51
- "aria-label": a("disconnectWhich"),
51
+ "aria-label": o("disconnectWhich"),
52
52
  value: j,
53
53
  onValueChange: (e) => e && O(e),
54
54
  items: k.map((e) => ({
@@ -60,7 +60,7 @@ function O({ workspace: n }) {
60
60
  variant: "danger",
61
61
  onClick: () => y(j),
62
62
  loading: v.isPending,
63
- children: a("disconnectAccount", { account: j })
63
+ children: o("disconnectAccount", { account: j })
64
64
  })]
65
65
  }),
66
66
  /* @__PURE__ */ C(h, {
@@ -72,8 +72,8 @@ function O({ workspace: n }) {
72
72
  ]
73
73
  });
74
74
  }
75
- function k({ workspace: n, isAdmin: i, result: c }) {
76
- let m = x("code"), { data: h } = D(r(n)), { person: g } = o(n), _ = s(), b = T({
75
+ function k({ workspace: n, isAdmin: i, result: a }) {
76
+ let m = x("code"), { data: h } = D(r(n)), { person: g } = s(n), _ = c(), b = T({
77
77
  mutationFn: async () => t(await e.POST("/api/v1/workspaces/{workspace}/code-host/connect", { params: { path: { workspace: n } } })),
78
78
  onMutate: _.clear,
79
79
  onSuccess: ({ url: e }) => {
@@ -86,13 +86,13 @@ function k({ workspace: n, isAdmin: i, result: c }) {
86
86
  className: "px-3 py-2 text-sm text-muted-foreground",
87
87
  children: m("notConfigured")
88
88
  }) }) : /* @__PURE__ */ w(S, { children: [
89
- c && c !== "choose" && /* @__PURE__ */ C("p", {
89
+ a && a !== "choose" && /* @__PURE__ */ C("p", {
90
90
  role: "status",
91
- className: `mb-3 rounded-md bg-muted px-3 py-2 text-sm ${c === "failed" ? "text-danger" : ""}`,
92
- children: m(`result.${c}`)
91
+ className: `mb-3 rounded-md bg-muted px-3 py-2 text-sm ${a === "failed" ? "text-danger" : ""}`,
92
+ children: m(`result.${a}`)
93
93
  }),
94
94
  /* @__PURE__ */ C(u, {
95
- icon: /* @__PURE__ */ C(a, { className: "size-7" }),
95
+ icon: /* @__PURE__ */ C(o, { className: "size-7" }),
96
96
  name: m("provider"),
97
97
  status: h.connections.length > 0 ? m("linkedCount", { count: h.connections.length }) : m("description"),
98
98
  error: _.error,
@@ -129,12 +129,12 @@ function k({ workspace: n, isAdmin: i, result: c }) {
129
129
  }),
130
130
  i && /* @__PURE__ */ C(A, {
131
131
  workspace: n,
132
- chosen: c === "choose"
132
+ chosen: a === "choose"
133
133
  })
134
134
  ] });
135
135
  }
136
136
  function A({ workspace: i, chosen: a }) {
137
- let o = x("code"), { data: c } = D(n(i)), u = E(), d = s(), f = T({
137
+ let o = x("code"), { data: s } = D(n(i)), u = E(), d = c(), f = T({
138
138
  mutationFn: async (n) => t(await e.POST("/api/v1/workspaces/{workspace}/code-host/connections", {
139
139
  params: { path: { workspace: i } },
140
140
  body: { id: n }
@@ -156,7 +156,7 @@ function A({ workspace: i, chosen: a }) {
156
156
  onMutate: d.clear,
157
157
  onError: d.set
158
158
  });
159
- return !a && c.length === 0 ? null : /* @__PURE__ */ w(m, {
159
+ return !a && s.length === 0 ? null : /* @__PURE__ */ w(m, {
160
160
  size: "fill",
161
161
  padding: "sm",
162
162
  className: "mt-4",
@@ -167,11 +167,11 @@ function A({ workspace: i, chosen: a }) {
167
167
  }),
168
168
  /* @__PURE__ */ C("p", {
169
169
  className: "mt-0.5 text-sm text-muted-foreground",
170
- children: c.length > 0 ? o("chooseDescription") : o("noAccounts")
170
+ children: s.length > 0 ? o("chooseDescription") : o("noAccounts")
171
171
  }),
172
- c.length > 0 && /* @__PURE__ */ C("ul", {
172
+ s.length > 0 && /* @__PURE__ */ C("ul", {
173
173
  className: "mt-3 divide-y divide-border rounded-md border border-border",
174
- children: c.map((e) => /* @__PURE__ */ w("li", {
174
+ children: s.map((e) => /* @__PURE__ */ w("li", {
175
175
  className: "px-3 py-2 text-sm",
176
176
  children: [/* @__PURE__ */ w("div", {
177
177
  className: "flex items-center gap-3",
@@ -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 };