@burdenoff/planmagnet-fe-sdk 2026.703.2 → 2026.704.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.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { createContext, useMemo, useEffect, useContext, useState, useCallback } from 'react';
2
- import { ApolloProvider, useApolloClient, useMutation, useQuery } from '@apollo/client/react';
2
+ import { ApolloProvider, useQuery, useApolloClient, useMutation } from '@apollo/client/react';
3
3
  import { createHttpLink, ApolloClient, from, InMemoryCache } from '@apollo/client/core';
4
4
  import { setContext } from '@apollo/client/link/context';
5
5
  import { onError } from '@apollo/client/link/error';
6
6
  import { CombinedGraphQLErrors } from '@apollo/client/errors';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
8
8
  import { gql } from '@apollo/client';
9
- import { CircleX, CircleCheckBig, CircleDotDashed, CircleDot, Circle, CircleDashed, User, CalendarDays, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, CalendarRange, List, LayoutGrid, Search, Plus } from 'lucide-react';
9
+ import { CircleX, CircleCheckBig, CircleDotDashed, CircleDot, Circle, CircleDashed, User, Link2, CalendarDays, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Flag, CalendarRange, List, LayoutGrid, Search, Plus, Trash2 } from 'lucide-react';
10
10
  import { clsx } from 'clsx';
11
11
  import { twMerge } from 'tailwind-merge';
12
12
  import { addWeeks, startOfWeek, endOfWeek, eachDayOfInterval, addMonths, startOfMonth, endOfMonth, format, isToday, isSameMonth, startOfDay, parseISO, isValid } from 'date-fns';
@@ -410,6 +410,108 @@ var MOVE_WORK_ITEM = gql`
410
410
  }
411
411
  ${WORK_ITEM_FIELDS}
412
412
  `;
413
+ var WORK_ITEM_LINK_FIELDS = gql`
414
+ fragment WorkItemLinkFields on WorkItemLink {
415
+ id
416
+ workspaceId
417
+ workItemId
418
+ sourceProduct
419
+ entityType
420
+ entityId
421
+ relationType
422
+ displayNameSnapshot
423
+ deepLinkSnapshot
424
+ metadata
425
+ createdBy
426
+ onBehalfOf
427
+ createdAt
428
+ updatedAt
429
+ }
430
+ `;
431
+ var LIST_WORK_ITEM_LINKS = gql`
432
+ query ListWorkItemLinks(
433
+ $workspaceId: ID!
434
+ $filter: PlanmagnetWorkItemLinkFilter
435
+ $pagination: PlanmagnetPaginationInput
436
+ ) {
437
+ planmagnetWorkItemLinks(
438
+ workspaceId: $workspaceId
439
+ filter: $filter
440
+ pagination: $pagination
441
+ ) {
442
+ items {
443
+ ...WorkItemLinkFields
444
+ }
445
+ pageInfo {
446
+ hasNextPage
447
+ hasPreviousPage
448
+ startCursor
449
+ endCursor
450
+ totalCount
451
+ }
452
+ totalCount
453
+ }
454
+ }
455
+ ${WORK_ITEM_LINK_FIELDS}
456
+ `;
457
+ var CREATE_WORK_ITEM_LINK = gql`
458
+ mutation CreateWorkItemLink($input: PlanmagnetCreateWorkItemLinkInput!) {
459
+ planmagnetLinkWorkItem(input: $input) {
460
+ ...WorkItemLinkFields
461
+ }
462
+ }
463
+ ${WORK_ITEM_LINK_FIELDS}
464
+ `;
465
+ var DELETE_WORK_ITEM_LINK = gql`
466
+ mutation UnlinkWorkItem($id: ID!) {
467
+ planmagnetUnlinkWorkItem(id: $id)
468
+ }
469
+ `;
470
+ var MILESTONE_FIELDS = gql`
471
+ fragment MilestoneFields on Milestone {
472
+ id
473
+ projectId
474
+ name
475
+ description
476
+ status
477
+ dueDate
478
+ completedAt
479
+ ownerId
480
+ createdAt
481
+ updatedAt
482
+ }
483
+ `;
484
+ var LIST_MILESTONES = gql`
485
+ query ListMilestones(
486
+ $workspaceId: ID!
487
+ $filter: PlanmagnetMilestoneFilter
488
+ $pagination: PlanmagnetPaginationInput
489
+ ) {
490
+ planmagnetMilestones(
491
+ workspaceId: $workspaceId
492
+ filter: $filter
493
+ pagination: $pagination
494
+ ) {
495
+ items {
496
+ ...MilestoneFields
497
+ }
498
+ pageInfo {
499
+ hasNextPage
500
+ hasPreviousPage
501
+ startCursor
502
+ endCursor
503
+ totalCount
504
+ }
505
+ totalCount
506
+ }
507
+ }
508
+ ${MILESTONE_FIELDS}
509
+ `;
510
+ var DELETE_WORK_ITEM = gql`
511
+ mutation DeleteWorkItem($id: ID!) {
512
+ planmagnetDeleteWorkItem(id: $id)
513
+ }
514
+ `;
413
515
  function cn(...inputs) {
414
516
  return twMerge(clsx(inputs));
415
517
  }
