@burdenoff/planmagnet-fe-sdk 2026.706.5 → 2026.706.7

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
@@ -6,12 +6,13 @@ 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, Link2, CalendarDays, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Flag, CalendarRange, List, LayoutGrid, Search, Plus, Trash2 } from 'lucide-react';
9
+ import { CircleX, CircleCheckBig, CircleDotDashed, CircleDot, Circle, CircleDashed, User, Link2, CalendarDays, Trash2, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Flag, Plus, CalendarRange, List, LayoutGrid, Search, Pencil, SmilePlus } from 'lucide-react';
10
10
  import { clsx } from 'clsx';
11
11
  import { twMerge } from 'tailwind-merge';
12
- import { addWeeks, startOfWeek, endOfWeek, eachDayOfInterval, addMonths, startOfMonth, endOfMonth, format, isToday, isSameMonth, startOfDay, parseISO, isValid } from 'date-fns';
12
+ import { startOfWeek, format, addDays, addWeeks, endOfWeek, eachDayOfInterval, addMonths, startOfMonth, endOfMonth, isToday, isSameMonth, startOfDay, parseISO, isValid } from 'date-fns';
13
13
  import { cva } from 'class-variance-authority';
14
14
  import { Card, CardContent } from '@burdenoff/fe-libs/ui';
15
+ import { enUS, ta, ar, es, zhCN, hi } from 'date-fns/locale';
15
16
 
16
17
  var clientInstance = null;
17
18
  function buildCache() {
@@ -507,11 +508,29 @@ var LIST_MILESTONES = gql`
507
508
  }
508
509
  ${MILESTONE_FIELDS}
509
510
  `;
511
+ var CREATE_MILESTONE = gql`
512
+ mutation CreateMilestone($input: PlanmagnetCreateMilestoneInput!) {
513
+ planmagnetCreateMilestone(input: $input) {
514
+ ...MilestoneFields
515
+ }
516
+ }
517
+ ${MILESTONE_FIELDS}
518
+ `;
510
519
  var DELETE_WORK_ITEM = gql`
511
520
  mutation DeleteWorkItem($id: ID!) {
512
521
  planmagnetDeleteWorkItem(id: $id)
513
522
  }
514
523
  `;
524
+ var BULK_UPDATE_WORK_ITEMS = gql`
525
+ mutation BulkUpdateWorkItems($input: PlanmagnetBulkUpdateWorkItemsInput!) {
526
+ planmagnetBulkUpdateWorkItems(input: $input) {
527
+ id
528
+ status
529
+ priority
530
+ assigneeId
531
+ }
532
+ }
533
+ `;
515
534
  var ENTITY_COMMENT_FIELDS = gql`
516
535
  fragment EntityCommentFields on EntityComment {
517
536
  id
@@ -530,6 +549,11 @@ var ENTITY_COMMENT_FIELDS = gql`
530
549
  mentions {
531
550
  mentionedUserId
532
551
  }
552
+ reactionSummary {
553
+ emoji
554
+ count
555
+ userIds
556
+ }
533
557
  }
534
558
  `;
535
559
  var GET_ENTITY_COMMENTS = gql`
@@ -556,6 +580,29 @@ var DELETE_ENTITY_COMMENT = gql`
556
580
  deleteEntityComment(input: $input)
557
581
  }
558
582
  `;
583
+ var UPDATE_ENTITY_COMMENT = gql`
584
+ mutation UpdateEntityComment($input: UpdateEntityCommentInput!) {
585
+ updateEntityComment(input: $input) {
586
+ ...EntityCommentFields
587
+ }
588
+ }
589
+ ${ENTITY_COMMENT_FIELDS}
590
+ `;
591
+ var ADD_ENTITY_COMMENT_REACTION = gql`
592
+ mutation AddEntityCommentReaction($input: AddReactionInput!) {
593
+ addEntityCommentReaction(input: $input) {
594
+ id
595
+ commentId
596
+ emoji
597
+ userId
598
+ }
599
+ }
600
+ `;
601
+ var REMOVE_ENTITY_COMMENT_REACTION = gql`
602
+ mutation RemoveEntityCommentReaction($input: RemoveReactionInput!) {
603
+ removeEntityCommentReaction(input: $input)
604
+ }
605
+ `;
559
606
  function cn(...inputs) {
560
607
  return twMerge(clsx(inputs));
561
608
  }
