@nextop-os/workspace-issue-manager 0.0.18 → 0.0.20

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