@@ -552,6 +654,141 @@ var TASK_STATUSES = [
552
654
  function enumLabel(value) {
553
655
  return value.toLowerCase().replace(/_/g, " ");
554
656
  }
657
+ function LinkChip({ link, renderIcon, className }) {
658
+ const label = link.displayNameSnapshot || enumLabel(link.entityType);
659
+ const icon = renderIcon?.(link.entityType) ?? /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" });
660
+ const body = /* @__PURE__ */ jsxs(
661
+ "span",
662
+ {
663
+ className: cn(
664
+ "inline-flex max-w-full items-center gap-1 rounded-full border border-primary/20 bg-primary/5 px-1.5 py-0.5 text-[10px] font-medium text-primary",
665
+ className
666
+ ),
667
+ title: `${enumLabel(link.relationType)} \xB7 ${enumLabel(link.entityType)}`,
668
+ children: [
669
+ icon,
670
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
671
+ ]
672
+ }
673
+ );
674
+ if (link.deepLinkSnapshot) {
675
+ return /* @__PURE__ */ jsx(
676
+ "a",
677
+ {
678
+ href: link.deepLinkSnapshot,
679
+ onClick: (e) => e.stopPropagation(),
680
+ className: "inline-flex max-w-full no-underline hover:brightness-95",
681
+ children: body
682
+ }
683
+ );
684
+ }
685
+ return body;
686
+ }
687
+ var DEFAULT_TASK_LABELS = {
688
+ board: "Board",
689
+ list: "List",
690
+ timeline: "Timeline",
691
+ searchPlaceholder: "Search tasks\u2026",
692
+ allPriorities: "All priorities",
693
+ allTypes: "All types",
694
+ newTask: "New task",
695
+ myTasks: "My tasks",
696
+ noTasks: "No tasks",
697
+ noTasksFound: "No tasks found.",
698
+ dropHere: "Drop here",
699
+ unassigned: "Unassigned",
700
+ assigned: "Assigned",
701
+ overdue: "{n} overdue",
702
+ noDueDate: "No due date ({n})",
703
+ milestones: "Milestones",
704
+ today: "Today",
705
+ week: "Week",
706
+ month: "Month",
707
+ tasksSingular: "task",
708
+ tasksPlural: "tasks",
709
+ colTask: "Task",
710
+ colStatus: "Status",
711
+ colPriority: "Priority",
712
+ colAssignee: "Assignee",
713
+ colDueDate: "Due Date",
714
+ colPoints: "Points",
715
+ colLinkedRecord: "Linked Record",
716
+ colType: "Type",
717
+ colKey: "Key",
718
+ colLabels: "Labels",
719
+ newTaskHeading: "New task",
720
+ newTaskSubtitle: "Create a work item in this workspace.",
721
+ title: "Title",
722
+ titlePlaceholder: "What needs doing?",
723
+ description: "Description",
724
+ descriptionPlaceholder: "Add more detail (optional)",
725
+ typeLabel: "Type",
726
+ statusLabel: "Status",
727
+ priorityLabel: "Priority",
728
+ assigneeLabel: "Assignee",
729
+ assigneePlaceholder: "Actor ID (optional)",
730
+ dueDateLabel: "Due date",
731
+ storyPointsLabel: "Story points",
732
+ labelsLabel: "Labels",
733
+ labelsPlaceholder: "comma, separated, labels",
734
+ create: "Create task",
735
+ creating: "Creating\u2026",
736
+ cancel: "Cancel",
737
+ edit: "Edit",
738
+ del: "Delete",
739
+ deletePrompt: "Delete?",
740
+ yes: "Yes",
741
+ no: "No",
742
+ save: "Save changes",
743
+ saving: "Saving\u2026",
744
+ taskNotFound: "Task not found.",
745
+ projectRequired: "A projectId is required to create a task.",
746
+ errorLoading: "Error loading tasks",
747
+ moveFailed: "Couldn't move the task. Please try again.",
748
+ failedToCreate: "Failed to create task",
749
+ failedToSave: "Failed to save",
750
+ failedToDelete: "Failed to delete",
751
+ overdueLabel: "Overdue",
752
+ more: "more",
753
+ status: {
754
+ BACKLOG: "Backlog",
755
+ TODO: "To Do",
756
+ IN_PROGRESS: "In Progress",
757
+ IN_REVIEW: "In Review",
758
+ TESTING: "Testing",
759
+ DONE: "Done",
760
+ CANCELLED: "Cancelled"
761
+ },
762
+ priority: {
763
+ NONE: "None",
764
+ LOW: "Low",
765
+ MEDIUM: "Medium",
766
+ HIGH: "High",
767
+ CRITICAL: "Critical"
768
+ },
769
+ type: {
770
+ TASK: "Task",
771
+ STORY: "Story",
772
+ BUG: "Bug",
773
+ EPIC: "Epic",
774
+ SUB_TASK: "Sub Task"
775
+ }
776
+ };
777
+ var TaskLabelsContext = createContext(DEFAULT_TASK_LABELS);
778
+ var TaskLabelsProvider = TaskLabelsContext.Provider;
779
+ function useTaskLabels() {
780
+ return useContext(TaskLabelsContext);
781
+ }
782
+ function mergeTaskLabels(overrides) {
783
+ if (!overrides) return DEFAULT_TASK_LABELS;
784
+ return {
785
+ ...DEFAULT_TASK_LABELS,
786
+ ...overrides,
787
+ status: { ...DEFAULT_TASK_LABELS.status, ...overrides.status },
788
+ priority: { ...DEFAULT_TASK_LABELS.priority, ...overrides.priority },
789
+ type: { ...DEFAULT_TASK_LABELS.type, ...overrides.type }
790
+ };
791
+ }
555
792
  var STATUS_META = {
556
793
  BACKLOG: { icon: CircleDashed, tone: "text-muted-foreground/60" },
557
794
  TODO: { icon: Circle, tone: "text-muted-foreground" },
@@ -573,6 +810,7 @@ function StatusIcon({ status, className }) {
573
810
  );
574
811
  }
575
812
  function StatusPill({ status, className }) {
813
+ const L = useTaskLabels();
576
814
  return /* @__PURE__ */ jsxs(
577
815
  "span",
578
816
  {
@@ -582,7 +820,7 @@ function StatusPill({ status, className }) {
582
820
  ),
583
821
  children: [
584
822
  /* @__PURE__ */ jsx(StatusIcon, { status }),
585
- enumLabel(status)
823
+ L.status[status]
586
824
  ]
587
825
  }
588
826
  );
@@ -600,12 +838,13 @@ function PriorityIndicator({
600
838
  showLabel = false,
601
839
  className
602
840
  }) {
841
+ const L = useTaskLabels();
603
842
  const meta = PRIORITY_META[priority] ?? PRIORITY_META.NONE;
604
843
  return /* @__PURE__ */ jsxs(
605
844
  "span",
606
845
  {
607
846
  className: cn("inline-flex items-center gap-1.5", meta.tone, className),
608
- title: `Priority: ${enumLabel(priority)}`,
847
+ title: `${L.priorityLabel}: ${L.priority[priority]}`,
609
848
  children: [
610
849
  /* @__PURE__ */ jsx("span", { className: "flex items-end gap-0.5", "aria-hidden": "true", children: BAR_HEIGHTS.map((h, i) => /* @__PURE__ */ jsx(
611
850
  "span",
@@ -618,7 +857,7 @@ function PriorityIndicator({
618
857
  },
619
858
  h
620
859
  )) }),
621
- showLabel && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium capitalize", children: enumLabel(priority) })
860
+ showLabel && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium capitalize", children: L.priority[priority] })
622
861
  ]
623
862
  }
624
863
  );
@@ -631,7 +870,8 @@ var TYPE_VARIANT = {
631
870
  SUB_TASK: "muted"
632
871
  };
633
872
  function TypeBadge({ type, className }) {
634
- return /* @__PURE__ */ jsx(Badge, { variant: TYPE_VARIANT[type], className, children: enumLabel(type) });
873
+ const L = useTaskLabels();
874
+ return /* @__PURE__ */ jsx(Badge, { variant: TYPE_VARIANT[type], className, children: L.type[type] });
635
875
  }
636
876
  function OverlayShell({
637
877
  open,
@@ -705,12 +945,16 @@ function TaskCard({
705
945
  onDragEnd,
706
946
  dragging,
707
947
  resolveAssignee,
948
+ links,
949
+ renderLinkIcon,
708
950
  className
709
951
  }) {
952
+ const L = useTaskLabels();
710
953
  const overdue = isOverdue(task.dueDate, task.status);
711
954
  const due = formatDueDate(task.dueDate);
712
955
  const resolved = task.assigneeId ? resolveAssignee?.(task.assigneeId) : null;
713
956
  const showTopRow = !hidden.has("key") || !hidden.has("type");
957
+ const showLinks = !hidden.has("links") && (links?.length ?? 0) > 0;
714
958
  const showLabels = !hidden.has("labels") && (task.labels?.length ?? 0) > 0;
715
959
  const showPriority = !hidden.has("priority");
716
960
  const showPoints = !hidden.has("storyPoints") && task.storyPoints != null;
@@ -749,6 +993,13 @@ function TaskCard({
749
993
  !hidden.has("type") && /* @__PURE__ */ jsx(TypeBadge, { type: task.type })
750
994
  ] }),
751
995
  /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-sm font-medium leading-snug text-foreground", children: task.title }),
996
+ showLinks && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap gap-1", children: [
997
+ links.slice(0, 3).map((link) => /* @__PURE__ */ jsx(LinkChip, { link, renderIcon: renderLinkIcon }, link.id)),
998
+ links.length > 3 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
999
+ "+",
1000
+ links.length - 3
1001
+ ] })
1002
+ ] }),
752
1003
  showLabels && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap gap-1", children: [
