@burdenoff/planmagnet-fe-sdk 2026.704.3 → 2026.705.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +41 -5
- package/dist/index.js +191 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -271,8 +271,9 @@ interface BoardColumn {
|
|
|
271
271
|
}
|
|
272
272
|
/**
|
|
273
273
|
* The default, ordered board columns. Product-agnostic — no farm semantics.
|
|
274
|
-
*
|
|
275
|
-
*
|
|
274
|
+
* Covers every TaskStatus so a task can never be "orphaned" off the board
|
|
275
|
+
* (a CANCELLED item has a home). Callers can trim/reorder via
|
|
276
|
+
* TaskBoardCoreProps.columns.
|
|
276
277
|
*/
|
|
277
278
|
declare const DEFAULT_BOARD_COLUMNS: BoardColumn[];
|
|
278
279
|
/** Priority filter options (UI order). */
|
|
@@ -432,6 +433,12 @@ interface TaskBoardCoreProps {
|
|
|
432
433
|
columns?: BoardColumn[];
|
|
433
434
|
/** Read-only mode — disables drag-to-move. */
|
|
434
435
|
readonly?: boolean;
|
|
436
|
+
/**
|
|
437
|
+
* Ask for confirmation before a drag-drop moves a task to another column.
|
|
438
|
+
* Defaults to `true` — an accidental drag shouldn't silently change a task's
|
|
439
|
+
* status. Set `false` for instant, Linear-style moves.
|
|
440
|
+
*/
|
|
441
|
+
confirmMove?: boolean;
|
|
435
442
|
/** Hide the board's own header (title + count). */
|
|
436
443
|
hideHeader?: boolean;
|
|
437
444
|
/**
|
|
@@ -483,7 +490,7 @@ interface TaskBoardCoreProps {
|
|
|
483
490
|
* (optimistic cache update + `UPDATE_WORK_ITEM`; reverts on error). Filtering
|
|
484
491
|
* is controlled by the parent toolbar. Farm-free, semantic-token only.
|
|
485
492
|
*/
|
|
486
|
-
declare function TaskBoardCore({ projectId, columns, readonly, hideHeader, priority, type, search, assigneeId, hiddenFields, resolveAssignee, linkSourceProduct, renderLinkIcon, onTaskClick, className, workspaceId: workspaceIdProp, }: TaskBoardCoreProps): react.JSX.Element;
|
|
493
|
+
declare function TaskBoardCore({ projectId, columns, readonly, confirmMove, hideHeader, priority, type, search, assigneeId, hiddenFields, resolveAssignee, linkSourceProduct, renderLinkIcon, onTaskClick, className, workspaceId: workspaceIdProp, }: TaskBoardCoreProps): react.JSX.Element;
|
|
487
494
|
|
|
488
495
|
interface TaskBoardProps extends TaskBoardCoreProps {
|
|
489
496
|
/** Workspace API gateway URL (URL mode). */
|
|
@@ -795,6 +802,21 @@ interface TaskDetailCoreProps {
|
|
|
795
802
|
resolveAssignee?: ResolveAssignee;
|
|
796
803
|
/** Optional host-provided member directory → renders a picker instead of a raw id field. */
|
|
797
804
|
assigneeOptions?: AssigneeOption[];
|
|
805
|
+
/**
|
|
806
|
+
* Product key for cross-product entity links (e.g. "healthybowl"). When set,
|
|
807
|
+
* the read view shows this task's linked records (fields/crops/animals). Opt-in
|
|
808
|
+
* so the SDK stays farm-free.
|
|
809
|
+
*/
|
|
810
|
+
linkSourceProduct?: string;
|
|
811
|
+
/** Optional host hook to render an icon per linked-entity type. */
|
|
812
|
+
renderLinkIcon?: RenderLinkIcon;
|
|
813
|
+
/** Open another work item's detail (parent link / sub-task row click). */
|
|
814
|
+
onOpenItem?: (id: string) => void;
|
|
815
|
+
/** Start creating a sub-task under this item (the "Add sub-task" affordance). */
|
|
816
|
+
onAddSubtask?: (parent: {
|
|
817
|
+
id: string;
|
|
818
|
+
projectId: string;
|
|
819
|
+
}) => void;
|
|
798
820
|
/** Extra classes on the root container. */
|
|
799
821
|
className?: string;
|
|
800
822
|
}
|
|
@@ -803,7 +825,7 @@ interface TaskDetailCoreProps {
|
|
|
803
825
|
* edit. Fetches via `planmagnetWorkItem(id)`, saves via
|
|
804
826
|
* `planmagnetUpdateWorkItem`. BYO-Apollo, semantic-token only, farm-free.
|
|
805
827
|
*/
|
|
806
|
-
declare function TaskDetailCore({ id, readonly, hiddenFields, hideHeader, onUpdated, onDeleted, onError, resolveAssignee, assigneeOptions, className, }: TaskDetailCoreProps): react.JSX.Element;
|
|
828
|
+
declare function TaskDetailCore({ id, readonly, hiddenFields, hideHeader, onUpdated, onDeleted, onError, resolveAssignee, assigneeOptions, linkSourceProduct, renderLinkIcon, onOpenItem, onAddSubtask, className, }: TaskDetailCoreProps): react.JSX.Element;
|
|
807
829
|
|
|
808
830
|
interface TaskDetailProps extends TaskDetailCoreProps {
|
|
809
831
|
/** Workspace API gateway URL (URL mode). */
|
|
@@ -862,6 +884,9 @@ interface TaskLabels {
|
|
|
862
884
|
noTasks: string;
|
|
863
885
|
noTasksFound: string;
|
|
864
886
|
dropHere: string;
|
|
887
|
+
moveConfirmTitle: string;
|
|
888
|
+
moveConfirmPrompt: string;
|
|
889
|
+
moveConfirm: string;
|
|
865
890
|
unassigned: string;
|
|
866
891
|
assigned: string;
|
|
867
892
|
overdue: string;
|
|
@@ -897,6 +922,12 @@ interface TaskLabels {
|
|
|
897
922
|
storyPointsLabel: string;
|
|
898
923
|
labelsLabel: string;
|
|
899
924
|
labelsPlaceholder: string;
|
|
925
|
+
linkedRecordsLabel: string;
|
|
926
|
+
createdLabel: string;
|
|
927
|
+
updatedLabel: string;
|
|
928
|
+
parentLabel: string;
|
|
929
|
+
subtasksLabel: string;
|
|
930
|
+
addSubtask: string;
|
|
900
931
|
create: string;
|
|
901
932
|
creating: string;
|
|
902
933
|
cancel: string;
|
|
@@ -973,6 +1004,11 @@ interface TasksPageCoreProps {
|
|
|
973
1004
|
views?: TaskView[];
|
|
974
1005
|
/** Initial view. Defaults to "board". */
|
|
975
1006
|
defaultView?: TaskView;
|
|
1007
|
+
/**
|
|
1008
|
+
* Ask for confirmation before a board drag-drop moves a task. Defaults to
|
|
1009
|
+
* `true`; set `false` for instant, Linear-style moves.
|
|
1010
|
+
*/
|
|
1011
|
+
confirmMove?: boolean;
|
|
976
1012
|
/** Optional host hook to resolve an assignee id → display name. */
|
|
977
1013
|
resolveAssignee?: ResolveAssignee;
|
|
978
1014
|
/**
|
|
@@ -1022,7 +1058,7 @@ interface TasksPageCoreProps {
|
|
|
1022
1058
|
* BYO-Apollo: reads the ambient `<ApolloProvider>` and takes `workspaceId` from
|
|
1023
1059
|
* a prop or the PlanMagnetProvider context. Semantic tokens only, farm-free.
|
|
1024
1060
|
*/
|
|
1025
|
-
declare function TasksPageCore({ workspaceId: workspaceIdProp, projectId, boardProjectId, columns, readonly, hiddenFields, views, defaultView, resolveAssignee, linkSourceProduct, renderLinkIcon, assigneeOptions, currentActorId, labels, openItemId, header, onTaskSaved, createSurface, detailSurface, className, }: TasksPageCoreProps): react.JSX.Element;
|
|
1061
|
+
declare function TasksPageCore({ workspaceId: workspaceIdProp, projectId, boardProjectId, columns, readonly, hiddenFields, views, defaultView, confirmMove, resolveAssignee, linkSourceProduct, renderLinkIcon, assigneeOptions, currentActorId, labels, openItemId, header, onTaskSaved, createSurface, detailSurface, className, }: TasksPageCoreProps): react.JSX.Element;
|
|
1026
1062
|
|
|
1027
1063
|
interface TasksPageProps extends TasksPageCoreProps {
|
|
1028
1064
|
/** Workspace API gateway URL (URL mode). */
|
package/dist/index.js
CHANGED
|
@@ -536,6 +536,10 @@ function formatDueDate(iso) {
|
|
|
536
536
|
d.getFullYear() === now.getFullYear() ? "MMM d" : "MMM d yyyy"
|
|
537
537
|
);
|
|
538
538
|
}
|
|
539
|
+
function formatDateFull(iso) {
|
|
540
|
+
const d = parseDate(iso);
|
|
541
|
+
return d ? format(d, "MMM d, yyyy") : null;
|
|
542
|
+
}
|
|
539
543
|
function isOverdue(iso, status) {
|
|
540
544
|
const d = parseDate(iso);
|
|
541
545
|
if (!d) return false;
|
|
@@ -632,7 +636,8 @@ var DEFAULT_BOARD_COLUMNS = [
|
|
|
632
636
|
{ status: "IN_PROGRESS", label: "In Progress" },
|
|
633
637
|
{ status: "IN_REVIEW", label: "In Review" },
|
|
634
638
|
{ status: "TESTING", label: "Testing" },
|
|
635
|
-
{ status: "DONE", label: "Done" }
|
|
639
|
+
{ status: "DONE", label: "Done" },
|
|
640
|
+
{ status: "CANCELLED", label: "Cancelled" }
|
|
636
641
|
];
|
|
637
642
|
var TASK_PRIORITIES = [
|
|
638
643
|
"NONE",
|
|
@@ -702,6 +707,9 @@ var DEFAULT_TASK_LABELS = {
|
|
|
702
707
|
noTasks: "No tasks",
|
|
703
708
|
noTasksFound: "No tasks found.",
|
|
704
709
|
dropHere: "Drop here",
|
|
710
|
+
moveConfirmTitle: "Move task?",
|
|
711
|
+
moveConfirmPrompt: 'Move "{task}" to {status}?',
|
|
712
|
+
moveConfirm: "Move",
|
|
705
713
|
unassigned: "Unassigned",
|
|
706
714
|
assigned: "Assigned",
|
|
707
715
|
overdue: "{n} overdue",
|
|
@@ -737,6 +745,12 @@ var DEFAULT_TASK_LABELS = {
|
|
|
737
745
|
storyPointsLabel: "Story points",
|
|
738
746
|
labelsLabel: "Labels",
|
|
739
747
|
labelsPlaceholder: "comma, separated, labels",
|
|
748
|
+
linkedRecordsLabel: "Linked records",
|
|
749
|
+
createdLabel: "Created",
|
|
750
|
+
updatedLabel: "Updated",
|
|
751
|
+
parentLabel: "Parent",
|
|
752
|
+
subtasksLabel: "Sub-tasks",
|
|
753
|
+
addSubtask: "Add sub-task",
|
|
740
754
|
create: "Create task",
|
|
741
755
|
creating: "Creating\u2026",
|
|
742
756
|
cancel: "Cancel",
|
|
@@ -1082,6 +1096,7 @@ function TaskBoardCore({
|
|
|
1082
1096
|
projectId,
|
|
1083
1097
|
columns = DEFAULT_BOARD_COLUMNS,
|
|
1084
1098
|
readonly,
|
|
1099
|
+
confirmMove = true,
|
|
1085
1100
|
hideHeader,
|
|
1086
1101
|
priority = "ALL",
|
|
1087
1102
|
type = "ALL",
|
|
@@ -1104,6 +1119,7 @@ function TaskBoardCore({
|
|
|
1104
1119
|
const [draggingId, setDraggingId] = useState(null);
|
|
1105
1120
|
const [dragOver, setDragOver] = useState(null);
|
|
1106
1121
|
const [moveError, setMoveError] = useState(null);
|
|
1122
|
+
const [pendingMove, setPendingMove] = useState(null);
|
|
1107
1123
|
const [updateItem] = useMutation(UPDATE_WORK_ITEM);
|
|
1108
1124
|
const { data, loading, error } = useQuery(
|
|
1109
1125
|
LIST_WORK_ITEMS,
|
|
@@ -1170,7 +1186,9 @@ function TaskBoardCore({
|
|
|
1170
1186
|
const task = tasks.find((t) => t.id === draggingId);
|
|
1171
1187
|
setDragOver(null);
|
|
1172
1188
|
setDraggingId(null);
|
|
1173
|
-
if (task
|
|
1189
|
+
if (!task || task.status === status) return;
|
|
1190
|
+
if (confirmMove) setPendingMove({ task, toStatus: status });
|
|
1191
|
+
else moveTask(task, status);
|
|
1174
1192
|
};
|
|
1175
1193
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
|
|
1176
1194
|
!hideHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
@@ -1230,7 +1248,43 @@ function TaskBoardCore({
|
|
|
1230
1248
|
},
|
|
1231
1249
|
col.status
|
|
1232
1250
|
);
|
|
1233
|
-
}) })
|
|
1251
|
+
}) }),
|
|
1252
|
+
/* @__PURE__ */ jsx(
|
|
1253
|
+
Modal,
|
|
1254
|
+
{
|
|
1255
|
+
open: pendingMove != null,
|
|
1256
|
+
onClose: () => setPendingMove(null),
|
|
1257
|
+
ariaLabel: L.moveConfirmTitle,
|
|
1258
|
+
className: "max-w-sm",
|
|
1259
|
+
children: pendingMove && /* @__PURE__ */ jsxs("div", { className: "space-y-4 p-6", children: [
|
|
1260
|
+
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-foreground", children: L.moveConfirmTitle }),
|
|
1261
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: L.moveConfirmPrompt.replace("{task}", pendingMove.task.title).replace("{status}", L.status[pendingMove.toStatus]) }),
|
|
1262
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
1263
|
+
/* @__PURE__ */ jsx(
|
|
1264
|
+
"button",
|
|
1265
|
+
{
|
|
1266
|
+
type: "button",
|
|
1267
|
+
onClick: () => setPendingMove(null),
|
|
1268
|
+
className: "rounded-md bg-muted px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted/70",
|
|
1269
|
+
children: L.cancel
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
/* @__PURE__ */ jsx(
|
|
1273
|
+
"button",
|
|
1274
|
+
{
|
|
1275
|
+
type: "button",
|
|
1276
|
+
onClick: () => {
|
|
1277
|
+
moveTask(pendingMove.task, pendingMove.toStatus);
|
|
1278
|
+
setPendingMove(null);
|
|
1279
|
+
},
|
|
1280
|
+
className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:brightness-110",
|
|
1281
|
+
children: L.moveConfirm
|
|
1282
|
+
}
|
|
1283
|
+
)
|
|
1284
|
+
] })
|
|
1285
|
+
] })
|
|
1286
|
+
}
|
|
1287
|
+
)
|
|
1234
1288
|
] });
|
|
1235
1289
|
}
|
|
1236
1290
|
function TaskBoard({
|
|
@@ -1319,6 +1373,10 @@ function CreateTaskCore({
|
|
|
1319
1373
|
projectId,
|
|
1320
1374
|
title: title.trim(),
|
|
1321
1375
|
type,
|
|
1376
|
+
// Sub-task linkage: parentId is not an editable form field — it rides
|
|
1377
|
+
// through from defaultValues (the "Add sub-task" flow) so a created work
|
|
1378
|
+
// item nests under its parent.
|
|
1379
|
+
...defaultValues?.parentId ? { parentId: defaultValues.parentId } : {},
|
|
1322
1380
|
...hidden.has("status") ? {} : { status },
|
|
1323
1381
|
...hidden.has("priority") ? {} : { priority },
|
|
1324
1382
|
...hidden.has("description") || !description.trim() ? {} : { description: description.trim() },
|
|
@@ -2415,6 +2473,10 @@ function TaskDetailCore({
|
|
|
2415
2473
|
onError: onError2,
|
|
2416
2474
|
resolveAssignee,
|
|
2417
2475
|
assigneeOptions,
|
|
2476
|
+
linkSourceProduct,
|
|
2477
|
+
renderLinkIcon,
|
|
2478
|
+
onOpenItem,
|
|
2479
|
+
onAddSubtask,
|
|
2418
2480
|
className
|
|
2419
2481
|
}) {
|
|
2420
2482
|
const client = useApolloClient();
|
|
@@ -2428,6 +2490,25 @@ function TaskDetailCore({
|
|
|
2428
2490
|
skip: !id
|
|
2429
2491
|
});
|
|
2430
2492
|
const item = data?.planmagnetWorkItem ?? null;
|
|
2493
|
+
const { linksByItem } = useWorkItemLinks(
|
|
2494
|
+
item?.workspaceId,
|
|
2495
|
+
linkSourceProduct
|
|
2496
|
+
);
|
|
2497
|
+
const links = item ? linksByItem.get(item.id) ?? [] : [];
|
|
2498
|
+
const { data: parentData } = useQuery(GET_WORK_ITEM, {
|
|
2499
|
+
variables: { id: item?.parentId },
|
|
2500
|
+
skip: !item?.parentId
|
|
2501
|
+
});
|
|
2502
|
+
const parent = parentData?.planmagnetWorkItem ?? null;
|
|
2503
|
+
const { data: childData } = useQuery(LIST_WORK_ITEMS, {
|
|
2504
|
+
variables: {
|
|
2505
|
+
workspaceId: item?.workspaceId,
|
|
2506
|
+
filter: { parentId: item?.id },
|
|
2507
|
+
pagination: { first: 100 }
|
|
2508
|
+
},
|
|
2509
|
+
skip: !item?.id || !item?.workspaceId
|
|
2510
|
+
});
|
|
2511
|
+
const children = childData?.planmagnetWorkItems?.items ?? [];
|
|
2431
2512
|
const [editing, setEditing] = useState(false);
|
|
2432
2513
|
const [confirmingDelete, setConfirmingDelete] = useState(false);
|
|
2433
2514
|
const [title, setTitle] = useState("");
|
|
@@ -2595,7 +2676,7 @@ function TaskDetailCore({
|
|
|
2595
2676
|
),
|
|
2596
2677
|
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: resolveAssignee?.(item.assigneeId)?.name ?? L.assigned })
|
|
2597
2678
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: L.unassigned }) }),
|
|
2598
|
-
!hidden.has("dueDate") && /* @__PURE__ */ jsx(Field, { label: L.dueDateLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.dueDate ?? "\u2014" }) }),
|
|
2679
|
+
!hidden.has("dueDate") && /* @__PURE__ */ jsx(Field, { label: L.dueDateLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: formatDateFull(item.dueDate) ?? "\u2014" }) }),
|
|
2599
2680
|
!hidden.has("storyPoints") && /* @__PURE__ */ jsx(Field, { label: L.storyPointsLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.storyPoints ?? 0 }) }),
|
|
2600
2681
|
!hidden.has("description") && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2601
2682
|
/* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.description }),
|
|
@@ -2611,6 +2692,79 @@ function TaskDetailCore({
|
|
|
2611
2692
|
},
|
|
2612
2693
|
l
|
|
2613
2694
|
)) })
|
|
2695
|
+
] }),
|
|
2696
|
+
links.length > 0 && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2697
|
+
/* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.linkedRecordsLabel }),
|
|
2698
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1 flex flex-wrap gap-1.5", children: links.map((link) => /* @__PURE__ */ jsx(
|
|
2699
|
+
LinkChip,
|
|
2700
|
+
{
|
|
2701
|
+
link,
|
|
2702
|
+
renderIcon: renderLinkIcon
|
|
2703
|
+
},
|
|
2704
|
+
link.id
|
|
2705
|
+
)) })
|
|
2706
|
+
] }),
|
|
2707
|
+
parent && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2708
|
+
/* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.parentLabel }),
|
|
2709
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1", children: /* @__PURE__ */ jsxs(
|
|
2710
|
+
"button",
|
|
2711
|
+
{
|
|
2712
|
+
type: "button",
|
|
2713
|
+
onClick: () => onOpenItem?.(parent.id),
|
|
2714
|
+
className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-muted/40 px-2 py-1 text-sm text-foreground hover:bg-muted",
|
|
2715
|
+
children: [
|
|
2716
|
+
/* @__PURE__ */ jsx(StatusIcon, { status: parent.status }),
|
|
2717
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: parent.key }),
|
|
2718
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: parent.title })
|
|
2719
|
+
]
|
|
2720
|
+
}
|
|
2721
|
+
) })
|
|
2722
|
+
] }),
|
|
2723
|
+
(children.length > 0 || onAddSubtask && canEdit) && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2724
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2725
|
+
/* @__PURE__ */ jsxs("dt", { className: labelClass2, children: [
|
|
2726
|
+
L.subtasksLabel,
|
|
2727
|
+
children.length > 0 ? ` (${children.length})` : ""
|
|
2728
|
+
] }),
|
|
2729
|
+
onAddSubtask && canEdit && /* @__PURE__ */ jsxs(
|
|
2730
|
+
"button",
|
|
2731
|
+
{
|
|
2732
|
+
type: "button",
|
|
2733
|
+
onClick: () => onAddSubtask({ id: item.id, projectId: item.projectId }),
|
|
2734
|
+
className: "text-xs font-medium text-primary hover:underline",
|
|
2735
|
+
children: [
|
|
2736
|
+
"+ ",
|
|
2737
|
+
L.addSubtask
|
|
2738
|
+
]
|
|
2739
|
+
}
|
|
2740
|
+
)
|
|
2741
|
+
] }),
|
|
2742
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1 space-y-1", children: children.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "\u2014" }) : children.map((c) => /* @__PURE__ */ jsxs(
|
|
2743
|
+
"button",
|
|
2744
|
+
{
|
|
2745
|
+
type: "button",
|
|
2746
|
+
onClick: () => onOpenItem?.(c.id),
|
|
2747
|
+
className: "flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-sm hover:bg-muted",
|
|
2748
|
+
children: [
|
|
2749
|
+
/* @__PURE__ */ jsx(StatusIcon, { status: c.status }),
|
|
2750
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: c.key }),
|
|
2751
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-foreground", children: c.title })
|
|
2752
|
+
]
|
|
2753
|
+
},
|
|
2754
|
+
c.id
|
|
2755
|
+
)) })
|
|
2756
|
+
] }),
|
|
2757
|
+
(item.createdAt || item.updatedAt) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-6 gap-y-1 border-t border-border pt-3 text-xs text-muted-foreground sm:col-span-2", children: [
|
|
2758
|
+
item.createdAt && /* @__PURE__ */ jsxs("span", { children: [
|
|
2759
|
+
L.createdLabel,
|
|
2760
|
+
" ",
|
|
2761
|
+
formatDateFull(item.createdAt)
|
|
2762
|
+
] }),
|
|
2763
|
+
item.updatedAt && /* @__PURE__ */ jsxs("span", { children: [
|
|
2764
|
+
L.updatedLabel,
|
|
2765
|
+
" ",
|
|
2766
|
+
formatDateFull(item.updatedAt)
|
|
2767
|
+
] })
|
|
2614
2768
|
] })
|
|
2615
2769
|
] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSave, className: "space-y-4", children: [
|
|
2616
2770
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
@@ -2818,6 +2972,7 @@ function TasksPageCore({
|
|
|
2818
2972
|
hiddenFields,
|
|
2819
2973
|
views,
|
|
2820
2974
|
defaultView = "board",
|
|
2975
|
+
confirmMove,
|
|
2821
2976
|
resolveAssignee,
|
|
2822
2977
|
linkSourceProduct,
|
|
2823
2978
|
renderLinkIcon,
|
|
@@ -2842,6 +2997,7 @@ function TasksPageCore({
|
|
|
2842
2997
|
const [mine, setMine] = useState(false);
|
|
2843
2998
|
const [creating, setCreating] = useState(false);
|
|
2844
2999
|
const [selectedId, setSelectedId] = useState(null);
|
|
3000
|
+
const [createDefaults, setCreateDefaults] = useState(null);
|
|
2845
3001
|
useEffect(() => {
|
|
2846
3002
|
if (openItemId) setSelectedId(openItemId);
|
|
2847
3003
|
}, [openItemId]);
|
|
@@ -2853,10 +3009,31 @@ function TasksPageCore({
|
|
|
2853
3009
|
(workItem) => {
|
|
2854
3010
|
refetchBoard();
|
|
2855
3011
|
setCreating(false);
|
|
3012
|
+
setCreateDefaults(null);
|
|
2856
3013
|
onTaskSaved?.({ workItem, operation: "created" });
|
|
2857
3014
|
},
|
|
2858
3015
|
[refetchBoard, onTaskSaved]
|
|
2859
3016
|
);
|
|
3017
|
+
const handleAddSubtask = useCallback(
|
|
3018
|
+
(parent) => {
|
|
3019
|
+
setSelectedId(null);
|
|
3020
|
+
setCreateDefaults({
|
|
3021
|
+
parentId: parent.id,
|
|
3022
|
+
projectId: parent.projectId,
|
|
3023
|
+
type: "SUB_TASK"
|
|
3024
|
+
});
|
|
3025
|
+
setCreating(true);
|
|
3026
|
+
},
|
|
3027
|
+
[]
|
|
3028
|
+
);
|
|
3029
|
+
const startCreate = useCallback(() => {
|
|
3030
|
+
setCreateDefaults(null);
|
|
3031
|
+
setCreating(true);
|
|
3032
|
+
}, []);
|
|
3033
|
+
const cancelCreate = useCallback(() => {
|
|
3034
|
+
setCreating(false);
|
|
3035
|
+
setCreateDefaults(null);
|
|
3036
|
+
}, []);
|
|
2860
3037
|
const handleUpdated = useCallback(
|
|
2861
3038
|
(workItem) => {
|
|
2862
3039
|
refetchBoard();
|
|
@@ -2884,8 +3061,9 @@ function TasksPageCore({
|
|
|
2884
3061
|
projectId,
|
|
2885
3062
|
assigneeOptions,
|
|
2886
3063
|
hiddenFields,
|
|
3064
|
+
defaultValues: createDefaults ?? void 0,
|
|
2887
3065
|
onCreated: handleCreated,
|
|
2888
|
-
onCancel:
|
|
3066
|
+
onCancel: cancelCreate
|
|
2889
3067
|
}
|
|
2890
3068
|
);
|
|
2891
3069
|
const detailView = selectedId != null ? /* @__PURE__ */ jsx(
|
|
@@ -2896,8 +3074,12 @@ function TasksPageCore({
|
|
|
2896
3074
|
hiddenFields,
|
|
2897
3075
|
resolveAssignee,
|
|
2898
3076
|
assigneeOptions,
|
|
3077
|
+
linkSourceProduct,
|
|
3078
|
+
renderLinkIcon,
|
|
2899
3079
|
onUpdated: handleUpdated,
|
|
2900
|
-
onDeleted: handleDeleted
|
|
3080
|
+
onDeleted: handleDeleted,
|
|
3081
|
+
onOpenItem: handleSelect,
|
|
3082
|
+
onAddSubtask: handleAddSubtask
|
|
2901
3083
|
}
|
|
2902
3084
|
) : null;
|
|
2903
3085
|
const listPriority = priority === "ALL" ? void 0 : priority;
|
|
@@ -2925,7 +3107,7 @@ function TasksPageCore({
|
|
|
2925
3107
|
onPriorityChange: setPriority,
|
|
2926
3108
|
type,
|
|
2927
3109
|
onTypeChange: setType,
|
|
2928
|
-
onNewTask:
|
|
3110
|
+
onNewTask: startCreate,
|
|
2929
3111
|
canCreate,
|
|
2930
3112
|
mine,
|
|
2931
3113
|
onMineChange: currentActorId ? setMine : void 0
|
|
@@ -2939,6 +3121,7 @@ function TasksPageCore({
|
|
|
2939
3121
|
projectId: boardProjectId,
|
|
2940
3122
|
columns,
|
|
2941
3123
|
readonly,
|
|
3124
|
+
confirmMove,
|
|
2942
3125
|
hideHeader: true,
|
|
2943
3126
|
priority,
|
|
2944
3127
|
type,
|
|
@@ -2986,7 +3169,7 @@ function TasksPageCore({
|
|
|
2986
3169
|
Modal,
|
|
2987
3170
|
{
|
|
2988
3171
|
open: creating,
|
|
2989
|
-
onClose:
|
|
3172
|
+
onClose: cancelCreate,
|
|
2990
3173
|
ariaLabel: "Create task",
|
|
2991
3174
|
className: "max-w-xl",
|
|
2992
3175
|
children: /* @__PURE__ */ jsx("div", { className: "p-2 pt-8", children: createForm })
|