@@ -772,11 +819,21 @@ var DEFAULT_TASK_LABELS = {
772
819
  overdue: "{n} overdue",
773
820
  noDueDate: "No due date ({n})",
774
821
  milestones: "Milestones",
822
+ addMilestone: "Add milestone",
823
+ milestoneNamePlaceholder: "Milestone name",
824
+ failedToCreateMilestone: "Failed to create milestone",
775
825
  today: "Today",
776
826
  week: "Week",
777
827
  month: "Month",
778
828
  tasksSingular: "task",
779
829
  tasksPlural: "tasks",
830
+ bulkSelected: "{n} selected",
831
+ bulkSetStatus: "Set status",
832
+ bulkSetPriority: "Set priority",
833
+ bulkAssign: "Assign",
834
+ bulkDelete: "Delete",
835
+ bulkClear: "Clear",
836
+ bulkApplying: "Applying\u2026",
780
837
  colTask: "Task",
781
838
  colStatus: "Status",
782
839
  colPriority: "Priority",
@@ -815,8 +872,13 @@ var DEFAULT_TASK_LABELS = {
815
872
  noComments: "No comments yet",
816
873
  you: "You",
817
874
  editedTag: "(edited)",
875
+ editComment: "Edit",
876
+ saveComment: "Save",
877
+ addReaction: "React",
818
878
  failedToComment: "Failed to post comment",
819
879
  failedToDeleteComment: "Failed to delete comment",
880
+ failedToEditComment: "Failed to edit comment",
881
+ failedToReact: "Failed to update reaction",
820
882
  reply: "Reply",
821
883
  replyPlaceholder: "Write a reply\u2026",
822
884
  repliesCount: "{n} replies",
@@ -1712,6 +1774,27 @@ var statusRank = {
1712
1774
  DONE: 5,
1713
1775
  CANCELLED: 6
1714
1776
  };
1777
+ var bulkFieldClass = "rounded-md border border-input bg-background px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50";
1778
+ function BulkCheckbox({
1779
+ checked,
1780
+ indeterminate = false,
1781
+ ...props
1782
+ }) {
1783
+ const ref = useRef(null);
1784
+ useEffect(() => {
1785
+ if (ref.current) ref.current.indeterminate = indeterminate;
1786
+ }, [indeterminate]);
1787
+ return /* @__PURE__ */ jsx(
1788
+ "input",
1789
+ {
1790
+ ref,
1791
+ type: "checkbox",
1792
+ checked,
1793
+ className: "h-4 w-4 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50",
1794
+ ...props
1795
+ }
1796
+ );
1797
+ }
1715
1798
  function columnLabel(col, L) {
1716
1799
  switch (col) {
1717
1800
  case "key":
@@ -1762,6 +1845,8 @@ function TaskListCore({
1762
1845
  linkSourceProduct,
1763
1846
  renderLinkIcon,
1764
1847
  limit = 200,
1848
+ selectable = false,
1849
+ assigneeOptions,
1765
1850
  className,
1766
1851
  workspaceId: workspaceIdProp
1767
1852
  }) {
@@ -1783,7 +1868,7 @@ function TaskListCore({
1783
1868
  if (search) f.search = search;
1784
1869
  return f;
1785
1870
  }, [projectId, status, type, priority, assigneeId, search]);
1786
- const { data, loading, error } = useQuery(
1871
+ const { data, loading, error, refetch } = useQuery(
1787
1872
  LIST_WORK_ITEMS,
1788
1873
  {
1789
1874
  variables: {
@@ -1801,6 +1886,66 @@ function TaskListCore({
1801
1886
  const key = sort.by;
1802
1887
  return [...items].sort((a, b) => dir * compareTasks(a, b, key));
1803
1888
  }, [data, sort]);
1889
+ const [selected, setSelected] = useState(
1890
+ () => /* @__PURE__ */ new Set()
1891
+ );
1892
+ const rowsKey = useMemo(() => rows.map((r) => r.id).join(","), [rows]);
1893
+ useEffect(() => {
1894
+ setSelected((prev) => prev.size ? /* @__PURE__ */ new Set() : prev);
1895
+ }, [rowsKey]);
1896
+ const [bulkUpdate, { loading: bulkUpdating }] = useMutation(
1897
+ BULK_UPDATE_WORK_ITEMS
1898
+ );
1899
+ const [bulkDelete, { loading: bulkDeleting }] = useMutation(DELETE_WORK_ITEM);
1900
+ const applying = bulkUpdating || bulkDeleting;
1901
+ const [bulkError, setBulkError] = useState(null);
1902
+ const allSelected = rows.length > 0 && rows.every((r) => selected.has(r.id));
1903
+ const someSelected = selected.size > 0 && !allSelected;
1904
+ const toggleRow = (id) => {
1905
+ setSelected((prev) => {
1906
+ const next = new Set(prev);
1907
+ if (next.has(id)) next.delete(id);
1908
+ else next.add(id);
1909
+ return next;
1910
+ });
1911
+ };
1912
+ const toggleAll = () => {
1913
+ setSelected(
1914
+ (prev) => prev.size === rows.length ? /* @__PURE__ */ new Set() : new Set(rows.map((r) => r.id))
1915
+ );
1916
+ };
1917
+ const clearSelection = () => {
1918
+ setSelected(/* @__PURE__ */ new Set());
1919
+ setBulkError(null);
1920
+ };
1921
+ const applyBulk = async (patch) => {
1922
+ if (selected.size === 0 || applying) return;
1923
+ setBulkError(null);
1924
+ try {
1925
+ await bulkUpdate({
1926
+ variables: { input: { ids: [...selected], ...patch } }
1927
+ });
1928
+ } catch {
1929
+ setBulkError(L.failedToSave);
1930
+ return;
1931
+ }
1932
+ await refetch().catch(() => {
1933
+ });
1934
+ clearSelection();
1935
+ };
1936
+ const applyBulkDelete = async () => {
1937
+ if (selected.size === 0 || applying) return;
1938
+ setBulkError(null);
1939
+ const results = await Promise.allSettled(
1940
+ [...selected].map((id) => bulkDelete({ variables: { id } }))
1941
+ );
1942
+ await refetch().catch(() => {
1943
+ });
1944
+ clearSelection();
1945
+ if (results.some((r) => r.status === "rejected")) {
1946
+ setBulkError(L.failedToDelete);
1947
+ }
1948
+ };
1804
1949
  const toggleSort = (col) => {
1805
1950
  const key = COLUMN_SORT[col];
1806
1951
  if (!key) return;
@@ -1821,6 +1966,7 @@ function TaskListCore({
1821
1966
  error.message
1822
1967
  ] });
1823
1968
  }
1969
+ const colCount = columns.length + (selectable ? 1 : 0);
1824
1970
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
1825
1971
  !hideHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
1826
1972
  /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: L.list }),
@@ -1830,56 +1976,160 @@ function TaskListCore({
1830
1976
  rows.length === 1 ? L.tasksSingular : L.tasksPlural
1831
1977
  ] })
1832
1978
  ] }),
1979
+ selectable && selected.size > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded-lg border border-border bg-muted/50 px-3 py-2 text-sm", children: [
1980
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: L.bulkSelected.replace("{n}", String(selected.size)) }),
1981
+ /* @__PURE__ */ jsxs(
1982
+ "select",
1983
+ {
1984
+ "aria-label": L.bulkSetStatus,
1985
+ disabled: applying,
1986
+ value: "",
1987
+ onChange: (e) => {
1988
+ const v = e.target.value;
1989
+ if (v) void applyBulk({ status: v });
1990
+ },
1991
+ className: bulkFieldClass,
1992
+ children: [
1993
+ /* @__PURE__ */ jsx("option", { value: "", children: L.bulkSetStatus }),
1994
+ TASK_STATUSES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: L.status[s] }, s))
1995
+ ]
1996
+ }
1997
+ ),
1998
+ /* @__PURE__ */ jsxs(
1999
+ "select",
2000
+ {
2001
+ "aria-label": L.bulkSetPriority,
2002
+ disabled: applying,
2003
+ value: "",
2004
+ onChange: (e) => {
2005
+ const v = e.target.value;
2006
+ if (v) void applyBulk({ priority: v });
2007
+ },
2008
+ className: bulkFieldClass,
2009
+ children: [
2010
+ /* @__PURE__ */ jsx("option", { value: "", children: L.bulkSetPriority }),
2011
+ TASK_PRIORITIES.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: L.priority[p] }, p))
2012
+ ]
2013
+ }
2014
+ ),
2015
+ assigneeOptions && assigneeOptions.length > 0 && /* @__PURE__ */ jsxs(
2016
+ "select",
2017
+ {
2018
+ "aria-label": L.bulkAssign,
2019
+ disabled: applying,
2020
+ value: "",
2021
+ onChange: (e) => {
2022
+ const v = e.target.value;
2023
+ if (v) void applyBulk({ assigneeId: v });
2024
+ },
2025
+ className: bulkFieldClass,
2026
+ children: [
2027
+ /* @__PURE__ */ jsx("option", { value: "", children: L.bulkAssign }),
2028
+ assigneeOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.id, children: o.name }, o.id))
2029
+ ]
2030
+ }
2031
+ ),
2032
+ /* @__PURE__ */ jsxs(
2033
+ "button",
2034
+ {
2035
+ type: "button",
2036
+ disabled: applying,
2037
+ onClick: () => void applyBulkDelete(),
2038
+ className: "inline-flex items-center gap-1 rounded-md px-2 py-1 text-destructive hover:bg-destructive/10 disabled:opacity-50",
2039
+ children: [
2040
+ /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2041
+ L.bulkDelete
2042
+ ]
2043
+ }
2044
+ ),
2045
+ /* @__PURE__ */ jsx(
2046
+ "button",
2047
+ {
2048
+ type: "button",
2049
+ disabled: applying,
2050
+ onClick: clearSelection,
2051
+ className: "rounded-md px-2 py-1 text-muted-foreground hover:bg-muted disabled:opacity-50",
2052
+ children: L.bulkClear
2053
+ }
2054
+ ),
2055
+ applying && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: L.bulkApplying }),
2056
+ bulkError && /* @__PURE__ */ jsx("span", { className: "text-xs text-destructive", children: bulkError })
2057
+ ] }),
1833
2058
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
1834
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border bg-muted/50 text-left", children: columns.map((col) => {
1835
- const sortable = Boolean(COLUMN_SORT[col]);
1836
- const active = sort.by === COLUMN_SORT[col];
1837
- return /* @__PURE__ */ jsx(
1838
- "th",
2059
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/50 text-left", children: [
2060
+ selectable && /* @__PURE__ */ jsx("th", { className: "w-9 px-3 py-2", children: /* @__PURE__ */ jsx(
2061
+ BulkCheckbox,
1839
2062
  {
1840
- onClick: sortable ? () => toggleSort(col) : void 0,
1841
- className: cn(
1842
- "px-3 py-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
1843
- sortable && "cursor-pointer select-none hover:text-foreground"
1844
- ),
1845
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
1846
- columnLabel(col, L),
1847
- 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" }))
1848
- ] })
1849
- },
1850
- col
1851
- );
1852
- }) }) }),
2063
+ checked: allSelected,
2064
+ indeterminate: someSelected,
2065
+ disabled: rows.length === 0 || applying,
2066
+ "aria-label": L.bulkSelected.replace("{n}", "all"),
2067
+ onChange: toggleAll
2068
+ }
2069
+ ) }),
2070
+ columns.map((col) => {
2071
+ const sortable = Boolean(COLUMN_SORT[col]);
2072
+ const active = sort.by === COLUMN_SORT[col];
2073
+ return /* @__PURE__ */ jsx(
2074
+ "th",
2075
+ {
2076
+ onClick: sortable ? () => toggleSort(col) : void 0,
2077
+ className: cn(
2078
+ "px-3 py-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
2079
+ sortable && "cursor-pointer select-none hover:text-foreground"
2080
+ ),
2081
+ children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
2082
+ columnLabel(col, L),
2083
+ 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" }))
2084
+ ] })
2085
+ },
2086
+ col
2087
+ );
2088
+ })
2089
+ ] }) }),
1853
2090
  /* @__PURE__ */ jsxs("tbody", { children: [
1854
2091
  rows.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1855
2092
  "td",
1856
2093
  {
1857
- colSpan: columns.length,
2094
+ colSpan: colCount,
1858
2095
  className: "px-3 py-8 text-center text-muted-foreground",
1859
2096
  children: L.noTasksFound
1860
2097
  }
1861
2098
  ) }),