753
1004
  task.labels.slice(0, 3).map((l) => /* @__PURE__ */ jsx(
754
1005
  "span",
@@ -769,7 +1020,7 @@ function TaskCard({
769
1020
  "span",
770
1021
  {
771
1022
  className: "flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/10 px-1 text-[10px] font-semibold text-primary",
772
- title: `${task.storyPoints} story points`,
1023
+ title: `${task.storyPoints} ${L.storyPointsLabel}`,
773
1024
  children: task.storyPoints
774
1025
  }
775
1026
  )
@@ -786,7 +1037,7 @@ function TaskCard({
786
1037
  "flex shrink-0 items-center gap-1 text-[11px]",
787
1038
  overdue ? "font-medium text-destructive" : "text-muted-foreground"
788
1039
  ),
789
- title: overdue ? "Overdue" : "Due date",
1040
+ title: overdue ? L.overdueLabel : L.dueDateLabel,
790
1041
  children: [
791
1042
  /* @__PURE__ */ jsx(CalendarDays, { className: "h-3 w-3", "aria-hidden": "true" }),
792
1043
  due
@@ -798,6 +1049,29 @@ function TaskCard({
798
1049
  }
799
1050
  );
800
1051
  }
1052
+ function useWorkItemLinks(workspaceId, sourceProduct, limit = 500) {
1053
+ const { data, loading } = useQuery(
1054
+ LIST_WORK_ITEM_LINKS,
1055
+ {
1056
+ variables: {
1057
+ workspaceId,
1058
+ ...sourceProduct ? { filter: { sourceProduct } } : {},
1059
+ pagination: { first: limit }
1060
+ },
1061
+ skip: !workspaceId || !sourceProduct
1062
+ }
1063
+ );
1064
+ const linksByItem = useMemo(() => {
1065
+ const map = /* @__PURE__ */ new Map();
1066
+ for (const link of data?.planmagnetWorkItemLinks?.items ?? []) {
1067
+ const arr = map.get(link.workItemId);
1068
+ if (arr) arr.push(link);
1069
+ else map.set(link.workItemId, [link]);
1070
+ }
1071
+ return map;
1072
+ }, [data]);
1073
+ return { linksByItem, loading };
1074
+ }
801
1075
  function TaskBoardCore({
802
1076
  projectId,
803
1077
  columns = DEFAULT_BOARD_COLUMNS,
@@ -809,6 +1083,8 @@ function TaskBoardCore({
809
1083
  assigneeId,
810
1084
  hiddenFields,
811
1085
  resolveAssignee,
1086
+ linkSourceProduct,
1087
+ renderLinkIcon,
812
1088
  onTaskClick,
813
1089
  className,
814
1090
  workspaceId: workspaceIdProp
@@ -816,7 +1092,9 @@ function TaskBoardCore({
816
1092
  const ctx = usePlanMagnetContextSafe();
817
1093
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
818
1094
  const client = useApolloClient();
1095
+ const L = useTaskLabels();
819
1096
  const hidden = useMemo(() => new Set(hiddenFields ?? []), [hiddenFields]);
1097
+ const { linksByItem } = useWorkItemLinks(workspaceId, linkSourceProduct);
820
1098
  const [draggingId, setDraggingId] = useState(null);
821
1099
  const [dragOver, setDragOver] = useState(null);
822
1100
  const [moveError, setMoveError] = useState(null);
@@ -844,10 +1122,10 @@ function TaskBoardCore({
844
1122
  variables: { id: task.id, input: { status: toStatus } }
845
1123
  }).catch(() => {
846
1124
  client.cache.modify({ id, fields: { status: () => from2 } });
847
- setMoveError("Couldn't move the task. Please try again.");
1125
+ setMoveError(L.moveFailed);
848
1126
  });
849
1127
  },
850
- [client, updateItem]
1128
+ [client, updateItem, L]
851
1129
  );
852
1130
  if (!workspaceId) {
853
1131
  return /* @__PURE__ */ jsx("div", { className: cn("p-6 text-sm text-destructive", className), children: "TaskBoard: no workspaceId provided (prop or PlanMagnetProvider)." });
@@ -857,7 +1135,8 @@ function TaskBoardCore({
857
1135
  }
858
1136
  if (error && !data) {
859
1137
  return /* @__PURE__ */ jsxs("div", { className: cn("p-6 text-sm text-destructive", className), children: [
860
- "Error loading tasks: ",
1138
+ L.errorLoading,
1139
+ ": ",
861
1140
  error.message
862
1141
  ] });
863
1142
  }
@@ -889,11 +1168,11 @@ function TaskBoardCore({
889
1168
  };
890
1169
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
891
1170
  !hideHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
892
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Board" }),
1171
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: L.board }),
893
1172
  /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
894
1173
  filtered.length,
895
1174
  " ",
896
- filtered.length === 1 ? "task" : "tasks"
1175
+ filtered.length === 1 ? L.tasksSingular : L.tasksPlural
897
1176
  ] })
898
1177
  ] }),
899
1178
  moveError && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-1.5 text-xs text-destructive", children: moveError }),
@@ -914,11 +1193,11 @@ function TaskBoardCore({
914
1193
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2", children: [
915
1194
  /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
916
1195
  /* @__PURE__ */ jsx(StatusIcon, { status: col.status }),
917
- col.label
1196
+ L.status[col.status]
918
1197
  ] }),
919
1198
  /* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 text-xs font-medium text-muted-foreground", children: colTasks.length })
920
1199
  ] }),
921
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 px-2 pb-2", children: colTasks.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-md border border-dashed border-border/70 px-3 py-6 text-center text-xs text-muted-foreground", children: isOver ? "Drop here" : "No tasks" }) : colTasks.map((task) => /* @__PURE__ */ jsx(
1200
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 px-2 pb-2", children: colTasks.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-md border border-dashed border-border/70 px-3 py-6 text-center text-xs text-muted-foreground", children: isOver ? L.dropHere : L.noTasks }) : colTasks.map((task) => /* @__PURE__ */ jsx(
922
1201
  TaskCard,
923
1202
  {
924
1203
  task,
@@ -927,6 +1206,8 @@ function TaskBoardCore({
927
1206
  draggable: canDrag,
928
1207
  dragging: draggingId === task.id,
929
1208
  resolveAssignee,
1209
+ links: linksByItem.get(task.id),
1210
+ renderLinkIcon,
930
1211
  onDragStart: (t, e) => {
931
1212
  setDraggingId(t.id);
932
1213
  e.dataTransfer.effectAllowed = "move";
@@ -981,10 +1262,11 @@ var fieldClass = "w-full rounded-md border border-input bg-background px-3 py-2
981
1262
  var labelClass = "text-sm font-medium text-foreground";
982
1263
  function CreateTaskCore({
983
1264
  projectId: projectIdProp,
1265
+ assigneeOptions,
984
1266
  hiddenFields,
985
1267
  defaultValues,
986
1268
  hideHeader,
987
- submitLabel = "Create task",
1269
+ submitLabel,
988
1270
  onCreated,
989
1271
  onError: onError2,
990
1272
  onCancel,
@@ -994,6 +1276,7 @@ function CreateTaskCore({
994
1276
  const ctx = usePlanMagnetContextSafe();
995
1277
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
996
1278
  const projectId = projectIdProp ?? defaultValues?.projectId;
1279
+ const L = useTaskLabels();
997
1280
  const hidden = useMemo(
998
1281
  () => new Set(hiddenFields ?? []),
999
1282
  [hiddenFields]
@@ -1076,12 +1359,12 @@ function CreateTaskCore({
1076
1359
  }
1077
1360
  return /* @__PURE__ */ jsx(Card, { className: cn("shadow-sm", className), children: /* @__PURE__ */ jsx(CardContent, { className: "p-6", children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
1078
1361
  !hideHeader && /* @__PURE__ */ jsxs("div", { children: [
1079
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-foreground", children: "New task" }),
1080
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Create a work item in this workspace." })
1362
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-foreground", children: L.newTaskHeading }),
1363
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: L.newTaskSubtitle })
1081
1364
  ] }),
1082
- !projectId && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-destructive/10 p-2 text-xs text-destructive", children: "A projectId is required to create a task." }),
1365
+ !projectId && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-destructive/10 p-2 text-xs text-destructive", children: L.projectRequired }),
1083
1366
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1084
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-title", className: labelClass, children: "Title" }),
1367
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-title", className: labelClass, children: L.title }),
1085
1368
  /* @__PURE__ */ jsx(
1086
1369
  "input",
1087
1370
  {
@@ -1089,13 +1372,13 @@ function CreateTaskCore({
1089
1372
  className: fieldClass,
1090
1373
  value: title,
1091
1374
  onChange: (e) => setTitle(e.target.value),
1092
- placeholder: "What needs doing?",
1375
+ placeholder: L.titlePlaceholder,
1093
1376
  required: true
1094
1377
  }
1095
1378
  )
1096
1379
  ] }),
1097
1380
  !hidden.has("description") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1098
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-description", className: labelClass, children: "Description" }),
1381
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-description", className: labelClass, children: L.description }),
1099
1382
  /* @__PURE__ */ jsx(
1100
1383
  "textarea",
1101
1384
  {
@@ -1103,13 +1386,13 @@ function CreateTaskCore({
1103
1386
  className: cn(fieldClass, "min-h-[80px]"),
1104
1387
  value: description,
1105
1388
  onChange: (e) => setDescription(e.target.value),
1106
- placeholder: "Add more detail (optional)"
1389
+ placeholder: L.descriptionPlaceholder
1107
1390
  }
1108
1391
  )
1109
1392
  ] }),
1110
1393
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
1111
1394
  !hidden.has("type") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1112
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-type", className: labelClass, children: "Type" }),
1395
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-type", className: labelClass, children: L.typeLabel }),
1113
1396
  /* @__PURE__ */ jsx(
1114
1397
  "select",
1115
1398
  {
@@ -1117,12 +1400,12 @@ function CreateTaskCore({
1117
1400
  className: cn(fieldClass, "capitalize"),
1118
1401
  value: type,
1119
1402
  onChange: (e) => setType(e.target.value),
1120
- children: TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: enumLabel(t) }, t))
1403
+ children: TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: L.type[t] }, t))
1121
1404
  }
1122
1405
  )
1123
1406
  ] }),
1124
1407
  !hidden.has("status") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1125
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-status", className: labelClass, children: "Status" }),
1408
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-status", className: labelClass, children: L.statusLabel }),
1126
1409
  /* @__PURE__ */ jsx(
1127
1410
  "select",
1128
1411
  {
@@ -1130,12 +1413,12 @@ function CreateTaskCore({
1130
1413
  className: cn(fieldClass, "capitalize"),
1131
1414
  value: status,
1132
1415
  onChange: (e) => setStatus(e.target.value),
1133
- children: TASK_STATUSES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: enumLabel(s) }, s))
1416
+ children: TASK_STATUSES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: L.status[s] }, s))
1134
1417
  }
1135
1418
  )
1136
1419
  ] }),
1137
1420
  !hidden.has("priority") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1138
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-priority", className: labelClass, children: "Priority" }),
1421
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-priority", className: labelClass, children: L.priorityLabel }),
1139
1422
  /* @__PURE__ */ jsx(
1140
1423
  "select",
1141
1424
  {
@@ -1143,25 +1426,37 @@ function CreateTaskCore({
1143
1426
  className: cn(fieldClass, "capitalize"),
1144
1427
  value: priority,
1145
1428
  onChange: (e) => setPriority(e.target.value),
1146
- children: TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: enumLabel(p) }, p))
1429
+ children: TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: L.priority[p] }, p))
1147
1430
  }
1148
1431
  )
1149
1432
  ] }),
1150
1433
  !hidden.has("assignee") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1151
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-assignee", className: labelClass, children: "Assignee" }),
1152
- /* @__PURE__ */ jsx(
1434
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-assignee", className: labelClass, children: L.assigneeLabel }),
1435
+ assigneeOptions && assigneeOptions.length > 0 ? /* @__PURE__ */ jsxs(
1436
+ "select",
1437
+ {
1438
+ id: "pm-assignee",
1439
+ className: fieldClass,
1440
+ value: assigneeId,
1441
+ onChange: (e) => setAssigneeId(e.target.value),
1442
+ children: [
1443
+ /* @__PURE__ */ jsx("option", { value: "", children: L.unassigned }),
1444
+ assigneeOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.id, children: o.name }, o.id))
1445
+ ]
1446
+ }
1447
+ ) : /* @__PURE__ */ jsx(
1153
1448
  "input",
1154
1449
  {
1155
1450
  id: "pm-assignee",
1156
1451
  className: fieldClass,
1157
1452
  value: assigneeId,
1158
1453
  onChange: (e) => setAssigneeId(e.target.value),
1159
- placeholder: "Actor ID (optional)"
1454
+ placeholder: L.assigneePlaceholder
1160
1455
  }
1161
1456
  )
1162
1457
  ] }),
