@parallelworks/tandem-web 0.142.0 → 0.144.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 (58) hide show
  1. package/_virtual/_virtual_i18n/en/common.js +156 -6
  2. package/_virtual/_virtual_i18n/es/common.js +156 -6
  3. package/_virtual/_virtual_i18n/ja/common.js +156 -6
  4. package/_virtual/_virtual_i18n/ko/common.js +156 -6
  5. package/_virtual/_virtual_i18n/zh/common.js +156 -6
  6. package/api/queries.js +85 -74
  7. package/components/AccessGrants.js +6 -6
  8. package/components/ActivityTimeline.js +2 -0
  9. package/components/CodeHostSettings.js +25 -25
  10. package/components/CustomFields.js +349 -0
  11. package/components/DocProperties.js +8 -2
  12. package/components/GitHub.js +22 -22
  13. package/components/IssueBoard.js +48 -43
  14. package/components/IssueEvent.js +2 -0
  15. package/components/IssueFilters.js +210 -122
  16. package/components/IssueImport.js +1 -1
  17. package/components/IssueRow.js +96 -79
  18. package/components/IssueTemplates.js +216 -156
  19. package/components/IssueTypes.js +318 -0
  20. package/components/NewIssueDialog.js +254 -216
  21. package/components/SettingsNav.js +45 -35
  22. package/components/TeamForm.js +49 -35
  23. package/components/TeamRepositories.js +51 -51
  24. package/components/TeamWorkflow.js +8 -8
  25. package/components/Updates.js +8 -8
  26. package/components/icons.js +8 -8
  27. package/lib/boardMove.js +69 -47
  28. package/lib/customFields.js +113 -0
  29. package/lib/issueDisplay.js +27 -12
  30. package/lib/issueList.js +166 -62
  31. package/lib/issueTypes.js +50 -0
  32. package/lib/teamTree.js +24 -0
  33. package/lib/views.js +13 -11
  34. package/package.json +1 -1
  35. package/pages/issues.js +331 -291
  36. package/routeTree.gen.js +186 -174
  37. package/routes/_workspace/agents/index2.js +9 -9
  38. package/routes/_workspace/issues/_identifier2.js +433 -370
  39. package/routes/_workspace/projects/_projectId3.js +213 -201
  40. package/routes/_workspace/settings/audit-log3.js +2 -0
  41. package/routes/_workspace/settings/fields.js +6 -0
  42. package/routes/_workspace/settings/fields2.js +30 -0
  43. package/routes/_workspace/settings/fields3.js +5 -0
  44. package/routes/_workspace/settings/groups2.js +74 -74
  45. package/routes/_workspace/settings/import.js +6 -0
  46. package/routes/_workspace/settings/import2.js +330 -0
  47. package/routes/_workspace/settings/import3.js +4 -0
  48. package/routes/_workspace/settings/labels2.js +33 -33
  49. package/routes/_workspace/settings/members2.js +35 -35
  50. package/routes/_workspace/settings/roles2.js +24 -24
  51. package/routes/_workspace/settings/runners2.js +18 -18
  52. package/routes/_workspace/settings/sessions2.js +9 -9
  53. package/routes/_workspace/settings/slack2.js +8 -8
  54. package/routes/_workspace/settings/sso2.js +50 -50
  55. package/routes/_workspace/settings/tokens2.js +15 -15
  56. package/routes/_workspace/settings/webhooks2.js +42 -42
  57. package/routes/_workspace/teams/_key/settings2.js +138 -76
  58. package/routes/_workspace2.js +320 -318
package/lib/issueList.js CHANGED
@@ -1,31 +1,34 @@
1
- import { PriorityIcon as e, StatusIcon as t } from "../components/icons.js";
2
- import { statusRef as n } from "./refs.js";
3
- import { Avatar as r } from "@parallelworks/ui";
4
- import { jsx as i } from "react/jsx-runtime";
1
+ import { fieldRef as e, groupableKinds as t, parseFieldFilters as n, sortableKinds as r } from "./customFields.js";
2
+ import { PriorityIcon as i, StatusIcon as a } from "../components/icons.js";
3
+ import { TypeIcon as o } from "../components/IssueTypes.js";
4
+ import { statusRef as s } from "./refs.js";
5
+ import { Avatar as c } from "@parallelworks/ui";
6
+ import { jsx as l } from "react/jsx-runtime";
5
7
  // src/lib/issueList.tsx
