@nextop-os/workspace-issue-manager 0.0.16 → 0.0.17
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/assets/workspace-dock-task.png +0 -0
- package/dist/chunk-5YEGAJKA.js +313 -0
- package/dist/chunk-5YEGAJKA.js.map +1 -0
- package/dist/chunk-LYYOPZIJ.js +308 -0
- package/dist/chunk-LYYOPZIJ.js.map +1 -0
- package/dist/chunk-RX6P2DPR.js +3316 -0
- package/dist/chunk-RX6P2DPR.js.map +1 -0
- package/dist/contracts/index.d.ts +13 -1
- package/dist/feature-B6_wXych.d.ts +25 -0
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.d.ts +34 -23
- package/dist/index.js +28 -4
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/workbench/index.d.ts +9 -2
- package/dist/workbench/index.js +22 -11
- package/dist/workbench/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-CSDFXQBD.js +0 -73
- package/dist/chunk-CSDFXQBD.js.map +0 -1
- package/dist/chunk-HMMAMS4Z.js +0 -33
- package/dist/chunk-HMMAMS4Z.js.map +0 -1
- package/dist/chunk-POBWWUUQ.js +0 -44
- package/dist/chunk-POBWWUUQ.js.map +0 -1
|
@@ -0,0 +1,3316 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendIssueManagerWorkspaceFileLinksToContent,
|
|
3
|
+
extractIssueManagerPlainTextFromContent,
|
|
4
|
+
extractIssueManagerWorkspaceFileLinksFromContent,
|
|
5
|
+
normalizeIssueManagerContent,
|
|
6
|
+
normalizeIssueManagerNodeState
|
|
7
|
+
} from "./chunk-LYYOPZIJ.js";
|
|
8
|
+
|
|
9
|
+
// src/react/internal/useIssueManagerController.ts
|
|
10
|
+
import { useDeferredValue, useEffect, useState } from "react";
|
|
11
|
+
|
|
12
|
+
// src/react/internal/controllerUtils.ts
|
|
13
|
+
var defaultTaskPriority = "medium";
|
|
14
|
+
function resolveIssueManagerSelectedIssueId(currentSelectedIssueId, issues) {
|
|
15
|
+
if (currentSelectedIssueId && issues.some((issue) => issue.issueId === currentSelectedIssueId)) {
|
|
16
|
+
return currentSelectedIssueId;
|
|
17
|
+
}
|
|
18
|
+
return issues[0]?.issueId ?? null;
|
|
19
|
+
}
|
|
20
|
+
function resolveIssueManagerSelectedTaskId(currentSelectedTaskId, tasks) {
|
|
21
|
+
if (currentSelectedTaskId && tasks.some((task) => task.taskId === currentSelectedTaskId)) {
|
|
22
|
+
return currentSelectedTaskId;
|
|
23
|
+
}
|
|
24
|
+
return tasks[0]?.taskId ?? null;
|
|
25
|
+
}
|
|
26
|
+
function toContextRefInput(ref) {
|
|
27
|
+
return {
|
|
28
|
+
displayName: ref.displayName,
|
|
29
|
+
path: ref.path,
|
|
30
|
+
refType: ref.kind === "folder" ? "folder" : "file"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function toIssueManagerWorkspaceFileLinkInput(ref) {
|
|
34
|
+
return {
|
|
35
|
+
kind: ref.kind === "folder" ? "folder" : "file",
|
|
36
|
+
name: ref.displayName,
|
|
37
|
+
path: ref.path
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function confirmIssueManagerMessage(message) {
|
|
41
|
+
try {
|
|
42
|
+
return globalThis.confirm?.(message) ?? true;
|
|
43
|
+
} catch {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function resolveIssueManagerErrorMessage(error, copy) {
|
|
48
|
+
const raw = error instanceof Error ? error.message : typeof error === "string" ? error : String(error);
|
|
49
|
+
if (!copy) {
|
|
50
|
+
return raw;
|
|
51
|
+
}
|
|
52
|
+
if (raw === "issue_manager.upload_type_conflict") {
|
|
53
|
+
return copy.t("messages.uploadTypeConflict");
|
|
54
|
+
}
|
|
55
|
+
if (raw === "issue_manager.workspace_path_unavailable") {
|
|
56
|
+
return copy.t("messages.workspacePathUnavailable");
|
|
57
|
+
}
|
|
58
|
+
if (raw === "issue_manager.run_status_missing") {
|
|
59
|
+
return copy.t("messages.runStatusMissing");
|
|
60
|
+
}
|
|
61
|
+
if (raw === "issue_manager.run_timed_out") {
|
|
62
|
+
return copy.t("messages.runTimedOut");
|
|
63
|
+
}
|
|
64
|
+
if (raw.startsWith("issue_manager.run_exit_code:")) {
|
|
65
|
+
return copy.t("messages.runExitCode", {
|
|
66
|
+
code: raw.slice("issue_manager.run_exit_code:".length)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return raw;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/react/internal/controllerActions.ts
|
|
73
|
+
function createIssueManagerControllerActions(input) {
|
|
74
|
+
const {
|
|
75
|
+
copy,
|
|
76
|
+
feature,
|
|
77
|
+
issueDetail,
|
|
78
|
+
issueDraft,
|
|
79
|
+
issueEditorMode,
|
|
80
|
+
nodeState,
|
|
81
|
+
referenceTarget,
|
|
82
|
+
refreshAll,
|
|
83
|
+
refreshDetails,
|
|
84
|
+
setIsRunningTask,
|
|
85
|
+
setIssueDraftInternal,
|
|
86
|
+
setIssueEditorModeState,
|
|
87
|
+
setNotice,
|
|
88
|
+
setReferenceTarget,
|
|
89
|
+
setTaskDraftInternal,
|
|
90
|
+
setTaskEditorModeState,
|
|
91
|
+
taskDetail,
|
|
92
|
+
taskDraft,
|
|
93
|
+
taskEditorMode,
|
|
94
|
+
updateNodeState,
|
|
95
|
+
workspaceId
|
|
96
|
+
} = input;
|
|
97
|
+
const submitReferences = async (refs, target = referenceTarget) => {
|
|
98
|
+
const dedupedRefs = refs.filter((ref) => ref.path.trim().length > 0);
|
|
99
|
+
if (!target || dedupedRefs.length === 0) {
|
|
100
|
+
setReferenceTarget(null);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (target.mode === "insert") {
|
|
104
|
+
if (target.parentKind === "issue") {
|
|
105
|
+
setIssueDraftInternal((current) => ({
|
|
106
|
+
...current,
|
|
107
|
+
content: appendIssueManagerWorkspaceFileLinksToContent(
|
|
108
|
+
current.content,
|
|
109
|
+
dedupedRefs.map(toIssueManagerWorkspaceFileLinkInput)
|
|
110
|
+
)
|
|
111
|
+
}));
|
|
112
|
+
} else {
|
|
113
|
+
setTaskDraftInternal((current) => ({
|
|
114
|
+
...current,
|
|
115
|
+
content: appendIssueManagerWorkspaceFileLinksToContent(
|
|
116
|
+
current.content,
|
|
117
|
+
dedupedRefs.map(toIssueManagerWorkspaceFileLinkInput)
|
|
118
|
+
)
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
setReferenceTarget(null);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
125
|
+
if (!selectedIssueId) {
|
|
126
|
+
setReferenceTarget(null);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
await feature.backend.addContextRefs(
|
|
130
|
+
target.parentKind === "task" ? {
|
|
131
|
+
issueId: selectedIssueId,
|
|
132
|
+
parentKind: "task",
|
|
133
|
+
refs: dedupedRefs.map(toContextRefInput),
|
|
134
|
+
taskId: target.taskId,
|
|
135
|
+
workspaceId
|
|
136
|
+
} : {
|
|
137
|
+
issueId: selectedIssueId,
|
|
138
|
+
parentKind: "issue",
|
|
139
|
+
refs: dedupedRefs.map(toContextRefInput),
|
|
140
|
+
workspaceId
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
setReferenceTarget(null);
|
|
144
|
+
refreshDetails();
|
|
145
|
+
};
|
|
146
|
+
const createInsertReferenceTarget = (parentKind) => parentKind === "task" ? {
|
|
147
|
+
mode: "insert",
|
|
148
|
+
parentKind: "task",
|
|
149
|
+
taskId: nodeState.selectedTaskId ?? ""
|
|
150
|
+
} : {
|
|
151
|
+
mode: "insert",
|
|
152
|
+
parentKind: "issue"
|
|
153
|
+
};
|
|
154
|
+
const syncContentReferences = async (payload) => {
|
|
155
|
+
const existingPaths = new Set(payload.existingRefs.map((ref) => ref.path));
|
|
156
|
+
const missingRefs = extractIssueManagerWorkspaceFileLinksFromContent(
|
|
157
|
+
payload.content
|
|
158
|
+
).filter((ref) => !existingPaths.has(ref.path)).map((ref) => ({
|
|
159
|
+
displayName: ref.name,
|
|
160
|
+
path: ref.path,
|
|
161
|
+
refType: ref.kind
|
|
162
|
+
}));
|
|
163
|
+
if (missingRefs.length === 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
await feature.backend.addContextRefs(
|
|
167
|
+
payload.parentKind === "task" ? {
|
|
168
|
+
issueId: payload.issueId,
|
|
169
|
+
parentKind: "task",
|
|
170
|
+
refs: missingRefs,
|
|
171
|
+
taskId: payload.taskId ?? "",
|
|
172
|
+
workspaceId
|
|
173
|
+
} : {
|
|
174
|
+
issueId: payload.issueId,
|
|
175
|
+
parentKind: "issue",
|
|
176
|
+
refs: missingRefs,
|
|
177
|
+
workspaceId
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
return {
|
|
182
|
+
async attachReferences(parentKind) {
|
|
183
|
+
if (!feature.fileAdapter) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (parentKind === "task" && !nodeState.selectedTaskId) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (feature.fileAdapter.requestReferences && !feature.fileAdapter.listDirectory && !feature.fileAdapter.searchReferences) {
|
|
190
|
+
const refs = await feature.fileAdapter.requestReferences({
|
|
191
|
+
workspaceId
|
|
192
|
+
});
|
|
193
|
+
await submitReferences(
|
|
194
|
+
refs,
|
|
195
|
+
parentKind === "task" ? {
|
|
196
|
+
mode: "attach",
|
|
197
|
+
parentKind: "task",
|
|
198
|
+
taskId: nodeState.selectedTaskId ?? ""
|
|
199
|
+
} : {
|
|
200
|
+
mode: "attach",
|
|
201
|
+
parentKind: "issue"
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
setReferenceTarget(
|
|
207
|
+
parentKind === "task" ? { mode: "attach", parentKind, taskId: nodeState.selectedTaskId } : { mode: "attach", parentKind }
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
createTaskDraft() {
|
|
211
|
+
setTaskEditorModeState("create");
|
|
212
|
+
setTaskDraftInternal({
|
|
213
|
+
content: nodeState.taskDraftContent ?? "",
|
|
214
|
+
priority: defaultTaskPriority,
|
|
215
|
+
title: nodeState.taskDraftTitle ?? ""
|
|
216
|
+
});
|
|
217
|
+
updateNodeState((current) => ({
|
|
218
|
+
...current,
|
|
219
|
+
selectedTaskId: null
|
|
220
|
+
}));
|
|
221
|
+
},
|
|
222
|
+
async deleteIssue() {
|
|
223
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
224
|
+
if (!selectedIssueId || !confirmIssueManagerMessage(copy.t("confirmations.deleteIssue"))) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
await feature.backend.deleteIssue({
|
|
229
|
+
issueId: selectedIssueId,
|
|
230
|
+
workspaceId
|
|
231
|
+
});
|
|
232
|
+
setNotice({
|
|
233
|
+
kind: "success",
|
|
234
|
+
message: copy.t("messages.issueDeleted")
|
|
235
|
+
});
|
|
236
|
+
setIssueEditorModeState("read");
|
|
237
|
+
setTaskEditorModeState("read");
|
|
238
|
+
updateNodeState((current) => ({
|
|
239
|
+
...current,
|
|
240
|
+
selectedIssueId: null,
|
|
241
|
+
selectedTaskId: null
|
|
242
|
+
}));
|
|
243
|
+
refreshAll();
|
|
244
|
+
} catch (error) {
|
|
245
|
+
setNotice({
|
|
246
|
+
kind: "error",
|
|
247
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
async deleteTask() {
|
|
252
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
253
|
+
const selectedTaskId = nodeState.selectedTaskId;
|
|
254
|
+
if (!selectedIssueId || !selectedTaskId || !confirmIssueManagerMessage(copy.t("confirmations.deleteTask"))) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
await feature.backend.deleteTask({
|
|
259
|
+
issueId: selectedIssueId,
|
|
260
|
+
taskId: selectedTaskId,
|
|
261
|
+
workspaceId
|
|
262
|
+
});
|
|
263
|
+
setNotice({
|
|
264
|
+
kind: "success",
|
|
265
|
+
message: copy.t("messages.taskDeleted")
|
|
266
|
+
});
|
|
267
|
+
setTaskEditorModeState("read");
|
|
268
|
+
updateNodeState((current) => ({
|
|
269
|
+
...current,
|
|
270
|
+
selectedTaskId: null
|
|
271
|
+
}));
|
|
272
|
+
refreshAll();
|
|
273
|
+
} catch (error) {
|
|
274
|
+
setNotice({
|
|
275
|
+
kind: "error",
|
|
276
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
async insertReferences(parentKind) {
|
|
281
|
+
if (!feature.fileAdapter) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (parentKind === "task" && !nodeState.selectedTaskId && taskEditorMode !== "create") {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (feature.fileAdapter.requestReferences && !feature.fileAdapter.listDirectory && !feature.fileAdapter.searchReferences) {
|
|
288
|
+
const refs = await feature.fileAdapter.requestReferences({
|
|
289
|
+
workspaceId
|
|
290
|
+
});
|
|
291
|
+
await submitReferences(refs, createInsertReferenceTarget(parentKind));
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
setReferenceTarget(createInsertReferenceTarget(parentKind));
|
|
295
|
+
},
|
|
296
|
+
async uploadReferences(parentKind, mode) {
|
|
297
|
+
if (!feature.fileAdapter?.requestUpload) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const refs = await feature.fileAdapter.requestUpload({
|
|
301
|
+
mode,
|
|
302
|
+
targetDirectoryPath: "/",
|
|
303
|
+
workspaceId
|
|
304
|
+
});
|
|
305
|
+
if (refs.length === 0) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
await feature.fileAdapter.refreshTree?.({
|
|
309
|
+
depth: 1,
|
|
310
|
+
paths: refs.map((ref) => ref.path),
|
|
311
|
+
workspaceId
|
|
312
|
+
});
|
|
313
|
+
await submitReferences(refs, createInsertReferenceTarget(parentKind));
|
|
314
|
+
},
|
|
315
|
+
async openReference(reference) {
|
|
316
|
+
await feature.fileAdapter?.openReference?.(reference);
|
|
317
|
+
},
|
|
318
|
+
async removeContextRef(ref) {
|
|
319
|
+
try {
|
|
320
|
+
await feature.backend.removeContextRef(
|
|
321
|
+
ref.parentKind === "task" ? {
|
|
322
|
+
contextRefId: ref.contextRefId,
|
|
323
|
+
issueId: ref.issueId,
|
|
324
|
+
parentKind: "task",
|
|
325
|
+
taskId: ref.taskId,
|
|
326
|
+
workspaceId
|
|
327
|
+
} : {
|
|
328
|
+
contextRefId: ref.contextRefId,
|
|
329
|
+
issueId: ref.issueId,
|
|
330
|
+
parentKind: "issue",
|
|
331
|
+
workspaceId
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
refreshDetails();
|
|
335
|
+
} catch (error) {
|
|
336
|
+
setNotice({
|
|
337
|
+
kind: "error",
|
|
338
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
async runTask(providerOverride) {
|
|
343
|
+
if (!issueDetail.value || !taskDetail.value) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const provider = providerOverride?.trim() || nodeState.selectedAgentProvider.trim();
|
|
347
|
+
if (!provider) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (provider !== nodeState.selectedAgentProvider) {
|
|
351
|
+
updateNodeState((current) => ({
|
|
352
|
+
...current,
|
|
353
|
+
selectedAgentProvider: provider
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
setIsRunningTask(true);
|
|
357
|
+
let createdRun = null;
|
|
358
|
+
try {
|
|
359
|
+
const currentUser = await Promise.resolve(
|
|
360
|
+
feature.identityAdapter.currentUser()
|
|
361
|
+
);
|
|
362
|
+
createdRun = await feature.backend.createRun({
|
|
363
|
+
agentProvider: provider,
|
|
364
|
+
agentUserId: currentUser?.userId ?? void 0,
|
|
365
|
+
issueId: issueDetail.value.issue.issueId,
|
|
366
|
+
taskId: taskDetail.value.task.taskId,
|
|
367
|
+
workspaceId
|
|
368
|
+
});
|
|
369
|
+
setNotice({
|
|
370
|
+
kind: "success",
|
|
371
|
+
message: copy.t("messages.runStarted")
|
|
372
|
+
});
|
|
373
|
+
refreshDetails();
|
|
374
|
+
const result = await feature.agentRunner.runTask({
|
|
375
|
+
issue: issueDetail.value.issue,
|
|
376
|
+
provider,
|
|
377
|
+
run: createdRun,
|
|
378
|
+
task: taskDetail.value.task,
|
|
379
|
+
workspaceId
|
|
380
|
+
});
|
|
381
|
+
await feature.backend.completeRun({
|
|
382
|
+
errorMessage: result.errorMessage,
|
|
383
|
+
issueId: issueDetail.value.issue.issueId,
|
|
384
|
+
outputs: result.outputs ?? [],
|
|
385
|
+
runId: createdRun.runId,
|
|
386
|
+
status: result.status,
|
|
387
|
+
summary: result.summary,
|
|
388
|
+
taskId: taskDetail.value.task.taskId,
|
|
389
|
+
workspaceId
|
|
390
|
+
});
|
|
391
|
+
setNotice({
|
|
392
|
+
kind: result.status === "completed" ? "success" : "error",
|
|
393
|
+
message: result.status === "completed" ? copy.t("messages.runCompleted") : copy.t("messages.runFailed")
|
|
394
|
+
});
|
|
395
|
+
} catch (error) {
|
|
396
|
+
const message = resolveIssueManagerErrorMessage(error, copy);
|
|
397
|
+
if (createdRun && issueDetail.value && taskDetail.value) {
|
|
398
|
+
try {
|
|
399
|
+
await feature.backend.completeRun({
|
|
400
|
+
errorMessage: message,
|
|
401
|
+
issueId: issueDetail.value.issue.issueId,
|
|
402
|
+
outputs: [],
|
|
403
|
+
runId: createdRun.runId,
|
|
404
|
+
status: "failed",
|
|
405
|
+
summary: copy.t("run.failedSummaryFallback"),
|
|
406
|
+
taskId: taskDetail.value.task.taskId,
|
|
407
|
+
workspaceId
|
|
408
|
+
});
|
|
409
|
+
} catch {
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
setNotice({
|
|
413
|
+
kind: "error",
|
|
414
|
+
message
|
|
415
|
+
});
|
|
416
|
+
} finally {
|
|
417
|
+
setIsRunningTask(false);
|
|
418
|
+
refreshDetails();
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
async saveIssue() {
|
|
422
|
+
const title = issueDraft.title.trim();
|
|
423
|
+
if (!title) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
const content = normalizeIssueManagerContent(issueDraft.content);
|
|
428
|
+
const savedIssue = issueEditorMode === "create" ? await feature.backend.createIssue({
|
|
429
|
+
content,
|
|
430
|
+
title,
|
|
431
|
+
workspaceId
|
|
432
|
+
}) : await feature.backend.updateIssue({
|
|
433
|
+
content,
|
|
434
|
+
issueId: nodeState.selectedIssueId ?? "",
|
|
435
|
+
title,
|
|
436
|
+
workspaceId
|
|
437
|
+
});
|
|
438
|
+
await syncContentReferences({
|
|
439
|
+
content,
|
|
440
|
+
existingRefs: issueEditorMode === "create" ? [] : issueDetail.value?.contextRefs.filter(
|
|
441
|
+
(ref) => ref.parentKind === "issue"
|
|
442
|
+
) ?? [],
|
|
443
|
+
issueId: savedIssue.issueId,
|
|
444
|
+
parentKind: "issue"
|
|
445
|
+
});
|
|
446
|
+
setIssueEditorModeState("read");
|
|
447
|
+
setNotice({
|
|
448
|
+
kind: "success",
|
|
449
|
+
message: copy.t("messages.issueSaved")
|
|
450
|
+
});
|
|
451
|
+
updateNodeState((current) => ({
|
|
452
|
+
...current,
|
|
453
|
+
issueDraftContent: null,
|
|
454
|
+
issueDraftTitle: null,
|
|
455
|
+
selectedIssueId: savedIssue.issueId
|
|
456
|
+
}));
|
|
457
|
+
refreshAll();
|
|
458
|
+
} catch (error) {
|
|
459
|
+
setNotice({
|
|
460
|
+
kind: "error",
|
|
461
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
async saveTask() {
|
|
466
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
467
|
+
if (!selectedIssueId) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const title = taskDraft.title.trim();
|
|
471
|
+
if (!title) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
const content = normalizeIssueManagerContent(taskDraft.content);
|
|
476
|
+
const savedTask = taskEditorMode === "create" ? await feature.backend.createTask({
|
|
477
|
+
content,
|
|
478
|
+
issueId: selectedIssueId,
|
|
479
|
+
priority: taskDraft.priority,
|
|
480
|
+
title,
|
|
481
|
+
workspaceId
|
|
482
|
+
}) : await feature.backend.updateTask({
|
|
483
|
+
content,
|
|
484
|
+
issueId: selectedIssueId,
|
|
485
|
+
priority: taskDraft.priority,
|
|
486
|
+
taskId: nodeState.selectedTaskId ?? "",
|
|
487
|
+
title,
|
|
488
|
+
workspaceId
|
|
489
|
+
});
|
|
490
|
+
await syncContentReferences({
|
|
491
|
+
content,
|
|
492
|
+
existingRefs: taskEditorMode === "create" ? [] : taskDetail.value?.contextRefs.filter(
|
|
493
|
+
(ref) => ref.parentKind === "task"
|
|
494
|
+
) ?? [],
|
|
495
|
+
issueId: selectedIssueId,
|
|
496
|
+
parentKind: "task",
|
|
497
|
+
taskId: savedTask.taskId
|
|
498
|
+
});
|
|
499
|
+
setTaskEditorModeState("read");
|
|
500
|
+
setNotice({
|
|
501
|
+
kind: "success",
|
|
502
|
+
message: copy.t("messages.taskSaved")
|
|
503
|
+
});
|
|
504
|
+
updateNodeState((current) => ({
|
|
505
|
+
...current,
|
|
506
|
+
selectedTaskId: savedTask.taskId,
|
|
507
|
+
taskDraftContent: null,
|
|
508
|
+
taskDraftTitle: null
|
|
509
|
+
}));
|
|
510
|
+
refreshAll();
|
|
511
|
+
} catch (error) {
|
|
512
|
+
setNotice({
|
|
513
|
+
kind: "error",
|
|
514
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
async shareSelection() {
|
|
519
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
520
|
+
if (!feature.shareAdapter?.createIssueLink || !selectedIssueId) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
try {
|
|
524
|
+
const link = await feature.shareAdapter.createIssueLink({
|
|
525
|
+
issueId: selectedIssueId,
|
|
526
|
+
taskId: nodeState.selectedTaskId ?? void 0,
|
|
527
|
+
workspaceId
|
|
528
|
+
});
|
|
529
|
+
if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
|
|
530
|
+
throw new Error(copy.t("messages.clipboardUnavailable"));
|
|
531
|
+
}
|
|
532
|
+
await navigator.clipboard.writeText(link);
|
|
533
|
+
setNotice({
|
|
534
|
+
kind: "success",
|
|
535
|
+
message: copy.t("messages.copiedShareLink")
|
|
536
|
+
});
|
|
537
|
+
} catch (error) {
|
|
538
|
+
setNotice({
|
|
539
|
+
kind: "error",
|
|
540
|
+
message: resolveIssueManagerErrorMessage(error, copy)
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
async submitReferenceSelection(refs) {
|
|
545
|
+
await submitReferences(refs);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// src/react/internal/controllerState.ts
|
|
551
|
+
function createIssueManagerIssueDraftFromNodeState(state) {
|
|
552
|
+
return {
|
|
553
|
+
content: state?.issueDraftContent ?? "",
|
|
554
|
+
title: state?.issueDraftTitle ?? ""
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function createIssueManagerTaskDraftFromNodeState(state, priority = defaultTaskPriority) {
|
|
558
|
+
return {
|
|
559
|
+
content: state?.taskDraftContent ?? "",
|
|
560
|
+
priority,
|
|
561
|
+
title: state?.taskDraftTitle ?? ""
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function applyIssueManagerIssueSelection(current, issueId) {
|
|
565
|
+
return {
|
|
566
|
+
...current,
|
|
567
|
+
selectedIssueId: issueId,
|
|
568
|
+
selectedTaskId: null
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function applyIssueManagerTaskSelection(current, taskId) {
|
|
572
|
+
return {
|
|
573
|
+
...current,
|
|
574
|
+
selectedTaskId: taskId
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
function applyIssueManagerIssueListResultToNodeState(current, result) {
|
|
578
|
+
return {
|
|
579
|
+
...current,
|
|
580
|
+
issueListNextPageToken: result.nextPageToken ?? null,
|
|
581
|
+
selectedIssueId: resolveIssueManagerSelectedIssueId(
|
|
582
|
+
current.selectedIssueId,
|
|
583
|
+
result.issues
|
|
584
|
+
)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function applyIssueManagerIssueDetailResultToNodeState(current, detail) {
|
|
588
|
+
return {
|
|
589
|
+
...current,
|
|
590
|
+
selectedTaskId: resolveIssueManagerSelectedTaskId(
|
|
591
|
+
current.selectedTaskId,
|
|
592
|
+
detail.tasks
|
|
593
|
+
)
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
function syncIssueManagerIssueDraftFromDetail(current, detail, editorMode) {
|
|
597
|
+
if (editorMode !== "read") {
|
|
598
|
+
return current;
|
|
599
|
+
}
|
|
600
|
+
return {
|
|
601
|
+
content: normalizeIssueManagerContent(detail?.issue.content ?? ""),
|
|
602
|
+
title: detail?.issue.title ?? ""
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function syncIssueManagerTaskDraftFromDetail(current, detail, editorMode) {
|
|
606
|
+
if (editorMode !== "read") {
|
|
607
|
+
return current;
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
content: normalizeIssueManagerContent(detail?.task.content ?? ""),
|
|
611
|
+
priority: detail?.task.priority ?? defaultTaskPriority,
|
|
612
|
+
title: detail?.task.title ?? ""
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
function applyIssueManagerIssueEditorModeToNodeState(current, editorMode) {
|
|
616
|
+
if (editorMode === "create") {
|
|
617
|
+
return current;
|
|
618
|
+
}
|
|
619
|
+
return {
|
|
620
|
+
...current,
|
|
621
|
+
issueDraftContent: null,
|
|
622
|
+
issueDraftTitle: null
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function applyIssueManagerTaskEditorModeToNodeState(current, editorMode) {
|
|
626
|
+
if (editorMode === "create") {
|
|
627
|
+
return current;
|
|
628
|
+
}
|
|
629
|
+
return {
|
|
630
|
+
...current,
|
|
631
|
+
taskDraftContent: null,
|
|
632
|
+
taskDraftTitle: null
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function persistIssueManagerIssueDraftContent(current, editorMode, content) {
|
|
636
|
+
if (editorMode !== "create") {
|
|
637
|
+
return current;
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
...current,
|
|
641
|
+
issueDraftContent: content
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function persistIssueManagerIssueDraftTitle(current, editorMode, title) {
|
|
645
|
+
if (editorMode !== "create") {
|
|
646
|
+
return current;
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
...current,
|
|
650
|
+
issueDraftTitle: title
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function persistIssueManagerTaskDraftContent(current, editorMode, content) {
|
|
654
|
+
if (editorMode !== "create") {
|
|
655
|
+
return current;
|
|
656
|
+
}
|
|
657
|
+
return {
|
|
658
|
+
...current,
|
|
659
|
+
taskDraftContent: content
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function persistIssueManagerTaskDraftTitle(current, editorMode, title) {
|
|
663
|
+
if (editorMode !== "create") {
|
|
664
|
+
return current;
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
...current,
|
|
668
|
+
taskDraftTitle: title
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/react/internal/useIssueManagerController.ts
|
|
673
|
+
var issueManagerProviderOptions = ["codex"];
|
|
674
|
+
function useIssueManagerController({
|
|
675
|
+
feature,
|
|
676
|
+
onStateChange,
|
|
677
|
+
state,
|
|
678
|
+
workspaceId
|
|
679
|
+
}) {
|
|
680
|
+
const copy = feature.i18n;
|
|
681
|
+
const [nodeState, setNodeStateInternal] = useState(
|
|
682
|
+
() => normalizeIssueManagerNodeState(state)
|
|
683
|
+
);
|
|
684
|
+
const [issueEditorMode, setIssueEditorModeState] = useState("read");
|
|
685
|
+
const [taskEditorMode, setTaskEditorModeState] = useState("read");
|
|
686
|
+
const [issueDraft, setIssueDraftInternal] = useState(
|
|
687
|
+
() => createIssueManagerIssueDraftFromNodeState(nodeState)
|
|
688
|
+
);
|
|
689
|
+
const [taskDraft, setTaskDraftInternal] = useState(
|
|
690
|
+
() => createIssueManagerTaskDraftFromNodeState(nodeState)
|
|
691
|
+
);
|
|
692
|
+
const [issueReloadToken, setIssueReloadToken] = useState(0);
|
|
693
|
+
const [detailReloadToken, setDetailReloadToken] = useState(0);
|
|
694
|
+
const [notice, setNotice] = useState(null);
|
|
695
|
+
const [isRunningTask, setIsRunningTask] = useState(false);
|
|
696
|
+
const [referenceTarget, setReferenceTarget] = useState(null);
|
|
697
|
+
const [issues, setIssues] = useState({
|
|
698
|
+
error: null,
|
|
699
|
+
isLoading: false,
|
|
700
|
+
value: []
|
|
701
|
+
});
|
|
702
|
+
const [issueDetail, setIssueDetail] = useState({
|
|
703
|
+
error: null,
|
|
704
|
+
isLoading: false,
|
|
705
|
+
value: null
|
|
706
|
+
});
|
|
707
|
+
const [taskDetail, setTaskDetail] = useState({
|
|
708
|
+
error: null,
|
|
709
|
+
isLoading: false,
|
|
710
|
+
value: null
|
|
711
|
+
});
|
|
712
|
+
const deferredIssueSearch = useDeferredValue(nodeState.issueSearchQuery);
|
|
713
|
+
const canReferenceWorkspaceFiles = hasFileAdapterMethod(feature.fileAdapter, "requestReferences") || hasFileAdapterMethod(feature.fileAdapter, "listDirectory") || hasFileAdapterMethod(feature.fileAdapter, "searchReferences");
|
|
714
|
+
const canUploadWorkspaceFiles = hasFileAdapterMethod(
|
|
715
|
+
feature.fileAdapter,
|
|
716
|
+
"requestUpload"
|
|
717
|
+
);
|
|
718
|
+
const updateNodeState = (updater) => {
|
|
719
|
+
setNodeStateInternal((current) => {
|
|
720
|
+
const next = typeof updater === "function" ? updater(current) : {
|
|
721
|
+
...current,
|
|
722
|
+
...updater
|
|
723
|
+
};
|
|
724
|
+
onStateChange?.(next);
|
|
725
|
+
return next;
|
|
726
|
+
});
|
|
727
|
+
};
|
|
728
|
+
const refreshIssues = () => {
|
|
729
|
+
setIssueReloadToken((current) => current + 1);
|
|
730
|
+
};
|
|
731
|
+
const refreshDetails = () => {
|
|
732
|
+
setDetailReloadToken((current) => current + 1);
|
|
733
|
+
};
|
|
734
|
+
const refreshAll = () => {
|
|
735
|
+
refreshIssues();
|
|
736
|
+
refreshDetails();
|
|
737
|
+
};
|
|
738
|
+
useEffect(() => {
|
|
739
|
+
const normalized = normalizeIssueManagerNodeState(state);
|
|
740
|
+
setNodeStateInternal(normalized);
|
|
741
|
+
setIssueDraftInternal(
|
|
742
|
+
createIssueManagerIssueDraftFromNodeState(normalized)
|
|
743
|
+
);
|
|
744
|
+
setTaskDraftInternal((current) => ({
|
|
745
|
+
...createIssueManagerTaskDraftFromNodeState(normalized, current.priority)
|
|
746
|
+
}));
|
|
747
|
+
}, [workspaceId]);
|
|
748
|
+
useEffect(() => {
|
|
749
|
+
let canceled = false;
|
|
750
|
+
setIssues((current) => ({
|
|
751
|
+
...current,
|
|
752
|
+
error: null,
|
|
753
|
+
isLoading: true
|
|
754
|
+
}));
|
|
755
|
+
void feature.backend.listIssues({
|
|
756
|
+
searchQuery: deferredIssueSearch || void 0,
|
|
757
|
+
statusFilter: nodeState.issueStatusFilter,
|
|
758
|
+
workspaceId
|
|
759
|
+
}).then((result) => {
|
|
760
|
+
if (canceled) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
setIssues({
|
|
764
|
+
error: null,
|
|
765
|
+
isLoading: false,
|
|
766
|
+
value: result.issues
|
|
767
|
+
});
|
|
768
|
+
updateNodeState(
|
|
769
|
+
(current) => applyIssueManagerIssueListResultToNodeState(current, result)
|
|
770
|
+
);
|
|
771
|
+
}).catch((error) => {
|
|
772
|
+
if (canceled) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
setIssues({
|
|
776
|
+
error: resolveIssueManagerErrorMessage(error, copy),
|
|
777
|
+
isLoading: false,
|
|
778
|
+
value: []
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
return () => {
|
|
782
|
+
canceled = true;
|
|
783
|
+
};
|
|
784
|
+
}, [
|
|
785
|
+
copy,
|
|
786
|
+
deferredIssueSearch,
|
|
787
|
+
feature.backend,
|
|
788
|
+
issueReloadToken,
|
|
789
|
+
nodeState.issueStatusFilter,
|
|
790
|
+
workspaceId
|
|
791
|
+
]);
|
|
792
|
+
useEffect(() => {
|
|
793
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
794
|
+
if (!selectedIssueId) {
|
|
795
|
+
setIssueDetail({
|
|
796
|
+
error: null,
|
|
797
|
+
isLoading: false,
|
|
798
|
+
value: null
|
|
799
|
+
});
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
let canceled = false;
|
|
803
|
+
setIssueDetail((current) => ({
|
|
804
|
+
...current,
|
|
805
|
+
error: null,
|
|
806
|
+
isLoading: true
|
|
807
|
+
}));
|
|
808
|
+
void feature.backend.getIssueDetail({
|
|
809
|
+
issueId: selectedIssueId,
|
|
810
|
+
workspaceId
|
|
811
|
+
}).then((result) => {
|
|
812
|
+
if (canceled) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
setIssueDetail({
|
|
816
|
+
error: null,
|
|
817
|
+
isLoading: false,
|
|
818
|
+
value: result
|
|
819
|
+
});
|
|
820
|
+
updateNodeState(
|
|
821
|
+
(current) => applyIssueManagerIssueDetailResultToNodeState(current, result)
|
|
822
|
+
);
|
|
823
|
+
}).catch((error) => {
|
|
824
|
+
if (canceled) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
setIssueDetail({
|
|
828
|
+
error: resolveIssueManagerErrorMessage(error, copy),
|
|
829
|
+
isLoading: false,
|
|
830
|
+
value: null
|
|
831
|
+
});
|
|
832
|
+
});
|
|
833
|
+
return () => {
|
|
834
|
+
canceled = true;
|
|
835
|
+
};
|
|
836
|
+
}, [
|
|
837
|
+
copy,
|
|
838
|
+
detailReloadToken,
|
|
839
|
+
feature.backend,
|
|
840
|
+
nodeState.selectedIssueId,
|
|
841
|
+
workspaceId
|
|
842
|
+
]);
|
|
843
|
+
useEffect(() => {
|
|
844
|
+
const selectedIssueId = nodeState.selectedIssueId;
|
|
845
|
+
const selectedTaskId = nodeState.selectedTaskId;
|
|
846
|
+
if (!selectedIssueId || !selectedTaskId) {
|
|
847
|
+
setTaskDetail({
|
|
848
|
+
error: null,
|
|
849
|
+
isLoading: false,
|
|
850
|
+
value: null
|
|
851
|
+
});
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
let canceled = false;
|
|
855
|
+
setTaskDetail((current) => ({
|
|
856
|
+
...current,
|
|
857
|
+
error: null,
|
|
858
|
+
isLoading: true
|
|
859
|
+
}));
|
|
860
|
+
void feature.backend.getTaskDetail({
|
|
861
|
+
issueId: selectedIssueId,
|
|
862
|
+
taskId: selectedTaskId,
|
|
863
|
+
workspaceId
|
|
864
|
+
}).then((result) => {
|
|
865
|
+
if (canceled) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
setTaskDetail({
|
|
869
|
+
error: null,
|
|
870
|
+
isLoading: false,
|
|
871
|
+
value: result
|
|
872
|
+
});
|
|
873
|
+
}).catch((error) => {
|
|
874
|
+
if (canceled) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
setTaskDetail({
|
|
878
|
+
error: resolveIssueManagerErrorMessage(error, copy),
|
|
879
|
+
isLoading: false,
|
|
880
|
+
value: null
|
|
881
|
+
});
|
|
882
|
+
});
|
|
883
|
+
return () => {
|
|
884
|
+
canceled = true;
|
|
885
|
+
};
|
|
886
|
+
}, [
|
|
887
|
+
copy,
|
|
888
|
+
detailReloadToken,
|
|
889
|
+
feature.backend,
|
|
890
|
+
nodeState.selectedIssueId,
|
|
891
|
+
nodeState.selectedTaskId,
|
|
892
|
+
workspaceId
|
|
893
|
+
]);
|
|
894
|
+
useEffect(() => {
|
|
895
|
+
setIssueDraftInternal(
|
|
896
|
+
(current) => syncIssueManagerIssueDraftFromDetail(
|
|
897
|
+
current,
|
|
898
|
+
issueDetail.value,
|
|
899
|
+
issueEditorMode
|
|
900
|
+
)
|
|
901
|
+
);
|
|
902
|
+
}, [
|
|
903
|
+
issueDetail.value?.issue.content,
|
|
904
|
+
issueDetail.value?.issue.title,
|
|
905
|
+
issueEditorMode
|
|
906
|
+
]);
|
|
907
|
+
useEffect(() => {
|
|
908
|
+
setTaskDraftInternal(
|
|
909
|
+
(current) => syncIssueManagerTaskDraftFromDetail(
|
|
910
|
+
current,
|
|
911
|
+
taskDetail.value,
|
|
912
|
+
taskEditorMode
|
|
913
|
+
)
|
|
914
|
+
);
|
|
915
|
+
}, [
|
|
916
|
+
taskDetail.value?.task.content,
|
|
917
|
+
taskDetail.value?.task.priority,
|
|
918
|
+
taskDetail.value?.task.title,
|
|
919
|
+
taskEditorMode
|
|
920
|
+
]);
|
|
921
|
+
const actions = createIssueManagerControllerActions({
|
|
922
|
+
copy,
|
|
923
|
+
feature,
|
|
924
|
+
issueDetail,
|
|
925
|
+
issueDraft,
|
|
926
|
+
issueEditorMode,
|
|
927
|
+
nodeState,
|
|
928
|
+
referenceTarget,
|
|
929
|
+
refreshAll,
|
|
930
|
+
refreshDetails,
|
|
931
|
+
setIsRunningTask,
|
|
932
|
+
setIssueDraftInternal,
|
|
933
|
+
setIssueEditorModeState,
|
|
934
|
+
setNotice,
|
|
935
|
+
setReferenceTarget,
|
|
936
|
+
setTaskDraftInternal,
|
|
937
|
+
setTaskEditorModeState,
|
|
938
|
+
taskDetail,
|
|
939
|
+
taskDraft,
|
|
940
|
+
taskEditorMode,
|
|
941
|
+
updateNodeState,
|
|
942
|
+
workspaceId
|
|
943
|
+
});
|
|
944
|
+
return {
|
|
945
|
+
...actions,
|
|
946
|
+
canReferenceWorkspaceFiles,
|
|
947
|
+
canUploadWorkspaceFiles,
|
|
948
|
+
clearNotice() {
|
|
949
|
+
setNotice(null);
|
|
950
|
+
},
|
|
951
|
+
copy,
|
|
952
|
+
issueDetail,
|
|
953
|
+
issueDraft,
|
|
954
|
+
issueEditorMode,
|
|
955
|
+
issues,
|
|
956
|
+
isRunningTask,
|
|
957
|
+
nodeState,
|
|
958
|
+
notice,
|
|
959
|
+
providerOptions: issueManagerProviderOptions,
|
|
960
|
+
refreshAll,
|
|
961
|
+
referenceTarget,
|
|
962
|
+
selectIssue(issueId) {
|
|
963
|
+
updateNodeState(
|
|
964
|
+
(current) => applyIssueManagerIssueSelection(current, issueId)
|
|
965
|
+
);
|
|
966
|
+
setIssueEditorModeState("read");
|
|
967
|
+
setTaskEditorModeState("read");
|
|
968
|
+
},
|
|
969
|
+
selectTask(taskId) {
|
|
970
|
+
updateNodeState(
|
|
971
|
+
(current) => applyIssueManagerTaskSelection(current, taskId)
|
|
972
|
+
);
|
|
973
|
+
setTaskEditorModeState("read");
|
|
974
|
+
},
|
|
975
|
+
setIssueContent(content) {
|
|
976
|
+
setIssueDraftInternal((current) => ({
|
|
977
|
+
...current,
|
|
978
|
+
content
|
|
979
|
+
}));
|
|
980
|
+
updateNodeState(
|
|
981
|
+
(current) => persistIssueManagerIssueDraftContent(current, issueEditorMode, content)
|
|
982
|
+
);
|
|
983
|
+
},
|
|
984
|
+
setIssueDraft(patch) {
|
|
985
|
+
setIssueDraftInternal((current) => ({
|
|
986
|
+
...current,
|
|
987
|
+
...patch
|
|
988
|
+
}));
|
|
989
|
+
},
|
|
990
|
+
setIssueEditorMode(mode) {
|
|
991
|
+
setIssueEditorModeState(mode);
|
|
992
|
+
if (mode === "create") {
|
|
993
|
+
setIssueDraftInternal(
|
|
994
|
+
createIssueManagerIssueDraftFromNodeState(nodeState)
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
updateNodeState(
|
|
998
|
+
(current) => applyIssueManagerIssueEditorModeToNodeState(current, mode)
|
|
999
|
+
);
|
|
1000
|
+
},
|
|
1001
|
+
setIssueSearchQuery(query) {
|
|
1002
|
+
updateNodeState((current) => ({
|
|
1003
|
+
...current,
|
|
1004
|
+
issueSearchQuery: query
|
|
1005
|
+
}));
|
|
1006
|
+
},
|
|
1007
|
+
setIssueStatusFilter(value) {
|
|
1008
|
+
updateNodeState((current) => ({
|
|
1009
|
+
...current,
|
|
1010
|
+
issueStatusFilter: value
|
|
1011
|
+
}));
|
|
1012
|
+
},
|
|
1013
|
+
setIssueTitle(title) {
|
|
1014
|
+
setIssueDraftInternal((current) => ({
|
|
1015
|
+
...current,
|
|
1016
|
+
title
|
|
1017
|
+
}));
|
|
1018
|
+
updateNodeState(
|
|
1019
|
+
(current) => persistIssueManagerIssueDraftTitle(current, issueEditorMode, title)
|
|
1020
|
+
);
|
|
1021
|
+
},
|
|
1022
|
+
setReferenceTarget,
|
|
1023
|
+
setSelectedAgentProvider(provider) {
|
|
1024
|
+
updateNodeState((current) => ({
|
|
1025
|
+
...current,
|
|
1026
|
+
selectedAgentProvider: provider
|
|
1027
|
+
}));
|
|
1028
|
+
},
|
|
1029
|
+
setTaskContent(content) {
|
|
1030
|
+
setTaskDraftInternal((current) => ({
|
|
1031
|
+
...current,
|
|
1032
|
+
content
|
|
1033
|
+
}));
|
|
1034
|
+
updateNodeState(
|
|
1035
|
+
(current) => persistIssueManagerTaskDraftContent(current, taskEditorMode, content)
|
|
1036
|
+
);
|
|
1037
|
+
},
|
|
1038
|
+
setTaskDraft(patch) {
|
|
1039
|
+
setTaskDraftInternal((current) => ({
|
|
1040
|
+
...current,
|
|
1041
|
+
...patch
|
|
1042
|
+
}));
|
|
1043
|
+
},
|
|
1044
|
+
setTaskEditorMode(mode) {
|
|
1045
|
+
setTaskEditorModeState(mode);
|
|
1046
|
+
if (mode === "create") {
|
|
1047
|
+
setTaskDraftInternal(
|
|
1048
|
+
createIssueManagerTaskDraftFromNodeState(nodeState)
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
updateNodeState(
|
|
1052
|
+
(current) => applyIssueManagerTaskEditorModeToNodeState(current, mode)
|
|
1053
|
+
);
|
|
1054
|
+
},
|
|
1055
|
+
setTaskPriority(priority) {
|
|
1056
|
+
setTaskDraftInternal((current) => ({
|
|
1057
|
+
...current,
|
|
1058
|
+
priority
|
|
1059
|
+
}));
|
|
1060
|
+
},
|
|
1061
|
+
setTaskTitle(title) {
|
|
1062
|
+
setTaskDraftInternal((current) => ({
|
|
1063
|
+
...current,
|
|
1064
|
+
title
|
|
1065
|
+
}));
|
|
1066
|
+
updateNodeState(
|
|
1067
|
+
(current) => persistIssueManagerTaskDraftTitle(current, taskEditorMode, title)
|
|
1068
|
+
);
|
|
1069
|
+
},
|
|
1070
|
+
taskDetail,
|
|
1071
|
+
taskDraft,
|
|
1072
|
+
taskEditorMode
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
function hasFileAdapterMethod(fileAdapter, methodName) {
|
|
1076
|
+
return typeof Reflect.get(fileAdapter ?? {}, methodName) === "function";
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// src/react/internal/IssueManagerReferencePicker.tsx
|
|
1080
|
+
import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
1081
|
+
import { createPortal } from "react-dom";
|
|
1082
|
+
import {
|
|
1083
|
+
Badge,
|
|
1084
|
+
Button,
|
|
1085
|
+
Card,
|
|
1086
|
+
CardContent,
|
|
1087
|
+
CardDescription,
|
|
1088
|
+
CardHeader,
|
|
1089
|
+
CardTitle,
|
|
1090
|
+
DirectoryIcon,
|
|
1091
|
+
FileIcon,
|
|
1092
|
+
Input,
|
|
1093
|
+
LoadingIcon,
|
|
1094
|
+
ScrollArea,
|
|
1095
|
+
SearchIcon,
|
|
1096
|
+
UploadIcon,
|
|
1097
|
+
cn
|
|
1098
|
+
} from "@nextop-os/ui-system";
|
|
1099
|
+
|
|
1100
|
+
// src/react/internal/model.ts
|
|
1101
|
+
function createIssueManagerDate(value) {
|
|
1102
|
+
if (!value || !Number.isFinite(value)) {
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
const normalized = value < 1e12 ? value * 1e3 : value;
|
|
1106
|
+
const date = new Date(normalized);
|
|
1107
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
1108
|
+
}
|
|
1109
|
+
function formatIssueManagerTimestamp(value) {
|
|
1110
|
+
return createIssueManagerDate(value)?.toLocaleString() ?? null;
|
|
1111
|
+
}
|
|
1112
|
+
function formatIssueManagerDate(value) {
|
|
1113
|
+
return createIssueManagerDate(value)?.toLocaleDateString() ?? "";
|
|
1114
|
+
}
|
|
1115
|
+
function resolveIssueManagerStatusLabel(copy, status) {
|
|
1116
|
+
switch (status) {
|
|
1117
|
+
case "not_started":
|
|
1118
|
+
return copy.t("status.notStarted");
|
|
1119
|
+
case "running":
|
|
1120
|
+
return copy.t("status.running");
|
|
1121
|
+
case "pending_acceptance":
|
|
1122
|
+
return copy.t("status.pendingAcceptance");
|
|
1123
|
+
case "completed":
|
|
1124
|
+
return copy.t("status.completed");
|
|
1125
|
+
case "failed":
|
|
1126
|
+
return copy.t("status.failed");
|
|
1127
|
+
case "canceled":
|
|
1128
|
+
return copy.t("status.canceled");
|
|
1129
|
+
default:
|
|
1130
|
+
return copy.t("status.unknown");
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
function resolveIssueManagerPriorityLabel(copy, priority) {
|
|
1134
|
+
switch (priority) {
|
|
1135
|
+
case "high":
|
|
1136
|
+
return copy.t("priority.high");
|
|
1137
|
+
case "low":
|
|
1138
|
+
return copy.t("priority.low");
|
|
1139
|
+
default:
|
|
1140
|
+
return copy.t("priority.medium");
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
function uniqueIssueManagerFileReferences(refs) {
|
|
1144
|
+
const unique = /* @__PURE__ */ new Map();
|
|
1145
|
+
for (const ref of refs) {
|
|
1146
|
+
const normalizedPath = ref.path.trim();
|
|
1147
|
+
if (!normalizedPath || unique.has(normalizedPath)) {
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
unique.set(normalizedPath, {
|
|
1151
|
+
displayName: ref.displayName?.trim() || void 0,
|
|
1152
|
+
kind: ref.kind === "folder" ? "folder" : "file",
|
|
1153
|
+
path: normalizedPath
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
return [...unique.values()];
|
|
1157
|
+
}
|
|
1158
|
+
function parentDirectoryPath(path) {
|
|
1159
|
+
const trimmed = path.trim();
|
|
1160
|
+
if (!trimmed || trimmed === "/") {
|
|
1161
|
+
return null;
|
|
1162
|
+
}
|
|
1163
|
+
const normalized = trimmed.endsWith("/") && trimmed.length > 1 ? trimmed.slice(0, -1) : trimmed;
|
|
1164
|
+
const index = normalized.lastIndexOf("/");
|
|
1165
|
+
if (index <= 0) {
|
|
1166
|
+
return "/";
|
|
1167
|
+
}
|
|
1168
|
+
return normalized.slice(0, index) || "/";
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/react/internal/IssueManagerReferencePicker.tsx
|
|
1172
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1173
|
+
var defaultDirectoryPath = "/";
|
|
1174
|
+
function IssueManagerReferencePicker({
|
|
1175
|
+
copy,
|
|
1176
|
+
fileAdapter,
|
|
1177
|
+
onClose,
|
|
1178
|
+
onConfirm,
|
|
1179
|
+
open,
|
|
1180
|
+
workspaceId
|
|
1181
|
+
}) {
|
|
1182
|
+
const [currentPath, setCurrentPath] = useState2(defaultDirectoryPath);
|
|
1183
|
+
const [searchQuery, setSearchQuery] = useState2("");
|
|
1184
|
+
const [entries, setEntries] = useState2([]);
|
|
1185
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
1186
|
+
const [selectedRefs, setSelectedRefs] = useState2(
|
|
1187
|
+
[]
|
|
1188
|
+
);
|
|
1189
|
+
const supportsSearch = hasFileAdapterMethod2(fileAdapter, "searchReferences");
|
|
1190
|
+
const supportsBrowse = hasFileAdapterMethod2(fileAdapter, "listDirectory");
|
|
1191
|
+
const mode = searchQuery.trim().length > 0 && supportsSearch ? "search" : "browse";
|
|
1192
|
+
const canUpload = hasFileAdapterMethod2(fileAdapter, "requestUpload");
|
|
1193
|
+
const parentPath = useMemo(
|
|
1194
|
+
() => parentDirectoryPath(currentPath),
|
|
1195
|
+
[currentPath]
|
|
1196
|
+
);
|
|
1197
|
+
useEffect2(() => {
|
|
1198
|
+
if (!open) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
setSearchQuery("");
|
|
1202
|
+
setCurrentPath(defaultDirectoryPath);
|
|
1203
|
+
setSelectedRefs([]);
|
|
1204
|
+
}, [open]);
|
|
1205
|
+
useEffect2(() => {
|
|
1206
|
+
if (!open || !fileAdapter) {
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
let canceled = false;
|
|
1210
|
+
const load = async () => {
|
|
1211
|
+
setIsLoading(true);
|
|
1212
|
+
try {
|
|
1213
|
+
if (mode === "search" && fileAdapter.searchReferences) {
|
|
1214
|
+
const refs = await fileAdapter.searchReferences({
|
|
1215
|
+
query: searchQuery.trim(),
|
|
1216
|
+
workspaceId
|
|
1217
|
+
});
|
|
1218
|
+
if (!canceled) {
|
|
1219
|
+
setEntries(uniqueIssueManagerFileReferences(refs));
|
|
1220
|
+
}
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
if (mode === "browse" && fileAdapter.listDirectory) {
|
|
1224
|
+
const listing = await fileAdapter.listDirectory({
|
|
1225
|
+
path: currentPath,
|
|
1226
|
+
workspaceId
|
|
1227
|
+
});
|
|
1228
|
+
if (!canceled) {
|
|
1229
|
+
setCurrentPath(listing.directoryPath || defaultDirectoryPath);
|
|
1230
|
+
setEntries(uniqueIssueManagerFileReferences(listing.entries));
|
|
1231
|
+
}
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
if (fileAdapter.requestReferences) {
|
|
1235
|
+
const refs = await fileAdapter.requestReferences({ workspaceId });
|
|
1236
|
+
if (!canceled) {
|
|
1237
|
+
onConfirm(uniqueIssueManagerFileReferences(refs));
|
|
1238
|
+
onClose();
|
|
1239
|
+
}
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
if (!canceled) {
|
|
1243
|
+
setEntries([]);
|
|
1244
|
+
}
|
|
1245
|
+
} finally {
|
|
1246
|
+
if (!canceled) {
|
|
1247
|
+
setIsLoading(false);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
void load();
|
|
1252
|
+
return () => {
|
|
1253
|
+
canceled = true;
|
|
1254
|
+
};
|
|
1255
|
+
}, [
|
|
1256
|
+
currentPath,
|
|
1257
|
+
fileAdapter,
|
|
1258
|
+
mode,
|
|
1259
|
+
onClose,
|
|
1260
|
+
onConfirm,
|
|
1261
|
+
open,
|
|
1262
|
+
searchQuery,
|
|
1263
|
+
workspaceId
|
|
1264
|
+
]);
|
|
1265
|
+
if (!open) {
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
const toggleRef = (ref) => {
|
|
1269
|
+
setSelectedRefs((current) => {
|
|
1270
|
+
const existing = current.some((item) => item.path === ref.path);
|
|
1271
|
+
return existing ? current.filter((item) => item.path !== ref.path) : uniqueIssueManagerFileReferences([...current, ref]);
|
|
1272
|
+
});
|
|
1273
|
+
};
|
|
1274
|
+
const upload = async (mode2) => {
|
|
1275
|
+
if (!fileAdapter?.requestUpload) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
const refs = await fileAdapter.requestUpload({
|
|
1279
|
+
mode: mode2,
|
|
1280
|
+
targetDirectoryPath: currentPath,
|
|
1281
|
+
workspaceId
|
|
1282
|
+
});
|
|
1283
|
+
setSelectedRefs(
|
|
1284
|
+
(current) => uniqueIssueManagerFileReferences([...current, ...refs])
|
|
1285
|
+
);
|
|
1286
|
+
};
|
|
1287
|
+
const dialog = /* @__PURE__ */ jsx(
|
|
1288
|
+
"div",
|
|
1289
|
+
{
|
|
1290
|
+
className: "fixed inset-0 grid place-items-center bg-black/26 px-4 backdrop-blur-sm",
|
|
1291
|
+
style: { zIndex: "var(--z-panel)" },
|
|
1292
|
+
onClick: onClose,
|
|
1293
|
+
children: /* @__PURE__ */ jsxs(
|
|
1294
|
+
Card,
|
|
1295
|
+
{
|
|
1296
|
+
"aria-modal": "true",
|
|
1297
|
+
className: "w-full max-w-4xl border-border/70 bg-popover/96 shadow-[var(--workbench-window-elevation)]",
|
|
1298
|
+
role: "dialog",
|
|
1299
|
+
onClick: (event) => event.stopPropagation(),
|
|
1300
|
+
children: [
|
|
1301
|
+
/* @__PURE__ */ jsxs(CardHeader, { className: "gap-3 border-b border-border/70", children: [
|
|
1302
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
|
|
1303
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
1304
|
+
/* @__PURE__ */ jsx(CardTitle, { children: copy.t("referencePicker.title") }),
|
|
1305
|
+
/* @__PURE__ */ jsx(CardDescription, { children: copy.t("referencePicker.selectedCount", {
|
|
1306
|
+
count: selectedRefs.length
|
|
1307
|
+
}) })
|
|
1308
|
+
] }),
|
|
1309
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1310
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onClose, children: copy.t("actions.cancel") }),
|
|
1311
|
+
/* @__PURE__ */ jsx(
|
|
1312
|
+
Button,
|
|
1313
|
+
{
|
|
1314
|
+
disabled: selectedRefs.length === 0,
|
|
1315
|
+
type: "button",
|
|
1316
|
+
onClick: () => onConfirm(selectedRefs),
|
|
1317
|
+
children: copy.t("referencePicker.confirm")
|
|
1318
|
+
}
|
|
1319
|
+
)
|
|
1320
|
+
] })
|
|
1321
|
+
] }),
|
|
1322
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1323
|
+
/* @__PURE__ */ jsxs("div", { className: "relative min-w-[16rem] flex-1", children: [
|
|
1324
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
1325
|
+
/* @__PURE__ */ jsx(
|
|
1326
|
+
Input,
|
|
1327
|
+
{
|
|
1328
|
+
className: "pl-8",
|
|
1329
|
+
placeholder: copy.t("referencePicker.searchPlaceholder"),
|
|
1330
|
+
value: searchQuery,
|
|
1331
|
+
onChange: (event) => setSearchQuery(event.target.value)
|
|
1332
|
+
}
|
|
1333
|
+
)
|
|
1334
|
+
] }),
|
|
1335
|
+
mode === "browse" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1336
|
+
/* @__PURE__ */ jsx(Badge, { className: "border-border/70 bg-background/80 text-muted-foreground", children: currentPath }),
|
|
1337
|
+
parentPath ? /* @__PURE__ */ jsx(
|
|
1338
|
+
Button,
|
|
1339
|
+
{
|
|
1340
|
+
size: "sm",
|
|
1341
|
+
type: "button",
|
|
1342
|
+
variant: "outline",
|
|
1343
|
+
onClick: () => setCurrentPath(parentPath),
|
|
1344
|
+
children: ".."
|
|
1345
|
+
}
|
|
1346
|
+
) : null
|
|
1347
|
+
] }) : null,
|
|
1348
|
+
canUpload ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1349
|
+
/* @__PURE__ */ jsxs(
|
|
1350
|
+
Button,
|
|
1351
|
+
{
|
|
1352
|
+
size: "sm",
|
|
1353
|
+
type: "button",
|
|
1354
|
+
variant: "outline",
|
|
1355
|
+
onClick: () => {
|
|
1356
|
+
void upload("files");
|
|
1357
|
+
},
|
|
1358
|
+
children: [
|
|
1359
|
+
/* @__PURE__ */ jsx(UploadIcon, { className: "size-3.5" }),
|
|
1360
|
+
copy.t("actions.uploadFiles")
|
|
1361
|
+
]
|
|
1362
|
+
}
|
|
1363
|
+
),
|
|
1364
|
+
/* @__PURE__ */ jsxs(
|
|
1365
|
+
Button,
|
|
1366
|
+
{
|
|
1367
|
+
size: "sm",
|
|
1368
|
+
type: "button",
|
|
1369
|
+
variant: "outline",
|
|
1370
|
+
onClick: () => {
|
|
1371
|
+
void upload("folder");
|
|
1372
|
+
},
|
|
1373
|
+
children: [
|
|
1374
|
+
/* @__PURE__ */ jsx(UploadIcon, { className: "size-3.5" }),
|
|
1375
|
+
copy.t("actions.uploadFolder")
|
|
1376
|
+
]
|
|
1377
|
+
}
|
|
1378
|
+
)
|
|
1379
|
+
] }) : null
|
|
1380
|
+
] })
|
|
1381
|
+
] }),
|
|
1382
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "grid min-h-[26rem] gap-4 pt-4 lg:grid-cols-[minmax(0,1fr)_18rem]", children: [
|
|
1383
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 rounded-xl border border-border/70 bg-background/72", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col p-2", children: isLoading ? /* @__PURE__ */ jsx(PickerFeedback, { children: /* @__PURE__ */ jsx(LoadingIcon, { className: "size-4 animate-spin" }) }) : entries.length === 0 ? /* @__PURE__ */ jsx(PickerFeedback, { children: mode === "search" ? copy.t("referencePicker.emptySearch") : copy.t("referencePicker.emptyDirectory") }) : entries.map((entry) => {
|
|
1384
|
+
const selected = selectedRefs.some(
|
|
1385
|
+
(item) => item.path === entry.path
|
|
1386
|
+
);
|
|
1387
|
+
const isFolder = entry.kind === "folder";
|
|
1388
|
+
return /* @__PURE__ */ jsxs(
|
|
1389
|
+
"div",
|
|
1390
|
+
{
|
|
1391
|
+
className: cn(
|
|
1392
|
+
"grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 rounded-lg px-2 py-1.5",
|
|
1393
|
+
selected && "bg-primary/[0.08]"
|
|
1394
|
+
),
|
|
1395
|
+
children: [
|
|
1396
|
+
/* @__PURE__ */ jsxs(
|
|
1397
|
+
"button",
|
|
1398
|
+
{
|
|
1399
|
+
className: "flex min-w-0 items-center gap-2 rounded-md px-2 py-1 text-left text-sm text-foreground hover:bg-accent/75",
|
|
1400
|
+
type: "button",
|
|
1401
|
+
onClick: () => {
|
|
1402
|
+
if (isFolder && mode === "browse" && supportsBrowse) {
|
|
1403
|
+
setCurrentPath(entry.path);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
toggleRef(entry);
|
|
1407
|
+
},
|
|
1408
|
+
children: [
|
|
1409
|
+
isFolder ? /* @__PURE__ */ jsx(DirectoryIcon, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(FileIcon, { className: "size-4 text-muted-foreground" }),
|
|
1410
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: entry.displayName || entry.path.split("/").filter(Boolean).at(-1) || entry.path })
|
|
1411
|
+
]
|
|
1412
|
+
}
|
|
1413
|
+
),
|
|
1414
|
+
/* @__PURE__ */ jsx(
|
|
1415
|
+
Button,
|
|
1416
|
+
{
|
|
1417
|
+
size: "xs",
|
|
1418
|
+
type: "button",
|
|
1419
|
+
variant: selected ? "secondary" : "outline",
|
|
1420
|
+
onClick: () => toggleRef(entry),
|
|
1421
|
+
children: selected ? "\u2713" : "+"
|
|
1422
|
+
}
|
|
1423
|
+
)
|
|
1424
|
+
]
|
|
1425
|
+
},
|
|
1426
|
+
entry.path
|
|
1427
|
+
);
|
|
1428
|
+
}) }) }),
|
|
1429
|
+
/* @__PURE__ */ jsxs("aside", { className: "flex min-h-0 flex-col gap-3 rounded-xl border border-border/70 bg-panel/72 p-3", children: [
|
|
1430
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
1431
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: copy.t("referencePicker.confirm") }),
|
|
1432
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: copy.t("referencePicker.selectedCount", {
|
|
1433
|
+
count: selectedRefs.length
|
|
1434
|
+
}) })
|
|
1435
|
+
] }),
|
|
1436
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 flex-1 rounded-lg border border-border/70 bg-background/75", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5 p-2", children: selectedRefs.length === 0 ? /* @__PURE__ */ jsx(PickerFeedback, { children: copy.t("referencePicker.emptySearch") }) : selectedRefs.map((ref) => /* @__PURE__ */ jsxs(
|
|
1437
|
+
"div",
|
|
1438
|
+
{
|
|
1439
|
+
className: "flex items-center justify-between gap-2 rounded-md border border-border/60 bg-background/92 px-2.5 py-2 text-sm",
|
|
1440
|
+
children: [
|
|
1441
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1442
|
+
/* @__PURE__ */ jsx("p", { className: "truncate font-medium text-foreground", children: ref.displayName || ref.path.split("/").filter(Boolean).at(-1) || ref.path }),
|
|
1443
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: ref.path })
|
|
1444
|
+
] }),
|
|
1445
|
+
/* @__PURE__ */ jsx(
|
|
1446
|
+
Button,
|
|
1447
|
+
{
|
|
1448
|
+
size: "icon-xs",
|
|
1449
|
+
type: "button",
|
|
1450
|
+
variant: "ghost",
|
|
1451
|
+
onClick: () => setSelectedRefs(
|
|
1452
|
+
(current) => current.filter((item) => item.path !== ref.path)
|
|
1453
|
+
),
|
|
1454
|
+
children: "x"
|
|
1455
|
+
}
|
|
1456
|
+
)
|
|
1457
|
+
]
|
|
1458
|
+
},
|
|
1459
|
+
ref.path
|
|
1460
|
+
)) }) })
|
|
1461
|
+
] })
|
|
1462
|
+
] })
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
)
|
|
1466
|
+
}
|
|
1467
|
+
);
|
|
1468
|
+
if (typeof document === "undefined") {
|
|
1469
|
+
return dialog;
|
|
1470
|
+
}
|
|
1471
|
+
return createPortal(dialog, document.body);
|
|
1472
|
+
}
|
|
1473
|
+
function hasFileAdapterMethod2(fileAdapter, methodName) {
|
|
1474
|
+
return typeof Reflect.get(fileAdapter ?? {}, methodName) === "function";
|
|
1475
|
+
}
|
|
1476
|
+
function PickerFeedback({ children }) {
|
|
1477
|
+
return /* @__PURE__ */ jsx("div", { className: "grid min-h-[10rem] place-items-center px-4 text-center text-sm text-muted-foreground", children });
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// src/react/internal/IssueManagerShell.tsx
|
|
1481
|
+
import {
|
|
1482
|
+
useEffect as useEffect4,
|
|
1483
|
+
useRef as useRef2,
|
|
1484
|
+
useState as useState4
|
|
1485
|
+
} from "react";
|
|
1486
|
+
import {
|
|
1487
|
+
ArrowLeftIcon,
|
|
1488
|
+
ArrowRightIcon,
|
|
1489
|
+
Badge as Badge5,
|
|
1490
|
+
Button as Button6,
|
|
1491
|
+
CloseIcon as CloseIcon2,
|
|
1492
|
+
FileCreateIcon as FileCreateIcon3,
|
|
1493
|
+
Input as Input5,
|
|
1494
|
+
RefreshIcon,
|
|
1495
|
+
ScrollArea as ScrollArea4,
|
|
1496
|
+
SearchIcon as SearchIcon2,
|
|
1497
|
+
cn as cn4
|
|
1498
|
+
} from "@nextop-os/ui-system";
|
|
1499
|
+
|
|
1500
|
+
// src/react/internal/IssueManagerPanels.tsx
|
|
1501
|
+
import {
|
|
1502
|
+
Badge as Badge3,
|
|
1503
|
+
Button as Button3,
|
|
1504
|
+
FileCreateIcon as FileCreateIcon2,
|
|
1505
|
+
Input as Input2,
|
|
1506
|
+
ScrollArea as ScrollArea2,
|
|
1507
|
+
cn as cn3
|
|
1508
|
+
} from "@nextop-os/ui-system";
|
|
1509
|
+
|
|
1510
|
+
// src/react/internal/IssueManagerPanelParts.tsx
|
|
1511
|
+
import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
|
|
1512
|
+
import {
|
|
1513
|
+
Badge as Badge2,
|
|
1514
|
+
Button as Button2,
|
|
1515
|
+
DirectoryIcon as DirectoryIcon2,
|
|
1516
|
+
FileCreateIcon,
|
|
1517
|
+
FileIcon as FileIcon2,
|
|
1518
|
+
Select,
|
|
1519
|
+
SelectContent,
|
|
1520
|
+
SelectItem,
|
|
1521
|
+
SelectTrigger,
|
|
1522
|
+
SparkIcon,
|
|
1523
|
+
cn as cn2
|
|
1524
|
+
} from "@nextop-os/ui-system";
|
|
1525
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1526
|
+
var workspaceDockTaskImage = new URL(
|
|
1527
|
+
"../../assets/workspace-dock-task.png",
|
|
1528
|
+
import.meta.url
|
|
1529
|
+
).href;
|
|
1530
|
+
function IssueManagerEmptyIllustration() {
|
|
1531
|
+
return /* @__PURE__ */ jsx2(
|
|
1532
|
+
"img",
|
|
1533
|
+
{
|
|
1534
|
+
alt: "",
|
|
1535
|
+
"aria-hidden": "true",
|
|
1536
|
+
className: "h-[84px] w-[84px] object-contain",
|
|
1537
|
+
decoding: "async",
|
|
1538
|
+
draggable: false,
|
|
1539
|
+
src: workspaceDockTaskImage
|
|
1540
|
+
}
|
|
1541
|
+
);
|
|
1542
|
+
}
|
|
1543
|
+
function IssueManagerDescriptionSection({
|
|
1544
|
+
content,
|
|
1545
|
+
emptyLabel,
|
|
1546
|
+
label,
|
|
1547
|
+
minHeightClass = "min-h-[14rem]",
|
|
1548
|
+
onOpen,
|
|
1549
|
+
variant = "card"
|
|
1550
|
+
}) {
|
|
1551
|
+
const contentRef = useRef(null);
|
|
1552
|
+
const [isOverflowing, setIsOverflowing] = useState3(false);
|
|
1553
|
+
const normalizedContent = normalizeIssueManagerContent(content).trim();
|
|
1554
|
+
useEffect3(() => {
|
|
1555
|
+
if (variant === "plain") {
|
|
1556
|
+
setIsOverflowing(false);
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
if (!normalizedContent) {
|
|
1560
|
+
setIsOverflowing(false);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
const contentElement = contentRef.current;
|
|
1564
|
+
if (!contentElement) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const measure = () => {
|
|
1568
|
+
setIsOverflowing(
|
|
1569
|
+
contentElement.scrollHeight > contentElement.clientHeight + 1
|
|
1570
|
+
);
|
|
1571
|
+
};
|
|
1572
|
+
measure();
|
|
1573
|
+
if (typeof ResizeObserver === "undefined") {
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
const observer = new ResizeObserver(() => {
|
|
1577
|
+
measure();
|
|
1578
|
+
});
|
|
1579
|
+
observer.observe(contentElement);
|
|
1580
|
+
return () => {
|
|
1581
|
+
observer.disconnect();
|
|
1582
|
+
};
|
|
1583
|
+
}, [normalizedContent, variant]);
|
|
1584
|
+
if (variant === "plain") {
|
|
1585
|
+
return /* @__PURE__ */ jsxs2("section", { className: "grid gap-2.5", children: [
|
|
1586
|
+
/* @__PURE__ */ jsx2("span", { className: "text-sm font-semibold text-foreground", children: label }),
|
|
1587
|
+
normalizedContent ? /* @__PURE__ */ jsx2("div", { className: "max-w-3xl text-sm leading-6 text-muted-foreground", children: /* @__PURE__ */ jsx2(
|
|
1588
|
+
IssueManagerDescriptionContent,
|
|
1589
|
+
{
|
|
1590
|
+
content: normalizedContent,
|
|
1591
|
+
onOpen
|
|
1592
|
+
}
|
|
1593
|
+
) }) : /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: emptyLabel })
|
|
1594
|
+
] });
|
|
1595
|
+
}
|
|
1596
|
+
return /* @__PURE__ */ jsxs2("section", { className: "grid gap-2", children: [
|
|
1597
|
+
/* @__PURE__ */ jsx2("span", { className: "text-sm font-semibold text-foreground", children: label }),
|
|
1598
|
+
/* @__PURE__ */ jsxs2(
|
|
1599
|
+
"div",
|
|
1600
|
+
{
|
|
1601
|
+
className: cn2(
|
|
1602
|
+
"relative min-w-0 rounded-[24px] border border-border/70 bg-transparent px-5 py-4",
|
|
1603
|
+
minHeightClass
|
|
1604
|
+
),
|
|
1605
|
+
children: [
|
|
1606
|
+
/* @__PURE__ */ jsx2(
|
|
1607
|
+
"div",
|
|
1608
|
+
{
|
|
1609
|
+
className: cn2(
|
|
1610
|
+
"max-h-[18rem] overflow-y-auto pr-2 text-sm leading-6 text-muted-foreground",
|
|
1611
|
+
isOverflowing && "pb-8"
|
|
1612
|
+
),
|
|
1613
|
+
ref: contentRef,
|
|
1614
|
+
children: normalizedContent ? /* @__PURE__ */ jsx2(
|
|
1615
|
+
IssueManagerDescriptionContent,
|
|
1616
|
+
{
|
|
1617
|
+
content: normalizedContent,
|
|
1618
|
+
onOpen
|
|
1619
|
+
}
|
|
1620
|
+
) : /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground", children: emptyLabel })
|
|
1621
|
+
}
|
|
1622
|
+
),
|
|
1623
|
+
isOverflowing ? /* @__PURE__ */ jsx2(
|
|
1624
|
+
"div",
|
|
1625
|
+
{
|
|
1626
|
+
className: "pointer-events-none absolute right-0 bottom-1 left-0 h-10",
|
|
1627
|
+
style: {
|
|
1628
|
+
background: "linear-gradient(to top, var(--workbench-node-surface), color-mix(in srgb, var(--workbench-node-surface) 80%, transparent), transparent)"
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
) : null
|
|
1632
|
+
]
|
|
1633
|
+
}
|
|
1634
|
+
)
|
|
1635
|
+
] });
|
|
1636
|
+
}
|
|
1637
|
+
function IssueManagerRunActionTrigger({
|
|
1638
|
+
controller,
|
|
1639
|
+
disabled = false,
|
|
1640
|
+
iconSize = 16,
|
|
1641
|
+
triggerClassName
|
|
1642
|
+
}) {
|
|
1643
|
+
const [resetToken, setResetToken] = useState3(0);
|
|
1644
|
+
return /* @__PURE__ */ jsxs2(
|
|
1645
|
+
Select,
|
|
1646
|
+
{
|
|
1647
|
+
disabled: controller.isRunningTask || disabled,
|
|
1648
|
+
onValueChange: (provider) => {
|
|
1649
|
+
setResetToken((current) => current + 1);
|
|
1650
|
+
void controller.runTask(provider);
|
|
1651
|
+
},
|
|
1652
|
+
children: [
|
|
1653
|
+
/* @__PURE__ */ jsx2(
|
|
1654
|
+
SelectTrigger,
|
|
1655
|
+
{
|
|
1656
|
+
"aria-label": controller.copy.t("actions.askAgentToRun"),
|
|
1657
|
+
className: triggerClassName,
|
|
1658
|
+
children: /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
1659
|
+
/* @__PURE__ */ jsx2(SparkIcon, { size: iconSize }),
|
|
1660
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: controller.copy.t("actions.askAgentToRun") })
|
|
1661
|
+
] })
|
|
1662
|
+
}
|
|
1663
|
+
),
|
|
1664
|
+
/* @__PURE__ */ jsx2(SelectContent, { style: { zIndex: "var(--z-panel-popover)" }, children: controller.providerOptions.map((provider) => /* @__PURE__ */ jsx2(SelectItem, { value: provider, children: provider }, provider)) })
|
|
1665
|
+
]
|
|
1666
|
+
},
|
|
1667
|
+
`${controller.nodeState.selectedAgentProvider}:${resetToken}`
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
function IssueManagerDescriptionContent({
|
|
1671
|
+
content,
|
|
1672
|
+
onOpen
|
|
1673
|
+
}) {
|
|
1674
|
+
const paragraphs = content.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean);
|
|
1675
|
+
return /* @__PURE__ */ jsx2("div", { className: "space-y-4", children: paragraphs.map((paragraph, paragraphIndex) => /* @__PURE__ */ jsx2(
|
|
1676
|
+
"p",
|
|
1677
|
+
{
|
|
1678
|
+
className: "whitespace-pre-wrap",
|
|
1679
|
+
children: renderIssueManagerInlineMarkdown(paragraph, onOpen)
|
|
1680
|
+
},
|
|
1681
|
+
`${paragraphIndex}:${paragraph}`
|
|
1682
|
+
)) });
|
|
1683
|
+
}
|
|
1684
|
+
function renderIssueManagerInlineMarkdown(content, onOpen) {
|
|
1685
|
+
const markdownLinkPattern = /\[([^\]]+)\]\(([^)\s]+)\)/g;
|
|
1686
|
+
const parts = [];
|
|
1687
|
+
let match;
|
|
1688
|
+
let cursor = 0;
|
|
1689
|
+
let index = 0;
|
|
1690
|
+
while ((match = markdownLinkPattern.exec(content)) !== null) {
|
|
1691
|
+
const [source, label = "", href = ""] = match;
|
|
1692
|
+
const start = match.index;
|
|
1693
|
+
if (start > cursor) {
|
|
1694
|
+
parts.push(
|
|
1695
|
+
/* @__PURE__ */ jsx2("span", { children: content.slice(cursor, start) }, `text:${index}:${cursor}`)
|
|
1696
|
+
);
|
|
1697
|
+
index += 1;
|
|
1698
|
+
}
|
|
1699
|
+
parts.push(
|
|
1700
|
+
/* @__PURE__ */ jsx2(
|
|
1701
|
+
IssueManagerInlineLink,
|
|
1702
|
+
{
|
|
1703
|
+
href,
|
|
1704
|
+
label: label || href,
|
|
1705
|
+
onOpen
|
|
1706
|
+
},
|
|
1707
|
+
`link:${index}:${href}`
|
|
1708
|
+
)
|
|
1709
|
+
);
|
|
1710
|
+
index += 1;
|
|
1711
|
+
cursor = start + source.length;
|
|
1712
|
+
}
|
|
1713
|
+
if (cursor < content.length) {
|
|
1714
|
+
parts.push(
|
|
1715
|
+
/* @__PURE__ */ jsx2("span", { children: content.slice(cursor) }, `text:${index}:${cursor}`)
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
return parts;
|
|
1719
|
+
}
|
|
1720
|
+
function IssueManagerInlineLink({
|
|
1721
|
+
href,
|
|
1722
|
+
label,
|
|
1723
|
+
onOpen
|
|
1724
|
+
}) {
|
|
1725
|
+
const trimmedHref = href.trim();
|
|
1726
|
+
const isExternal = /^(?:[a-z]+:)?\/\//i.test(trimmedHref);
|
|
1727
|
+
if (!trimmedHref || isExternal || !onOpen) {
|
|
1728
|
+
return /* @__PURE__ */ jsx2(
|
|
1729
|
+
"a",
|
|
1730
|
+
{
|
|
1731
|
+
className: "font-medium text-foreground underline decoration-border underline-offset-4 hover:text-primary",
|
|
1732
|
+
href: trimmedHref || void 0,
|
|
1733
|
+
rel: "noreferrer",
|
|
1734
|
+
target: "_blank",
|
|
1735
|
+
children: label
|
|
1736
|
+
}
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
return /* @__PURE__ */ jsx2(
|
|
1740
|
+
"button",
|
|
1741
|
+
{
|
|
1742
|
+
className: "font-medium text-foreground underline decoration-border underline-offset-4 hover:text-primary",
|
|
1743
|
+
type: "button",
|
|
1744
|
+
onClick: () => {
|
|
1745
|
+
void onOpen({
|
|
1746
|
+
displayName: label,
|
|
1747
|
+
kind: trimmedHref.endsWith("/") ? "folder" : "file",
|
|
1748
|
+
path: trimmedHref
|
|
1749
|
+
});
|
|
1750
|
+
},
|
|
1751
|
+
children: label
|
|
1752
|
+
}
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
function IssueManagerContextSection({
|
|
1756
|
+
copy,
|
|
1757
|
+
emptyLabel,
|
|
1758
|
+
onAdd,
|
|
1759
|
+
onOpen,
|
|
1760
|
+
onRemove,
|
|
1761
|
+
refs
|
|
1762
|
+
}) {
|
|
1763
|
+
return /* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
|
|
1764
|
+
/* @__PURE__ */ jsxs2("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
|
|
1765
|
+
/* @__PURE__ */ jsx2("h4", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.contextReferences") }),
|
|
1766
|
+
/* @__PURE__ */ jsx2(
|
|
1767
|
+
Button2,
|
|
1768
|
+
{
|
|
1769
|
+
className: "h-8 rounded-lg border-border/70 px-3 text-[13px] font-semibold",
|
|
1770
|
+
size: "sm",
|
|
1771
|
+
type: "button",
|
|
1772
|
+
variant: "outline",
|
|
1773
|
+
onClick: onAdd,
|
|
1774
|
+
children: copy.t("actions.addReferences")
|
|
1775
|
+
}
|
|
1776
|
+
)
|
|
1777
|
+
] }),
|
|
1778
|
+
refs.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: emptyLabel }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: refs.map((ref) => /* @__PURE__ */ jsxs2(
|
|
1779
|
+
"div",
|
|
1780
|
+
{
|
|
1781
|
+
className: "flex items-center justify-between gap-3 rounded-xl border border-border/65 bg-transparent px-3.5 py-3",
|
|
1782
|
+
children: [
|
|
1783
|
+
/* @__PURE__ */ jsxs2(
|
|
1784
|
+
"button",
|
|
1785
|
+
{
|
|
1786
|
+
className: "flex min-w-0 flex-1 items-center gap-3 text-left",
|
|
1787
|
+
type: "button",
|
|
1788
|
+
onClick: () => {
|
|
1789
|
+
void onOpen({
|
|
1790
|
+
displayName: ref.displayName,
|
|
1791
|
+
kind: ref.path.endsWith("/") ? "folder" : "file",
|
|
1792
|
+
path: ref.path
|
|
1793
|
+
});
|
|
1794
|
+
},
|
|
1795
|
+
children: [
|
|
1796
|
+
ref.path.endsWith("/") ? /* @__PURE__ */ jsx2(
|
|
1797
|
+
DirectoryIcon2,
|
|
1798
|
+
{
|
|
1799
|
+
className: "shrink-0 text-muted-foreground",
|
|
1800
|
+
size: 16
|
|
1801
|
+
}
|
|
1802
|
+
) : /* @__PURE__ */ jsx2(
|
|
1803
|
+
FileIcon2,
|
|
1804
|
+
{
|
|
1805
|
+
className: "shrink-0 text-muted-foreground",
|
|
1806
|
+
size: 16
|
|
1807
|
+
}
|
|
1808
|
+
),
|
|
1809
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
|
|
1810
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-sm font-semibold text-foreground", children: ref.displayName }),
|
|
1811
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-xs text-muted-foreground", children: ref.path })
|
|
1812
|
+
] })
|
|
1813
|
+
]
|
|
1814
|
+
}
|
|
1815
|
+
),
|
|
1816
|
+
/* @__PURE__ */ jsx2(
|
|
1817
|
+
Button2,
|
|
1818
|
+
{
|
|
1819
|
+
className: "h-7 px-2 text-[13px] font-semibold text-muted-foreground hover:text-foreground",
|
|
1820
|
+
size: "sm",
|
|
1821
|
+
type: "button",
|
|
1822
|
+
variant: "ghost",
|
|
1823
|
+
onClick: () => {
|
|
1824
|
+
void onRemove(ref);
|
|
1825
|
+
},
|
|
1826
|
+
children: copy.t("actions.removeReference")
|
|
1827
|
+
}
|
|
1828
|
+
)
|
|
1829
|
+
]
|
|
1830
|
+
},
|
|
1831
|
+
ref.contextRefId
|
|
1832
|
+
)) })
|
|
1833
|
+
] });
|
|
1834
|
+
}
|
|
1835
|
+
function IssueManagerRunPanels({
|
|
1836
|
+
copy,
|
|
1837
|
+
onOpen,
|
|
1838
|
+
outputs,
|
|
1839
|
+
recentRuns
|
|
1840
|
+
}) {
|
|
1841
|
+
return /* @__PURE__ */ jsxs2("div", { className: "grid gap-4", children: [
|
|
1842
|
+
/* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
|
|
1843
|
+
/* @__PURE__ */ jsx2("h4", { className: "mb-3 text-sm font-semibold text-foreground", children: copy.t("labels.recentRuns") }),
|
|
1844
|
+
recentRuns.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noRecentRuns") }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: recentRuns.map((run) => /* @__PURE__ */ jsxs2(
|
|
1845
|
+
"div",
|
|
1846
|
+
{
|
|
1847
|
+
className: "rounded-xl border border-border/65 bg-transparent px-3.5 py-3",
|
|
1848
|
+
children: [
|
|
1849
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1850
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
1851
|
+
/* @__PURE__ */ jsx2("p", { className: "truncate text-sm font-semibold text-foreground", children: run.summary || run.runId }),
|
|
1852
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(
|
|
1853
|
+
run.updatedAtUnix ?? run.createdAtUnix
|
|
1854
|
+
) })
|
|
1855
|
+
] }),
|
|
1856
|
+
/* @__PURE__ */ jsx2(Badge2, { className: "rounded-full border-transparent bg-muted px-2.5 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, run.status) })
|
|
1857
|
+
] }),
|
|
1858
|
+
run.errorMessage ? /* @__PURE__ */ jsx2("p", { className: "mt-2 text-xs text-destructive", children: run.errorMessage }) : null
|
|
1859
|
+
]
|
|
1860
|
+
},
|
|
1861
|
+
run.runId
|
|
1862
|
+
)) })
|
|
1863
|
+
] }),
|
|
1864
|
+
/* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
|
|
1865
|
+
/* @__PURE__ */ jsx2("h4", { className: "mb-3 text-sm font-semibold text-foreground", children: copy.t("labels.outputs") }),
|
|
1866
|
+
outputs.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noOutputs") }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: outputs.map((output) => /* @__PURE__ */ jsxs2(
|
|
1867
|
+
"button",
|
|
1868
|
+
{
|
|
1869
|
+
className: "rounded-xl border border-border/65 bg-transparent px-3.5 py-3 text-left transition-colors hover:bg-accent/25",
|
|
1870
|
+
type: "button",
|
|
1871
|
+
onClick: () => {
|
|
1872
|
+
void onOpen({
|
|
1873
|
+
displayName: output.displayName,
|
|
1874
|
+
kind: "file",
|
|
1875
|
+
path: output.path
|
|
1876
|
+
});
|
|
1877
|
+
},
|
|
1878
|
+
children: [
|
|
1879
|
+
/* @__PURE__ */ jsx2("p", { className: "truncate text-sm font-semibold text-foreground", children: output.displayName }),
|
|
1880
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: output.path })
|
|
1881
|
+
]
|
|
1882
|
+
},
|
|
1883
|
+
output.outputId
|
|
1884
|
+
)) })
|
|
1885
|
+
] })
|
|
1886
|
+
] });
|
|
1887
|
+
}
|
|
1888
|
+
function IssueManagerPaneLoadingState() {
|
|
1889
|
+
return /* @__PURE__ */ jsxs2(
|
|
1890
|
+
"div",
|
|
1891
|
+
{
|
|
1892
|
+
className: "mx-auto flex w-full max-w-4xl flex-col gap-6",
|
|
1893
|
+
"aria-hidden": "true",
|
|
1894
|
+
children: [
|
|
1895
|
+
/* @__PURE__ */ jsx2("div", { className: "h-6 w-28 rounded-full bg-muted" }),
|
|
1896
|
+
/* @__PURE__ */ jsx2("div", { className: "h-12 w-2/3 rounded-full bg-muted" }),
|
|
1897
|
+
/* @__PURE__ */ jsxs2("div", { className: "rounded-[28px] border border-border/70 bg-transparent px-5 py-5", children: [
|
|
1898
|
+
/* @__PURE__ */ jsx2("div", { className: "h-4 w-24 rounded-full bg-muted" }),
|
|
1899
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-5 h-4 w-full rounded-full bg-muted" }),
|
|
1900
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-11/12 rounded-full bg-muted" }),
|
|
1901
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-10/12 rounded-full bg-muted" })
|
|
1902
|
+
] }),
|
|
1903
|
+
/* @__PURE__ */ jsxs2("div", { className: "rounded-[24px] border border-border/70 bg-transparent px-5 py-5", children: [
|
|
1904
|
+
/* @__PURE__ */ jsx2("div", { className: "h-4 w-32 rounded-full bg-muted" }),
|
|
1905
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-5 h-4 w-full rounded-full bg-muted" }),
|
|
1906
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-9/12 rounded-full bg-muted" })
|
|
1907
|
+
] })
|
|
1908
|
+
]
|
|
1909
|
+
}
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
function IssueManagerTaskDrawerLoadingState() {
|
|
1913
|
+
return /* @__PURE__ */ jsxs2("div", { className: "grid gap-5", "aria-hidden": "true", children: [
|
|
1914
|
+
/* @__PURE__ */ jsx2("div", { className: "h-12 w-full rounded-2xl bg-muted" }),
|
|
1915
|
+
/* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
1916
|
+
/* @__PURE__ */ jsx2("div", { className: "h-10 rounded-xl bg-muted" }),
|
|
1917
|
+
/* @__PURE__ */ jsx2("div", { className: "h-10 rounded-xl bg-muted" })
|
|
1918
|
+
] }),
|
|
1919
|
+
/* @__PURE__ */ jsxs2("div", { className: "rounded-[24px] border border-border/70 bg-transparent px-4 py-4", children: [
|
|
1920
|
+
/* @__PURE__ */ jsx2("div", { className: "h-4 w-24 rounded-full bg-muted" }),
|
|
1921
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-4 h-4 w-full rounded-full bg-muted" }),
|
|
1922
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-11/12 rounded-full bg-muted" }),
|
|
1923
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-9/12 rounded-full bg-muted" })
|
|
1924
|
+
] })
|
|
1925
|
+
] });
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// src/react/internal/IssueManagerPanelText.ts
|
|
1929
|
+
function summarizeIssueManagerContent(content, fallback) {
|
|
1930
|
+
const plainText = extractIssueManagerPlainTextFromContent(
|
|
1931
|
+
content ?? ""
|
|
1932
|
+
).trim();
|
|
1933
|
+
if (!plainText) {
|
|
1934
|
+
return fallback;
|
|
1935
|
+
}
|
|
1936
|
+
if (plainText.length <= 120) {
|
|
1937
|
+
return plainText;
|
|
1938
|
+
}
|
|
1939
|
+
return `${plainText.slice(0, 117)}...`;
|
|
1940
|
+
}
|
|
1941
|
+
function resolveTaskCreatorLabel(task) {
|
|
1942
|
+
return resolveIssueManagerCreatorLabel(task);
|
|
1943
|
+
}
|
|
1944
|
+
function resolveIssueManagerCreatorLabel(entity) {
|
|
1945
|
+
return entity.creatorDisplayName?.trim() || entity.creatorUserId;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
// src/react/internal/IssueManagerPanels.tsx
|
|
1949
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1950
|
+
function IssueManagerIssuePane({
|
|
1951
|
+
controller,
|
|
1952
|
+
selectedIssue,
|
|
1953
|
+
onDismissCreate
|
|
1954
|
+
}) {
|
|
1955
|
+
const copy = controller.copy;
|
|
1956
|
+
const issueRefs = controller.issueDetail.value?.contextRefs.filter(
|
|
1957
|
+
(ref) => ref.parentKind === "issue"
|
|
1958
|
+
) ?? [];
|
|
1959
|
+
const isCreatingIssue = controller.issueEditorMode === "create";
|
|
1960
|
+
const isEditingIssue = controller.issueEditorMode === "edit";
|
|
1961
|
+
const issueContent = selectedIssue?.content ?? "";
|
|
1962
|
+
const tasks = controller.issueDetail.value?.tasks ?? [];
|
|
1963
|
+
const selectedTaskId = controller.nodeState.selectedTaskId;
|
|
1964
|
+
const selectedTask = selectedTaskId ? (controller.taskDetail.value?.task?.taskId === selectedTaskId ? controller.taskDetail.value.task : tasks.find((task) => task.taskId === selectedTaskId)) ?? null : null;
|
|
1965
|
+
const latestRun = selectedTask ? controller.taskDetail.value?.latestRun ?? controller.taskDetail.value?.recentRuns[0] ?? null : null;
|
|
1966
|
+
const latestOutputs = selectedTask ? controller.taskDetail.value?.latestOutputs ?? [] : [];
|
|
1967
|
+
if (isCreatingIssue || isEditingIssue) {
|
|
1968
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
|
|
1969
|
+
/* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-8", children: /* @__PURE__ */ jsxs3("div", { className: "flex w-full flex-col gap-5", children: [
|
|
1970
|
+
/* @__PURE__ */ jsx3("div", { className: "grid gap-3", children: /* @__PURE__ */ jsx3("h2", { className: "text-[1.65rem] font-semibold tracking-tight text-foreground", children: isCreatingIssue ? copy.t("actions.createIssue") : copy.t("actions.editIssue") }) }),
|
|
1971
|
+
/* @__PURE__ */ jsxs3("div", { className: "grid gap-5", children: [
|
|
1972
|
+
/* @__PURE__ */ jsxs3("label", { className: "grid gap-2.5", children: [
|
|
1973
|
+
/* @__PURE__ */ jsx3("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
|
|
1974
|
+
/* @__PURE__ */ jsx3(
|
|
1975
|
+
Input2,
|
|
1976
|
+
{
|
|
1977
|
+
className: "h-10 rounded-xl border-border/80 text-base font-semibold shadow-none",
|
|
1978
|
+
placeholder: copy.t("composer.issueTitlePlaceholder"),
|
|
1979
|
+
value: controller.issueDraft.title,
|
|
1980
|
+
onChange: (event) => controller.setIssueTitle(event.target.value)
|
|
1981
|
+
}
|
|
1982
|
+
)
|
|
1983
|
+
] }),
|
|
1984
|
+
/* @__PURE__ */ jsxs3("div", { className: "grid min-h-0 gap-2.5", children: [
|
|
1985
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-3", children: [
|
|
1986
|
+
/* @__PURE__ */ jsx3("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.content") }),
|
|
1987
|
+
/* @__PURE__ */ jsx3(
|
|
1988
|
+
Button3,
|
|
1989
|
+
{
|
|
1990
|
+
className: "h-8 rounded-lg border-border/70 px-3 text-[13px] font-semibold",
|
|
1991
|
+
size: "sm",
|
|
1992
|
+
type: "button",
|
|
1993
|
+
variant: "outline",
|
|
1994
|
+
onClick: () => {
|
|
1995
|
+
void controller.insertReferences("issue");
|
|
1996
|
+
},
|
|
1997
|
+
children: copy.t("actions.insertReferences")
|
|
1998
|
+
}
|
|
1999
|
+
)
|
|
2000
|
+
] }),
|
|
2001
|
+
/* @__PURE__ */ jsx3(
|
|
2002
|
+
"textarea",
|
|
2003
|
+
{
|
|
2004
|
+
className: "min-h-[12rem] w-full resize-none rounded-2xl border border-border/70 bg-transparent px-4 py-3 text-sm leading-6 text-foreground outline-none",
|
|
2005
|
+
placeholder: copy.t("composer.issueContentPlaceholder"),
|
|
2006
|
+
value: controller.issueDraft.content,
|
|
2007
|
+
onChange: (event) => controller.setIssueContent(event.target.value)
|
|
2008
|
+
}
|
|
2009
|
+
)
|
|
2010
|
+
] })
|
|
2011
|
+
] })
|
|
2012
|
+
] }) }),
|
|
2013
|
+
/* @__PURE__ */ jsx3("div", { className: "border-t border-border/70 px-7 py-4", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-end gap-3", children: [
|
|
2014
|
+
/* @__PURE__ */ jsx3(
|
|
2015
|
+
Button3,
|
|
2016
|
+
{
|
|
2017
|
+
size: "default",
|
|
2018
|
+
type: "button",
|
|
2019
|
+
variant: "secondary",
|
|
2020
|
+
onClick: onDismissCreate,
|
|
2021
|
+
children: copy.t("actions.cancel")
|
|
2022
|
+
}
|
|
2023
|
+
),
|
|
2024
|
+
/* @__PURE__ */ jsx3(
|
|
2025
|
+
Button3,
|
|
2026
|
+
{
|
|
2027
|
+
size: "default",
|
|
2028
|
+
type: "button",
|
|
2029
|
+
onClick: () => void controller.saveIssue(),
|
|
2030
|
+
children: copy.t("actions.saveIssue")
|
|
2031
|
+
}
|
|
2032
|
+
)
|
|
2033
|
+
] }) })
|
|
2034
|
+
] });
|
|
2035
|
+
}
|
|
2036
|
+
if (!selectedIssue) {
|
|
2037
|
+
return /* @__PURE__ */ jsx3("div", { className: "h-full min-h-0" });
|
|
2038
|
+
}
|
|
2039
|
+
return /* @__PURE__ */ jsx3("div", { className: "flex min-h-0 flex-col", children: /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 overflow-y-auto px-8 py-7", children: controller.issueDetail.isLoading && controller.issueDetail.value === null ? /* @__PURE__ */ jsx3(IssueManagerPaneLoadingState, {}) : /* @__PURE__ */ jsxs3("div", { className: "flex w-full max-w-[44rem] flex-col gap-9", children: [
|
|
2040
|
+
/* @__PURE__ */ jsxs3("header", { className: "flex items-start justify-between gap-6", children: [
|
|
2041
|
+
/* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
|
|
2042
|
+
/* @__PURE__ */ jsx3("h2", { className: "line-clamp-2 text-base font-semibold leading-6 text-foreground", children: selectedIssue.title }),
|
|
2043
|
+
/* @__PURE__ */ jsxs3("div", { className: "mt-3 flex flex-wrap items-center gap-x-5 gap-y-2 text-sm text-muted-foreground", children: [
|
|
2044
|
+
/* @__PURE__ */ jsx3(Badge3, { className: "rounded-full border-transparent bg-muted px-2 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, selectedIssue.status) }),
|
|
2045
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
2046
|
+
copy.t("labels.creator"),
|
|
2047
|
+
" ",
|
|
2048
|
+
resolveIssueManagerCreatorLabel(selectedIssue)
|
|
2049
|
+
] }),
|
|
2050
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
2051
|
+
copy.t("labels.createdAt"),
|
|
2052
|
+
" ",
|
|
2053
|
+
formatIssueManagerTimestamp(selectedIssue.createdAtUnix) || "-"
|
|
2054
|
+
] })
|
|
2055
|
+
] })
|
|
2056
|
+
] }),
|
|
2057
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex shrink-0 items-center gap-5 pt-1", children: [
|
|
2058
|
+
/* @__PURE__ */ jsx3(
|
|
2059
|
+
Button3,
|
|
2060
|
+
{
|
|
2061
|
+
className: "h-auto px-0 text-sm font-semibold text-muted-foreground hover:text-foreground",
|
|
2062
|
+
size: "sm",
|
|
2063
|
+
type: "button",
|
|
2064
|
+
variant: "ghost",
|
|
2065
|
+
onClick: () => controller.setIssueEditorMode("edit"),
|
|
2066
|
+
children: copy.t("actions.edit")
|
|
2067
|
+
}
|
|
2068
|
+
),
|
|
2069
|
+
/* @__PURE__ */ jsx3(
|
|
2070
|
+
Button3,
|
|
2071
|
+
{
|
|
2072
|
+
className: "h-auto px-0 text-sm font-semibold text-destructive hover:text-destructive",
|
|
2073
|
+
size: "sm",
|
|
2074
|
+
type: "button",
|
|
2075
|
+
variant: "ghost",
|
|
2076
|
+
onClick: () => {
|
|
2077
|
+
void controller.deleteIssue();
|
|
2078
|
+
},
|
|
2079
|
+
children: copy.t("actions.delete")
|
|
2080
|
+
}
|
|
2081
|
+
)
|
|
2082
|
+
] })
|
|
2083
|
+
] }),
|
|
2084
|
+
/* @__PURE__ */ jsx3(
|
|
2085
|
+
IssueManagerDescriptionSection,
|
|
2086
|
+
{
|
|
2087
|
+
content: issueContent,
|
|
2088
|
+
emptyLabel: copy.t("messages.issueContentEmpty"),
|
|
2089
|
+
label: copy.t("labels.description"),
|
|
2090
|
+
onOpen: controller.openReference,
|
|
2091
|
+
variant: "plain"
|
|
2092
|
+
}
|
|
2093
|
+
),
|
|
2094
|
+
/* @__PURE__ */ jsx3(
|
|
2095
|
+
IssueManagerDetailTextSection,
|
|
2096
|
+
{
|
|
2097
|
+
body: latestRun ? latestRun.summary?.trim() || resolveIssueManagerStatusLabel(copy, latestRun.status) : copy.t("messages.noExecutionStatus"),
|
|
2098
|
+
label: copy.t("labels.latestRunStatus"),
|
|
2099
|
+
meta: latestRun ? formatIssueManagerTimestamp(
|
|
2100
|
+
latestRun.updatedAtUnix ?? latestRun.createdAtUnix
|
|
2101
|
+
) || void 0 : void 0,
|
|
2102
|
+
tone: latestRun?.status === "failed" ? "destructive" : "muted"
|
|
2103
|
+
}
|
|
2104
|
+
),
|
|
2105
|
+
/* @__PURE__ */ jsx3(
|
|
2106
|
+
IssueManagerOutputSection,
|
|
2107
|
+
{
|
|
2108
|
+
copy,
|
|
2109
|
+
outputs: latestOutputs,
|
|
2110
|
+
onOpen: controller.openReference
|
|
2111
|
+
}
|
|
2112
|
+
),
|
|
2113
|
+
issueRefs.length > 0 ? /* @__PURE__ */ jsx3(
|
|
2114
|
+
IssueManagerContextSection,
|
|
2115
|
+
{
|
|
2116
|
+
copy,
|
|
2117
|
+
emptyLabel: copy.t("messages.noIssueReferences"),
|
|
2118
|
+
refs: issueRefs,
|
|
2119
|
+
onAdd: () => {
|
|
2120
|
+
void controller.attachReferences("issue");
|
|
2121
|
+
},
|
|
2122
|
+
onOpen: controller.openReference,
|
|
2123
|
+
onRemove: controller.removeContextRef
|
|
2124
|
+
}
|
|
2125
|
+
) : null,
|
|
2126
|
+
/* @__PURE__ */ jsx3(
|
|
2127
|
+
IssueManagerSubtaskSection,
|
|
2128
|
+
{
|
|
2129
|
+
copy,
|
|
2130
|
+
onCreate: controller.createTaskDraft,
|
|
2131
|
+
onSelectTask: controller.selectTask,
|
|
2132
|
+
selectedTaskId: selectedTask?.taskId ?? null,
|
|
2133
|
+
tasks
|
|
2134
|
+
}
|
|
2135
|
+
)
|
|
2136
|
+
] }) }) });
|
|
2137
|
+
}
|
|
2138
|
+
function IssueManagerDetailTextSection({
|
|
2139
|
+
body,
|
|
2140
|
+
label,
|
|
2141
|
+
meta,
|
|
2142
|
+
tone = "muted"
|
|
2143
|
+
}) {
|
|
2144
|
+
return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
|
|
2145
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: label }),
|
|
2146
|
+
/* @__PURE__ */ jsxs3("div", { className: "grid gap-1.5", children: [
|
|
2147
|
+
/* @__PURE__ */ jsx3(
|
|
2148
|
+
"p",
|
|
2149
|
+
{
|
|
2150
|
+
className: cn3(
|
|
2151
|
+
"text-sm leading-6",
|
|
2152
|
+
tone === "destructive" ? "text-destructive" : "text-muted-foreground"
|
|
2153
|
+
),
|
|
2154
|
+
children: body
|
|
2155
|
+
}
|
|
2156
|
+
),
|
|
2157
|
+
meta ? /* @__PURE__ */ jsx3("p", { className: "text-xs leading-5 text-muted-foreground", children: meta }) : null
|
|
2158
|
+
] })
|
|
2159
|
+
] });
|
|
2160
|
+
}
|
|
2161
|
+
function IssueManagerOutputSection({
|
|
2162
|
+
copy,
|
|
2163
|
+
onOpen,
|
|
2164
|
+
outputs
|
|
2165
|
+
}) {
|
|
2166
|
+
return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
|
|
2167
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.executionOutputs") }),
|
|
2168
|
+
outputs.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noExecutionOutputs") }) : /* @__PURE__ */ jsx3("div", { className: "grid gap-2", children: outputs.map((output) => /* @__PURE__ */ jsxs3(
|
|
2169
|
+
"button",
|
|
2170
|
+
{
|
|
2171
|
+
className: "flex items-start justify-between gap-4 rounded-xl border border-border/65 px-4 py-3 text-left transition-colors hover:bg-accent/18",
|
|
2172
|
+
type: "button",
|
|
2173
|
+
onClick: () => {
|
|
2174
|
+
void onOpen({
|
|
2175
|
+
displayName: output.displayName,
|
|
2176
|
+
kind: "file",
|
|
2177
|
+
path: output.path
|
|
2178
|
+
});
|
|
2179
|
+
},
|
|
2180
|
+
children: [
|
|
2181
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1", children: [
|
|
2182
|
+
/* @__PURE__ */ jsx3("span", { className: "block truncate text-sm font-semibold text-foreground", children: output.displayName }),
|
|
2183
|
+
/* @__PURE__ */ jsx3("span", { className: "mt-1 block truncate text-xs text-muted-foreground", children: output.path })
|
|
2184
|
+
] }),
|
|
2185
|
+
/* @__PURE__ */ jsx3("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(output.createdAtUnix) || "" })
|
|
2186
|
+
]
|
|
2187
|
+
},
|
|
2188
|
+
output.outputId
|
|
2189
|
+
)) })
|
|
2190
|
+
] });
|
|
2191
|
+
}
|
|
2192
|
+
function IssueManagerSubtaskSection({
|
|
2193
|
+
copy,
|
|
2194
|
+
onCreate,
|
|
2195
|
+
onSelectTask,
|
|
2196
|
+
selectedTaskId,
|
|
2197
|
+
tasks
|
|
2198
|
+
}) {
|
|
2199
|
+
return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
|
|
2200
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2201
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.subtasks") }),
|
|
2202
|
+
/* @__PURE__ */ jsxs3(
|
|
2203
|
+
Button3,
|
|
2204
|
+
{
|
|
2205
|
+
className: "h-auto gap-1.5 px-0 text-sm font-semibold text-foreground hover:text-foreground",
|
|
2206
|
+
size: "sm",
|
|
2207
|
+
type: "button",
|
|
2208
|
+
variant: "ghost",
|
|
2209
|
+
onClick: onCreate,
|
|
2210
|
+
children: [
|
|
2211
|
+
/* @__PURE__ */ jsx3(FileCreateIcon2, { size: 14 }),
|
|
2212
|
+
copy.t("actions.add")
|
|
2213
|
+
]
|
|
2214
|
+
}
|
|
2215
|
+
)
|
|
2216
|
+
] }),
|
|
2217
|
+
tasks.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noSubtasksForIssue") }) : /* @__PURE__ */ jsx3("div", { className: "grid gap-2", children: tasks.map((task) => /* @__PURE__ */ jsxs3(
|
|
2218
|
+
"button",
|
|
2219
|
+
{
|
|
2220
|
+
className: cn3(
|
|
2221
|
+
"flex items-start justify-between gap-4 rounded-xl border px-4 py-3 text-left transition-colors",
|
|
2222
|
+
selectedTaskId === task.taskId ? "border-border/90 bg-background-fronted" : "border-border/65 hover:bg-accent/18"
|
|
2223
|
+
),
|
|
2224
|
+
type: "button",
|
|
2225
|
+
onClick: () => onSelectTask(task.taskId),
|
|
2226
|
+
children: [
|
|
2227
|
+
/* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
|
|
2228
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
2229
|
+
/* @__PURE__ */ jsx3("span", { className: "truncate text-sm font-semibold text-foreground", children: task.title }),
|
|
2230
|
+
/* @__PURE__ */ jsx3(Badge3, { className: "rounded-md border-transparent bg-muted px-2 py-1 text-[11px] font-medium text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, task.status) })
|
|
2231
|
+
] }),
|
|
2232
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-2 line-clamp-2 text-sm leading-6 text-muted-foreground", children: summarizeIssueManagerContent(
|
|
2233
|
+
task.content,
|
|
2234
|
+
copy.t("messages.taskContentEmpty")
|
|
2235
|
+
) })
|
|
2236
|
+
] }),
|
|
2237
|
+
/* @__PURE__ */ jsx3("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(
|
|
2238
|
+
task.createdAtUnix ?? task.updatedAtUnix
|
|
2239
|
+
) || "" })
|
|
2240
|
+
]
|
|
2241
|
+
},
|
|
2242
|
+
task.taskId
|
|
2243
|
+
)) })
|
|
2244
|
+
] });
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// src/react/internal/IssueManagerTaskComposerPane.tsx
|
|
2248
|
+
import {
|
|
2249
|
+
Button as Button4,
|
|
2250
|
+
FileSearchIcon,
|
|
2251
|
+
Input as Input3,
|
|
2252
|
+
Select as Select2,
|
|
2253
|
+
SelectContent as SelectContent2,
|
|
2254
|
+
SelectItem as SelectItem2,
|
|
2255
|
+
SelectTrigger as SelectTrigger2,
|
|
2256
|
+
SelectValue,
|
|
2257
|
+
UploadIcon as UploadIcon2
|
|
2258
|
+
} from "@nextop-os/ui-system";
|
|
2259
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2260
|
+
var taskPriorityOptions = ["high", "medium", "low"];
|
|
2261
|
+
function IssueManagerTaskComposerPane({
|
|
2262
|
+
controller,
|
|
2263
|
+
onCancel,
|
|
2264
|
+
selectedIssue
|
|
2265
|
+
}) {
|
|
2266
|
+
const copy = controller.copy;
|
|
2267
|
+
const showAttachmentActions = controller.canUploadWorkspaceFiles || controller.canReferenceWorkspaceFiles;
|
|
2268
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
|
|
2269
|
+
/* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1 overflow-y-auto px-8 py-8", children: /* @__PURE__ */ jsxs4("div", { className: "flex w-full max-w-[76rem] flex-col gap-8", children: [
|
|
2270
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-4", children: [
|
|
2271
|
+
/* @__PURE__ */ jsx4("h2", { className: "text-base font-semibold leading-6 text-foreground", children: copy.t("actions.addSubtask") }),
|
|
2272
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3", children: [
|
|
2273
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm text-muted-foreground", children: copy.t("labels.priority") }),
|
|
2274
|
+
/* @__PURE__ */ jsxs4(
|
|
2275
|
+
Select2,
|
|
2276
|
+
{
|
|
2277
|
+
value: controller.taskDraft.priority,
|
|
2278
|
+
onValueChange: (value) => controller.setTaskPriority(value),
|
|
2279
|
+
children: [
|
|
2280
|
+
/* @__PURE__ */ jsx4(
|
|
2281
|
+
SelectTrigger2,
|
|
2282
|
+
{
|
|
2283
|
+
"aria-label": copy.t("labels.priority"),
|
|
2284
|
+
className: "min-w-28 rounded-xl border-border/70 bg-muted/25",
|
|
2285
|
+
children: /* @__PURE__ */ jsx4(SelectValue, {})
|
|
2286
|
+
}
|
|
2287
|
+
),
|
|
2288
|
+
/* @__PURE__ */ jsx4(SelectContent2, { style: { zIndex: "var(--z-panel-popover)" }, children: taskPriorityOptions.map((priority) => /* @__PURE__ */ jsx4(SelectItem2, { value: priority, children: resolveIssueManagerPriorityLabel(copy, priority) }, priority)) })
|
|
2289
|
+
]
|
|
2290
|
+
}
|
|
2291
|
+
)
|
|
2292
|
+
] })
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsxs4("label", { className: "grid gap-3", children: [
|
|
2295
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
|
|
2296
|
+
/* @__PURE__ */ jsx4(
|
|
2297
|
+
Input3,
|
|
2298
|
+
{
|
|
2299
|
+
className: "h-14 rounded-2xl border-0 bg-muted/28 px-5 text-base font-medium shadow-none placeholder:text-muted-foreground",
|
|
2300
|
+
placeholder: copy.t("composer.subtaskTitlePlaceholder"),
|
|
2301
|
+
value: controller.taskDraft.title,
|
|
2302
|
+
onChange: (event) => controller.setTaskTitle(event.target.value)
|
|
2303
|
+
}
|
|
2304
|
+
)
|
|
2305
|
+
] }),
|
|
2306
|
+
/* @__PURE__ */ jsxs4("section", { className: "grid gap-3", children: [
|
|
2307
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.requirementDescription") }),
|
|
2308
|
+
/* @__PURE__ */ jsxs4("div", { className: "overflow-hidden rounded-[28px] border border-border/70 bg-muted/18", children: [
|
|
2309
|
+
/* @__PURE__ */ jsx4(
|
|
2310
|
+
"textarea",
|
|
2311
|
+
{
|
|
2312
|
+
className: "min-h-[20rem] w-full resize-none border-0 bg-transparent px-5 py-5 text-sm leading-6 text-foreground outline-none placeholder:text-muted-foreground",
|
|
2313
|
+
placeholder: copy.t("composer.subtaskContentPlaceholder"),
|
|
2314
|
+
value: controller.taskDraft.content,
|
|
2315
|
+
onChange: (event) => controller.setTaskContent(event.target.value)
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
showAttachmentActions ? /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-3 border-t border-border/60 px-5 py-4", children: [
|
|
2319
|
+
controller.canUploadWorkspaceFiles ? /* @__PURE__ */ jsxs4(
|
|
2320
|
+
Button4,
|
|
2321
|
+
{
|
|
2322
|
+
className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
|
|
2323
|
+
size: "sm",
|
|
2324
|
+
type: "button",
|
|
2325
|
+
variant: "secondary",
|
|
2326
|
+
onClick: () => {
|
|
2327
|
+
void controller.uploadReferences("task", "files");
|
|
2328
|
+
},
|
|
2329
|
+
children: [
|
|
2330
|
+
/* @__PURE__ */ jsx4(UploadIcon2, { size: 16 }),
|
|
2331
|
+
copy.t("actions.uploadFiles")
|
|
2332
|
+
]
|
|
2333
|
+
}
|
|
2334
|
+
) : null,
|
|
2335
|
+
controller.canUploadWorkspaceFiles ? /* @__PURE__ */ jsxs4(
|
|
2336
|
+
Button4,
|
|
2337
|
+
{
|
|
2338
|
+
className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
|
|
2339
|
+
size: "sm",
|
|
2340
|
+
type: "button",
|
|
2341
|
+
variant: "secondary",
|
|
2342
|
+
onClick: () => {
|
|
2343
|
+
void controller.uploadReferences("task", "folder");
|
|
2344
|
+
},
|
|
2345
|
+
children: [
|
|
2346
|
+
/* @__PURE__ */ jsx4(UploadIcon2, { size: 16 }),
|
|
2347
|
+
copy.t("actions.uploadFolder")
|
|
2348
|
+
]
|
|
2349
|
+
}
|
|
2350
|
+
) : null,
|
|
2351
|
+
controller.canReferenceWorkspaceFiles ? /* @__PURE__ */ jsxs4(
|
|
2352
|
+
Button4,
|
|
2353
|
+
{
|
|
2354
|
+
className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
|
|
2355
|
+
size: "sm",
|
|
2356
|
+
type: "button",
|
|
2357
|
+
variant: "secondary",
|
|
2358
|
+
onClick: () => {
|
|
2359
|
+
void controller.insertReferences("task");
|
|
2360
|
+
},
|
|
2361
|
+
children: [
|
|
2362
|
+
/* @__PURE__ */ jsx4(FileSearchIcon, { size: 16 }),
|
|
2363
|
+
copy.t("actions.referenceWorkspaceFiles")
|
|
2364
|
+
]
|
|
2365
|
+
}
|
|
2366
|
+
) : null
|
|
2367
|
+
] }) : null
|
|
2368
|
+
] })
|
|
2369
|
+
] })
|
|
2370
|
+
] }) }),
|
|
2371
|
+
/* @__PURE__ */ jsx4("div", { className: "border-t border-border/70 px-8 py-4", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-end gap-3", children: [
|
|
2372
|
+
/* @__PURE__ */ jsx4(
|
|
2373
|
+
Button4,
|
|
2374
|
+
{
|
|
2375
|
+
size: "default",
|
|
2376
|
+
type: "button",
|
|
2377
|
+
variant: "secondary",
|
|
2378
|
+
onClick: onCancel,
|
|
2379
|
+
children: copy.t("actions.cancel")
|
|
2380
|
+
}
|
|
2381
|
+
),
|
|
2382
|
+
/* @__PURE__ */ jsx4(
|
|
2383
|
+
Button4,
|
|
2384
|
+
{
|
|
2385
|
+
disabled: !selectedIssue,
|
|
2386
|
+
size: "default",
|
|
2387
|
+
type: "button",
|
|
2388
|
+
onClick: () => void controller.saveTask(),
|
|
2389
|
+
children: copy.t("actions.saveSubtask")
|
|
2390
|
+
}
|
|
2391
|
+
)
|
|
2392
|
+
] }) })
|
|
2393
|
+
] });
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
// src/react/internal/IssueManagerTaskDrawer.tsx
|
|
2397
|
+
import {
|
|
2398
|
+
Badge as Badge4,
|
|
2399
|
+
Button as Button5,
|
|
2400
|
+
CloseIcon,
|
|
2401
|
+
DropdownMenu,
|
|
2402
|
+
DropdownMenuContent,
|
|
2403
|
+
DropdownMenuItem,
|
|
2404
|
+
DropdownMenuTrigger,
|
|
2405
|
+
Input as Input4,
|
|
2406
|
+
ScrollArea as ScrollArea3,
|
|
2407
|
+
Select as Select3,
|
|
2408
|
+
SelectContent as SelectContent3,
|
|
2409
|
+
SelectItem as SelectItem3,
|
|
2410
|
+
SelectTrigger as SelectTrigger3,
|
|
2411
|
+
SelectValue as SelectValue2,
|
|
2412
|
+
SparkIcon as SparkIcon2
|
|
2413
|
+
} from "@nextop-os/ui-system";
|
|
2414
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2415
|
+
var taskPriorityOptions2 = ["high", "medium", "low"];
|
|
2416
|
+
function IssueManagerTaskDrawer({
|
|
2417
|
+
controller,
|
|
2418
|
+
selectedIssue,
|
|
2419
|
+
selectedTask,
|
|
2420
|
+
onClose
|
|
2421
|
+
}) {
|
|
2422
|
+
const copy = controller.copy;
|
|
2423
|
+
const isCreate = controller.taskEditorMode === "create";
|
|
2424
|
+
const isEdit = controller.taskEditorMode === "edit";
|
|
2425
|
+
const isRead = !isCreate && !isEdit;
|
|
2426
|
+
const taskRefs = controller.taskDetail.value?.contextRefs.filter(
|
|
2427
|
+
(ref) => ref.parentKind === "task"
|
|
2428
|
+
) ?? [];
|
|
2429
|
+
const title = isCreate || isEdit ? isCreate ? copy.t("actions.createTask") : copy.t("actions.editTask") : selectedTask?.title || copy.t("labels.taskDetails");
|
|
2430
|
+
const taskContent = selectedTask?.content ?? "";
|
|
2431
|
+
return /* @__PURE__ */ jsx5(
|
|
2432
|
+
"div",
|
|
2433
|
+
{
|
|
2434
|
+
className: "absolute inset-0 z-20 flex justify-end bg-foreground/6 backdrop-blur-[1px]",
|
|
2435
|
+
onClick: onClose,
|
|
2436
|
+
children: /* @__PURE__ */ jsxs5(
|
|
2437
|
+
"aside",
|
|
2438
|
+
{
|
|
2439
|
+
className: "flex h-full w-[34rem] max-w-[92vw] flex-col border-l border-border/70 [background:var(--workbench-node-surface)] shadow-[-20px_0_60px_rgba(15,23,42,0.12)]",
|
|
2440
|
+
onClick: (event) => event.stopPropagation(),
|
|
2441
|
+
children: [
|
|
2442
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-start justify-between gap-4 border-b border-border/70 px-6 py-5", children: [
|
|
2443
|
+
/* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
|
|
2444
|
+
isRead && selectedTask ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2445
|
+
/* @__PURE__ */ jsx5("h3", { className: "line-clamp-2 text-lg font-semibold leading-7 tracking-tight text-foreground", children: title }),
|
|
2446
|
+
/* @__PURE__ */ jsx5(Badge4, { className: "rounded-full border-transparent bg-primary/10 px-2.5 py-1 text-[11px] text-primary", children: resolveIssueManagerStatusLabel(copy, selectedTask.status) }),
|
|
2447
|
+
/* @__PURE__ */ jsx5(Badge4, { className: "rounded-full border-transparent bg-muted px-2.5 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerPriorityLabel(
|
|
2448
|
+
copy,
|
|
2449
|
+
selectedTask.priority
|
|
2450
|
+
) })
|
|
2451
|
+
] }) : /* @__PURE__ */ jsx5("h3", { className: "line-clamp-2 text-lg font-semibold leading-7 tracking-tight text-foreground", children: title }),
|
|
2452
|
+
isRead && selectedTask ? /* @__PURE__ */ jsxs5("div", { className: "mt-3 flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [
|
|
2453
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
2454
|
+
copy.t("labels.updatedAt"),
|
|
2455
|
+
" ",
|
|
2456
|
+
formatIssueManagerTimestamp(
|
|
2457
|
+
selectedTask.updatedAtUnix ?? selectedTask.createdAtUnix
|
|
2458
|
+
) || "-"
|
|
2459
|
+
] }),
|
|
2460
|
+
/* @__PURE__ */ jsx5("span", { className: "h-1 w-1 rounded-full bg-border" }),
|
|
2461
|
+
/* @__PURE__ */ jsx5("span", { children: resolveTaskCreatorLabel(selectedTask) })
|
|
2462
|
+
] }) : null
|
|
2463
|
+
] }),
|
|
2464
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
2465
|
+
isRead && selectedTask ? /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
|
|
2466
|
+
/* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(
|
|
2467
|
+
Button5,
|
|
2468
|
+
{
|
|
2469
|
+
"aria-label": copy.t("actions.moreActions"),
|
|
2470
|
+
size: "icon-sm",
|
|
2471
|
+
type: "button",
|
|
2472
|
+
variant: "ghost",
|
|
2473
|
+
children: /* @__PURE__ */ jsx5(
|
|
2474
|
+
"span",
|
|
2475
|
+
{
|
|
2476
|
+
"aria-hidden": "true",
|
|
2477
|
+
className: "text-base leading-none tracking-[0.18em] text-muted-foreground",
|
|
2478
|
+
children: "..."
|
|
2479
|
+
}
|
|
2480
|
+
)
|
|
2481
|
+
}
|
|
2482
|
+
) }),
|
|
2483
|
+
/* @__PURE__ */ jsxs5(DropdownMenuContent, { align: "end", sideOffset: 8, children: [
|
|
2484
|
+
/* @__PURE__ */ jsx5(
|
|
2485
|
+
DropdownMenuItem,
|
|
2486
|
+
{
|
|
2487
|
+
onClick: () => controller.setTaskEditorMode("edit"),
|
|
2488
|
+
children: copy.t("actions.editTask")
|
|
2489
|
+
}
|
|
2490
|
+
),
|
|
2491
|
+
/* @__PURE__ */ jsx5(
|
|
2492
|
+
DropdownMenuItem,
|
|
2493
|
+
{
|
|
2494
|
+
variant: "destructive",
|
|
2495
|
+
onClick: () => {
|
|
2496
|
+
void controller.deleteTask();
|
|
2497
|
+
},
|
|
2498
|
+
children: copy.t("actions.deleteTask")
|
|
2499
|
+
}
|
|
2500
|
+
)
|
|
2501
|
+
] })
|
|
2502
|
+
] }) : null,
|
|
2503
|
+
/* @__PURE__ */ jsx5(
|
|
2504
|
+
Button5,
|
|
2505
|
+
{
|
|
2506
|
+
"aria-label": copy.t("actions.cancel"),
|
|
2507
|
+
size: "icon-sm",
|
|
2508
|
+
type: "button",
|
|
2509
|
+
variant: "ghost",
|
|
2510
|
+
onClick: onClose,
|
|
2511
|
+
children: /* @__PURE__ */ jsx5(CloseIcon, { size: 16 })
|
|
2512
|
+
}
|
|
2513
|
+
)
|
|
2514
|
+
] })
|
|
2515
|
+
] }),
|
|
2516
|
+
/* @__PURE__ */ jsx5(ScrollArea3, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx5("div", { className: "flex flex-col gap-6 px-6 py-6", children: controller.taskDetail.isLoading && !isCreate && controller.taskDetail.value === null ? /* @__PURE__ */ jsx5(IssueManagerTaskDrawerLoadingState, {}) : isCreate || isEdit ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2517
|
+
/* @__PURE__ */ jsxs5("div", { className: "grid gap-5", children: [
|
|
2518
|
+
/* @__PURE__ */ jsxs5("label", { className: "grid gap-2.5", children: [
|
|
2519
|
+
/* @__PURE__ */ jsx5("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
|
|
2520
|
+
/* @__PURE__ */ jsx5(
|
|
2521
|
+
Input4,
|
|
2522
|
+
{
|
|
2523
|
+
className: "h-10 rounded-xl border-border/80 text-base font-semibold shadow-none",
|
|
2524
|
+
placeholder: copy.t("composer.taskTitlePlaceholder"),
|
|
2525
|
+
value: controller.taskDraft.title,
|
|
2526
|
+
onChange: (event) => controller.setTaskTitle(event.target.value)
|
|
2527
|
+
}
|
|
2528
|
+
)
|
|
2529
|
+
] }),
|
|
2530
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
2531
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
|
|
2532
|
+
/* @__PURE__ */ jsx5("span", { className: "text-sm font-medium text-muted-foreground", children: copy.t("labels.priority") }),
|
|
2533
|
+
/* @__PURE__ */ jsxs5(
|
|
2534
|
+
Select3,
|
|
2535
|
+
{
|
|
2536
|
+
value: controller.taskDraft.priority,
|
|
2537
|
+
onValueChange: (value) => controller.setTaskPriority(value),
|
|
2538
|
+
children: [
|
|
2539
|
+
/* @__PURE__ */ jsx5(
|
|
2540
|
+
SelectTrigger3,
|
|
2541
|
+
{
|
|
2542
|
+
"aria-label": copy.t("labels.priority"),
|
|
2543
|
+
className: "min-w-28 rounded-xl border-border/70 bg-muted/30",
|
|
2544
|
+
children: /* @__PURE__ */ jsx5(SelectValue2, {})
|
|
2545
|
+
}
|
|
2546
|
+
),
|
|
2547
|
+
/* @__PURE__ */ jsx5(
|
|
2548
|
+
SelectContent3,
|
|
2549
|
+
{
|
|
2550
|
+
style: { zIndex: "var(--z-panel-popover)" },
|
|
2551
|
+
children: taskPriorityOptions2.map((priority) => /* @__PURE__ */ jsx5(SelectItem3, { value: priority, children: resolveIssueManagerPriorityLabel(copy, priority) }, priority))
|
|
2552
|
+
}
|
|
2553
|
+
)
|
|
2554
|
+
]
|
|
2555
|
+
}
|
|
2556
|
+
)
|
|
2557
|
+
] }),
|
|
2558
|
+
/* @__PURE__ */ jsx5(
|
|
2559
|
+
Button5,
|
|
2560
|
+
{
|
|
2561
|
+
className: "h-8 justify-center rounded-lg border-border/70 px-3 text-[13px] font-semibold",
|
|
2562
|
+
size: "sm",
|
|
2563
|
+
type: "button",
|
|
2564
|
+
variant: "outline",
|
|
2565
|
+
onClick: () => {
|
|
2566
|
+
void controller.insertReferences("task");
|
|
2567
|
+
},
|
|
2568
|
+
children: copy.t("actions.insertReferences")
|
|
2569
|
+
}
|
|
2570
|
+
)
|
|
2571
|
+
] }),
|
|
2572
|
+
/* @__PURE__ */ jsxs5("div", { className: "grid gap-2.5", children: [
|
|
2573
|
+
/* @__PURE__ */ jsx5("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.content") }),
|
|
2574
|
+
/* @__PURE__ */ jsx5(
|
|
2575
|
+
"textarea",
|
|
2576
|
+
{
|
|
2577
|
+
className: "min-h-[12rem] w-full resize-none rounded-2xl border border-border/70 bg-transparent px-4 py-3 text-sm leading-6 text-foreground outline-none",
|
|
2578
|
+
placeholder: copy.t("composer.taskContentPlaceholder"),
|
|
2579
|
+
value: controller.taskDraft.content,
|
|
2580
|
+
onChange: (event) => controller.setTaskContent(event.target.value)
|
|
2581
|
+
}
|
|
2582
|
+
)
|
|
2583
|
+
] })
|
|
2584
|
+
] }),
|
|
2585
|
+
/* @__PURE__ */ jsx5(
|
|
2586
|
+
IssueManagerContextSection,
|
|
2587
|
+
{
|
|
2588
|
+
copy,
|
|
2589
|
+
emptyLabel: copy.t("messages.noTaskReferences"),
|
|
2590
|
+
refs: taskRefs,
|
|
2591
|
+
onAdd: () => {
|
|
2592
|
+
void controller.attachReferences("task");
|
|
2593
|
+
},
|
|
2594
|
+
onOpen: controller.openReference,
|
|
2595
|
+
onRemove: controller.removeContextRef
|
|
2596
|
+
}
|
|
2597
|
+
),
|
|
2598
|
+
!isCreate ? /* @__PURE__ */ jsx5(
|
|
2599
|
+
IssueManagerRunPanels,
|
|
2600
|
+
{
|
|
2601
|
+
copy,
|
|
2602
|
+
outputs: controller.taskDetail.value?.latestOutputs ?? [],
|
|
2603
|
+
recentRuns: controller.taskDetail.value?.recentRuns ?? [],
|
|
2604
|
+
onOpen: controller.openReference
|
|
2605
|
+
}
|
|
2606
|
+
) : null
|
|
2607
|
+
] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2608
|
+
/* @__PURE__ */ jsx5(
|
|
2609
|
+
IssueManagerDescriptionSection,
|
|
2610
|
+
{
|
|
2611
|
+
content: taskContent,
|
|
2612
|
+
emptyLabel: copy.t("messages.taskContentEmpty"),
|
|
2613
|
+
label: copy.t("labels.content"),
|
|
2614
|
+
minHeightClass: "min-h-[8rem]",
|
|
2615
|
+
onOpen: controller.openReference
|
|
2616
|
+
}
|
|
2617
|
+
),
|
|
2618
|
+
/* @__PURE__ */ jsx5(
|
|
2619
|
+
IssueManagerContextSection,
|
|
2620
|
+
{
|
|
2621
|
+
copy,
|
|
2622
|
+
emptyLabel: copy.t("messages.noTaskReferences"),
|
|
2623
|
+
refs: taskRefs,
|
|
2624
|
+
onAdd: () => {
|
|
2625
|
+
void controller.attachReferences("task");
|
|
2626
|
+
},
|
|
2627
|
+
onOpen: controller.openReference,
|
|
2628
|
+
onRemove: controller.removeContextRef
|
|
2629
|
+
}
|
|
2630
|
+
),
|
|
2631
|
+
/* @__PURE__ */ jsx5(
|
|
2632
|
+
IssueManagerRunPanels,
|
|
2633
|
+
{
|
|
2634
|
+
copy,
|
|
2635
|
+
outputs: controller.taskDetail.value?.latestOutputs ?? [],
|
|
2636
|
+
recentRuns: controller.taskDetail.value?.recentRuns ?? [],
|
|
2637
|
+
onOpen: controller.openReference
|
|
2638
|
+
}
|
|
2639
|
+
)
|
|
2640
|
+
] }) }) }),
|
|
2641
|
+
isRead && selectedTask ? /* @__PURE__ */ jsx5("div", { className: "border-t border-border/70 px-6 py-5", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2642
|
+
/* @__PURE__ */ jsx5(
|
|
2643
|
+
IssueManagerRunActionTrigger,
|
|
2644
|
+
{
|
|
2645
|
+
controller,
|
|
2646
|
+
iconSize: 15,
|
|
2647
|
+
triggerClassName: "min-w-[11rem] rounded-xl border-border/70 bg-secondary/90 px-3.5 py-2"
|
|
2648
|
+
}
|
|
2649
|
+
),
|
|
2650
|
+
/* @__PURE__ */ jsx5(
|
|
2651
|
+
Button5,
|
|
2652
|
+
{
|
|
2653
|
+
className: "shrink-0 rounded-xl bg-foreground px-4 text-background hover:bg-foreground/92",
|
|
2654
|
+
size: "sm",
|
|
2655
|
+
type: "button",
|
|
2656
|
+
onClick: () => {
|
|
2657
|
+
void controller.shareSelection();
|
|
2658
|
+
},
|
|
2659
|
+
children: copy.t("actions.inviteCollaborator")
|
|
2660
|
+
}
|
|
2661
|
+
)
|
|
2662
|
+
] }) }) : isCreate || isEdit ? /* @__PURE__ */ jsx5("div", { className: "border-t border-border/70 px-6 py-5", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2663
|
+
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: !isCreate && selectedTask ? /* @__PURE__ */ jsx5(
|
|
2664
|
+
Button5,
|
|
2665
|
+
{
|
|
2666
|
+
size: "default",
|
|
2667
|
+
type: "button",
|
|
2668
|
+
variant: "destructive",
|
|
2669
|
+
onClick: () => {
|
|
2670
|
+
void controller.deleteTask();
|
|
2671
|
+
},
|
|
2672
|
+
children: copy.t("actions.deleteTask")
|
|
2673
|
+
}
|
|
2674
|
+
) : null }),
|
|
2675
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
|
|
2676
|
+
/* @__PURE__ */ jsx5(
|
|
2677
|
+
Button5,
|
|
2678
|
+
{
|
|
2679
|
+
size: "default",
|
|
2680
|
+
type: "button",
|
|
2681
|
+
variant: "secondary",
|
|
2682
|
+
onClick: () => controller.setTaskEditorMode("read"),
|
|
2683
|
+
children: copy.t("actions.cancel")
|
|
2684
|
+
}
|
|
2685
|
+
),
|
|
2686
|
+
/* @__PURE__ */ jsxs5(
|
|
2687
|
+
Button5,
|
|
2688
|
+
{
|
|
2689
|
+
disabled: !selectedIssue,
|
|
2690
|
+
size: "default",
|
|
2691
|
+
type: "button",
|
|
2692
|
+
onClick: () => void controller.saveTask(),
|
|
2693
|
+
children: [
|
|
2694
|
+
/* @__PURE__ */ jsx5(SparkIcon2, { size: 16 }),
|
|
2695
|
+
copy.t("actions.saveTask")
|
|
2696
|
+
]
|
|
2697
|
+
}
|
|
2698
|
+
)
|
|
2699
|
+
] })
|
|
2700
|
+
] }) }) : null
|
|
2701
|
+
]
|
|
2702
|
+
}
|
|
2703
|
+
)
|
|
2704
|
+
}
|
|
2705
|
+
);
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// src/react/internal/IssueManagerShell.tsx
|
|
2709
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2710
|
+
var issueStatusFilters = [
|
|
2711
|
+
"all",
|
|
2712
|
+
"not_started",
|
|
2713
|
+
"running",
|
|
2714
|
+
"pending_acceptance",
|
|
2715
|
+
"completed",
|
|
2716
|
+
"failed",
|
|
2717
|
+
"canceled"
|
|
2718
|
+
];
|
|
2719
|
+
var sidebarDefaultWidth = 352;
|
|
2720
|
+
var sidebarMinWidth = 248;
|
|
2721
|
+
var sidebarMaxWidth = 520;
|
|
2722
|
+
var mainMinWidth = 460;
|
|
2723
|
+
function IssueManagerShell({
|
|
2724
|
+
controller,
|
|
2725
|
+
onClearNotice,
|
|
2726
|
+
onCloseTaskDrawer,
|
|
2727
|
+
onDismissIssueCreate,
|
|
2728
|
+
selectedIssue,
|
|
2729
|
+
selectedTask
|
|
2730
|
+
}) {
|
|
2731
|
+
const isIssueEditing = controller.issueEditorMode !== "read";
|
|
2732
|
+
const isTaskCreating = !isIssueEditing && controller.taskEditorMode === "create";
|
|
2733
|
+
const isTaskDrawerOpen = !isIssueEditing && !isTaskCreating && (controller.taskEditorMode === "edit" || selectedTask !== null);
|
|
2734
|
+
const layoutRef = useRef2(null);
|
|
2735
|
+
const resizeRef = useRef2(null);
|
|
2736
|
+
const [sidebarWidth, setSidebarWidth] = useState4(sidebarDefaultWidth);
|
|
2737
|
+
useEffect4(() => {
|
|
2738
|
+
const clamp = () => {
|
|
2739
|
+
const width = layoutRef.current?.getBoundingClientRect().width ?? 0;
|
|
2740
|
+
if (!width) {
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2743
|
+
setSidebarWidth((current) => clampSidebarWidth(current, width));
|
|
2744
|
+
};
|
|
2745
|
+
const layout = layoutRef.current;
|
|
2746
|
+
const observer = layout && typeof ResizeObserver !== "undefined" ? new ResizeObserver(clamp) : null;
|
|
2747
|
+
if (observer && layout) {
|
|
2748
|
+
observer.observe(layout);
|
|
2749
|
+
}
|
|
2750
|
+
window.addEventListener("resize", clamp);
|
|
2751
|
+
return () => {
|
|
2752
|
+
observer?.disconnect();
|
|
2753
|
+
window.removeEventListener("resize", clamp);
|
|
2754
|
+
};
|
|
2755
|
+
}, []);
|
|
2756
|
+
const layoutStyle = {
|
|
2757
|
+
"--issue-manager-sidebar-width": `${sidebarWidth}px`
|
|
2758
|
+
};
|
|
2759
|
+
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2760
|
+
controller.notice ? /* @__PURE__ */ jsx6(
|
|
2761
|
+
IssueManagerNoticeBanner,
|
|
2762
|
+
{
|
|
2763
|
+
kind: controller.notice.kind,
|
|
2764
|
+
label: controller.notice.message,
|
|
2765
|
+
onClear: onClearNotice,
|
|
2766
|
+
copy: controller.copy
|
|
2767
|
+
}
|
|
2768
|
+
) : null,
|
|
2769
|
+
/* @__PURE__ */ jsxs6(
|
|
2770
|
+
"div",
|
|
2771
|
+
{
|
|
2772
|
+
className: "grid min-h-0 flex-1 grid-cols-[var(--issue-manager-sidebar-width)_12px_minmax(0,1fr)] overflow-hidden bg-transparent",
|
|
2773
|
+
ref: layoutRef,
|
|
2774
|
+
style: layoutStyle,
|
|
2775
|
+
children: [
|
|
2776
|
+
/* @__PURE__ */ jsx6(IssueManagerSidebar, { controller }),
|
|
2777
|
+
/* @__PURE__ */ jsx6(
|
|
2778
|
+
"div",
|
|
2779
|
+
{
|
|
2780
|
+
"aria-label": controller.copy.t("labels.resizeIssueList"),
|
|
2781
|
+
"aria-orientation": "vertical",
|
|
2782
|
+
"aria-valuemax": sidebarMaxWidth,
|
|
2783
|
+
"aria-valuemin": sidebarMinWidth,
|
|
2784
|
+
"aria-valuenow": sidebarWidth,
|
|
2785
|
+
className: "group flex cursor-col-resize items-center justify-center",
|
|
2786
|
+
role: "separator",
|
|
2787
|
+
tabIndex: 0,
|
|
2788
|
+
onKeyDown: (event) => handleSidebarResizeKeyDown(event, layoutRef, setSidebarWidth),
|
|
2789
|
+
onPointerCancel: (event) => handleSidebarResizePointerEnd(event, resizeRef),
|
|
2790
|
+
onPointerDown: (event) => handleSidebarResizePointerDown(
|
|
2791
|
+
event,
|
|
2792
|
+
layoutRef,
|
|
2793
|
+
resizeRef,
|
|
2794
|
+
sidebarWidth,
|
|
2795
|
+
setSidebarWidth
|
|
2796
|
+
),
|
|
2797
|
+
onPointerMove: (event) => handleSidebarResizePointerMove(event, resizeRef, setSidebarWidth),
|
|
2798
|
+
onPointerUp: (event) => handleSidebarResizePointerEnd(event, resizeRef),
|
|
2799
|
+
children: /* @__PURE__ */ jsx6("span", { className: "h-full w-px rounded-full bg-border/70 transition-colors group-hover:bg-primary/40" })
|
|
2800
|
+
}
|
|
2801
|
+
),
|
|
2802
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative min-h-0 overflow-hidden bg-transparent", children: [
|
|
2803
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
2804
|
+
/* @__PURE__ */ jsx6("div", { className: "min-h-0 flex-1 overflow-hidden", children: isIssueEditing ? /* @__PURE__ */ jsx6(
|
|
2805
|
+
IssueManagerIssuePane,
|
|
2806
|
+
{
|
|
2807
|
+
controller,
|
|
2808
|
+
selectedIssue,
|
|
2809
|
+
onDismissCreate: onDismissIssueCreate
|
|
2810
|
+
}
|
|
2811
|
+
) : isTaskCreating ? /* @__PURE__ */ jsx6(
|
|
2812
|
+
IssueManagerTaskComposerPane,
|
|
2813
|
+
{
|
|
2814
|
+
controller,
|
|
2815
|
+
selectedIssue,
|
|
2816
|
+
onCancel: () => controller.setTaskEditorMode("read")
|
|
2817
|
+
}
|
|
2818
|
+
) : selectedIssue ? /* @__PURE__ */ jsx6(
|
|
2819
|
+
IssueManagerIssuePane,
|
|
2820
|
+
{
|
|
2821
|
+
controller,
|
|
2822
|
+
selectedIssue,
|
|
2823
|
+
onDismissCreate: onDismissIssueCreate
|
|
2824
|
+
}
|
|
2825
|
+
) : /* @__PURE__ */ jsx6("div", { className: "flex h-full min-h-0 items-center justify-center px-10 py-10", children: /* @__PURE__ */ jsxs6("div", { className: "flex max-w-2xl flex-col items-center gap-5 text-center", children: [
|
|
2826
|
+
/* @__PURE__ */ jsx6(IssueManagerEmptyIllustration, {}),
|
|
2827
|
+
/* @__PURE__ */ jsxs6("div", { className: "space-y-3", children: [
|
|
2828
|
+
/* @__PURE__ */ jsx6("h2", { className: "text-[2.05rem] font-semibold tracking-tight text-foreground", children: controller.copy.t("messages.noIssues") }),
|
|
2829
|
+
/* @__PURE__ */ jsx6("p", { className: "max-w-xl text-[1.15rem] leading-8 text-muted-foreground", children: controller.copy.t("emptyState") })
|
|
2830
|
+
] }),
|
|
2831
|
+
/* @__PURE__ */ jsxs6(
|
|
2832
|
+
Button6,
|
|
2833
|
+
{
|
|
2834
|
+
className: "h-12 rounded-xl bg-foreground px-6 text-base font-semibold text-background hover:bg-foreground/92",
|
|
2835
|
+
size: "lg",
|
|
2836
|
+
type: "button",
|
|
2837
|
+
onClick: () => controller.setIssueEditorMode("create"),
|
|
2838
|
+
children: [
|
|
2839
|
+
/* @__PURE__ */ jsx6(FileCreateIcon3, { size: 18 }),
|
|
2840
|
+
controller.copy.t("actions.createIssue")
|
|
2841
|
+
]
|
|
2842
|
+
}
|
|
2843
|
+
)
|
|
2844
|
+
] }) }) }),
|
|
2845
|
+
/* @__PURE__ */ jsx6(
|
|
2846
|
+
IssueManagerBottomBar,
|
|
2847
|
+
{
|
|
2848
|
+
controller,
|
|
2849
|
+
selectedIssue,
|
|
2850
|
+
selectedTask
|
|
2851
|
+
}
|
|
2852
|
+
)
|
|
2853
|
+
] }),
|
|
2854
|
+
isTaskDrawerOpen ? /* @__PURE__ */ jsx6(
|
|
2855
|
+
IssueManagerTaskDrawer,
|
|
2856
|
+
{
|
|
2857
|
+
controller,
|
|
2858
|
+
selectedIssue,
|
|
2859
|
+
selectedTask,
|
|
2860
|
+
onClose: onCloseTaskDrawer
|
|
2861
|
+
}
|
|
2862
|
+
) : null
|
|
2863
|
+
] })
|
|
2864
|
+
]
|
|
2865
|
+
}
|
|
2866
|
+
)
|
|
2867
|
+
] });
|
|
2868
|
+
}
|
|
2869
|
+
function IssueManagerNoticeBanner({
|
|
2870
|
+
copy,
|
|
2871
|
+
kind,
|
|
2872
|
+
label,
|
|
2873
|
+
onClear
|
|
2874
|
+
}) {
|
|
2875
|
+
return /* @__PURE__ */ jsx6(
|
|
2876
|
+
"div",
|
|
2877
|
+
{
|
|
2878
|
+
className: cn4(
|
|
2879
|
+
"border-b px-4 py-2.5 text-sm",
|
|
2880
|
+
kind === "error" ? "border-destructive/20 bg-destructive/8 text-destructive" : "border-primary/15 bg-primary/[0.06] text-foreground"
|
|
2881
|
+
),
|
|
2882
|
+
children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2883
|
+
/* @__PURE__ */ jsx6("span", { children: label }),
|
|
2884
|
+
/* @__PURE__ */ jsx6(
|
|
2885
|
+
Button6,
|
|
2886
|
+
{
|
|
2887
|
+
"aria-label": copy.t("actions.cancel"),
|
|
2888
|
+
size: "icon-xs",
|
|
2889
|
+
type: "button",
|
|
2890
|
+
variant: "ghost",
|
|
2891
|
+
onClick: onClear,
|
|
2892
|
+
children: /* @__PURE__ */ jsx6(CloseIcon2, { size: 14 })
|
|
2893
|
+
}
|
|
2894
|
+
)
|
|
2895
|
+
] })
|
|
2896
|
+
}
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2899
|
+
function IssueManagerSidebar({
|
|
2900
|
+
controller
|
|
2901
|
+
}) {
|
|
2902
|
+
const copy = controller.copy;
|
|
2903
|
+
const counts = buildIssueManagerStatusCounts(controller.issues.value);
|
|
2904
|
+
const showRefreshAction = controller.issues.isLoading || controller.issues.error !== null;
|
|
2905
|
+
const tabsViewportRef = useRef2(null);
|
|
2906
|
+
const [canScrollTabsLeft, setCanScrollTabsLeft] = useState4(false);
|
|
2907
|
+
const [canScrollTabsRight, setCanScrollTabsRight] = useState4(false);
|
|
2908
|
+
useEffect4(() => {
|
|
2909
|
+
const viewport = tabsViewportRef.current;
|
|
2910
|
+
if (!viewport) {
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
const updateScrollState = () => {
|
|
2914
|
+
const maxScrollLeft = viewport.scrollWidth - viewport.clientWidth;
|
|
2915
|
+
setCanScrollTabsLeft(viewport.scrollLeft > 4);
|
|
2916
|
+
setCanScrollTabsRight(
|
|
2917
|
+
maxScrollLeft > 4 && viewport.scrollLeft < maxScrollLeft - 4
|
|
2918
|
+
);
|
|
2919
|
+
};
|
|
2920
|
+
updateScrollState();
|
|
2921
|
+
viewport.addEventListener("scroll", updateScrollState, { passive: true });
|
|
2922
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateScrollState) : null;
|
|
2923
|
+
observer?.observe(viewport);
|
|
2924
|
+
if (viewport.parentElement) {
|
|
2925
|
+
observer?.observe(viewport.parentElement);
|
|
2926
|
+
}
|
|
2927
|
+
return () => {
|
|
2928
|
+
viewport.removeEventListener("scroll", updateScrollState);
|
|
2929
|
+
observer?.disconnect();
|
|
2930
|
+
};
|
|
2931
|
+
}, [controller.issues.value.length]);
|
|
2932
|
+
return /* @__PURE__ */ jsxs6("aside", { className: "flex min-h-0 flex-col border-r border-border/70 bg-transparent", children: [
|
|
2933
|
+
/* @__PURE__ */ jsx6("div", { className: "border-b border-border/70 px-4 py-4", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
2934
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative flex-1", children: [
|
|
2935
|
+
/* @__PURE__ */ jsx6(SearchIcon2, { className: "pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-muted-foreground" }),
|
|
2936
|
+
/* @__PURE__ */ jsx6(
|
|
2937
|
+
Input5,
|
|
2938
|
+
{
|
|
2939
|
+
className: "h-8 rounded-lg border-0 bg-muted/45 pr-3 pl-9 text-[14px] shadow-none placeholder:text-muted-foreground",
|
|
2940
|
+
placeholder: copy.t("labels.searchIssues"),
|
|
2941
|
+
value: controller.nodeState.issueSearchQuery,
|
|
2942
|
+
onChange: (event) => controller.setIssueSearchQuery(event.target.value)
|
|
2943
|
+
}
|
|
2944
|
+
)
|
|
2945
|
+
] }),
|
|
2946
|
+
/* @__PURE__ */ jsxs6(
|
|
2947
|
+
Button6,
|
|
2948
|
+
{
|
|
2949
|
+
className: "h-8 rounded-lg border-0 bg-secondary px-3 text-[13px] font-semibold text-foreground shadow-none hover:bg-accent/35",
|
|
2950
|
+
size: "sm",
|
|
2951
|
+
type: "button",
|
|
2952
|
+
variant: "secondary",
|
|
2953
|
+
onClick: () => controller.setIssueEditorMode("create"),
|
|
2954
|
+
children: [
|
|
2955
|
+
/* @__PURE__ */ jsx6(FileCreateIcon3, { size: 16 }),
|
|
2956
|
+
copy.t("actions.createIssue")
|
|
2957
|
+
]
|
|
2958
|
+
}
|
|
2959
|
+
)
|
|
2960
|
+
] }) }),
|
|
2961
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative border-b border-border/70 px-4 pt-3", children: [
|
|
2962
|
+
canScrollTabsLeft ? /* @__PURE__ */ jsx6(
|
|
2963
|
+
Button6,
|
|
2964
|
+
{
|
|
2965
|
+
"aria-label": copy.t("labels.scrollStatusTabsLeft"),
|
|
2966
|
+
className: "absolute top-1/2 left-4 z-10 h-6 w-6 -translate-y-1/2 rounded-full border-0 bg-background/96 p-0 shadow-sm",
|
|
2967
|
+
size: "icon-xs",
|
|
2968
|
+
type: "button",
|
|
2969
|
+
variant: "ghost",
|
|
2970
|
+
onClick: () => scrollIssueManagerStatusTabs(tabsViewportRef, -120),
|
|
2971
|
+
children: /* @__PURE__ */ jsx6(ArrowLeftIcon, { size: 14 })
|
|
2972
|
+
}
|
|
2973
|
+
) : null,
|
|
2974
|
+
/* @__PURE__ */ jsx6(
|
|
2975
|
+
"div",
|
|
2976
|
+
{
|
|
2977
|
+
className: cn4(
|
|
2978
|
+
"flex h-8 items-center gap-[14px] overflow-x-auto pb-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
2979
|
+
canScrollTabsLeft ? "pl-8" : "",
|
|
2980
|
+
canScrollTabsRight ? "pr-8" : ""
|
|
2981
|
+
),
|
|
2982
|
+
ref: tabsViewportRef,
|
|
2983
|
+
children: issueStatusFilters.map((status) => {
|
|
2984
|
+
const isActive = controller.nodeState.issueStatusFilter === status;
|
|
2985
|
+
return /* @__PURE__ */ jsxs6(
|
|
2986
|
+
"button",
|
|
2987
|
+
{
|
|
2988
|
+
className: cn4(
|
|
2989
|
+
"flex h-6 shrink-0 items-center gap-1.5 border-b-2 px-0 pb-2 text-[13px] font-semibold transition-colors",
|
|
2990
|
+
isActive ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"
|
|
2991
|
+
),
|
|
2992
|
+
type: "button",
|
|
2993
|
+
onClick: () => controller.setIssueStatusFilter(status),
|
|
2994
|
+
children: [
|
|
2995
|
+
/* @__PURE__ */ jsx6("span", { children: status === "all" ? copy.t("labels.allStatus") : resolveIssueManagerStatusLabel(copy, status) }),
|
|
2996
|
+
/* @__PURE__ */ jsx6("span", { className: "text-[12px] text-muted-foreground/80", children: counts[status] ?? 0 })
|
|
2997
|
+
]
|
|
2998
|
+
},
|
|
2999
|
+
status
|
|
3000
|
+
);
|
|
3001
|
+
})
|
|
3002
|
+
}
|
|
3003
|
+
),
|
|
3004
|
+
canScrollTabsRight ? /* @__PURE__ */ jsx6(
|
|
3005
|
+
Button6,
|
|
3006
|
+
{
|
|
3007
|
+
"aria-label": copy.t("labels.scrollStatusTabsRight"),
|
|
3008
|
+
className: "absolute top-1/2 right-4 z-10 h-6 w-6 -translate-y-1/2 rounded-full border-0 bg-background/96 p-0 shadow-sm",
|
|
3009
|
+
size: "icon-xs",
|
|
3010
|
+
type: "button",
|
|
3011
|
+
variant: "ghost",
|
|
3012
|
+
onClick: () => scrollIssueManagerStatusTabs(tabsViewportRef, 120),
|
|
3013
|
+
children: /* @__PURE__ */ jsx6(ArrowRightIcon, { size: 14 })
|
|
3014
|
+
}
|
|
3015
|
+
) : null
|
|
3016
|
+
] }),
|
|
3017
|
+
/* @__PURE__ */ jsx6(ScrollArea4, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx6("div", { className: "flex min-h-full flex-col px-0 py-0", children: controller.issues.isLoading && controller.issues.value.length === 0 ? /* @__PURE__ */ jsx6(IssueManagerSidebarLoadingState, {}) : controller.issues.error ? /* @__PURE__ */ jsx6(
|
|
3018
|
+
IssueManagerSidebarEmptyState,
|
|
3019
|
+
{
|
|
3020
|
+
body: controller.issues.error,
|
|
3021
|
+
title: copy.t("messages.noIssues"),
|
|
3022
|
+
tone: "destructive"
|
|
3023
|
+
}
|
|
3024
|
+
) : controller.issues.value.length === 0 ? /* @__PURE__ */ jsx6(
|
|
3025
|
+
IssueManagerSidebarEmptyState,
|
|
3026
|
+
{
|
|
3027
|
+
body: copy.t("messages.noIssuesForFilterBody"),
|
|
3028
|
+
title: copy.t("messages.noIssuesForFilterTitle")
|
|
3029
|
+
}
|
|
3030
|
+
) : /* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-2.5 px-4 pt-1.5 pb-4", children: controller.issues.value.map((issue) => /* @__PURE__ */ jsx6(
|
|
3031
|
+
IssueManagerSidebarItem,
|
|
3032
|
+
{
|
|
3033
|
+
copy,
|
|
3034
|
+
issue,
|
|
3035
|
+
selected: controller.nodeState.selectedIssueId === issue.issueId,
|
|
3036
|
+
onSelect: controller.selectIssue
|
|
3037
|
+
},
|
|
3038
|
+
issue.issueId
|
|
3039
|
+
)) }) }) }),
|
|
3040
|
+
showRefreshAction ? /* @__PURE__ */ jsx6("div", { className: "border-t border-border/70 px-6 py-4", children: /* @__PURE__ */ jsxs6(
|
|
3041
|
+
Button6,
|
|
3042
|
+
{
|
|
3043
|
+
className: "w-full justify-center",
|
|
3044
|
+
size: "sm",
|
|
3045
|
+
type: "button",
|
|
3046
|
+
variant: "ghost",
|
|
3047
|
+
onClick: controller.refreshAll,
|
|
3048
|
+
children: [
|
|
3049
|
+
/* @__PURE__ */ jsx6(RefreshIcon, { size: 14 }),
|
|
3050
|
+
copy.t("actions.refresh")
|
|
3051
|
+
]
|
|
3052
|
+
}
|
|
3053
|
+
) }) : null
|
|
3054
|
+
] });
|
|
3055
|
+
}
|
|
3056
|
+
function IssueManagerBottomBar({
|
|
3057
|
+
controller,
|
|
3058
|
+
selectedIssue,
|
|
3059
|
+
selectedTask
|
|
3060
|
+
}) {
|
|
3061
|
+
const copy = controller.copy;
|
|
3062
|
+
if (!selectedIssue || controller.issueEditorMode !== "read" || controller.taskEditorMode !== "read") {
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
return /* @__PURE__ */ jsx6("div", { className: "border-t border-border/70 bg-transparent px-6 py-4 backdrop-blur", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-end gap-3", children: [
|
|
3066
|
+
/* @__PURE__ */ jsx6(
|
|
3067
|
+
IssueManagerRunActionTrigger,
|
|
3068
|
+
{
|
|
3069
|
+
controller,
|
|
3070
|
+
disabled: !selectedTask,
|
|
3071
|
+
triggerClassName: "min-w-[14rem] rounded-xl border-border/70 bg-secondary/90 px-4 py-2"
|
|
3072
|
+
}
|
|
3073
|
+
),
|
|
3074
|
+
/* @__PURE__ */ jsx6(
|
|
3075
|
+
Button6,
|
|
3076
|
+
{
|
|
3077
|
+
disabled: !selectedIssue,
|
|
3078
|
+
className: "rounded-xl bg-foreground px-4 text-background hover:bg-foreground/92",
|
|
3079
|
+
size: "sm",
|
|
3080
|
+
type: "button",
|
|
3081
|
+
onClick: () => {
|
|
3082
|
+
void controller.shareSelection();
|
|
3083
|
+
},
|
|
3084
|
+
children: copy.t("actions.inviteCollaborator")
|
|
3085
|
+
}
|
|
3086
|
+
)
|
|
3087
|
+
] }) });
|
|
3088
|
+
}
|
|
3089
|
+
function IssueManagerSidebarItem({
|
|
3090
|
+
copy,
|
|
3091
|
+
issue,
|
|
3092
|
+
onSelect,
|
|
3093
|
+
selected
|
|
3094
|
+
}) {
|
|
3095
|
+
return /* @__PURE__ */ jsxs6(
|
|
3096
|
+
"button",
|
|
3097
|
+
{
|
|
3098
|
+
className: cn4(
|
|
3099
|
+
"w-full rounded-lg border px-3.5 py-3.5 text-left transition-colors",
|
|
3100
|
+
selected ? "border-border/90 bg-background-fronted" : "border-border/80 bg-transparent hover:bg-accent/18"
|
|
3101
|
+
),
|
|
3102
|
+
type: "button",
|
|
3103
|
+
onClick: () => onSelect(issue.issueId),
|
|
3104
|
+
children: [
|
|
3105
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-start justify-between gap-3", children: [
|
|
3106
|
+
/* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1 space-y-2", children: [
|
|
3107
|
+
/* @__PURE__ */ jsx6("p", { className: "text-[12px] leading-[1.55] text-muted-foreground", children: formatSidebarTimestamp(issue.updatedAtUnix ?? issue.createdAtUnix) }),
|
|
3108
|
+
/* @__PURE__ */ jsx6("p", { className: "line-clamp-4 text-[14px] font-semibold leading-[1.35rem] text-foreground", children: issue.title })
|
|
3109
|
+
] }),
|
|
3110
|
+
/* @__PURE__ */ jsx6(Badge5, { className: "rounded-full border-transparent bg-muted px-2 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, issue.status) })
|
|
3111
|
+
] }),
|
|
3112
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-2 text-[12px] leading-[1.55] text-muted-foreground", children: copy.t("labels.taskCount", { count: issue.taskCount ?? 0 }) })
|
|
3113
|
+
]
|
|
3114
|
+
}
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
function IssueManagerSidebarLoadingState() {
|
|
3118
|
+
return /* @__PURE__ */ jsx6("div", { className: "grid gap-2.5 px-4 pt-1.5 pb-4", "aria-hidden": "true", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-transparent px-3.5 py-3.5", children: [
|
|
3119
|
+
/* @__PURE__ */ jsx6("div", { className: "h-3.5 w-20 rounded-full bg-muted" }),
|
|
3120
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-3 h-4 w-4/5 rounded-full bg-muted" }),
|
|
3121
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-4 h-3.5 w-24 rounded-full bg-muted" })
|
|
3122
|
+
] }, index)) });
|
|
3123
|
+
}
|
|
3124
|
+
function IssueManagerSidebarEmptyState({
|
|
3125
|
+
body,
|
|
3126
|
+
title,
|
|
3127
|
+
tone = "default"
|
|
3128
|
+
}) {
|
|
3129
|
+
return /* @__PURE__ */ jsxs6("div", { className: "relative flex min-h-[240px] flex-1 flex-col items-center justify-center gap-1.5 overflow-hidden px-6 py-8 text-center", children: [
|
|
3130
|
+
/* @__PURE__ */ jsx6(
|
|
3131
|
+
"div",
|
|
3132
|
+
{
|
|
3133
|
+
"aria-hidden": "true",
|
|
3134
|
+
className: "pointer-events-none absolute inset-0 flex flex-col gap-2.5 opacity-[0.72] [mask-image:linear-gradient(to_bottom,black_0%,black_30%,transparent_100%)]",
|
|
3135
|
+
children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx6("div", { className: "mx-4 h-24 rounded-lg bg-muted/45" }, index))
|
|
3136
|
+
}
|
|
3137
|
+
),
|
|
3138
|
+
/* @__PURE__ */ jsx6(
|
|
3139
|
+
"p",
|
|
3140
|
+
{
|
|
3141
|
+
className: cn4(
|
|
3142
|
+
"relative z-[1] text-sm font-semibold leading-5 text-foreground",
|
|
3143
|
+
tone === "destructive" ? "text-destructive" : "text-foreground"
|
|
3144
|
+
),
|
|
3145
|
+
children: title
|
|
3146
|
+
}
|
|
3147
|
+
),
|
|
3148
|
+
/* @__PURE__ */ jsx6("p", { className: "relative z-[1] max-w-sm text-sm leading-5 text-muted-foreground", children: body })
|
|
3149
|
+
] });
|
|
3150
|
+
}
|
|
3151
|
+
function buildIssueManagerStatusCounts(issues) {
|
|
3152
|
+
const counts = {
|
|
3153
|
+
all: issues.length,
|
|
3154
|
+
canceled: 0,
|
|
3155
|
+
completed: 0,
|
|
3156
|
+
failed: 0,
|
|
3157
|
+
not_started: 0,
|
|
3158
|
+
pending_acceptance: 0,
|
|
3159
|
+
running: 0
|
|
3160
|
+
};
|
|
3161
|
+
for (const issue of issues) {
|
|
3162
|
+
if (issue.status in counts) {
|
|
3163
|
+
counts[issue.status] += 1;
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
return counts;
|
|
3167
|
+
}
|
|
3168
|
+
function formatSidebarTimestamp(value) {
|
|
3169
|
+
return formatIssueManagerDate(value);
|
|
3170
|
+
}
|
|
3171
|
+
function scrollIssueManagerStatusTabs(tabsViewportRef, delta) {
|
|
3172
|
+
tabsViewportRef.current?.scrollBy({
|
|
3173
|
+
behavior: "smooth",
|
|
3174
|
+
left: delta
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
function clampSidebarWidth(width, layoutWidth) {
|
|
3178
|
+
const maxWidth = Math.max(
|
|
3179
|
+
sidebarMinWidth,
|
|
3180
|
+
Math.min(sidebarMaxWidth, layoutWidth - mainMinWidth - 12)
|
|
3181
|
+
);
|
|
3182
|
+
return Math.min(Math.max(width, sidebarMinWidth), maxWidth);
|
|
3183
|
+
}
|
|
3184
|
+
function handleSidebarResizePointerDown(event, layoutRef, resizeRef, sidebarWidth, setSidebarWidth) {
|
|
3185
|
+
if (event.button !== 0) {
|
|
3186
|
+
return;
|
|
3187
|
+
}
|
|
3188
|
+
const layoutWidth = layoutRef.current?.getBoundingClientRect().width ?? 0;
|
|
3189
|
+
if (!layoutWidth) {
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
const startWidth = clampSidebarWidth(sidebarWidth, layoutWidth);
|
|
3193
|
+
resizeRef.current = {
|
|
3194
|
+
maxWidth: clampSidebarWidth(sidebarMaxWidth, layoutWidth),
|
|
3195
|
+
pointerId: event.pointerId,
|
|
3196
|
+
startClientX: event.clientX,
|
|
3197
|
+
startWidth
|
|
3198
|
+
};
|
|
3199
|
+
setSidebarWidth(startWidth);
|
|
3200
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
3201
|
+
}
|
|
3202
|
+
function handleSidebarResizePointerMove(event, resizeRef, setSidebarWidth) {
|
|
3203
|
+
const state = resizeRef.current;
|
|
3204
|
+
if (!state || state.pointerId !== event.pointerId) {
|
|
3205
|
+
return;
|
|
3206
|
+
}
|
|
3207
|
+
setSidebarWidth(
|
|
3208
|
+
Math.min(
|
|
3209
|
+
Math.max(
|
|
3210
|
+
state.startWidth + event.clientX - state.startClientX,
|
|
3211
|
+
sidebarMinWidth
|
|
3212
|
+
),
|
|
3213
|
+
state.maxWidth
|
|
3214
|
+
)
|
|
3215
|
+
);
|
|
3216
|
+
}
|
|
3217
|
+
function handleSidebarResizePointerEnd(event, resizeRef) {
|
|
3218
|
+
resizeRef.current = null;
|
|
3219
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
3220
|
+
}
|
|
3221
|
+
function handleSidebarResizeKeyDown(event, layoutRef, setSidebarWidth) {
|
|
3222
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") {
|
|
3223
|
+
return;
|
|
3224
|
+
}
|
|
3225
|
+
const delta = event.key === "ArrowRight" ? 16 : -16;
|
|
3226
|
+
const layoutWidth = layoutRef.current?.getBoundingClientRect().width ?? 0;
|
|
3227
|
+
if (!layoutWidth) {
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
event.preventDefault();
|
|
3231
|
+
setSidebarWidth((current) => clampSidebarWidth(current + delta, layoutWidth));
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// src/react/IssueManagerNode.tsx
|
|
3235
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3236
|
+
function IssueManagerNode({
|
|
3237
|
+
feature,
|
|
3238
|
+
nodeId,
|
|
3239
|
+
onStateChange,
|
|
3240
|
+
state,
|
|
3241
|
+
workspaceId
|
|
3242
|
+
}) {
|
|
3243
|
+
const controller = useIssueManagerController({
|
|
3244
|
+
feature,
|
|
3245
|
+
onStateChange,
|
|
3246
|
+
state,
|
|
3247
|
+
workspaceId
|
|
3248
|
+
});
|
|
3249
|
+
const selectedIssue = resolveSelectedIssue(controller);
|
|
3250
|
+
const selectedTask = resolveSelectedTask(controller);
|
|
3251
|
+
return /* @__PURE__ */ jsxs7(
|
|
3252
|
+
"section",
|
|
3253
|
+
{
|
|
3254
|
+
"aria-label": controller.copy.t("title"),
|
|
3255
|
+
className: "flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden text-foreground",
|
|
3256
|
+
"data-issue-manager-node-id": nodeId,
|
|
3257
|
+
"data-issue-manager-workspace-id": workspaceId,
|
|
3258
|
+
children: [
|
|
3259
|
+
/* @__PURE__ */ jsx7(
|
|
3260
|
+
IssueManagerShell,
|
|
3261
|
+
{
|
|
3262
|
+
controller,
|
|
3263
|
+
selectedIssue,
|
|
3264
|
+
selectedTask,
|
|
3265
|
+
onClearNotice: controller.clearNotice,
|
|
3266
|
+
onCloseTaskDrawer: () => {
|
|
3267
|
+
controller.setTaskEditorMode("read");
|
|
3268
|
+
controller.selectTask(null);
|
|
3269
|
+
},
|
|
3270
|
+
onDismissIssueCreate: () => {
|
|
3271
|
+
controller.setIssueEditorMode("read");
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
),
|
|
3275
|
+
/* @__PURE__ */ jsx7(
|
|
3276
|
+
IssueManagerReferencePicker,
|
|
3277
|
+
{
|
|
3278
|
+
copy: controller.copy,
|
|
3279
|
+
fileAdapter: feature.fileAdapter,
|
|
3280
|
+
open: controller.referenceTarget !== null,
|
|
3281
|
+
workspaceId,
|
|
3282
|
+
onClose: () => controller.setReferenceTarget(null),
|
|
3283
|
+
onConfirm: (refs) => {
|
|
3284
|
+
void controller.submitReferenceSelection(refs);
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
)
|
|
3288
|
+
]
|
|
3289
|
+
}
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3292
|
+
function IssueManagerNodeHeader() {
|
|
3293
|
+
return null;
|
|
3294
|
+
}
|
|
3295
|
+
function resolveSelectedIssue(controller) {
|
|
3296
|
+
const issueId = controller.nodeState.selectedIssueId;
|
|
3297
|
+
if (!issueId) {
|
|
3298
|
+
return null;
|
|
3299
|
+
}
|
|
3300
|
+
return controller.issueDetail.value?.issue ?? controller.issues.value.find((issue) => issue.issueId === issueId) ?? null;
|
|
3301
|
+
}
|
|
3302
|
+
function resolveSelectedTask(controller) {
|
|
3303
|
+
const taskId = controller.nodeState.selectedTaskId;
|
|
3304
|
+
if (!taskId) {
|
|
3305
|
+
return null;
|
|
3306
|
+
}
|
|
3307
|
+
return controller.taskDetail.value?.task ?? controller.issueDetail.value?.tasks.find(
|
|
3308
|
+
(task) => task.taskId === taskId
|
|
3309
|
+
) ?? null;
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
export {
|
|
3313
|
+
IssueManagerNode,
|
|
3314
|
+
IssueManagerNodeHeader
|
|
3315
|
+
};
|
|
3316
|
+
//# sourceMappingURL=chunk-RX6P2DPR.js.map
|