1163
1458
  !hidden.has("dueDate") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1164
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-due", className: labelClass, children: "Due date" }),
1459
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-due", className: labelClass, children: L.dueDateLabel }),
1165
1460
  /* @__PURE__ */ jsx(
1166
1461
  "input",
1167
1462
  {
@@ -1174,7 +1469,7 @@ function CreateTaskCore({
1174
1469
  )
1175
1470
  ] }),
1176
1471
  !hidden.has("storyPoints") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1177
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-points", className: labelClass, children: "Story points" }),
1472
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-points", className: labelClass, children: L.storyPointsLabel }),
1178
1473
  /* @__PURE__ */ jsx(
1179
1474
  "input",
1180
1475
  {
@@ -1190,7 +1485,7 @@ function CreateTaskCore({
1190
1485
  ] })
1191
1486
  ] }),
1192
1487
  !hidden.has("labels") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1193
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-labels", className: labelClass, children: "Labels" }),
1488
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-labels", className: labelClass, children: L.labelsLabel }),
1194
1489
  /* @__PURE__ */ jsx(
1195
1490
  "input",
1196
1491
  {
@@ -1198,12 +1493,13 @@ function CreateTaskCore({
1198
1493
  className: fieldClass,
1199
1494
  value: labels,
1200
1495
  onChange: (e) => setLabels(e.target.value),
1201
- placeholder: "comma, separated, labels"
1496
+ placeholder: L.labelsPlaceholder
1202
1497
  }
1203
1498
  )
1204
1499
  ] }),
1205
1500
  error && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
1206
- "Failed to create task: ",
1501
+ L.failedToCreate,
1502
+ ": ",
1207
1503
  error.message
1208
1504
  ] }),
1209
1505
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
@@ -1213,7 +1509,7 @@ function CreateTaskCore({
1213
1509
  type: "button",
1214
1510
  onClick: onCancel,
1215
1511
  className: "rounded-md bg-muted px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted/70",
1216
- children: "Cancel"
1512
+ children: L.cancel
1217
1513
  }
1218
1514
  ),
1219
1515
  /* @__PURE__ */ jsx(
@@ -1225,7 +1521,7 @@ function CreateTaskCore({
1225
1521
  "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground",
1226
1522
  (!canSubmit || loading) && "cursor-not-allowed opacity-50"
1227
1523
  ),
1228
- children: loading ? "Creating\u2026" : submitLabel
1524
+ children: loading ? L.creating : submitLabel ?? L.create
1229
1525
  }
1230
1526
  )
1231
1527
  ] })
@@ -1283,17 +1579,32 @@ var statusRank = {
1283
1579
  DONE: 5,
1284
1580
  CANCELLED: 6
1285
1581
  };
1286
- var COLUMN_LABELS = {
1287
- key: "Key",
1288
- title: "Task",
1289
- type: "Type",
1290
- status: "Status",
1291
- priority: "Priority",
1292
- assignee: "Assignee",
1293
- dueDate: "Due Date",
1294
- storyPoints: "Points",
1295
- labels: "Labels"
1296
- };
1582
+ function columnLabel(col, L) {
1583
+ switch (col) {
1584
+ case "key":
1585
+ return L.colKey;
1586
+ case "title":
1587
+ return L.colTask;
1588
+ case "type":
1589
+ return L.colType;
1590
+ case "status":
1591
+ return L.colStatus;
1592
+ case "priority":
1593
+ return L.colPriority;
1594
+ case "assignee":
1595
+ return L.colAssignee;
1596
+ case "dueDate":
1597
+ return L.colDueDate;
1598
+ case "storyPoints":
1599
+ return L.colPoints;
1600
+ case "linkedRecord":
1601
+ return L.colLinkedRecord;
1602
+ case "labels":
1603
+ return L.colLabels;
1604
+ default:
1605
+ return col;
1606
+ }
1607
+ }
1297
1608
  var COLUMN_SORT = {
1298
1609
  title: "title",
1299
1610
  type: "type",
@@ -1315,12 +1626,16 @@ function TaskListCore({
1315
1626
  hideHeader,
1316
1627
  onSelect,
1317
1628
  resolveAssignee,
1629
+ linkSourceProduct,
1630
+ renderLinkIcon,
1318
1631
  limit = 200,
1319
1632
  className,
1320
1633
  workspaceId: workspaceIdProp
1321
1634
  }) {
1322
1635
  const ctx = usePlanMagnetContextSafe();
1323
1636
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
1637
+ const { linksByItem } = useWorkItemLinks(workspaceId, linkSourceProduct);
1638
+ const L = useTaskLabels();
1324
1639
  const [sort, setSort] = useState({
1325
1640
  by: sortBy ?? null,
1326
1641
  dir: sortDir
@@ -1368,17 +1683,18 @@ function TaskListCore({
1368
1683
  }
1369
1684
  if (error && !data) {
1370
1685
  return /* @__PURE__ */ jsxs("div", { className: cn("p-6 text-sm text-destructive", className), children: [
1371
- "Error loading tasks: ",
1686
+ L.errorLoading,
1687
+ ": ",
1372
1688
  error.message
1373
1689
  ] });
1374
1690
  }
1375
1691
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
1376
1692
  !hideHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
1377
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: "List" }),
1693
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: L.list }),
1378
1694
  /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1379
1695
  rows.length,
1380
1696
  " ",
1381
- rows.length === 1 ? "task" : "tasks"
1697
+ rows.length === 1 ? L.tasksSingular : L.tasksPlural
1382
1698
  ] })
1383
1699
  ] }),
1384
1700
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
@@ -1394,7 +1710,7 @@ function TaskListCore({
1394
1710
  sortable && "cursor-pointer select-none hover:text-foreground"
1395
1711
  ),
1396
1712
  children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
1397
- COLUMN_LABELS[col],
1713
+ columnLabel(col, L),
1398
1714
  active && (sort.dir === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3", "aria-hidden": "true" }))
1399
1715
  ] })
1400
1716
  },
@@ -1407,7 +1723,7 @@ function TaskListCore({
1407
1723
  {
1408
1724
  colSpan: columns.length,
1409
1725
  className: "px-3 py-8 text-center text-muted-foreground",
1410
- children: "No tasks found."
1726
+ children: L.noTasksFound
1411
1727
  }
1412
1728
  ) }),
1413
1729
  rows.map((task) => /* @__PURE__ */ jsx(
@@ -1422,7 +1738,12 @@ function TaskListCore({
1422
1738
  "td",
1423
1739
  {
1424
1740
  className: "px-3 py-2 align-middle text-foreground",
1425
- children: renderCell(col, task, resolveAssignee)
1741
+ children: renderCell(col, task, {
1742
+ resolveAssignee,
1743
+ links: linksByItem.get(task.id),
1744
+ renderLinkIcon,
1745
+ unassigned: L.unassigned
1746
+ })
1426
1747
  },
1427
1748
  col
1428
1749
  ))
@@ -1433,7 +1754,8 @@ function TaskListCore({
1433
1754
  ] }) })
1434
1755
  ] });
1435
1756
  }
1436
- function renderCell(col, task, resolveAssignee) {
1757
+ function renderCell(col, task, opts) {
1758
+ const { resolveAssignee, links, renderLinkIcon, unassigned } = opts;
1437
1759
  switch (col) {
1438
1760
  case "key":
1439
1761
  return /* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-muted-foreground", children: task.key });
@@ -1452,7 +1774,7 @@ function renderCell(col, task, resolveAssignee) {
1452
1774
  const resolved = task.assigneeId ? resolveAssignee?.(task.assigneeId) : null;
1453
1775
  return /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
1454
1776
  /* @__PURE__ */ jsx(Avatar, { id: task.assigneeId, name: resolved?.name, size: "sm" }),
1455
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: resolved?.name ?? (task.assigneeId ? "" : "Unassigned") })
1777
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: resolved?.name ?? (task.assigneeId ? "" : unassigned) })
1456
1778
  ] });
1457
1779
  }
1458
1780
  case "dueDate": {
@@ -1471,6 +1793,17 @@ function renderCell(col, task, resolveAssignee) {
1471
1793
  }
1472
1794
  case "storyPoints":
1473
1795
  return task.storyPoints != null ? /* @__PURE__ */ jsx("span", { className: "flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/10 px-1 text-[10px] font-semibold text-primary", children: task.storyPoints }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
1796
+ case "linkedRecord":
1797
+ if (!links || links.length === 0) {
1798
+ return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
1799
+ }
1800
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
1801
+ links.slice(0, 2).map((link) => /* @__PURE__ */ jsx(LinkChip, { link, renderIcon: renderLinkIcon }, link.id)),
1802
+ links.length > 2 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
1803
+ "+",
1804
+ links.length - 2
1805
+ ] })
1806
+ ] });
1474
1807
  case "labels":