1862
- rows.map((task) => /* @__PURE__ */ jsx(
2099
+ rows.map((task) => /* @__PURE__ */ jsxs(
1863
2100
  "tr",
1864
2101
  {
1865
2102
  onClick: onSelect ? () => onSelect(task.id) : void 0,
1866
2103
  className: cn(
1867
2104
  "border-b border-border last:border-0",
1868
- onSelect && "cursor-pointer hover:bg-muted/40"
2105
+ onSelect && "cursor-pointer hover:bg-muted/40",
2106
+ selectable && selected.has(task.id) && "bg-primary/5"
1869
2107
  ),
1870
- children: columns.map((col) => /* @__PURE__ */ jsx(
1871
- "td",
1872
- {
1873
- className: "px-3 py-2 align-middle text-foreground",
1874
- children: renderCell(col, task, {
1875
- resolveAssignee,
1876
- links: linksByItem.get(task.id),
1877
- renderLinkIcon,
1878
- unassigned: L.unassigned
1879
- })
1880
- },
1881
- col
1882
- ))
2108
+ children: [
2109
+ selectable && /* @__PURE__ */ jsx("td", { className: "w-9 px-3 py-2 align-middle", children: /* @__PURE__ */ jsx(
2110
+ BulkCheckbox,
2111
+ {
2112
+ checked: selected.has(task.id),
2113
+ disabled: applying,
2114
+ "aria-label": task.title,
2115
+ onClick: (e) => e.stopPropagation(),
2116
+ onChange: () => toggleRow(task.id)
2117
+ }
2118
+ ) }),
2119
+ columns.map((col) => /* @__PURE__ */ jsx(
2120
+ "td",
2121
+ {
2122
+ className: "px-3 py-2 align-middle text-foreground",
2123
+ children: renderCell(col, task, {
2124
+ resolveAssignee,
2125
+ links: linksByItem.get(task.id),
2126
+ renderLinkIcon,
2127
+ unassigned: L.unassigned
2128
+ })
2129
+ },
2130
+ col
2131
+ ))
2132
+ ]
1883
2133
  },
1884
2134
  task.id
1885
2135
  ))
@@ -1996,17 +2246,52 @@ function TaskList({
1996
2246
  }
1997
2247
  );
1998
2248
  }
2249
+ function dayToLocalNoonIso(day) {
2250
+ const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(day);
2251
+ if (!m) return void 0;
2252
+ return new Date(
2253
+ Number(m[1]),
2254
+ Number(m[2]) - 1,
2255
+ Number(m[3]),
2256
+ 12,
2257
+ 0,
2258
+ 0
2259
+ ).toISOString();
2260
+ }
1999
2261
  function useMilestones(workspaceId, opts = {}) {
2000
2262
  const { projectId, enabled = true, limit = 100 } = opts;
2001
- const { data, loading } = useQuery(LIST_MILESTONES, {
2002
- variables: {
2003
- workspaceId,
2004
- ...projectId ? { filter: { projectId } } : {},
2005
- pagination: { first: limit }
2263
+ const { data, loading, refetch } = useQuery(
2264
+ LIST_MILESTONES,
2265
+ {
2266
+ variables: {
2267
+ workspaceId,
2268
+ ...projectId ? { filter: { projectId } } : {},
2269
+ pagination: { first: limit }
2270
+ },
2271
+ skip: !workspaceId || !enabled,
2272
+ errorPolicy: "all"
2273
+ }
2274
+ );
2275
+ const [createMutation, { loading: creating }] = useMutation(CREATE_MILESTONE);
2276
+ const createMilestone = useCallback(
2277
+ async (args) => {
2278
+ const iso = args.dueDate ? dayToLocalNoonIso(args.dueDate) : void 0;
2279
+ const res = await createMutation({
2280
+ variables: {
2281
+ input: {
2282
+ projectId: args.projectId,
2283
+ name: args.name,
2284
+ ...iso ? { dueDate: iso } : {},
2285
+ ...args.status ? { status: args.status } : {},
2286
+ ...args.description ? { description: args.description } : {}
2287
+ }
2288
+ }
2289
+ });
2290
+ await refetch();
2291
+ return res.data?.planmagnetCreateMilestone ?? null;
2006
2292
  },
2007
- skip: !workspaceId || !enabled,
2008
- errorPolicy: "all"
2009
- });
2293
+ [createMutation, refetch]
2294
+ );
2010
2295
  const milestones = useMemo(
2011
2296
  () => data?.planmagnetMilestones?.items ?? [],
2012
2297
  [data]
@@ -2023,7 +2308,20 @@ function useMilestones(workspaceId, opts = {}) {
2023
2308
  }
2024
2309
  return map;
2025
2310
  }, [milestones]);
2026
- return { milestones, byDay, loading };
2311
+ return { milestones, byDay, loading, creating, createMilestone };
2312
+ }
2313
+ var LOCALE_MAP = {
2314
+ en: enUS,
2315
+ hi,
2316
+ zh: zhCN,
2317
+ es,
2318
+ ar,
2319
+ ta
2320
+ };
2321
+ function resolveDateLocale(lang) {
2322
+ if (!lang) return enUS;
2323
+ const primary = lang.toLowerCase().split(/[-_]/)[0];
2324
+ return LOCALE_MAP[primary] ?? enUS;
2027
2325
  }
2028
2326
  var WEEK_OPTS = { weekStartsOn: 1 };
2029
2327
  function dayKey(d) {
@@ -2039,18 +2337,58 @@ function TaskTimelineCore({
2039
2337
  onSelect,
2040
2338
  resolveAssignee,
2041
2339
  showMilestones = true,
2340
+ canCreateMilestone = false,
2341
+ milestoneProjectId,
2342
+ locale,
2042
2343
  className,
2043
2344
  workspaceId: workspaceIdProp
2044
2345
  }) {
2045
2346
  const ctx = usePlanMagnetContextSafe();
2046
2347
  const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
2047
2348
  const L = useTaskLabels();
2048
- const { milestones, byDay: milestonesByDay } = useMilestones(workspaceId, {
2349
+ const dfLocale = resolveDateLocale(locale);
2350
+ const weekdayHeaders = useMemo(() => {
2351
+ const weekStart = startOfWeek(new Date(2026, 0, 5), WEEK_OPTS);
2352
+ return Array.from(
2353
+ { length: 7 },
2354
+ (_, i) => format(addDays(weekStart, i), "EEE", { locale: dfLocale })
2355
+ );
2356
+ }, [dfLocale]);
2357
+ const {
2358
+ milestones,
2359
+ byDay: milestonesByDay,
2360
+ creating: creatingMilestone,
2361
+ createMilestone
2362
+ } = useMilestones(workspaceId, {
2049
2363
  projectId,
2050
2364
  enabled: showMilestones
2051
2365
  });
2052
2366
  const [mode, setMode] = useState(defaultMode);
2053
2367
  const [offset, setOffset] = useState(0);
2368
+ const milestoneProject = milestoneProjectId ?? projectId;
2369
+ const canAddMilestone = canCreateMilestone && Boolean(milestoneProject);
2370
+ const [showMilestoneForm, setShowMilestoneForm] = useState(false);
2371
+ const [milestoneName, setMilestoneName] = useState("");
2372
+ const [milestoneDue, setMilestoneDue] = useState("");
2373
+ const [milestoneError, setMilestoneError] = useState(null);
2374
+ const submitMilestone = async (e) => {
2375
+ e.preventDefault();
2376
+ const name = milestoneName.trim();
2377
+ if (!name || !milestoneProject) return;
2378
+ setMilestoneError(null);
2379
+ try {
2380
+ await createMilestone({
2381
+ projectId: milestoneProject,
2382
+ name,
2383
+ dueDate: milestoneDue || void 0
2384
+ });
2385
+ setMilestoneName("");
2386
+ setMilestoneDue("");
2387
+ setShowMilestoneForm(false);
2388
+ } catch {
2389
+ setMilestoneError(L.failedToCreateMilestone);
2390
+ }
2391
+ };
2054
2392
  const { data, loading, error } = useQuery(
2055
2393
  LIST_WORK_ITEMS,
2056
2394
  {
@@ -2133,7 +2471,7 @@ function TaskTimelineCore({
2133
2471
  error.message
2134
2472
  ] });
2135
2473
  }
2136
- const rangeLabel = mode === "week" ? `${format(rangeStart, "MMM d")} \u2013 ${format(rangeEnd, "MMM d")}` : format(anchor, "MMMM yyyy");
2474
+ const rangeLabel = mode === "week" ? `${format(rangeStart, "MMM d", { locale: dfLocale })} \u2013 ${format(rangeEnd, "MMM d", { locale: dfLocale })}` : format(anchor, "MMMM yyyy", { locale: dfLocale });
2137
2475
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
2138
2476
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
2139
2477
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
@@ -2198,12 +2536,82 @@ function TaskTimelineCore({
2198
2536
  t.id
2199
2537
  )) })
2200
2538
  ] }),
