@burdenoff/planmagnet-fe-sdk 2026.704.2 → 2026.704.4
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 +31 -5
- package/dist/index.js +97 -6
- 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,14 @@ 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;
|
|
798
813
|
/** Extra classes on the root container. */
|
|
799
814
|
className?: string;
|
|
800
815
|
}
|
|
@@ -803,7 +818,7 @@ interface TaskDetailCoreProps {
|
|
|
803
818
|
* edit. Fetches via `planmagnetWorkItem(id)`, saves via
|
|
804
819
|
* `planmagnetUpdateWorkItem`. BYO-Apollo, semantic-token only, farm-free.
|
|
805
820
|
*/
|
|
806
|
-
declare function TaskDetailCore({ id, readonly, hiddenFields, hideHeader, onUpdated, onDeleted, onError, resolveAssignee, assigneeOptions, className, }: TaskDetailCoreProps): react.JSX.Element;
|
|
821
|
+
declare function TaskDetailCore({ id, readonly, hiddenFields, hideHeader, onUpdated, onDeleted, onError, resolveAssignee, assigneeOptions, linkSourceProduct, renderLinkIcon, className, }: TaskDetailCoreProps): react.JSX.Element;
|
|
807
822
|
|
|
808
823
|
interface TaskDetailProps extends TaskDetailCoreProps {
|
|
809
824
|
/** Workspace API gateway URL (URL mode). */
|
|
@@ -862,6 +877,9 @@ interface TaskLabels {
|
|
|
862
877
|
noTasks: string;
|
|
863
878
|
noTasksFound: string;
|
|
864
879
|
dropHere: string;
|
|
880
|
+
moveConfirmTitle: string;
|
|
881
|
+
moveConfirmPrompt: string;
|
|
882
|
+
moveConfirm: string;
|
|
865
883
|
unassigned: string;
|
|
866
884
|
assigned: string;
|
|
867
885
|
overdue: string;
|
|
@@ -897,6 +915,9 @@ interface TaskLabels {
|
|
|
897
915
|
storyPointsLabel: string;
|
|
898
916
|
labelsLabel: string;
|
|
899
917
|
labelsPlaceholder: string;
|
|
918
|
+
linkedRecordsLabel: string;
|
|
919
|
+
createdLabel: string;
|
|
920
|
+
updatedLabel: string;
|
|
900
921
|
create: string;
|
|
901
922
|
creating: string;
|
|
902
923
|
cancel: string;
|
|
@@ -973,6 +994,11 @@ interface TasksPageCoreProps {
|
|
|
973
994
|
views?: TaskView[];
|
|
974
995
|
/** Initial view. Defaults to "board". */
|
|
975
996
|
defaultView?: TaskView;
|
|
997
|
+
/**
|
|
998
|
+
* Ask for confirmation before a board drag-drop moves a task. Defaults to
|
|
999
|
+
* `true`; set `false` for instant, Linear-style moves.
|
|
1000
|
+
*/
|
|
1001
|
+
confirmMove?: boolean;
|
|
976
1002
|
/** Optional host hook to resolve an assignee id → display name. */
|
|
977
1003
|
resolveAssignee?: ResolveAssignee;
|
|
978
1004
|
/**
|
|
@@ -1022,7 +1048,7 @@ interface TasksPageCoreProps {
|
|
|
1022
1048
|
* BYO-Apollo: reads the ambient `<ApolloProvider>` and takes `workspaceId` from
|
|
1023
1049
|
* a prop or the PlanMagnetProvider context. Semantic tokens only, farm-free.
|
|
1024
1050
|
*/
|
|
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;
|
|
1051
|
+
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
1052
|
|
|
1027
1053
|
interface TasksPageProps extends TasksPageCoreProps {
|
|
1028
1054
|
/** Workspace API gateway URL (URL mode). */
|
package/dist/index.js
CHANGED
|
@@ -521,6 +521,12 @@ function parseDate(iso) {
|
|
|
521
521
|
const d = parseISO(iso);
|
|
522
522
|
return isValid(d) ? d : null;
|
|
523
523
|
}
|
|
524
|
+
function toIsoDate(value) {
|
|
525
|
+
if (!value) return void 0;
|
|
526
|
+
const iso = /^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}T00:00:00.000Z` : value;
|
|
527
|
+
const d = new Date(iso);
|
|
528
|
+
return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
|
|
529
|
+
}
|
|
524
530
|
function formatDueDate(iso) {
|
|
525
531
|
const d = parseDate(iso);
|
|
526
532
|
if (!d) return null;
|
|
@@ -530,6 +536,10 @@ function formatDueDate(iso) {
|
|
|
530
536
|
d.getFullYear() === now.getFullYear() ? "MMM d" : "MMM d yyyy"
|
|
531
537
|
);
|
|
532
538
|
}
|
|
539
|
+
function formatDateFull(iso) {
|
|
540
|
+
const d = parseDate(iso);
|
|
541
|
+
return d ? format(d, "MMM d, yyyy") : null;
|
|
542
|
+
}
|
|
533
543
|
function isOverdue(iso, status) {
|
|
534
544
|
const d = parseDate(iso);
|
|
535
545
|
if (!d) return false;
|
|
@@ -626,7 +636,8 @@ var DEFAULT_BOARD_COLUMNS = [
|
|
|
626
636
|
{ status: "IN_PROGRESS", label: "In Progress" },
|
|
627
637
|
{ status: "IN_REVIEW", label: "In Review" },
|
|
628
638
|
{ status: "TESTING", label: "Testing" },
|
|
629
|
-
{ status: "DONE", label: "Done" }
|
|
639
|
+
{ status: "DONE", label: "Done" },
|
|
640
|
+
{ status: "CANCELLED", label: "Cancelled" }
|
|
630
641
|
];
|
|
631
642
|
var TASK_PRIORITIES = [
|
|
632
643
|
"NONE",
|
|
@@ -696,6 +707,9 @@ var DEFAULT_TASK_LABELS = {
|
|
|
696
707
|
noTasks: "No tasks",
|
|
697
708
|
noTasksFound: "No tasks found.",
|
|
698
709
|
dropHere: "Drop here",
|
|
710
|
+
moveConfirmTitle: "Move task?",
|
|
711
|
+
moveConfirmPrompt: 'Move "{task}" to {status}?',
|
|
712
|
+
moveConfirm: "Move",
|
|
699
713
|
unassigned: "Unassigned",
|
|
700
714
|
assigned: "Assigned",
|
|
701
715
|
overdue: "{n} overdue",
|
|
@@ -731,6 +745,9 @@ var DEFAULT_TASK_LABELS = {
|
|
|
731
745
|
storyPointsLabel: "Story points",
|
|
732
746
|
labelsLabel: "Labels",
|
|
733
747
|
labelsPlaceholder: "comma, separated, labels",
|
|
748
|
+
linkedRecordsLabel: "Linked records",
|
|
749
|
+
createdLabel: "Created",
|
|
750
|
+
updatedLabel: "Updated",
|
|
734
751
|
create: "Create task",
|
|
735
752
|
creating: "Creating\u2026",
|
|
736
753
|
cancel: "Cancel",
|
|
@@ -1076,6 +1093,7 @@ function TaskBoardCore({
|
|
|
1076
1093
|
projectId,
|
|
1077
1094
|
columns = DEFAULT_BOARD_COLUMNS,
|
|
1078
1095
|
readonly,
|
|
1096
|
+
confirmMove = true,
|
|
1079
1097
|
hideHeader,
|
|
1080
1098
|
priority = "ALL",
|
|
1081
1099
|
type = "ALL",
|
|
@@ -1098,6 +1116,7 @@ function TaskBoardCore({
|
|
|
1098
1116
|
const [draggingId, setDraggingId] = useState(null);
|
|
1099
1117
|
const [dragOver, setDragOver] = useState(null);
|
|
1100
1118
|
const [moveError, setMoveError] = useState(null);
|
|
1119
|
+
const [pendingMove, setPendingMove] = useState(null);
|
|
1101
1120
|
const [updateItem] = useMutation(UPDATE_WORK_ITEM);
|
|
1102
1121
|
const { data, loading, error } = useQuery(
|
|
1103
1122
|
LIST_WORK_ITEMS,
|
|
@@ -1164,7 +1183,9 @@ function TaskBoardCore({
|
|
|
1164
1183
|
const task = tasks.find((t) => t.id === draggingId);
|
|
1165
1184
|
setDragOver(null);
|
|
1166
1185
|
setDraggingId(null);
|
|
1167
|
-
if (task
|
|
1186
|
+
if (!task || task.status === status) return;
|
|
1187
|
+
if (confirmMove) setPendingMove({ task, toStatus: status });
|
|
1188
|
+
else moveTask(task, status);
|
|
1168
1189
|
};
|
|
1169
1190
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
|
|
1170
1191
|
!hideHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
@@ -1224,7 +1245,43 @@ function TaskBoardCore({
|
|
|
1224
1245
|
},
|
|
1225
1246
|
col.status
|
|
1226
1247
|
);
|
|
1227
|
-
}) })
|
|
1248
|
+
}) }),
|
|
1249
|
+
/* @__PURE__ */ jsx(
|
|
1250
|
+
Modal,
|
|
1251
|
+
{
|
|
1252
|
+
open: pendingMove != null,
|
|
1253
|
+
onClose: () => setPendingMove(null),
|
|
1254
|
+
ariaLabel: L.moveConfirmTitle,
|
|
1255
|
+
className: "max-w-sm",
|
|
1256
|
+
children: pendingMove && /* @__PURE__ */ jsxs("div", { className: "space-y-4 p-6", children: [
|
|
1257
|
+
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-foreground", children: L.moveConfirmTitle }),
|
|
1258
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: L.moveConfirmPrompt.replace("{task}", pendingMove.task.title).replace("{status}", L.status[pendingMove.toStatus]) }),
|
|
1259
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
1260
|
+
/* @__PURE__ */ jsx(
|
|
1261
|
+
"button",
|
|
1262
|
+
{
|
|
1263
|
+
type: "button",
|
|
1264
|
+
onClick: () => setPendingMove(null),
|
|
1265
|
+
className: "rounded-md bg-muted px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted/70",
|
|
1266
|
+
children: L.cancel
|
|
1267
|
+
}
|
|
1268
|
+
),
|
|
1269
|
+
/* @__PURE__ */ jsx(
|
|
1270
|
+
"button",
|
|
1271
|
+
{
|
|
1272
|
+
type: "button",
|
|
1273
|
+
onClick: () => {
|
|
1274
|
+
moveTask(pendingMove.task, pendingMove.toStatus);
|
|
1275
|
+
setPendingMove(null);
|
|
1276
|
+
},
|
|
1277
|
+
className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:brightness-110",
|
|
1278
|
+
children: L.moveConfirm
|
|
1279
|
+
}
|
|
1280
|
+
)
|
|
1281
|
+
] })
|
|
1282
|
+
] })
|
|
1283
|
+
}
|
|
1284
|
+
)
|
|
1228
1285
|
] });
|
|
1229
1286
|
}
|
|
1230
1287
|
function TaskBoard({
|
|
@@ -1317,7 +1374,7 @@ function CreateTaskCore({
|
|
|
1317
1374
|
...hidden.has("priority") ? {} : { priority },
|
|
1318
1375
|
...hidden.has("description") || !description.trim() ? {} : { description: description.trim() },
|
|
1319
1376
|
...hidden.has("assignee") || !assigneeId.trim() ? {} : { assigneeId: assigneeId.trim() },
|
|
1320
|
-
...hidden.has("dueDate") || !dueDate.trim() ? {} : { dueDate },
|
|
1377
|
+
...hidden.has("dueDate") || !dueDate.trim() ? {} : { dueDate: toIsoDate(dueDate) },
|
|
1321
1378
|
...hidden.has("labels") || parsedLabels.length === 0 ? {} : { labels: parsedLabels },
|
|
1322
1379
|
...hidden.has("storyPoints") || parsedPoints == null || Number.isNaN(parsedPoints) ? {} : { storyPoints: parsedPoints }
|
|
1323
1380
|
};
|
|
@@ -2409,6 +2466,8 @@ function TaskDetailCore({
|
|
|
2409
2466
|
onError: onError2,
|
|
2410
2467
|
resolveAssignee,
|
|
2411
2468
|
assigneeOptions,
|
|
2469
|
+
linkSourceProduct,
|
|
2470
|
+
renderLinkIcon,
|
|
2412
2471
|
className
|
|
2413
2472
|
}) {
|
|
2414
2473
|
const client = useApolloClient();
|
|
@@ -2422,6 +2481,11 @@ function TaskDetailCore({
|
|
|
2422
2481
|
skip: !id
|
|
2423
2482
|
});
|
|
2424
2483
|
const item = data?.planmagnetWorkItem ?? null;
|
|
2484
|
+
const { linksByItem } = useWorkItemLinks(
|
|
2485
|
+
item?.workspaceId,
|
|
2486
|
+
linkSourceProduct
|
|
2487
|
+
);
|
|
2488
|
+
const links = item ? linksByItem.get(item.id) ?? [] : [];
|
|
2425
2489
|
const [editing, setEditing] = useState(false);
|
|
2426
2490
|
const [confirmingDelete, setConfirmingDelete] = useState(false);
|
|
2427
2491
|
const [title, setTitle] = useState("");
|
|
@@ -2474,7 +2538,7 @@ function TaskDetailCore({
|
|
|
2474
2538
|
...hidden.has("status") ? {} : { status },
|
|
2475
2539
|
...hidden.has("priority") ? {} : { priority },
|
|
2476
2540
|
...hidden.has("assignee") ? {} : { assigneeId: assigneeId.trim() },
|
|
2477
|
-
...hidden.has("dueDate") ? {} : { dueDate: dueDate
|
|
2541
|
+
...hidden.has("dueDate") ? {} : { dueDate: toIsoDate(dueDate) },
|
|
2478
2542
|
...hidden.has("labels") ? {} : { labels: parsedLabels },
|
|
2479
2543
|
...hidden.has("storyPoints") || parsedPoints == null || Number.isNaN(parsedPoints) ? {} : { storyPoints: parsedPoints }
|
|
2480
2544
|
};
|
|
@@ -2589,7 +2653,7 @@ function TaskDetailCore({
|
|
|
2589
2653
|
),
|
|
2590
2654
|
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: resolveAssignee?.(item.assigneeId)?.name ?? L.assigned })
|
|
2591
2655
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: L.unassigned }) }),
|
|
2592
|
-
!hidden.has("dueDate") && /* @__PURE__ */ jsx(Field, { label: L.dueDateLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.dueDate ?? "\u2014" }) }),
|
|
2656
|
+
!hidden.has("dueDate") && /* @__PURE__ */ jsx(Field, { label: L.dueDateLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: formatDateFull(item.dueDate) ?? "\u2014" }) }),
|
|
2593
2657
|
!hidden.has("storyPoints") && /* @__PURE__ */ jsx(Field, { label: L.storyPointsLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.storyPoints ?? 0 }) }),
|
|
2594
2658
|
!hidden.has("description") && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2595
2659
|
/* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.description }),
|
|
@@ -2605,6 +2669,29 @@ function TaskDetailCore({
|
|
|
2605
2669
|
},
|
|
2606
2670
|
l
|
|
2607
2671
|
)) })
|
|
2672
|
+
] }),
|
|
2673
|
+
links.length > 0 && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2674
|
+
/* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.linkedRecordsLabel }),
|
|
2675
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1 flex flex-wrap gap-1.5", children: links.map((link) => /* @__PURE__ */ jsx(
|
|
2676
|
+
LinkChip,
|
|
2677
|
+
{
|
|
2678
|
+
link,
|
|
2679
|
+
renderIcon: renderLinkIcon
|
|
2680
|
+
},
|
|
2681
|
+
link.id
|
|
2682
|
+
)) })
|
|
2683
|
+
] }),
|
|
2684
|
+
(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: [
|
|
2685
|
+
item.createdAt && /* @__PURE__ */ jsxs("span", { children: [
|
|
2686
|
+
L.createdLabel,
|
|
2687
|
+
" ",
|
|
2688
|
+
formatDateFull(item.createdAt)
|
|
2689
|
+
] }),
|
|
2690
|
+
item.updatedAt && /* @__PURE__ */ jsxs("span", { children: [
|
|
2691
|
+
L.updatedLabel,
|
|
2692
|
+
" ",
|
|
2693
|
+
formatDateFull(item.updatedAt)
|
|
2694
|
+
] })
|
|
2608
2695
|
] })
|
|
2609
2696
|
] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSave, className: "space-y-4", children: [
|
|
2610
2697
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
@@ -2812,6 +2899,7 @@ function TasksPageCore({
|
|
|
2812
2899
|
hiddenFields,
|
|
2813
2900
|
views,
|
|
2814
2901
|
defaultView = "board",
|
|
2902
|
+
confirmMove,
|
|
2815
2903
|
resolveAssignee,
|
|
2816
2904
|
linkSourceProduct,
|
|
2817
2905
|
renderLinkIcon,
|
|
@@ -2890,6 +2978,8 @@ function TasksPageCore({
|
|
|
2890
2978
|
hiddenFields,
|
|
2891
2979
|
resolveAssignee,
|
|
2892
2980
|
assigneeOptions,
|
|
2981
|
+
linkSourceProduct,
|
|
2982
|
+
renderLinkIcon,
|
|
2893
2983
|
onUpdated: handleUpdated,
|
|
2894
2984
|
onDeleted: handleDeleted
|
|
2895
2985
|
}
|
|
@@ -2933,6 +3023,7 @@ function TasksPageCore({
|
|
|
2933
3023
|
projectId: boardProjectId,
|
|
2934
3024
|
columns,
|
|
2935
3025
|
readonly,
|
|
3026
|
+
confirmMove,
|
|
2936
3027
|
hideHeader: true,
|
|
2937
3028
|
priority,
|
|
2938
3029
|
type,
|