1475
1808
  return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: (task.labels ?? []).slice(0, 3).map((l) => /* @__PURE__ */ jsx(
1476
1809
  "span",
@@ -1530,6 +1863,35 @@ function TaskList({
1530
1863
  }
1531
1864
  );
1532
1865
  }
1866
+ function useMilestones(workspaceId, opts = {}) {
1867
+ const { projectId, enabled = true, limit = 100 } = opts;
1868
+ const { data, loading } = useQuery(LIST_MILESTONES, {
1869
+ variables: {
1870
+ workspaceId,
1871
+ ...projectId ? { filter: { projectId } } : {},
1872
+ pagination: { first: limit }
1873
+ },
1874
+ skip: !workspaceId || !enabled,
1875
+ errorPolicy: "all"
1876
+ });
1877
+ const milestones = useMemo(
1878
+ () => data?.planmagnetMilestones?.items ?? [],
1879
+ [data]
1880
+ );
1881
+ const byDay = useMemo(() => {
1882
+ const map = /* @__PURE__ */ new Map();
1883
+ for (const m of milestones) {
1884
+ const d = parseDate(m.dueDate);
1885
+ if (!d) continue;
1886
+ const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
1887
+ const arr = map.get(key);
1888
+ if (arr) arr.push(m);
1889
+ else map.set(key, [m]);
1890
+ }
1891
+ return map;
1892
+ }, [milestones]);
1893
+ return { milestones, byDay, loading };
1894
+ }
1533
1895
  var WEEK_OPTS = { weekStartsOn: 1 };
1534
1896
  function dayKey(d) {
1535
1897
  return format(d, "yyyy-MM-dd");
@@ -1543,11 +1905,17 @@ function TaskTimelineCore({
1543
1905
  defaultMode = "week",
1544
1906
  onSelect,
1545
1907
  resolveAssignee,
1908
+ showMilestones = true,
1546
1909
  className,
1547
1910
  workspaceId: workspaceIdProp
1548
1911
  }) {
1549
1912
  const ctx = usePlanMagnetContextSafe();
1550
1913
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
1914
+ const L = useTaskLabels();
1915
+ const { milestones, byDay: milestonesByDay } = useMilestones(workspaceId, {
1916
+ projectId,
1917
+ enabled: showMilestones
1918
+ });
1551
1919
  const [mode, setMode] = useState(defaultMode);
1552
1920
  const [offset, setOffset] = useState(0);
1553
1921
  const { data, loading, error } = useQuery(
@@ -1627,7 +1995,8 @@ function TaskTimelineCore({
1627
1995
  }
1628
1996
  if (error && !data) {
1629
1997
  return /* @__PURE__ */ jsxs("div", { className: cn("p-6 text-sm text-destructive", className), children: [
1630
- "Error loading timeline: ",
1998
+ L.errorLoading,
1999
+ ": ",
1631
2000
  error.message
1632
2001
  ] });
1633
2002
  }
@@ -1651,7 +2020,7 @@ function TaskTimelineCore({
1651
2020
  type: "button",
1652
2021
  onClick: () => setOffset(0),
1653
2022
  className: "h-8 rounded-md border border-border px-3 text-xs font-medium text-foreground hover:bg-muted/50",
1654
- children: "Today"
2023
+ children: L.today
1655
2024
  }
1656
2025
  ),
1657
2026
  /* @__PURE__ */ jsx(
@@ -1678,16 +2047,13 @@ function TaskTimelineCore({
1678
2047
  "rounded px-3 py-1 text-xs font-medium capitalize transition-colors",
1679
2048
  mode === m ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground"
1680
2049
  ),
1681
- children: m
2050
+ children: m === "week" ? L.week : L.month
1682
2051
  },
1683
2052
  m
1684
2053
  )) })
1685
2054
  ] }),
1686
2055
  overdue.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2", children: [
1687
- /* @__PURE__ */ jsxs("p", { className: "mb-1 text-xs font-semibold text-destructive", children: [
1688
- overdue.length,
1689
- " overdue"
1690
- ] }),
2056
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold text-destructive", children: L.overdue.replace("{n}", String(overdue.length)) }),
1691
2057
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: overdue.map((t) => /* @__PURE__ */ jsx(
1692
2058
  TaskChip,
1693
2059
  {
@@ -1699,8 +2065,16 @@ function TaskTimelineCore({
1699
2065
  t.id
1700
2066
  )) })
1701
2067
  ] }),
2068
+ milestones.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2", children: [
2069
+ /* @__PURE__ */ jsxs("p", { className: "mb-1 flex items-center gap-1 text-xs font-semibold text-primary", children: [
2070
+ /* @__PURE__ */ jsx(Flag, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2071
+ L.milestones
2072
+ ] }),
2073
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: milestones.map((m) => /* @__PURE__ */ jsx(MilestoneFlag, { milestone: m }, m.id)) })
2074
+ ] }),
1702
2075
  mode === "week" ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: days.map((day) => {
1703
2076
  const items = byDay.get(dayKey(day)) ?? [];
2077
+ const dayMilestones = milestonesByDay.get(dayKey(day)) ?? [];
1704
2078
  const today = isToday(day);
1705
2079
  return /* @__PURE__ */ jsxs(
1706
2080
  "div",
@@ -1732,15 +2106,18 @@ function TaskTimelineCore({
1732
2106
  }
1733
2107
  )
1734
2108
  ] }),
1735
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5", children: items.map((t) => /* @__PURE__ */ jsx(
1736
- TaskChip,
1737
- {
1738
- task: t,
1739
- onSelect,
1740
- resolveAssignee
1741
- },
1742
- t.id
1743
- )) })
2109
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
2110
+ dayMilestones.map((m) => /* @__PURE__ */ jsx(MilestoneFlag, { milestone: m, compact: true }, m.id)),
2111
+ items.map((t) => /* @__PURE__ */ jsx(
2112
+ TaskChip,
2113
+ {
2114
+ task: t,
2115
+ onSelect,
2116
+ resolveAssignee
2117
+ },
2118
+ t.id
2119
+ ))
2120
+ ] })
1744
2121
  ]
1745
2122
  },
1746
2123
  dayKey(day)
@@ -1790,7 +2167,8 @@ function TaskTimelineCore({
1790
2167
  items.length > 3 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
1791
2168
  "+",
1792
2169
  items.length - 3,
1793
- " more"
2170
+ " ",
2171
+ L.more
1794
2172
  ] })
1795
2173
  ]
1796
2174
  },
@@ -1799,11 +2177,7 @@ function TaskTimelineCore({
1799
2177
  })
1800
2178
  ] }),
1801
2179
  undated.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
1802
- /* @__PURE__ */ jsxs("p", { className: "mb-1 text-xs font-semibold text-muted-foreground", children: [
1803
- "No due date (",
1804
- undated.length,
1805
- ")"
1806
- ] }),
2180
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold text-muted-foreground", children: L.noDueDate.replace("{n}", String(undated.length)) }),
1807
2181
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: undated.map((t) => /* @__PURE__ */ jsx(
1808
2182
  TaskChip,
1809
2183
  {
@@ -1816,6 +2190,30 @@ function TaskTimelineCore({
1816
2190
  ] })
1817
2191
  ] });
1818
2192
  }
2193
+ function MilestoneFlag({
2194
+ milestone,
2195
+ compact
2196
+ }) {
2197
+ const due = formatDueDate(milestone.dueDate);
2198
+ return /* @__PURE__ */ jsxs(
2199
+ "span",
2200
+ {
2201
+ className: cn(
2202
+ "inline-flex max-w-full items-center gap-1 rounded-md border border-primary/40 bg-primary/10 px-1.5 py-1 text-[11px] font-medium text-primary",
2203
+ compact && "w-full"
2204
+ ),
2205
+ title: milestone.name + (due ? ` \xB7 ${due}` : ""),
2206
+ children: [
2207
+ /* @__PURE__ */ jsx(Flag, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
2208
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: milestone.name }),
2209
+ !compact && due && /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-primary/70", children: [
2210
+ "\xB7 ",
2211
+ due
2212
+ ] })
2213
+ ]
2214
+ }
2215
+ );
2216
+ }
1819
2217
  function TaskChip({
1820
2218
  task,
1821
2219
  onSelect,
@@ -1845,10 +2243,10 @@ function TaskChip({
1845
2243
  }
1846
2244
  );
1847
2245
  }
1848
- var VIEW_META = {
1849
- board: { label: "Board", icon: LayoutGrid },
1850
- list: { label: "List", icon: List },
1851
- timeline: { label: "Timeline", icon: CalendarRange }
2246
+ var VIEW_ICONS = {
2247
+ board: LayoutGrid,
2248
+ list: List,
2249
+ timeline: CalendarRange
1852
2250
  };
1853
2251
  var SELECT_CLASS = "h-8 rounded-md border border-border bg-background px-2 text-xs font-medium text-foreground capitalize transition-colors hover:bg-muted/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring";
1854
2252
  function TaskToolbar({
@@ -1863,8 +2261,16 @@ function TaskToolbar({
1863
2261
  onTypeChange,
1864
2262
  onNewTask,
1865
2263
  canCreate,
2264
+ mine,
2265
+ onMineChange,
1866
2266
  className
1867
2267
  }) {
2268
+ const L = useTaskLabels();
2269
+ const viewLabel = {
2270
+ board: L.board,
2271
+ list: L.list,
2272
+ timeline: L.timeline
2273
+ };
1868
2274
  return /* @__PURE__ */ jsxs(
1869
2275
  "div",
1870
2276
  {
@@ -1880,8 +2286,7 @@ function TaskToolbar({
1880
2286
  role: "tablist",
1881
2287
  "aria-label": "Task views",
1882
2288
  children: views.map((v) => {
1883
- const meta = VIEW_META[v];
1884
- const Icon = meta.icon;
2289
+ const Icon = VIEW_ICONS[v];
1885
2290
  const active = v === view;
1886
2291
  return /* @__PURE__ */ jsxs(
1887
2292
  "button",
@@ -1896,7 +2301,7 @@ function TaskToolbar({
1896
2301
  ),
1897
2302
  children: [
1898
2303
  /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", "aria-hidden": "true" }),
1899
- meta.label,
2304
+ viewLabel[v],
1900
2305
  active && /* @__PURE__ */ jsx("span", { className: "absolute inset-x-1 -bottom-[9px] h-0.5 rounded-full bg-primary" })
1901
2306
  ]
1902
2307
  },
@@ -1920,22 +2325,38 @@ function TaskToolbar({
1920
2325
  type: "search",
1921
2326
  value: search,
1922
2327
  onChange: (e) => onSearchChange(e.target.value),
1923
- placeholder: "Search tasks\u2026",
1924
- "aria-label": "Search tasks",
2328
+ placeholder: L.searchPlaceholder,
2329
+ "aria-label": L.searchPlaceholder,
1925
2330
  className: "h-8 w-40 rounded-md border border-border bg-background pl-7 pr-2 text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1926
2331
  }
1927
2332
  )
1928
2333
  ] }),
2334
+ onMineChange && /* @__PURE__ */ jsxs(
2335
+ "button",
2336
+ {
2337
+ type: "button",
2338
+ onClick: () => onMineChange(!mine),
2339
+ "aria-pressed": mine,
2340
+ className: cn(
2341
+ "flex h-8 items-center gap-1.5 rounded-md border px-2.5 text-xs font-medium transition-colors",
2342
+ mine ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground"
2343
+ ),
2344
+ children: [
2345
+ /* @__PURE__ */ jsx(User, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2346
+ L.myTasks
2347
+ ]
2348
+ }
2349
+ ),
1929
2350
  /* @__PURE__ */ jsxs(
1930
2351
  "select",
1931
2352
  {
1932
2353
  value: priority,
1933
2354
  onChange: (e) => onPriorityChange(e.target.value),
1934
- "aria-label": "Filter by priority",
2355
+ "aria-label": L.priorityLabel,
1935
2356
  className: SELECT_CLASS,
1936
2357
  children: [
1937
- /* @__PURE__ */ jsx("option", { value: "ALL", children: "All priorities" }),
1938
- TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: enumLabel(p) }, p))
2358
+ /* @__PURE__ */ jsx("option", { value: "ALL", children: L.allPriorities }),
2359
+ TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: L.priority[p] }, p))
1939
2360
  ]
1940
2361
  }
1941
2362
  ),
@@ -1944,11 +2365,11 @@ function TaskToolbar({
1944
2365
  {
1945
2366
  value: type,
1946
2367
  onChange: (e) => onTypeChange(e.target.value),
1947
- "aria-label": "Filter by type",
2368
+ "aria-label": L.typeLabel,
1948
2369
  className: SELECT_CLASS,
1949
2370
  children: [
1950
- /* @__PURE__ */ jsx("option", { value: "ALL", children: "All types" }),
1951
- TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: enumLabel(t) }, t))
2371
+ /* @__PURE__ */ jsx("option", { value: "ALL", children: L.allTypes }),
2372
+ TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: L.type[t] }, t))
1952
2373
  ]
1953
2374
  }