2201
- milestones.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2", children: [
2202
- /* @__PURE__ */ jsxs("p", { className: "mb-1 flex items-center gap-1 text-xs font-semibold text-primary", children: [
2203
- /* @__PURE__ */ jsx(Flag, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2204
- L.milestones
2539
+ (milestones.length > 0 || canAddMilestone) && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2", children: [
2540
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [
2541
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1 text-xs font-semibold text-primary", children: [
2542
+ /* @__PURE__ */ jsx(Flag, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2543
+ L.milestones
2544
+ ] }),
2545
+ canAddMilestone && /* @__PURE__ */ jsx(
2546
+ "button",
2547
+ {
2548
+ type: "button",
2549
+ onClick: () => {
2550
+ setShowMilestoneForm((v) => !v);
2551
+ setMilestoneError(null);
2552
+ },
2553
+ "aria-label": L.addMilestone,
2554
+ "aria-expanded": showMilestoneForm,
2555
+ title: L.addMilestone,
2556
+ className: "flex h-6 w-6 items-center justify-center rounded-md border border-primary/40 text-primary hover:bg-primary/10",
2557
+ children: /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
2558
+ }
2559
+ )
2205
2560
  ] }),
2206
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: milestones.map((m) => /* @__PURE__ */ jsx(MilestoneFlag, { milestone: m }, m.id)) })
2561
+ showMilestoneForm && canAddMilestone && /* @__PURE__ */ jsxs(
2562
+ "form",
2563
+ {
2564
+ onSubmit: submitMilestone,
2565
+ className: "mb-2 flex flex-wrap items-center gap-2",
2566
+ children: [
2567
+ /* @__PURE__ */ jsx(
2568
+ "input",
2569
+ {
2570
+ type: "text",
2571
+ value: milestoneName,
2572
+ onChange: (e) => setMilestoneName(e.target.value),
2573
+ placeholder: L.milestoneNamePlaceholder,
2574
+ "aria-label": L.milestoneNamePlaceholder,
2575
+ autoFocus: true,
2576
+ className: "h-8 min-w-40 flex-1 rounded-md border border-border bg-background px-2 text-xs text-foreground"
2577
+ }
2578
+ ),
2579
+ /* @__PURE__ */ jsx(
2580
+ "input",
2581
+ {
2582
+ type: "date",
2583
+ value: milestoneDue,
2584
+ onChange: (e) => setMilestoneDue(e.target.value),
2585
+ "aria-label": L.dueDateLabel,
2586
+ className: "h-8 rounded-md border border-border bg-background px-2 text-xs text-foreground"
2587
+ }
2588
+ ),
2589
+ /* @__PURE__ */ jsx(
2590
+ "button",
2591
+ {
2592
+ type: "submit",
2593
+ disabled: !milestoneName.trim() || creatingMilestone,
2594
+ className: "h-8 rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50",
2595
+ children: creatingMilestone ? L.creating : L.addMilestone
2596
+ }
2597
+ ),
2598
+ /* @__PURE__ */ jsx(
2599
+ "button",
2600
+ {
2601
+ type: "button",
2602
+ onClick: () => {
2603
+ setShowMilestoneForm(false);
2604
+ setMilestoneError(null);
2605
+ },
2606
+ className: "h-8 rounded-md border border-border px-3 text-xs font-medium text-foreground hover:bg-muted/50",
2607
+ children: L.cancel
2608
+ }
2609
+ )
2610
+ ]
2611
+ }
2612
+ ),
2613
+ milestoneError && /* @__PURE__ */ jsx("p", { className: "mb-1 text-[11px] text-destructive", children: milestoneError }),
2614
+ milestones.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: milestones.map((m) => /* @__PURE__ */ jsx(MilestoneFlag, { milestone: m }, m.id)) })
2207
2615
  ] }),