6
- var a = {
8
+ var u = {
7
9
  active: { categories: ["started", "unstarted"] },
8
10
  backlog: { categories: ["backlog"] },
9
11
  done: { categories: ["completed", "canceled"] },
10
12
  all: { categories: [] }
11
- }, o = [
13
+ }, d = [
12
14
  "updated",
13
15
  "priority",
14
16
  "created",
15
17
  "due",
16
18
  "requests"
17
- ], s = [
19
+ ], f = [
18
20
  "status",
19
21
  "assignee",
20
22
  "priority",
21
23
  "project",
22
24
  "label",
25
+ "type",
23
26
  "none"
24
- ], c = (e) => typeof e == "number" ? String(e) : typeof e == "string" && e !== "" ? e : void 0;
25
- function l(e) {
26
- let t = {}, n = c(e.view);
27
- n && n in a && (t.view = n);
28
- for (let n of [
27
+ ], p = (t, n) => d.includes(t) || n.some((n) => e(t) === n.id && r.includes(n.kind)), m = (n, r) => f.includes(n) || r.some((r) => e(n) === r.id && t.includes(r.kind)), h = (e) => typeof e == "number" ? String(e) : typeof e == "string" && e !== "" ? e : void 0;
28
+ function g(t) {
29
+ let n = {}, r = h(t.view);
30
+ r && r in u && (n.view = r);
31
+ for (let e of [
29
32
  "team",
30
33
  "assignee",
31
34
  "creator",
@@ -35,103 +38,202 @@ function l(e) {
35
38
  "project",
36
39
  "customer",
37
40
  "cycle",
41
+ "type",
42
+ "fields",
38
43
  "q",
39
44
  "saved"
40
45
  ]) {
41
- let r = c(e[n]);
42
- r && (t[n] = r);
46
+ let r = h(t[e]);
47
+ r && (n[e] = r);
43
48
  }
44
- t.assignee && e.assigneeKind === "agent" && (t.assigneeKind = "agent"), (e.overdue === "true" || e.overdue === !0) && (t.overdue = "true");
45
- let r = c(e.order);
46
- r && r !== "updated" && o.includes(r) && (t.order = r), e.layout === "board" && (t.layout = "board");
47
- let i = c(e.group);
48
- return i && i !== "status" && s.includes(i) && (t.group = i), t;
49
+ n.assignee && t.assigneeKind === "agent" && (n.assigneeKind = "agent"), (t.overdue === "true" || t.overdue === !0) && (n.overdue = "true");
50
+ let i = h(t.order);
51
+ i && i !== "updated" && (d.includes(i) || e(i)) && (n.order = i), t.layout === "board" && (n.layout = "board");
52
+ let a = h(t.group);
53
+ return a && a !== "status" && (f.includes(a) || e(a)) && (n.group = a), n;
49
54
  }
50
- var u = [
55
+ var _ = [
51
56
  "started",
52
57
  "unstarted",
53
58
  "backlog",
54
59
  "triage",
55
60
  "completed",
56
61
  "canceled"
57
- ], d = (e) => e === 0 ? 5 : e;
58
- function f(e, t) {
59
- let n = {
62
+ ], v = (e) => e === 0 ? 5 : e;
63
+ function y(t, n, r = []) {
64
+ let i = r.find((t) => t.id === e(n));
65
+ if (i) return [...t].sort(b(i));
66
+ let a = {
60
67
  updated: () => 0,
61
- priority: (e, t) => d(e.priority) - d(t.priority),
68
+ priority: (e, t) => v(e.priority) - v(t.priority),
62
69
  created: (e, t) => t.createdAt.localeCompare(e.createdAt),
63
70
  due: (e, t) => (e.dueDate ?? "9999").localeCompare(t.dueDate ?? "9999"),
64
71
  requests: (e, t) => (t.requests ?? 0) - (e.requests ?? 0)
65
- }[t];
66
- return [...e].sort(n);
72
+ }[n];
73
+ return [...t].sort(a ?? (() => 0));
67
74
  }
68
- function p(n, a, o, s = !1) {
69
- if (a === "none") return n.length > 0 ? [{
75
+ function b(e) {
76
+ let t = (t) => {
77
+ let n = t.fields[e.id];
78
+ if (n != null) return e.kind === "select" ? e.options.findIndex((e) => e.id === n) : typeof n == "number" ? n : String(n);
79
+ };
80
+ return (e, n) => {
81
+ let r = t(e), i = t(n);
82
+ return r === void 0 || i === void 0 ? Number(r === void 0) - Number(i === void 0) : typeof r == "number" && typeof i == "number" ? r - i : String(r).localeCompare(String(i));
83
+ };
84
+ }
85
+ function x(t, n, r, s = !1, u = [], d = []) {
86
+ let f = u.find((t) => t.id === e(n));
87
+ if (f) return S(t, f, r, s);
88
+ if (n === "type") {
89
+ let e = {
90
+ key: "none",
91
+ label: r.noType ?? r.none.all,
92
+ issues: []
93
+ }, n = d.map((e) => ({
94
+ key: e.id,
95
+ label: e.name,
96
+ icon: /* @__PURE__ */ l(o, {
97
+ type: e,
98
+ className: "size-3.5"
99
+ }),
100
+ issues: []
101
+ }));
102
+ for (let r of t) {
103
+ if (!r.type) {
104
+ e.issues.push(r);
105
+ continue;
106
+ }
107
+ let t = n.find((e) => e.key === r.type?.id);
108
+ t || (t = {
109
+ key: r.type.id,
110
+ label: r.type.name,
111
+ icon: /* @__PURE__ */ l(o, {
112
+ type: r.type,
113
+ className: "size-3.5"
114
+ }),
115
+ issues: []
116
+ }, n.push(t)), t.issues.push(r);
117
+ }
118
+ return n.push(e), n.filter((e) => s || e.issues.length > 0);
119
+ }
120
+ if (n === "none") return t.length > 0 ? [{
70
121
  key: "all",
71
- label: o.none.all,
72
- issues: n
122
+ label: r.none.all,
123
+ issues: t
73
124
  }] : [];
74
- if (a === "status") return u.map((e) => ({
125
+ if (n === "status") return _.map((e) => ({
75
126
  key: e,
76
- label: o.status(e),
77
- icon: /* @__PURE__ */ i(t, { category: e }),
78
- issues: n.filter((t) => t.status.category === e)
127
+ label: r.status(e),
128
+ icon: /* @__PURE__ */ l(a, { category: e }),
129
+ issues: t.filter((t) => t.status.category === e)
79
130
  })).filter((e) => s || e.issues.length > 0);
80
- if (a === "priority") return [
131
+ if (n === "priority") return [
81
132
  1,
82
133
  2,
83
134
  3,
84
135
  4,
85
136
  0
86
- ].map((t) => ({
87
- key: String(t),
88
- label: o.priority(t),
89
- icon: /* @__PURE__ */ i(e, { priority: t }),
90
- issues: n.filter((e) => e.priority === t)
137
+ ].map((e) => ({
138
+ key: String(e),
139
+ label: r.priority(e),
140
+ icon: /* @__PURE__ */ l(i, { priority: e }),
141
+ issues: t.filter((t) => t.priority === e)
91
142
  })).filter((e) => s || e.issues.length > 0);
92
- let c = /* @__PURE__ */ new Map(), l = {
143
+ let p = /* @__PURE__ */ new Map(), m = {
93
144
  key: "",
94
145
  label: "",
95
146
  issues: []
96
- }, d = (e, t, n, r) => {
97
- let i = c.get(t) ?? {
147
+ }, h = (e, t, n, r) => {
148
+ let i = p.get(t) ?? {
98
149
  key: t,
99
150
  label: n,
100
151
  icon: r,
101
152
  issues: []
102
153
  };
103
- i.issues.push(e), c.set(t, i);
154
+ i.issues.push(e), p.set(t, i);
104
155
  };
105
- for (let e of n) if (a === "assignee") {
156
+ for (let e of t) if (n === "assignee") {
106
157
  for (let t of s ? e.assignees : e.assignees.slice(0, 1)) {
107
- let n = o.person(t.kind, t.handle);
108
- d(e, `${t.kind}:${t.handle}`, n, /* @__PURE__ */ i(r, {
158
+ let n = r.person(t.kind, t.handle);
159
+ h(e, `${t.kind}:${t.handle}`, n, /* @__PURE__ */ l(c, {
109
160
  name: n,
110
- src: o.avatar(t.kind, t.handle),
161
+ src: r.avatar(t.kind, t.handle),
111
162
  size: "xs",
112
163
  decorative: !0
113
164
  }));
114
165
  }
115
- e.assignees.length === 0 && l.issues.push(e);
116
- } else if (a === "project") e.project ? d(e, e.project.id, e.project.name) : l.issues.push(e);
166
+ e.assignees.length === 0 && m.issues.push(e);
167
+ } else if (n === "project") e.project ? h(e, e.project.id, e.project.name) : m.issues.push(e);
117
168
  else {
118
- for (let t of s ? e.labels : e.labels.slice(0, 1)) d(e, t.id, t.name, /* @__PURE__ */ i("span", {
169
+ for (let t of s ? e.labels : e.labels.slice(0, 1)) h(e, t.id, t.name, /* @__PURE__ */ l("span", {
119
170
  className: "size-2 rounded-full",
120
171
  style: { background: t.color }
121
172
  }));
122
- e.labels.length === 0 && l.issues.push(e);
173
+ e.labels.length === 0 && m.issues.push(e);
123
174
  }
124
- let f = [...c.values()].sort((e, t) => e.label.localeCompare(t.label));
125
- return (s || l.issues.length > 0) && f.push({
126
- ...l,
175
+ let g = [...p.values()].sort((e, t) => e.label.localeCompare(t.label));
176
+ return (s || m.issues.length > 0) && g.push({
177
+ ...m,
127
178
  key: "none",
128
- label: o.none[a]
129
- }), f;
179
+ label: r.none[n]
180
+ }), g;
181
+ }
182
+ function S(e, t, n, r) {
183
+ let i = {
184
+ key: "none",
185
+ label: n.noField?.(t.name) ?? n.none.all,
186
+ issues: []
187
+ }, a = (e) => {
188
+ let n = e.fields[t.id];
189
+ return Array.isArray(n) ? r ? n.map(String) : n.slice(0, 1).map(String) : n === !0 ? ["true"] : typeof n == "string" && n ? [n] : [];
190
+ }, o = /* @__PURE__ */ new Map(), s = (e) => e ? /* @__PURE__ */ l("span", {
191
+ className: "size-2 rounded-full",
192
+ style: { background: e }
193
+ }) : void 0;
194
+ if (t.kind === "select" || t.kind === "multi_select") for (let e of t.options) {
195
+ let t = s(e.color);
196
+ o.set(e.id ?? "", {
197
+ key: e.id ?? "",
198
+ label: e.name,
199
+ issues: [],
200
+ ...t && { icon: t }
201
+ });
202
+ }
203
+ t.kind === "checkbox" && o.set("true", {
204
+ key: "true",
205
+ label: n.yes ?? t.name,
206
+ issues: []
207
+ });
208
+ for (let r of e) {
209
+ let e = a(r);
210
+ e.length === 0 && i.issues.push(r);
211
+ for (let i of e) {
212
+ let e = o.get(i);
213
+ if (!e) {
214
+ let r = t.kind === "person" ? n.person("user", i) : i;
215
+ e = {
216
+ key: i,
217
+ label: r,
218
+ issues: [],
219
+ ...t.kind === "person" && { icon: /* @__PURE__ */ l(c, {
220
+ name: r,
221
+ src: n.avatar("user", i),
222
+ size: "xs",
223
+ decorative: !0
224
+ }) }
225
+ }, o.set(i, e);
226
+ }
227
+ e.issues.push(r);
228
+ }
229
+ }
230
+ let u = [...o.values()];
231
+ return t.kind === "person" && u.sort((e, t) => e.label.localeCompare(t.label)), u.push(i), u.filter((e) => r || e.issues.length > 0);
130
232
  }
131
- function m(e, t) {
233
+ function C(e, t) {
132
234
  let r = e.view ?? "active", i = (e.status ?? "").split(",").flatMap((e) => {
133
- let r = t?.filter((t) => n(t) === e).map((e) => e.id) ?? [];
134
- return r.length > 0 ? r : [e];
235
+ let n = t?.filter((t) => s(t) === e).map((e) => e.id) ?? [];
236
+ return n.length > 0 ? n : [e];
135
237
  });
136
238
  return {
137
239
  ...e.team && { team: e.team },
@@ -144,10 +246,12 @@ function m(e, t) {
144
246
  ...e.project && { project: e.project },
145
247
  ...e.customer && { customer: e.customer },
146
248
  ...e.cycle && { cycle: e.cycle },
249
+ ...e.type && { type: e.type.split(",") },
250
+ ...e.fields && { field: n(e.fields).map((e) => `${e.field}:${e.value}`) },
147
251
  ...e.overdue && { overdue: !0 },
148
252
  ...e.q && { q: e.q },
149
- ...a[r].categories.length > 0 && { category: a[r].categories },
253
+ ...u[r].categories.length > 0 && { category: u[r].categories },
150
254
  ...r === "all" && { triage: "include" }
151
255
  };
152
256
  }
153
- export { p as groupIssues, s as groupings, m as issueFilterOf, l as issueSearch, o as orders, f as sortIssues, a as views };
257
+ export { x as groupIssues, f as groupings, m as isGrouping, p as isOrder, C as issueFilterOf, g as issueSearch, d as orders, y as sortIssues, u as views };
@@ -0,0 +1,50 @@
1
+ import { api as e, unwrap as t } from "../api/client.js";
2
+ import { queryOptions as n, useMutation as r, useQueryClient as i } from "@tanstack/react-query";
3
+ // src/lib/issueTypes.ts
4
+ var a = (r) => n({
5
+ queryKey: [
6
+ "workspace",
7
+ r,
8
+ "issueTypes"
9
+ ],
10
+ queryFn: async ({ signal: n }) => t(await e.GET("/api/v1/workspaces/{workspace}/issue-types", {
11
+ params: { path: { workspace: r } },
12
+ signal: n
13
+ })).types
14
+ }), o = (e, t) => (e ?? []).filter((e) => !e.archivedAt && (e.teamIds.length === 0 || !!t && e.teamIds.includes(t))), s = (e, t) => !e || e.fieldIds.length === 0 || e.fieldIds.includes(t);
15
+ function c(n) {
16
+ let o = i(), s = () => {
17
+ o.invalidateQueries({ queryKey: a(n).queryKey }), o.invalidateQueries({ queryKey: [
18
+ "workspace",
19
+ n,
20
+ "issues"
21
+ ] });
22
+ };
23
+ return {
24
+ create: r({
25
+ mutationFn: async (r) => t(await e.POST("/api/v1/workspaces/{workspace}/issue-types", {
26
+ params: { path: { workspace: n } },
27
+ body: r
28
+ })),
29
+ onSettled: s
30
+ }),
31
+ update: r({
32
+ mutationFn: async ({ id: r, ...i }) => t(await e.PUT("/api/v1/workspaces/{workspace}/issue-types/{type}", {
33
+ params: { path: {
34
+ workspace: n,
35
+ type: r
36
+ } },
37
+ body: i
38
+ })),
39
+ onSettled: s
40
+ }),
41
+ remove: r({
42
+ mutationFn: async (r) => t(await e.DELETE("/api/v1/workspaces/{workspace}/issue-types/{type}", { params: { path: {
43
+ workspace: n,
44
+ type: r
45
+ } } })),
46
+ onSettled: s
47
+ })
48
+ };
49
+ }
50
+ export { a as issueTypesQuery, s as typeShows, o as typesFor, c as useIssueTypeActions };
@@ -0,0 +1,24 @@
1
+ // src/lib/teamTree.ts
2
+ function e(e) {
3
+ let t = new Set(e.map((e) => e.id)), n = /* @__PURE__ */ new Map();
4
+ for (let r of e) {
5
+ let e = r.parentId && t.has(r.parentId) ? r.parentId : "";
6
+ n.set(e, [...n.get(e) ?? [], r]);
7
+ }
8
+ let r = [], i = (e, t) => {
9
+ for (let a of n.get(e) ?? []) r.push({
10
+ team: a,
11
+ depth: t
12
+ }), i(a.id, t + 1);
13
+ };
14
+ return i("", 0), r;
15
+ }
16
+ function t(e, t) {
17
+ let n = /* @__PURE__ */ new Set([t]);
18
+ for (let t = !0; t;) {
19
+ t = !1;
20
+ for (let r of e) r.parentId && n.has(r.parentId) && !n.has(r.id) && (n.add(r.id), t = !0);
21
+ }
22
+ return n;
23
+ }
24
+ export { e as teamTree, t as withSubTeams };
package/lib/views.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { api as e, unwrap as t } from "../api/client.js";
2
2
  import { useNavigate as n } from "./router.js";
3
3
  import { viewsQuery as r } from "../api/queries.js";
4
- import { viewRef as i } from "./refs.js";
5
- import { issuesHref as a } from "./teamPaths.js";
6
- import { useLinkItems as o } from "./menus.js";
7
- import { ViewDialog as s } from "../components/ViewDialog.js";
8
- import { useConfirm as c } from "./confirm.js";
4
+ import { useConfirm as i } from "./confirm.js";
5
+ import { viewRef as a } from "./refs.js";
6
+ import { issuesHref as o } from "./teamPaths.js";
7
+ import { useLinkItems as s } from "./menus.js";
8
+ import { ViewDialog as c } from "../components/ViewDialog.js";
9
9
  import { menuDivider as l } from "@parallelworks/ui";
10
10
  import { useState as u } from "react";
11
11
  import { useTranslations as d } from "use-intl";
@@ -23,6 +23,8 @@ var v = [
23
23
  "label",
24
24
  "project",
25
25
  "cycle",
26
+ "type",
27
+ "fields",
26
28
  "overdue",
27
29
  "q",
28
30
  "order",
@@ -44,11 +46,11 @@ function b(e, t) {
44
46
  function x(e) {
45
47
  return {
46
48
  ...y(e.filters),
47
- saved: i(e)
49
+ saved: a(e)
48
50
  };
49
51
  }
50
52
  function S(e, t) {
51
- return a(e, x(t));
53
+ return o(e, x(t));
52
54
  }
53
55
  function C(n) {
54
56
  let i = _(), { data: a = [] } = g(r(n)), o = () => i.invalidateQueries({ queryKey: r(n).queryKey });
@@ -81,12 +83,12 @@ function C(n) {
81
83
  };
82
84
  }
83
85
  function w(e) {
84
- let t = d("savedViews"), r = d("common"), i = n(), a = o(), { update: h, remove: g } = C(e), { confirm: _, dialog: v } = c(), [y, b] = u(null);
86
+ let t = d("savedViews"), r = d("common"), a = n(), o = s(), { update: h, remove: g } = C(e), { confirm: _, dialog: v } = i(), [y, b] = u(null);
85
87
  return {
86
88
  menu: (n) => [
87
89
  {
88
90
  label: r("open"),
89
- onClick: () => i({
91
+ onClick: () => a({
90
92
  to: "/$workspace/issues",
91
93
  params: { workspace: e },
92
94
  search: x(n)
@@ -98,7 +100,7 @@ function w(e) {
98
100
  onClick: () => b(n)
99
101
  },
100
102
  l,
101
- ...a(S(e, n)),
103
+ ...o(S(e, n)),
102
104
  l,
103
105
  {
104
106
  label: t("delete"),
@@ -112,7 +114,7 @@ function w(e) {
112
114
  })
113
115
  }
114
116
  ],
115
- dialogs: /* @__PURE__ */ m(f, { children: [v, y && /* @__PURE__ */ p(s, {
117
+ dialogs: /* @__PURE__ */ m(f, { children: [v, y && /* @__PURE__ */ p(c, {
116
118
  title: t("renameTitle"),
117
119
  submitLabel: r("save"),
118
120
  defaultName: y.name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parallelworks/tandem-web",
3
- "version": "0.142.0",
3
+ "version": "0.144.0",
4
4
  "description": "Tandem's pages, for a host app to render in its own",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",