1954
2375
  ),
@@ -1960,7 +2381,7 @@ function TaskToolbar({
1960
2381
  className: "flex h-8 items-center gap-1.5 rounded-md bg-primary px-3 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90",
1961
2382
  children: [
1962
2383
  /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" }),
1963
- "New task"
2384
+ L.newTask
1964
2385
  ]
1965
2386
  }
1966
2387
  )
@@ -1984,9 +2405,14 @@ function TaskDetailCore({
1984
2405
  hiddenFields,
1985
2406
  hideHeader,
1986
2407
  onUpdated,
2408
+ onDeleted,
1987
2409
  onError: onError2,
2410
+ resolveAssignee,
2411
+ assigneeOptions,
1988
2412
  className
1989
2413
  }) {
2414
+ const client = useApolloClient();
2415
+ const L = useTaskLabels();
1990
2416
  const hidden = useMemo(
1991
2417
  () => new Set(hiddenFields ?? []),
1992
2418
  [hiddenFields]
@@ -1997,6 +2423,7 @@ function TaskDetailCore({
1997
2423
  });
1998
2424
  const item = data?.planmagnetWorkItem ?? null;
1999
2425
  const [editing, setEditing] = useState(false);
2426
+ const [confirmingDelete, setConfirmingDelete] = useState(false);
2000
2427
  const [title, setTitle] = useState("");
2001
2428
  const [description, setDescription] = useState("");
2002
2429
  const [type, setType] = useState("TASK");
@@ -2019,6 +2446,22 @@ function TaskDetailCore({
2019
2446
  setStoryPoints(item.storyPoints != null ? String(item.storyPoints) : "");
2020
2447
  }, [item]);
2021
2448
  const [updateWorkItem, { loading: saving, error: saveError }] = useMutation(UPDATE_WORK_ITEM);
2449
+ const [deleteWorkItem, { loading: deleting, error: deleteError }] = useMutation(DELETE_WORK_ITEM);
2450
+ const handleDelete = async () => {
2451
+ if (!item) return;
2452
+ try {
2453
+ await deleteWorkItem({ variables: { id: item.id } });
2454
+ client.cache.evict({
2455
+ id: client.cache.identify({ __typename: "WorkItem", id: item.id })
2456
+ });
2457
+ client.cache.gc();
2458
+ void client.refetchQueries({ include: [LIST_WORK_ITEMS] }).catch(() => {
2459
+ });
2460
+ onDeleted?.(item.id);
2461
+ } catch (err) {
2462
+ onError2?.(err instanceof Error ? err : new Error(String(err)));
2463
+ }
2464
+ };
2022
2465
  const handleSave = async (e) => {
2023
2466
  e.preventDefault();
2024
2467
  if (!item) return;
@@ -2067,12 +2510,13 @@ function TaskDetailCore({
2067
2510
  }
2068
2511
  if (error && !data) {
2069
2512
  return /* @__PURE__ */ jsxs("div", { className: cn("p-6 text-sm text-destructive", className), children: [
2070
- "Error loading task: ",
2513
+ L.errorLoading,
2514
+ ": ",
2071
2515
  error.message
2072
2516
  ] });
2073
2517
  }
2074
2518
  if (!item) {
2075
- return /* @__PURE__ */ jsx("div", { className: cn("p-6 text-sm text-muted-foreground", className), children: "Task not found." });
2519
+ return /* @__PURE__ */ jsx("div", { className: cn("p-6 text-sm text-muted-foreground", className), children: L.taskNotFound });
2076
2520
  }
2077
2521
  const canEdit = !readonly;
2078
2522
  return /* @__PURE__ */ jsx(Card, { className: cn("shadow-sm", className), children: /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4 p-6", children: [
@@ -2081,29 +2525,78 @@ function TaskDetailCore({
2081
2525
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: item.key }),
2082
2526
  /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-foreground", children: item.title })
2083
2527
  ] }),
2084
- canEdit && !editing && /* @__PURE__ */ jsx(
2085
- "button",
2086
- {
2087
- type: "button",
2088
- onClick: () => setEditing(true),
2089
- className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground",
2090
- children: "Edit"
2091
- }
2092
- )
2528
+ canEdit && !editing && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
2529
+ onDeleted && (confirmingDelete ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs", children: [
2530
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: L.deletePrompt }),
2531
+ /* @__PURE__ */ jsx(
2532
+ "button",
2533
+ {
2534
+ type: "button",
2535
+ disabled: deleting,
2536
+ onClick: handleDelete,
2537
+ className: "rounded bg-destructive px-2 py-1 font-medium text-destructive-foreground disabled:opacity-50",
2538
+ children: deleting ? "\u2026" : L.yes
2539
+ }
2540
+ ),
2541
+ /* @__PURE__ */ jsx(
2542
+ "button",
2543
+ {
2544
+ type: "button",
2545
+ onClick: () => setConfirmingDelete(false),
2546
+ className: "rounded bg-muted px-2 py-1 text-muted-foreground",
2547
+ children: L.no
2548
+ }
2549
+ )
2550
+ ] }) : /* @__PURE__ */ jsx(
2551
+ "button",
2552
+ {
2553
+ type: "button",
2554
+ onClick: () => setConfirmingDelete(true),
2555
+ title: L.del,
2556
+ "aria-label": L.del,
2557
+ className: "rounded-md p-1.5 text-destructive hover:bg-destructive/10",
2558
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
2559
+ }
2560
+ )),
2561
+ /* @__PURE__ */ jsx(
2562
+ "button",
2563
+ {
2564
+ type: "button",
2565
+ onClick: () => setEditing(true),
2566
+ className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground",
2567
+ children: L.edit
2568
+ }
2569
+ )
2570
+ ] })
2571
+ ] }),
2572
+ deleteError && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
2573
+ L.failedToDelete,
2574
+ ": ",
2575
+ deleteError.message
2093
2576
  ] }),
2094
2577
  !editing ? /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