2208
2616
  mode === "week" ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: days.map((day) => {
2209
2617
  const items = byDay.get(dayKey(day)) ?? [];
@@ -2225,7 +2633,7 @@ function TaskTimelineCore({
2225
2633
  "text-xs font-semibold uppercase",
2226
2634
  today ? "text-primary" : "text-muted-foreground"
2227
2635
  ),
2228
- children: format(day, "EEE")
2636
+ children: format(day, "EEE", { locale: dfLocale })
2229
2637
  }
2230
2638
  ),
2231
2639
  /* @__PURE__ */ jsx(
@@ -2235,7 +2643,7 @@ function TaskTimelineCore({
2235
2643
  "text-sm font-semibold",
2236
2644
  today ? "text-primary" : "text-foreground"
2237
2645
  ),
2238
- children: format(day, "d")
2646
+ children: format(day, "d", { locale: dfLocale })
2239
2647
  }
2240
2648
  )
2241
2649
  ] }),
@@ -2256,13 +2664,13 @@ function TaskTimelineCore({
2256
2664
  dayKey(day)
2257
2665
  );
2258
2666
  }) }) : /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-7 gap-1", children: [
2259
- ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map((d) => /* @__PURE__ */ jsx(
2667
+ weekdayHeaders.map((d, i) => /* @__PURE__ */ jsx(
2260
2668
  "div",
2261
2669
  {
2262
2670
  className: "px-1 pb-1 text-center text-[10px] font-semibold uppercase text-muted-foreground",
2263
2671
  children: d
2264
2672
  },
2265
- d
2673
+ i
2266
2674
  )),
2267
2675
  days.map((day) => {
2268
2676
  const items = byDay.get(dayKey(day)) ?? [];
@@ -2284,7 +2692,7 @@ function TaskTimelineCore({
2284
2692
  "text-[10px] font-semibold",
2285
2693
  today ? "text-primary" : "text-muted-foreground"
2286
2694
  ),
2287
- children: format(day, "d")
2695
+ children: format(day, "d", { locale: dfLocale })
2288
2696
  }
2289
2697
  ),
2290
2698
  items.slice(0, 3).map((t) => /* @__PURE__ */ jsx(
@@ -2627,6 +3035,7 @@ function CommentComposer({
2627
3035
  ) })
2628
3036
  ] });
2629
3037
  }
