@dxos/react-ui-task 0.13.0 → 0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a

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.
@@ -7,8 +7,10 @@ import { Person, PullRequest, RemoteSession, Task } from "@dxos/types";
7
7
  import { getHashHue, getStyles, mx, toHue } from "@dxos/ui-theme";
8
8
  import { translationKey } from "#translations";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ import { useAtomValue } from "@effect/atom-react/Hooks";
11
+ import * as Atom from "effect/reactivity/Atom";
10
12
  import { Filter, Obj, Ref, Tag } from "@dxos/echo";
11
- import { useObject, useQuery } from "@dxos/echo-react";
13
+ import { useLabel, useObject, useQuery } from "@dxos/echo-react";
12
14
  import { Tree, createStaticTreeModel } from "@dxos/react-ui-list";
13
15
  import { ActionMenu, createMenuAction, executeMenuAction, fallbackIcon } from "@dxos/react-ui-menu";
14
16
  import * as Button from "@dxos/react-ui/Button";
@@ -391,10 +393,13 @@ var [TaskListProvider, useTaskListContext] = Hooks.createContext("TaskList.Root"
391
393
  //#endregion
392
394
  //#region src/components/TaskList/TaskRowCells.tsx
393
395
  /** The status glyph, which is also the control that completes the task. */
396
+ var useAgentWorking = (task) => useAtomValue(useMemo(() => Atom.make((get) => Task.isAgentWorking(get(Obj.atom(task)))), [task]));
394
397
  var TaskStatusControl = ({ task, onTaskUpdate, active, classNames }) => {
395
398
  const { t } = Hooks.useTranslation(translationKey);
396
- const status = task.status ?? "todo";
397
- const { icon, classNames: iconClassNames } = active ?? Task.isAgentWorking(task) ? {
399
+ const [storedStatus] = useObject(task, "status");
400
+ const status = storedStatus ?? "todo";
401
+ const agentWorking = useAgentWorking(task);
402
+ const { icon, classNames: iconClassNames } = active ?? agentWorking ? {
398
403
  icon: "ph--spinner--regular",
399
404
  classNames: "text-info-text animate-spin"
400
405
  } : {
@@ -517,8 +522,9 @@ TaskCheckbox.displayName = "TaskList.Checkbox";
517
522
  */
518
523
  var TaskEstimateControl = ({ task, classNames }) => {
519
524
  const { onTaskUpdate } = useTaskListContext("TaskList.EstimateControl");
525
+ const [estimate] = useObject(task, "estimate");
520
526
  return /* @__PURE__ */ jsx(TaskEstimatePicker, {
521
- estimate: task.estimate,
527
+ estimate,
522
528
  onChange: onTaskUpdate && ((estimate) => onTaskUpdate(task, { estimate: estimate ?? null })),
523
529
  testId: "taskList.item.estimate",
524
530
  classNames
@@ -564,8 +570,9 @@ TaskEstimateControl.displayName = "TaskList.EstimateControl";
564
570
  */
565
571
  var TaskPriorityIcon = ({ task, classNames }) => {
566
572
  const { onTaskUpdate } = useTaskListContext("TaskList.PriorityIcon");
573
+ const [priority] = useObject(task, "priority");
567
574
  return /* @__PURE__ */ jsx(TaskPriorityPicker, {
568
- priority: task.priority ?? void 0,
575
+ priority: priority ?? void 0,
569
576
  onChange: onTaskUpdate && ((priority) => onTaskUpdate(task, { priority: priority ?? null })),
570
577
  testId: "taskList.item.priority",
571
578
  classNames
@@ -1668,12 +1675,10 @@ var TaskListItem = ({ node, indicator, ordinal, checked, translationKey: itemTra
1668
1675
  }),
1669
1676
  /* @__PURE__ */ jsx(Layout.Flex, {
1670
1677
  align: "center",
1671
- classNames: "col-[title] row-start-2 empty:hidden",
1678
+ gap: "xs",
1679
+ classNames: "col-[title] row-start-2 px-(--dx-gap-size) empty:hidden",
1672
1680
  "data-testid": "taskList.item.chips",
1673
- children: /* @__PURE__ */ jsx(TaskListItemTags, {
1674
- task,
1675
- tags: Obj.getMeta(task).tags
1676
- })
1681
+ children: /* @__PURE__ */ jsx(TaskListItemTags, { task })
1677
1682
  }),
1678
1683
  description && /* @__PURE__ */ jsx(TaskDescription, {
1679
1684
  content: description,
@@ -1730,12 +1735,13 @@ TaskListItemActions.displayName = "TaskList.ItemActions";
1730
1735
  */
1731
1736
  var TaskListItemArtifacts = ({ task, filter }) => {
1732
1737
  const db = Obj.getDatabase(task);
1733
- const ids = useMemo(() => (task.artifacts ?? []).flatMap((ref) => {
1738
+ const [refs] = useObject(task, "artifacts");
1739
+ const ids = useMemo(() => (refs ?? []).flatMap((ref) => {
1734
1740
  const id = Task.refEntityId(ref);
1735
1741
  return id ? [id] : [];
1736
- }), [task.artifacts]);
1742
+ }), [refs]);
1737
1743
  const queried = useQuery(ids.length > 0 ? db : void 0, Filter.id(...ids));
1738
- const resolved = db ? queried : (task.artifacts ?? []).flatMap((ref) => ref.target ? [ref.target] : []);
1744
+ const resolved = db ? queried : (refs ?? []).flatMap((ref) => ref.target ? [ref.target] : []);
1739
1745
  const artifacts = filter ? resolved.filter(filter) : resolved;
1740
1746
  return /* @__PURE__ */ jsx(Fragment, { children: artifacts.map((artifact) => /* @__PURE__ */ jsx(ArtifactTag, { artifact }, artifact.id)) });
1741
1747
  };
@@ -1744,10 +1750,7 @@ TaskListItemArtifacts.displayName = "TaskList.ItemArtifacts";
1744
1750
  * Everything a task carries as a chip: its tags, what it produced, and who has it.
1745
1751
  */
1746
1752
  var TaskTags = ({ task }) => {
1747
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TaskListItemTags, {
1748
- task,
1749
- tags: Obj.getMeta(task).tags
1750
- }), /* @__PURE__ */ jsx(TaskListItemArtifacts, {
1753
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TaskListItemTags, { task }), /* @__PURE__ */ jsx(TaskListItemArtifacts, {
1751
1754
  task,
1752
1755
  filter: (artifact) => PullRequest.instanceOf(artifact)
1753
1756
  })] });
@@ -1757,15 +1760,21 @@ TaskTags.displayName = "TaskList.Tags";
1757
1760
  * The task's tags, as chips in the same cell as its artifacts and assignee. Queried by id for the
1758
1761
  * reason artifacts are: a tag's target is not in memory on a cold load.
1759
1762
  */
1760
- var TaskListItemTags = ({ task, tags }) => {
1763
+ var TaskListItemTags = ({ task }) => {
1761
1764
  const db = Obj.getDatabase(task);
1765
+ const tags = useAtomValue(Obj.tagsAtom(task));
1762
1766
  const ids = useMemo(() => tags.flatMap((ref) => {
1763
1767
  const id = Task.refEntityId(ref);
1764
1768
  return id ? [id] : [];
1765
1769
  }), [tags]);
1766
1770
  const queried = useQuery(ids.length > 0 ? db : void 0, Filter.id(...ids));
1767
- const resolved = db ? queried : tags.flatMap((ref) => ref.target ? [ref.target] : []);
1768
- const labelled = useMemo(() => resolved.filter((object) => Obj.instanceOf(Tag.Tag, object)).sort(Tag.sortTags), [resolved]);
1771
+ const resolved = useMemo(() => db ? queried : tags.flatMap((ref) => ref.target ? [ref.target] : []), [
1772
+ db,
1773
+ queried,
1774
+ tags
1775
+ ]);
1776
+ const labelledAtom = useMemo(() => Atom.make((get) => resolved.filter((object) => Obj.instanceOf(Tag.Tag, object)).map((tag) => get(Obj.atom(tag))).sort(Tag.sortTags)), [resolved]);
1777
+ const labelled = useAtomValue(labelledAtom);
1769
1778
  return /* @__PURE__ */ jsx(Fragment, { children: labelled.map((tag) => /* @__PURE__ */ jsx(Tag$1.Tag, {
1770
1779
  hue: toHue(tag.hue),
1771
1780
  "data-testid": "taskList.item.tag",
@@ -1782,20 +1791,14 @@ TaskListItemTags.displayName = "TaskList.ItemTags";
1782
1791
  * markdown — so a row reads the same as the text that references it.
1783
1792
  */
1784
1793
  var ArtifactTag = ({ artifact }) => {
1785
- const label = Obj.getLabel(artifact) ?? Obj.getTypename(artifact) ?? "";
1794
+ const label = useLabel(artifact, { fallback: "typename" }) ?? "";
1786
1795
  const anchor = usePreviewAnchor({
1787
1796
  eid: Obj.getURI(artifact).toString(),
1788
1797
  label
1789
1798
  });
1790
- if (PullRequest.instanceOf(artifact)) return /* @__PURE__ */ jsx(Button.Root, {
1791
- ...anchor,
1792
- hue: "neutral",
1793
- size: "sm",
1794
- classNames: "bg-input-surface text-fg font-normal ring-inset ring ring-neutral-border hover:bg-hover-surface hover:ring-info-border",
1795
- icon: "ph--git-pull-request--regular",
1796
- iconClassNames: pullRequestStateStyle[artifact.state],
1797
- label: `#${artifact.number}`,
1798
- tabIndex: -1
1799
+ if (Obj.instanceOf(PullRequest.PullRequest, artifact)) return /* @__PURE__ */ jsx(PullRequestTag, {
1800
+ pullRequest: artifact,
1801
+ anchor
1799
1802
  });
1800
1803
  return /* @__PURE__ */ jsx(Tag$1.Tag, {
1801
1804
  ...anchor,
@@ -1805,6 +1808,21 @@ var ArtifactTag = ({ artifact }) => {
1805
1808
  });
1806
1809
  };
1807
1810
  ArtifactTag.displayName = "TaskList.ArtifactTag";
1811
+ var PullRequestTag = ({ pullRequest, anchor }) => {
1812
+ const [state] = useObject(pullRequest, "state");
1813
+ const [number] = useObject(pullRequest, "number");
1814
+ return /* @__PURE__ */ jsx(Button.Root, {
1815
+ ...anchor,
1816
+ hue: "neutral",
1817
+ size: "sm",
1818
+ classNames: "bg-input-surface text-fg font-normal ring-inset ring ring-neutral-border hover:bg-hover-surface hover:ring-info-border",
1819
+ icon: "ph--git-pull-request--regular",
1820
+ iconClassNames: pullRequestStateStyle[state],
1821
+ label: `#${number}`,
1822
+ tabIndex: -1
1823
+ });
1824
+ };
1825
+ PullRequestTag.displayName = "TaskList.PullRequestTag";
1808
1826
  /** GitHub's own state colours, so the icon reads as open, merged or closed at a glance. */
1809
1827
  var pullRequestStateStyle = {
1810
1828
  open: "text-green-500",
@@ -1870,10 +1888,14 @@ var ESTIMATE_ICON = "ph--ruler--regular";
1870
1888
  */
1871
1889
  var TaskProperties = ({ task, members = [], onTaskUpdate, classNames }) => {
1872
1890
  const { t } = Hooks.useTranslation(translationKey);
1873
- const status = task.status ?? "todo";
1874
- const priority = task.priority ?? void 0;
1875
- const estimate = task.estimate ?? void 0;
1876
- const assignee = task.assignee ?? void 0;
1891
+ const [storedStatus] = useObject(task, "status");
1892
+ const [storedPriority] = useObject(task, "priority");
1893
+ const [storedEstimate] = useObject(task, "estimate");
1894
+ const [storedAssignee] = useObject(task, "assignee");
1895
+ const status = storedStatus ?? "todo";
1896
+ const priority = storedPriority ?? void 0;
1897
+ const estimate = storedEstimate ?? void 0;
1898
+ const assignee = storedAssignee ?? void 0;
1877
1899
  const db = Obj.getDatabase(task);
1878
1900
  const people = useQuery(onTaskUpdate ? db : void 0, Filter.type(Person.Person));
1879
1901
  const { label: assigneeLabel, icon: assigneeIcon } = useAssigneeDisplay(assignee);