2095
- !hidden.has("type") && /* @__PURE__ */ jsx(Field, { label: "Type", children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: enumLabel(item.type) }) }),
2096
- !hidden.has("status") && /* @__PURE__ */ jsx(Field, { label: "Status", children: /* @__PURE__ */ jsx("span", { className: "capitalize text-foreground", children: enumLabel(item.status) }) }),
2097
- !hidden.has("priority") && /* @__PURE__ */ jsx(Field, { label: "Priority", children: /* @__PURE__ */ jsx(Badge, { variant: priorityVariant[item.priority], children: enumLabel(item.priority) }) }),
2098
- !hidden.has("assignee") && /* @__PURE__ */ jsx(Field, { label: "Assignee", children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.assigneeId ?? "Unassigned" }) }),
2099
- !hidden.has("dueDate") && /* @__PURE__ */ jsx(Field, { label: "Due date", children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.dueDate ?? "\u2014" }) }),
2100
- !hidden.has("storyPoints") && /* @__PURE__ */ jsx(Field, { label: "Story points", children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.storyPoints ?? 0 }) }),
2578
+ !hidden.has("type") && /* @__PURE__ */ jsx(Field, { label: L.typeLabel, children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: L.type[item.type] }) }),
2579
+ !hidden.has("status") && /* @__PURE__ */ jsx(Field, { label: L.statusLabel, children: /* @__PURE__ */ jsx("span", { className: "capitalize text-foreground", children: L.status[item.status] }) }),
2580
+ !hidden.has("priority") && /* @__PURE__ */ jsx(Field, { label: L.priorityLabel, children: /* @__PURE__ */ jsx(Badge, { variant: priorityVariant[item.priority], children: L.priority[item.priority] }) }),
2581
+ !hidden.has("assignee") && /* @__PURE__ */ jsx(Field, { label: L.assigneeLabel, children: item.assigneeId ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
2582
+ /* @__PURE__ */ jsx(
2583
+ Avatar,
2584
+ {
2585
+ id: item.assigneeId,
2586
+ name: resolveAssignee?.(item.assigneeId)?.name,
2587
+ size: "sm"
2588
+ }
2589
+ ),
2590
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: resolveAssignee?.(item.assigneeId)?.name ?? L.assigned })
2591
+ ] }) : /* @__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" }) }),
2593
+ !hidden.has("storyPoints") && /* @__PURE__ */ jsx(Field, { label: L.storyPointsLabel, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: item.storyPoints ?? 0 }) }),
2101
2594
  !hidden.has("description") && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
2102
- /* @__PURE__ */ jsx("dt", { className: labelClass2, children: "Description" }),
2595
+ /* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.description }),
2103
2596
  /* @__PURE__ */ jsx("dd", { className: "mt-1 whitespace-pre-wrap text-sm text-foreground", children: item.description || "\u2014" })
2104
2597
  ] }),
2105
2598
  !hidden.has("labels") && /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
2106
- /* @__PURE__ */ jsx("dt", { className: labelClass2, children: "Labels" }),
2599
+ /* @__PURE__ */ jsx("dt", { className: labelClass2, children: L.labelsLabel }),
2107
2600
  /* @__PURE__ */ jsx("dd", { className: "mt-1 flex flex-wrap gap-1", children: (item.labels ?? []).length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "\u2014" }) : item.labels.map((l) => /* @__PURE__ */ jsx(
2108
2601
  "span",
2109
2602
  {
@@ -2115,7 +2608,7 @@ function TaskDetailCore({
2115
2608
  ] })
2116
2609
  ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSave, className: "space-y-4", children: [
2117
2610
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2118
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-title", className: labelClass2, children: "Title" }),
2611
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-title", className: labelClass2, children: L.title }),
2119
2612
  /* @__PURE__ */ jsx(
2120
2613
  "input",
2121
2614
  {
@@ -2128,7 +2621,7 @@ function TaskDetailCore({
2128
2621
  )
2129
2622
  ] }),
2130
2623
  !hidden.has("description") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2131
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-desc", className: labelClass2, children: "Description" }),
2624
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-desc", className: labelClass2, children: L.description }),
2132
2625
  /* @__PURE__ */ jsx(
2133
2626
  "textarea",
2134
2627
  {
@@ -2141,7 +2634,7 @@ function TaskDetailCore({
2141
2634
  ] }),
2142
2635
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
2143
2636
  !hidden.has("type") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2144
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-type", className: labelClass2, children: "Type" }),
2637
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-type", className: labelClass2, children: L.typeLabel }),
2145
2638
  /* @__PURE__ */ jsx(
2146
2639
  "select",
2147
2640
  {
@@ -2149,12 +2642,12 @@ function TaskDetailCore({
2149
2642
  className: cn(fieldClass2, "capitalize"),
2150
2643
  value: type,
2151
2644
  onChange: (e) => setType(e.target.value),
2152
- children: TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: enumLabel(t) }, t))
2645
+ children: TASK_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: L.type[t] }, t))
2153
2646
  }
2154
2647
  )
2155
2648
  ] }),
2156
2649
  !hidden.has("status") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2157
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-status", className: labelClass2, children: "Status" }),
2650
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-status", className: labelClass2, children: L.statusLabel }),
2158
2651
  /* @__PURE__ */ jsx(
2159
2652
  "select",
2160
2653
  {
@@ -2162,12 +2655,12 @@ function TaskDetailCore({
2162
2655
  className: cn(fieldClass2, "capitalize"),
2163
2656
  value: status,
2164
2657
  onChange: (e) => setStatus(e.target.value),
2165
- children: TASK_STATUSES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: enumLabel(s) }, s))
2658
+ children: TASK_STATUSES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: L.status[s] }, s))
2166
2659
  }
2167
2660
  )
2168
2661
  ] }),
2169
2662
  !hidden.has("priority") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2170
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-priority", className: labelClass2, children: "Priority" }),
2663
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-priority", className: labelClass2, children: L.priorityLabel }),
2171
2664
  /* @__PURE__ */ jsx(
2172
2665
  "select",
2173
2666
  {
@@ -2175,25 +2668,37 @@ function TaskDetailCore({
2175
2668
  className: cn(fieldClass2, "capitalize"),
2176
2669
  value: priority,
2177
2670
  onChange: (e) => setPriority(e.target.value),
2178
- children: TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: enumLabel(p) }, p))
2671
+ children: TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: L.priority[p] }, p))
2179
2672
  }
2180
2673
  )
2181
2674
  ] }),
2182
2675
  !hidden.has("assignee") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2183
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-assignee", className: labelClass2, children: "Assignee" }),
2184
- /* @__PURE__ */ jsx(
2676
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-assignee", className: labelClass2, children: L.assigneeLabel }),
2677
+ assigneeOptions && assigneeOptions.length > 0 ? /* @__PURE__ */ jsxs(
2678
+ "select",
2679
+ {
2680
+ id: "pm-detail-assignee",
2681
+ className: fieldClass2,
2682
+ value: assigneeId,
2683
+ onChange: (e) => setAssigneeId(e.target.value),
2684
+ children: [
2685
+ /* @__PURE__ */ jsx("option", { value: "", children: L.unassigned }),
2686
+ assigneeOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.id, children: o.name }, o.id))
2687
+ ]
2688
+ }
2689
+ ) : /* @__PURE__ */ jsx(
2185
2690
  "input",
2186
2691
  {
2187
2692
  id: "pm-detail-assignee",
2188
2693
  className: fieldClass2,
2189
2694
  value: assigneeId,
2190
2695
  onChange: (e) => setAssigneeId(e.target.value),
2191
- placeholder: "Actor ID"
2696
+ placeholder: L.assigneePlaceholder
2192
2697
  }
2193
2698
  )
2194
2699
  ] }),
2195
2700
  !hidden.has("dueDate") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2196
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-due", className: labelClass2, children: "Due date" }),
2701
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-due", className: labelClass2, children: L.dueDateLabel }),
2197
2702
  /* @__PURE__ */ jsx(
2198
2703
  "input",
2199
2704
  {
@@ -2206,7 +2711,7 @@ function TaskDetailCore({
2206
2711
  )
2207
2712
  ] }),
2208
2713
  !hidden.has("storyPoints") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2209
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-points", className: labelClass2, children: "Story points" }),
2714
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-points", className: labelClass2, children: L.storyPointsLabel }),
2210
2715
  /* @__PURE__ */ jsx(
2211
2716
  "input",
2212
2717
  {
@@ -2221,7 +2726,7 @@ function TaskDetailCore({
2221
2726
  ] })
2222
2727
  ] }),
2223
2728
  !hidden.has("labels") && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2224
- /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-labels", className: labelClass2, children: "Labels" }),
2729
+ /* @__PURE__ */ jsx("label", { htmlFor: "pm-detail-labels", className: labelClass2, children: L.labelsLabel }),
2225
2730
  /* @__PURE__ */ jsx(
2226
2731
  "input",
2227
2732
  {
@@ -2229,12 +2734,13 @@ function TaskDetailCore({
2229
2734
  className: fieldClass2,
2230
2735
  value: labels,
2231
2736
  onChange: (e) => setLabels(e.target.value),
2232
- placeholder: "comma, separated, labels"
2737
+ placeholder: L.labelsPlaceholder
2233
2738
  }
2234
2739
  )
2235
2740
  ] }),
2236
2741
  saveError && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive", children: [
2237
- "Failed to save: ",
2742
+ L.failedToSave,
2743
+ ": ",
2238
2744
  saveError.message
2239
2745
  ] }),
2240
2746
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
@@ -2244,7 +2750,7 @@ function TaskDetailCore({
2244
2750
  type: "button",
2245
2751
  onClick: () => setEditing(false),
2246
2752
  className: "rounded-md bg-muted px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted/70",
2247
- children: "Cancel"
2753
+ children: L.cancel
2248
2754
  }
2249
2755
  ),