3038
+ var REACTION_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F389}", "\u{1F440}"];
2630
3039
  var labelClass2 = "text-xs font-medium uppercase tracking-wide text-muted-foreground";
2631
3040
  var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2632
3041
  function TaskCommentsCore({
@@ -2642,6 +3051,11 @@ function TaskCommentsCore({
2642
3051
  const L = useTaskLabels();
2643
3052
  const [error, setError] = useState(null);
2644
3053
  const [replyingTo, setReplyingTo] = useState(null);
3054
+ const [editingId, setEditingId] = useState(null);
3055
+ const [editText, setEditText] = useState("");
3056
+ const [savingEdit, setSavingEdit] = useState(false);
3057
+ const [pickerOpenId, setPickerOpenId] = useState(null);
3058
+ const [reactingId, setReactingId] = useState(null);
2645
3059
  const { data, loading, refetch } = useQuery(
2646
3060
  GET_ENTITY_COMMENTS,
2647
3061
  {
@@ -2684,6 +3098,13 @@ function TaskCommentsCore({
2684
3098
  const [deleteComment] = useMutation(
2685
3099
  DELETE_ENTITY_COMMENT
2686
3100
  );
3101
+ const [updateComment] = useMutation(
3102
+ UPDATE_ENTITY_COMMENT
3103
+ );
3104
+ const [addReaction] = useMutation(
3105
+ ADD_ENTITY_COMMENT_REACTION
3106
+ );
3107
+ const [removeReaction] = useMutation(REMOVE_ENTITY_COMMENT_REACTION);
2687
3108
  const authorName = (id) => id === currentActorId ? L.you : resolveAssignee?.(id)?.name ?? void 0;
2688
3109
  const post = async ({ text, mentionUserIds }, parentCommentId) => {
2689
3110
  setError(null);
@@ -2724,6 +3145,57 @@ function TaskCommentsCore({
2724
3145
  setError(L.failedToDeleteComment);
2725
3146
  }
2726
3147
  };
3148
+ const startEdit = (c) => {
3149
+ setError(null);
3150
+ setEditingId(c.id);
3151
+ setEditText(c.content?.text ?? "");
3152
+ };
3153
+ const cancelEdit = () => {
3154
+ setEditingId(null);
3155
+ setEditText("");
3156
+ };
3157
+ const saveEdit = async (id) => {
3158
+ const text = editText.trim();
3159
+ if (!text || savingEdit) return;
3160
+ setError(null);
3161
+ setSavingEdit(true);
3162
+ try {
3163
+ await updateComment({
3164
+ variables: { input: { id, content: { text }, contentType: "TEXT" } }
3165
+ });
3166
+ await refetch();
3167
+ setEditingId(null);
3168
+ setEditText("");
3169
+ } catch {
3170
+ setError(L.failedToEditComment);
3171
+ } finally {
3172
+ setSavingEdit(false);
3173
+ }
3174
+ };
3175
+ const hasReacted = (c, emoji) => {
3176
+ if (!currentActorId) return false;
3177
+ const row = (c.reactionSummary ?? []).find((r) => r.emoji === emoji);
3178
+ return !!row?.userIds.includes(currentActorId);
3179
+ };
3180
+ const toggleReaction = async (c, emoji) => {
3181
+ if (!currentActorId || reactingId === c.id) return;
3182
+ setError(null);
3183
+ setPickerOpenId(null);
3184
+ setReactingId(c.id);
3185
+ const input = { commentId: c.id, emoji, userId: currentActorId };
3186
+ try {
3187
+ if (hasReacted(c, emoji)) {
3188
+ await removeReaction({ variables: { input } });
3189
+ } else {
3190
+ await addReaction({ variables: { input } });
3191
+ }
3192
+ await refetch();
3193
+ } catch {
3194
+ setError(L.failedToReact);
3195
+ } finally {
3196
+ setReactingId(null);
3197
+ }
3198
+ };
2727
3199
  const renderBody = (c) => {
2728
3200
  const text = c.content?.text ?? "";
2729
3201
  const names = (members ?? []).map((m) => m.name).filter((n) => text.includes(`@${n}`));
@@ -2741,37 +3213,150 @@ function TaskCommentsCore({
2741
3213
  ) : /* @__PURE__ */ jsx("span", { children: part }, i)
2742
3214
  );
2743
3215
  };
2744
- const commentBlock = (c, isReply) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2745
- /* @__PURE__ */ jsx(Avatar, { id: c.authorId, name: authorName(c.authorId), size: "sm" }),
2746
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2747
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2748
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: authorName(c.authorId) ?? c.authorId.slice(0, 8) }),
2749
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: formatDateFull(c.createdAt) }),
2750
- c.edited && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: L.editedTag }),
2751
- !readonly && c.authorId === currentActorId && /* @__PURE__ */ jsx(
3216
+ const reactionBar = (c) => {
3217
+ const summary = (c.reactionSummary ?? []).filter((r) => r.count > 0);
3218
+ const canReact = !readonly && !!currentActorId;
3219
+ if (summary.length === 0 && !canReact) return null;
3220
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
3221
+ summary.map((r) => {
3222
+ const mine = hasReacted(c, r.emoji);
3223
+ return /* @__PURE__ */ jsxs(
2752
3224
  "button",
2753
3225
  {
2754
3226
  type: "button",
2755
- onClick: () => handleDelete(c.id),
2756
- "aria-label": L.del,
2757
- title: L.del,
2758
- className: "ml-auto rounded p-1 text-muted-foreground hover:text-destructive",
2759
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
3227
+ disabled: !canReact || reactingId === c.id,
3228
+ onClick: () => toggleReaction(c, r.emoji),
3229
+ "aria-label": `${r.emoji} ${r.count}`,
3230
+ "aria-pressed": mine,
3231
+ className: cn(
3232
+ "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-xs",
3233
+ mine ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground",
3234
+ canReact ? "hover:border-primary" : "cursor-default"
3235
+ ),
3236
+ children: [
3237
+ /* @__PURE__ */ jsx("span", { children: r.emoji }),
3238
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: r.count })
3239
+ ]
3240
+ },
3241
+ r.emoji
3242
+ );
3243
+ }),
3244
+ canReact && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3245
+ /* @__PURE__ */ jsx(
3246
+ "button",
3247
+ {
3248
+ type: "button",
3249
+ onClick: () => setPickerOpenId((prev) => prev === c.id ? null : c.id),
3250
+ "aria-label": L.addReaction,
3251
+ "aria-expanded": pickerOpenId === c.id,
3252
+ title: L.addReaction,
3253
+ className: "inline-flex items-center rounded-full border border-border p-1 text-muted-foreground hover:border-primary hover:text-primary",
3254
+ children: /* @__PURE__ */ jsx(SmilePlus, { className: "h-3.5 w-3.5" })
3255
+ }
3256
+ ),
3257
+ pickerOpenId === c.id && /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-full z-20 mt-1 flex gap-1 rounded-md border border-border bg-popover p-1 shadow-md", children: REACTION_EMOJIS.map((emoji) => /* @__PURE__ */ jsx(
3258
+ "button",
3259
+ {
3260
+ type: "button",
3261
+ disabled: reactingId === c.id,
3262
+ onClick: () => toggleReaction(c, emoji),
3263
+ "aria-label": emoji,
3264
+ className: cn(
3265
+ "rounded px-1 py-0.5 text-sm hover:bg-muted",
3266
+ hasReacted(c, emoji) && "bg-primary/10"
3267
+ ),
3268
+ children: emoji
3269
+ },
3270
+ emoji
3271
+ )) })
3272
+ ] })
3273
+ ] });
3274
+ };
3275
+ const commentBlock = (c, isReply) => {
3276
+ const isMine = c.authorId === currentActorId;
3277
+ const isEditing = editingId === c.id;
3278
+ return /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3279
+ /* @__PURE__ */ jsx(Avatar, { id: c.authorId, name: authorName(c.authorId), size: "sm" }),
3280
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3281
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3282
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: authorName(c.authorId) ?? c.authorId.slice(0, 8) }),
3283
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: formatDateFull(c.createdAt) }),
3284
+ c.edited && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: L.editedTag }),
3285
+ !readonly && isMine && !isEditing && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
3286
+ /* @__PURE__ */ jsx(
3287
+ "button",
3288
+ {
3289
+ type: "button",
3290
+ onClick: () => startEdit(c),
3291
+ "aria-label": L.editComment,
3292
+ title: L.editComment,
3293
+ className: "rounded p-1 text-muted-foreground hover:text-foreground",
3294
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
3295
+ }
3296
+ ),
3297
+ /* @__PURE__ */ jsx(
3298
+ "button",
3299
+ {
3300
+ type: "button",
3301
+ onClick: () => handleDelete(c.id),
3302
+ "aria-label": L.del,
3303
+ title: L.del,
3304
+ className: "rounded p-1 text-muted-foreground hover:text-destructive",
3305
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
3306
+ }
3307
+ )
3308
+ ] })
3309
+ ] }),
3310
+ isEditing ? /* @__PURE__ */ jsxs("div", { className: "mt-1 space-y-2", children: [
3311
+ /* @__PURE__ */ jsx(
3312
+ "textarea",
3313
+ {
3314
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring",
3315
+ rows: 2,
3316
+ value: editText,
3317
+ autoFocus: true,
3318
+ "aria-label": L.editComment,
3319
+ onChange: (e) => setEditText(e.target.value)
3320
+ }
3321
+ ),
3322
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
3323
+ /* @__PURE__ */ jsx(
3324
+ "button",
3325
+ {
3326
+ type: "button",
3327
+ onClick: cancelEdit,
3328
+ className: "rounded-md px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground",
3329
+ children: L.cancel
3330
+ }
3331
+ ),
3332
+ /* @__PURE__ */ jsx(
3333
+ "button",
3334
+ {
3335
+ type: "button",
3336
+ onClick: () => saveEdit(c.id),
3337
+ disabled: savingEdit || !editText.trim(),
3338
+ className: cn(
3339
+ "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground",
3340
+ (savingEdit || !editText.trim()) && "cursor-not-allowed opacity-50"
3341
+ ),
3342
+ children: savingEdit ? L.saving : L.saveComment
3343
+ }
3344
+ )
3345
+ ] })
3346
+ ] }) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words text-sm text-foreground", children: renderBody(c) }),
3347
+ !isEditing && reactionBar(c),
3348
+ !isReply && !readonly && !isEditing && /* @__PURE__ */ jsx(
3349
+ "button",
3350
+ {
3351
+ type: "button",
3352
+ onClick: () => setReplyingTo((prev) => prev === c.id ? null : c.id),
3353
+ className: "mt-1 text-xs font-medium text-muted-foreground hover:text-foreground",
3354
+ children: L.reply
2760
3355
  }
2761
3356
  )