2250
2756
  /* @__PURE__ */ jsx(
@@ -2256,7 +2762,7 @@ function TaskDetailCore({
2256
2762
  "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground",
2257
2763
  (saving || !title.trim()) && "cursor-not-allowed opacity-50"
2258
2764
  ),
2259
- children: saving ? "Saving\u2026" : "Save changes"
2765
+ children: saving ? L.saving : L.save
2260
2766
  }
2261
2767
  )
2262
2768
  ] })
@@ -2307,6 +2813,11 @@ function TasksPageCore({
2307
2813
  views,
2308
2814
  defaultView = "board",
2309
2815
  resolveAssignee,
2816
+ linkSourceProduct,
2817
+ renderLinkIcon,
2818
+ assigneeOptions,
2819
+ currentActorId,
2820
+ labels,
2310
2821
  header,
2311
2822
  onTaskSaved,
2312
2823
  createSurface = "modal",
@@ -2316,10 +2827,12 @@ function TasksPageCore({
2316
2827
  const ctx = usePlanMagnetContextSafe();
2317
2828
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
2318
2829
  const client = useApolloClient();
2830
+ const mergedLabels = mergeTaskLabels(labels);
2319
2831
  const [view, setView] = useState(defaultView);
2320
2832
  const [search, setSearch] = useState("");
2321
2833
  const [priority, setPriority] = useState("ALL");
2322
2834
  const [type, setType] = useState("ALL");
2835
+ const [mine, setMine] = useState(false);
2323
2836
  const [creating, setCreating] = useState(false);
2324
2837
  const [selectedId, setSelectedId] = useState(null);
2325
2838
  const refetchBoard = useCallback(() => {
@@ -2341,6 +2854,9 @@ function TasksPageCore({
2341
2854
  },
2342
2855
  [refetchBoard, onTaskSaved]
2343
2856
  );
2857
+ const handleDeleted = useCallback(() => {
2858
+ setSelectedId(null);
2859
+ }, []);
2344
2860
  const handleTaskClick = useCallback((task) => {
2345
2861
  setSelectedId(task.id);
2346
2862
  }, []);
@@ -2356,6 +2872,7 @@ function TasksPageCore({
2356
2872
  {
2357
2873
  workspaceId,
2358
2874
  projectId,
2875
+ assigneeOptions,
2359
2876
  hiddenFields,
2360
2877
  onCreated: handleCreated,
2361
2878
  onCancel: () => setCreating(false)
@@ -2367,12 +2884,24 @@ function TasksPageCore({
2367
2884
  id: selectedId,
2368
2885
  readonly,
2369
2886
  hiddenFields,
2370
- onUpdated: handleUpdated
2887
+ resolveAssignee,
2888
+ assigneeOptions,
2889
+ onUpdated: handleUpdated,
2890
+ onDeleted: handleDeleted
2371
2891
  }
2372
2892
  ) : null;
2373
2893
  const listPriority = priority === "ALL" ? void 0 : priority;
2374
2894
  const listType = type === "ALL" ? void 0 : type;
2375
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4 p-6", className), children: [
2895
+ const mineAssignee = mine && currentActorId ? currentActorId : void 0;
2896
+ const listColumns = linkSourceProduct ? [
2897
+ "title",
2898
+ "status",
2899
+ "priority",
2900
+ "assignee",
2901
+ "dueDate",
2902
+ "linkedRecord"
2903
+ ] : void 0;
2904
+ return /* @__PURE__ */ jsx(TaskLabelsProvider, { value: mergedLabels, children: /* @__PURE__ */ jsxs("div", { className: cn("space-y-4 p-6", className), children: [
2376
2905
  header && /* @__PURE__ */ jsx("div", { className: "min-w-0", children: typeof header === "string" ? /* @__PURE__ */ jsx("h1", { className: "truncate text-2xl font-semibold text-foreground", children: header }) : header }),
2377
2906
  /* @__PURE__ */ jsx(
2378
2907
  TaskToolbar,
@@ -2387,7 +2916,9 @@ function TasksPageCore({
2387
2916
  type,
2388
2917
  onTypeChange: setType,
2389
2918
  onNewTask: () => setCreating(true),
2390
- canCreate
2919
+ canCreate,
2920
+ mine,
2921
+ onMineChange: currentActorId ? setMine : void 0
2391
2922
  }
2392
2923
  ),
2393
2924
  showInlineCreate && /* @__PURE__ */ jsx("div", { children: createForm }),
@@ -2402,8 +2933,11 @@ function TasksPageCore({
2402
2933
  priority,
2403
2934
  type,
2404
2935
  search,
2936
+ assigneeId: mineAssignee,
2405
2937
  hiddenFields,
2406
2938
  resolveAssignee,
2939
+ linkSourceProduct,
2940
+ renderLinkIcon,
2407
2941
  onTaskClick: handleTaskClick
2408
2942
  }
2409
2943
  ),
@@ -2415,8 +2949,12 @@ function TasksPageCore({
2415
2949
  priority: listPriority,
2416
2950
  type: listType,
2417
2951
  search: search || void 0,
2952
+ assigneeId: mineAssignee,
2418
2953
  hideHeader: true,
2419
2954
  resolveAssignee,
2955
+ linkSourceProduct,
2956
+ renderLinkIcon,
2957
+ columns: listColumns ? [...listColumns] : void 0,
2420
2958
  onSelect: handleSelect
2421
2959
  }
2422
2960
  ),
@@ -2428,6 +2966,7 @@ function TasksPageCore({
2428
2966
  priority,
2429
2967
  type,
2430
2968
  search,
2969
+ assigneeId: mineAssignee,
2431
2970
  resolveAssignee,
2432
2971
  onSelect: handleSelect
2433
2972
  }
@@ -2452,7 +2991,7 @@ function TasksPageCore({
2452
2991
  children: /* @__PURE__ */ jsx("div", { className: "p-2 pt-8", children: detailView })
2453
2992
  }
2454
2993
  )
2455
- ] });
2994
+ ] }) });
2456
2995
  }
2457
2996
  function TasksPage({
2458
2997
  apiGatewayUrl,
@@ -2483,6 +3022,6 @@ function TasksPage({
2483
3022
  );
2484
3023
  }
2485
3024
 
2486
- export { Avatar, Badge, CREATE_WORK_ITEM, CreateTask, CreateTaskCore, DEFAULT_BOARD_COLUMNS, Drawer, GET_PROJECTS, GET_WORK_ITEM, LIST_WORK_ITEMS, MOVE_WORK_ITEM, Modal, PRIORITY_META, PROJECT_SUMMARY_FIELDS, PlanMagnetProvider, PriorityIndicator, STATUS_META, StatusIcon, StatusPill, TASK_PRIORITIES, TASK_STATUSES, TASK_TYPES, TaskBoard, TaskBoardCore, TaskCard, TaskDetail, TaskDetailCore, TaskList, TaskListCore, TaskTimelineCore, TaskToolbar, TasksPage, TasksPageCore, TypeBadge, UPDATE_WORK_ITEM, WORK_ITEM_FIELDS, WORK_ITEM_SUMMARY_FIELDS, badgeVariants, cn, config, createPlanMagnetClient, enumLabel, getGraphQLEndpoint, getPlanMagnetClient, getPlanMagnetClientSafe, getPlanMagnetConfig, isPlanMagnetClientReady, resetPlanMagnetClient, resetPlanMagnetConfig, setPlanMagnetClient, setPlanMagnetConfig, usePlanMagnetContext, usePlanMagnetContextSafe, validateTrustedOrigin, waitForPlanMagnetClient };
3025
+ export { Avatar, Badge, CREATE_WORK_ITEM, CREATE_WORK_ITEM_LINK, CreateTask, CreateTaskCore, DEFAULT_BOARD_COLUMNS, DEFAULT_TASK_LABELS, DELETE_WORK_ITEM, DELETE_WORK_ITEM_LINK, Drawer, GET_PROJECTS, GET_WORK_ITEM, LIST_MILESTONES, LIST_WORK_ITEMS, LIST_WORK_ITEM_LINKS, LinkChip, MILESTONE_FIELDS, MOVE_WORK_ITEM, Modal, PRIORITY_META, PROJECT_SUMMARY_FIELDS, PlanMagnetProvider, PriorityIndicator, STATUS_META, StatusIcon, StatusPill, TASK_PRIORITIES, TASK_STATUSES, TASK_TYPES, TaskBoard, TaskBoardCore, TaskCard, TaskDetail, TaskDetailCore, TaskLabelsProvider, TaskList, TaskListCore, TaskTimelineCore, TaskToolbar, TasksPage, TasksPageCore, TypeBadge, UPDATE_WORK_ITEM, WORK_ITEM_FIELDS, WORK_ITEM_LINK_FIELDS, WORK_ITEM_SUMMARY_FIELDS, badgeVariants, cn, config, createPlanMagnetClient, enumLabel, getGraphQLEndpoint, getPlanMagnetClient, getPlanMagnetClientSafe, getPlanMagnetConfig, isPlanMagnetClientReady, mergeTaskLabels, resetPlanMagnetClient, resetPlanMagnetConfig, setPlanMagnetClient, setPlanMagnetConfig, useMilestones, usePlanMagnetContext, usePlanMagnetContextSafe, useTaskLabels, useWorkItemLinks, validateTrustedOrigin, waitForPlanMagnetClient };
2487
3026
  //# sourceMappingURL=index.js.map
2488
3027
  //# sourceMappingURL=index.js.map