2762
- ] }),
2763
- /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words text-sm text-foreground", children: renderBody(c) }),
2764
- !isReply && !readonly && /* @__PURE__ */ jsx(
2765
- "button",
2766
- {
2767
- type: "button",
2768
- onClick: () => setReplyingTo((prev) => prev === c.id ? null : c.id),
2769
- className: "mt-1 text-xs font-medium text-muted-foreground hover:text-foreground",
2770
- children: L.reply
2771
- }
2772
- )
2773
- ] })
2774
- ] });
3357
+ ] })
3358
+ ] });
3359
+ };
2775
3360
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
2776
3361
  /* @__PURE__ */ jsxs("div", { className: labelClass2, children: [
2777
3362
  L.commentsLabel,
@@ -3342,6 +3927,8 @@ function TasksPageCore({
3342
3927
  boardProjectId,
3343
3928
  columns,
3344
3929
  readonly,
3930
+ canCreateMilestone,
3931
+ locale,
3345
3932
  hiddenFields,
3346
3933
  views,
3347
3934
  defaultView = "board",
@@ -3522,6 +4109,8 @@ function TasksPageCore({
3522
4109
  search: search || void 0,
3523
4110
  assigneeId: mineAssignee,
3524
4111
  hideHeader: true,
4112
+ selectable: !readonly,
4113
+ assigneeOptions,
3525
4114
  resolveAssignee,
3526
4115
  linkSourceProduct,
3527
4116
  renderLinkIcon,
@@ -3539,7 +4128,10 @@ function TasksPageCore({
3539
4128
  search,
3540
4129
  assigneeId: mineAssignee,
3541
4130
  resolveAssignee,
3542
- onSelect: handleSelect
4131
+ onSelect: handleSelect,
4132
+ canCreateMilestone: canCreateMilestone ?? !readonly,
4133
+ milestoneProjectId: boardProjectId ?? projectId,
4134
+ locale
3543
4135
  }
3544
4136
  ),
3545
4137
  showInlineDetail && /* @__PURE__ */ jsx("div", { className: "pb-6", children: detailView }),
@@ -3593,6 +4185,6 @@ function TasksPage({
3593
4185
  );
3594
4186
  }
3595
4187
 
3596
- 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, TaskCommentsCore, 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 };
4188
+ export { Avatar, BULK_UPDATE_WORK_ITEMS, 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, TaskCommentsCore, 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 };
3597
4189
  //# sourceMappingURL=index.js.map
3598
4190
  //# sourceMappingURL=index.js.map