@gaia-ai/addon-gaia-ui 0.16.0 → 0.16.2

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.
Files changed (220) hide show
  1. package/dist/src/Component/badge/index.d.ts +11 -0
  2. package/dist/src/Component/badge/index.js +10 -0
  3. package/dist/src/Component/bar-chart/index.d.ts +16 -0
  4. package/dist/src/Component/bar-chart/index.js +63 -0
  5. package/dist/src/Component/card/index.d.ts +16 -0
  6. package/dist/src/Component/card/index.js +39 -0
  7. package/dist/src/Component/divider/index.d.ts +7 -0
  8. package/dist/src/Component/divider/index.js +13 -0
  9. package/dist/src/Component/heat-map/index.d.ts +21 -0
  10. package/dist/src/Component/heat-map/index.js +86 -0
  11. package/dist/src/Component/key-value/index.d.ts +18 -0
  12. package/dist/src/Component/key-value/index.js +30 -0
  13. package/dist/src/Component/markdown/index.d.ts +35 -5
  14. package/dist/src/Component/markdown/index.js +72 -16
  15. package/dist/src/Entity/team/Data/workload.d.ts +3 -1
  16. package/dist/src/Entity/team/Data/workload.js +6 -4
  17. package/dist/src/Entity/team/Screen/team-work.d.ts +12 -1
  18. package/dist/src/Entity/team/Screen/team-work.js +47 -2
  19. package/dist/src/Entity/ticket/Component/demo-statistics.d.ts +14 -0
  20. package/dist/src/Entity/ticket/Component/demo-statistics.js +88 -0
  21. package/dist/src/Entity/ticket/Component/react-statistics.d.ts +14 -22
  22. package/dist/src/Entity/ticket/Component/react-statistics.js +21 -42
  23. package/dist/src/Entity/ticket/Component/ticket-content/index.d.ts +28 -3
  24. package/dist/src/Entity/ticket/Component/ticket-content/index.js +331 -157
  25. package/dist/src/Entity/ticket/Data/parents.js +1 -1
  26. package/dist/src/Entity/ticket/Data/query.d.ts +2 -2
  27. package/dist/src/Entity/ticket/Data/query.js +13 -9
  28. package/dist/src/Entity/ticket/Data/store.js +1 -1
  29. package/dist/src/Entity/ticket/Data/tickets.d.ts +1 -1
  30. package/dist/src/Entity/ticket/Data/tickets.js +1 -1
  31. package/dist/src/Entity/ticket/Form/edit.d.ts +13 -0
  32. package/dist/src/Entity/ticket/Form/edit.js +17 -7
  33. package/dist/src/Entity/ticket/Screen/conductor-tickets.d.ts +7 -1
  34. package/dist/src/Entity/ticket/Screen/conductor-tickets.js +30 -6
  35. package/dist/src/Entity/ticket/Screen/edit-assignment-form.d.ts +3 -1
  36. package/dist/src/Entity/ticket/Screen/edit-assignment-form.js +21 -6
  37. package/dist/src/Entity/ticket/Screen/my-work.d.ts +8 -1
  38. package/dist/src/Entity/ticket/Screen/my-work.js +37 -4
  39. package/dist/src/Entity/ticket/Screen/ticket-comments.d.ts +6 -12
  40. package/dist/src/Entity/ticket/Screen/ticket-comments.js +11 -16
  41. package/dist/src/Entity/ticket/Screen/ticket-content-screen.d.ts +25 -44
  42. package/dist/src/Entity/ticket/Screen/ticket-content-screen.js +79 -87
  43. package/dist/src/Entity/ticket/Screen/ticket-detail.d.ts +6 -11
  44. package/dist/src/Entity/ticket/Screen/ticket-detail.js +14 -19
  45. package/dist/src/Entity/ticket/Screen/ticket-filter-bar.js +2 -9
  46. package/dist/src/Entity/ticket/Screen/ticket-planning.d.ts +6 -12
  47. package/dist/src/Entity/ticket/Screen/ticket-planning.js +11 -16
  48. package/dist/src/Entity/ticket/Screen/ticket-react-markdown.d.ts +9 -7
  49. package/dist/src/Entity/ticket/Screen/ticket-react-markdown.js +36 -13
  50. package/dist/src/Entity/ticket/Screen/ticket-react.d.ts +21 -8
  51. package/dist/src/Entity/ticket/Screen/ticket-react.js +109 -34
  52. package/dist/src/Entity/ticket/Screen/ticket-search.d.ts +44 -0
  53. package/dist/src/Entity/ticket/Screen/ticket-search.js +97 -0
  54. package/dist/src/Entity/ticket/Screen/tickets.d.ts +9 -7
  55. package/dist/src/Entity/ticket/Screen/tickets.js +25 -85
  56. package/dist/src/Entity/ticket/Screen/user-tickets.d.ts +7 -0
  57. package/dist/src/Entity/ticket/Screen/user-tickets.js +30 -2
  58. package/dist/src/Kernel/renderer.d.ts +1 -3
  59. package/dist/src/Kernel/renderer.js +2 -5
  60. package/dist/src/Kernel/tui-kernel.js +7 -16
  61. package/dist/src/Screen/async-screen.d.ts +13 -0
  62. package/dist/src/Screen/async-screen.js +34 -5
  63. package/dist/src/Screen/list-screen.d.ts +11 -2
  64. package/dist/src/Screen/list-screen.js +20 -2
  65. package/dist/src/Screen/screen.d.ts +6 -2
  66. package/dist/src/Statistics/comparison-chart.d.ts +4 -2
  67. package/dist/src/Statistics/comparison-chart.js +14 -6
  68. package/dist/src/Statistics/figures.d.ts +17 -3
  69. package/dist/src/Statistics/figures.js +104 -41
  70. package/dist/src/Statistics/presentation.d.ts +3 -5
  71. package/dist/src/Statistics/presentation.js +3 -5
  72. package/dist/src/Statistics/screen.d.ts +16 -5
  73. package/dist/src/Statistics/screen.js +59 -26
  74. package/dist/src/lib/theme.d.ts +0 -56
  75. package/dist/src/lib/theme.js +0 -42
  76. package/dist/src/lib/vnode.d.ts +29 -0
  77. package/dist/src/lib/vnode.js +69 -0
  78. package/dist/src/route.js +37 -0
  79. package/dist/src/types.d.ts +5 -1
  80. package/dist/src/ui.d.ts +0 -1
  81. package/dist/src/ui.js +0 -1
  82. package/package.json +2 -2
  83. package/dist/src/Agent/Component/agent-list/index.d.ts +0 -6
  84. package/dist/src/Agent/Component/agent-list/index.js +0 -14
  85. package/dist/src/Component/agent-list/index.d.ts +0 -6
  86. package/dist/src/Component/agent-list/index.js +0 -14
  87. package/dist/src/Component/comment-item/index.d.ts +0 -21
  88. package/dist/src/Component/comment-item/index.js +0 -39
  89. package/dist/src/Component/create-form/index.d.ts +0 -3
  90. package/dist/src/Component/create-form/index.js +0 -26
  91. package/dist/src/Component/dashboard-list/index.d.ts +0 -8
  92. package/dist/src/Component/dashboard-list/index.js +0 -7
  93. package/dist/src/Component/project-picker/index.d.ts +0 -15
  94. package/dist/src/Component/project-picker/index.js +0 -42
  95. package/dist/src/Component/run-table/index.d.ts +0 -10
  96. package/dist/src/Component/run-table/index.js +0 -20
  97. package/dist/src/Component/tab-bar/index.d.ts +0 -20
  98. package/dist/src/Component/tab-bar/index.js +0 -42
  99. package/dist/src/Component/ticket-detail/index.d.ts +0 -38
  100. package/dist/src/Component/ticket-detail/index.js +0 -193
  101. package/dist/src/Component/ticket-table/index.d.ts +0 -5
  102. package/dist/src/Component/ticket-table/index.js +0 -14
  103. package/dist/src/Component/ticket-teaser/index.d.ts +0 -7
  104. package/dist/src/Component/ticket-teaser/index.js +0 -76
  105. package/dist/src/Deriver/liveness.d.ts +0 -12
  106. package/dist/src/Deriver/liveness.js +0 -34
  107. package/dist/src/Deriver/run-status.d.ts +0 -12
  108. package/dist/src/Deriver/run-status.js +0 -36
  109. package/dist/src/Entity/conductor/Component/conductor-list/index.d.ts +0 -25
  110. package/dist/src/Entity/conductor/Component/conductor-list/index.js +0 -60
  111. package/dist/src/Entity/project/Component/dashboard-list/index.d.ts +0 -8
  112. package/dist/src/Entity/project/Component/dashboard-list/index.js +0 -7
  113. package/dist/src/Entity/project/Component/project-list/index.d.ts +0 -8
  114. package/dist/src/Entity/project/Component/project-list/index.js +0 -7
  115. package/dist/src/Entity/project/Component/project-picker/index.d.ts +0 -15
  116. package/dist/src/Entity/project/Component/project-picker/index.js +0 -42
  117. package/dist/src/Entity/project/Screen/project-work.d.ts +0 -33
  118. package/dist/src/Entity/project/Screen/project-work.js +0 -114
  119. package/dist/src/Entity/run/Component/run-table/index.d.ts +0 -8
  120. package/dist/src/Entity/run/Component/run-table/index.js +0 -11
  121. package/dist/src/Entity/statistics/Data/statistics.d.ts +0 -147
  122. package/dist/src/Entity/statistics/Data/statistics.js +0 -235
  123. package/dist/src/Entity/statistics/Screen/dashboard.d.ts +0 -70
  124. package/dist/src/Entity/statistics/Screen/dashboard.js +0 -216
  125. package/dist/src/Entity/statistics/render.d.ts +0 -6
  126. package/dist/src/Entity/statistics/render.js +0 -71
  127. package/dist/src/Entity/ticket/Component/tab-bar/index.d.ts +0 -20
  128. package/dist/src/Entity/ticket/Component/tab-bar/index.js +0 -71
  129. package/dist/src/Entity/ticket/Component/ticket-table/index.d.ts +0 -7
  130. package/dist/src/Entity/ticket/Component/ticket-table/index.js +0 -10
  131. package/dist/src/Entity/user/Screen/user-overview.d.ts +0 -33
  132. package/dist/src/Entity/user/Screen/user-overview.js +0 -80
  133. package/dist/src/Extension/contract.d.ts +0 -204
  134. package/dist/src/Extension/contract.js +0 -1
  135. package/dist/src/Kernel/react-body.d.ts +0 -9
  136. package/dist/src/Kernel/react-body.js +0 -42
  137. package/dist/src/Screen/async-react-screen.d.ts +0 -45
  138. package/dist/src/Screen/async-react-screen.js +0 -120
  139. package/dist/src/Screen/dashboard.d.ts +0 -1
  140. package/dist/src/Screen/dashboard.js +0 -1
  141. package/dist/src/Screen/project.d.ts +0 -1
  142. package/dist/src/Screen/project.js +0 -1
  143. package/dist/src/Screen/projects.d.ts +0 -1
  144. package/dist/src/Screen/projects.js +0 -1
  145. package/dist/src/Screen/react-screen.d.ts +0 -14
  146. package/dist/src/Screen/react-screen.js +0 -34
  147. package/dist/src/Screen/ticket.d.ts +0 -1
  148. package/dist/src/Screen/ticket.js +0 -1
  149. package/dist/src/Service/agent.d.ts +0 -17
  150. package/dist/src/Service/agent.js +0 -28
  151. package/dist/src/Service/create-form-data.d.ts +0 -10
  152. package/dist/src/Service/create-form-data.js +0 -52
  153. package/dist/src/Service/create-form.d.ts +0 -52
  154. package/dist/src/Service/create-form.js +0 -98
  155. package/dist/src/Service/project-data.d.ts +0 -48
  156. package/dist/src/Service/project-data.js +0 -92
  157. package/dist/src/Service/projects.d.ts +0 -21
  158. package/dist/src/Service/projects.js +0 -80
  159. package/dist/src/Service/route.d.ts +0 -11
  160. package/dist/src/Service/route.js +0 -215
  161. package/dist/src/Service/run-data.d.ts +0 -35
  162. package/dist/src/Service/run-data.js +0 -62
  163. package/dist/src/Service/ticket-data.d.ts +0 -6
  164. package/dist/src/Service/ticket-data.js +0 -7
  165. package/dist/src/Tui/controller.d.ts +0 -13
  166. package/dist/src/Tui/controller.js +0 -1794
  167. package/dist/src/Vendor/termcn/hooks/use-motion.d.ts +0 -5
  168. package/dist/src/Vendor/termcn/hooks/use-motion.js +0 -7
  169. package/dist/src/Vendor/termcn/hooks/use-theme.d.ts +0 -5
  170. package/dist/src/Vendor/termcn/hooks/use-theme.js +0 -10
  171. package/dist/src/Vendor/termcn/hooks/use-unicode.d.ts +0 -5
  172. package/dist/src/Vendor/termcn/hooks/use-unicode.js +0 -34
  173. package/dist/src/Vendor/termcn/lib/dither-chart-utils.d.ts +0 -130
  174. package/dist/src/Vendor/termcn/lib/dither-chart-utils.js +0 -357
  175. package/dist/src/Vendor/termcn/lib/dither-line-chart-utils.d.ts +0 -2
  176. package/dist/src/Vendor/termcn/lib/dither-line-chart-utils.js +0 -72
  177. package/dist/src/Vendor/termcn/lib/dither-radar-chart-utils.d.ts +0 -2
  178. package/dist/src/Vendor/termcn/lib/dither-radar-chart-utils.js +0 -113
  179. package/dist/src/Vendor/termcn/themes/default.d.ts +0 -1
  180. package/dist/src/Vendor/termcn/themes/default.js +0 -3
  181. package/dist/src/Vendor/termcn/ui/badge.d.ts +0 -13
  182. package/dist/src/Vendor/termcn/ui/badge.js +0 -33
  183. package/dist/src/Vendor/termcn/ui/bar-chart.d.ts +0 -16
  184. package/dist/src/Vendor/termcn/ui/bar-chart.js +0 -61
  185. package/dist/src/Vendor/termcn/ui/card.d.ts +0 -18
  186. package/dist/src/Vendor/termcn/ui/card.js +0 -7
  187. package/dist/src/Vendor/termcn/ui/dither-chart.d.ts +0 -118
  188. package/dist/src/Vendor/termcn/ui/dither-chart.js +0 -418
  189. package/dist/src/Vendor/termcn/ui/dither-line-chart.d.ts +0 -10
  190. package/dist/src/Vendor/termcn/ui/dither-line-chart.js +0 -11
  191. package/dist/src/Vendor/termcn/ui/dither-radar-chart.d.ts +0 -21
  192. package/dist/src/Vendor/termcn/ui/dither-radar-chart.js +0 -11
  193. package/dist/src/Vendor/termcn/ui/divider.d.ts +0 -14
  194. package/dist/src/Vendor/termcn/ui/divider.js +0 -25
  195. package/dist/src/Vendor/termcn/ui/gauge.d.ts +0 -12
  196. package/dist/src/Vendor/termcn/ui/gauge.js +0 -48
  197. package/dist/src/Vendor/termcn/ui/heat-map.d.ts +0 -13
  198. package/dist/src/Vendor/termcn/ui/heat-map.js +0 -59
  199. package/dist/src/Vendor/termcn/ui/key-value.d.ts +0 -16
  200. package/dist/src/Vendor/termcn/ui/key-value.js +0 -24
  201. package/dist/src/Vendor/termcn/ui/line-chart.d.ts +0 -15
  202. package/dist/src/Vendor/termcn/ui/line-chart.js +0 -102
  203. package/dist/src/Vendor/termcn/ui/markdown.d.ts +0 -24
  204. package/dist/src/Vendor/termcn/ui/markdown.js +0 -39
  205. package/dist/src/Vendor/termcn/ui/progress-bar.d.ts +0 -13
  206. package/dist/src/Vendor/termcn/ui/progress-bar.js +0 -13
  207. package/dist/src/Vendor/termcn/ui/sparkline.d.ts +0 -8
  208. package/dist/src/Vendor/termcn/ui/sparkline.js +0 -30
  209. package/dist/src/Vendor/termcn/ui/types.d.ts +0 -82
  210. package/dist/src/Vendor/termcn/ui/types.js +0 -1
  211. package/dist/src/lib/ansi.d.ts +0 -34
  212. package/dist/src/lib/ansi.js +0 -97
  213. package/dist/src/lib/hit-test.d.ts +0 -138
  214. package/dist/src/lib/hit-test.js +0 -138
  215. package/dist/src/lib/mouse.d.ts +0 -35
  216. package/dist/src/lib/mouse.js +0 -89
  217. package/dist/src/lib/table.d.ts +0 -37
  218. package/dist/src/lib/table.js +0 -20
  219. package/dist/src/lib/ticket-query.d.ts +0 -21
  220. package/dist/src/lib/ticket-query.js +0 -72
@@ -1,29 +1,28 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@opentui/react/jsx-runtime";
2
- // biome-ignore-all lint/suspicious/noArrayIndexKey: Painted body rows are identified by their positions in an already-parsed line list.
3
- /* @jsxImportSource @opentui/react */
4
- import { useTerminalDimensions } from '@opentui/react';
5
- import { useEffect, useState } from 'react';
6
- import { markdownLineFromStyled } from '../../../../Component/markdown/index.js';
1
+ import { BoxRenderable, h } from '@opentui/core';
2
+ import { Card } from '../../../../Component/card/index.js';
3
+ import { Divider } from '../../../../Component/divider/index.js';
4
+ import { HeatMap } from '../../../../Component/heat-map/index.js';
5
+ import { KeyValue, } from '../../../../Component/key-value/index.js';
6
+ import { HeadlineMarkdown, MarkdownLines, } from '../../../../Component/markdown/index.js';
7
7
  import { lineText, } from '../../../../Component/section-list/index.js';
8
- import { useTheme } from '../../../../Vendor/termcn/hooks/use-theme.js';
9
- import { Card } from '../../../../Vendor/termcn/ui/card.js';
10
- import { Divider } from '../../../../Vendor/termcn/ui/divider.js';
11
- import { HeatMap } from '../../../../Vendor/termcn/ui/heat-map.js';
12
- import { KeyValue, } from '../../../../Vendor/termcn/ui/key-value.js';
13
- import { HeadlineMarkdown, MarkdownLines, } from '../../../../Vendor/termcn/ui/markdown.js';
8
+ import { BORDER, FOREGROUND, FOREGROUND_ACTIVE, FOREGROUND_HIGHLIGHT, } from '../../../../lib/theme.js';
9
+ import { BOLD, DIM, paragraphNode, plainRun, pressHandler, } from '../../../../lib/vnode.js';
14
10
  import { documentTabLabel, ticketContentRowId, } from './model.js';
15
- const isCells = (line) => typeof line !== 'string' && 'cells' in line;
16
- const isStyled = (line) => typeof line !== 'string' && 'runs' in line;
17
- const TECHNICAL_KEY = 'section:Technical details';
18
- const LINKS_KEY = 'section:Links';
19
- const WIDE_OVERVIEW_COLUMNS = 100;
20
11
  // Links are NOT here: a URL cannot fit the narrow sidebar without wrapping, so
21
- // they render full-width in the left column (see LinksSection) instead.
22
- const SIDEBAR_TABS = [
12
+ // they render full-width in the left column (see linksSection) instead.
13
+ export const SIDEBAR_TABS = [
23
14
  { id: 'details', label: 'Details' },
24
15
  { id: 'stats', label: 'Stats' },
25
16
  { id: 'related', label: 'Related' },
26
17
  ];
18
+ /** The pane a sidebar opens on: Stats once the ticket is done, else Details. */
19
+ export const defaultSidebarTab = (sidebar) => sidebar.showMetrics ? 'stats' : 'details';
20
+ const isCells = (line) => typeof line !== 'string' && 'cells' in line;
21
+ const isStyled = (line) => typeof line !== 'string' && 'runs' in line;
22
+ const TECHNICAL_KEY = 'section:Technical details';
23
+ const LINKS_KEY = 'section:Links';
24
+ const WIDE_OVERVIEW_COLUMNS = 100;
25
+ const column = (id, props, ...children) => h(BoxRenderable, { id, flexDirection: 'column', ...props }, ...children);
27
26
  const kvItems = (lines) => {
28
27
  const items = [];
29
28
  for (const line of lines) {
@@ -57,191 +56,366 @@ const linkItems = (lines) => {
57
56
  }
58
57
  return items;
59
58
  };
60
- const Lines = ({ lines, emphasis = false, }) => {
61
- const theme = useTheme();
59
+ /** Plain and cell rows as wrapped paragraphs, styled runs as Markdown. */
60
+ const lines = (id, source, emphasis) => {
62
61
  const parts = [];
63
62
  let styled = [];
64
63
  const flushStyled = () => {
65
64
  if (styled.length === 0)
66
65
  return;
67
- parts.push(_jsx(MarkdownLines, { lines: styled, ...(emphasis ? { emphasis: true } : {}) }, parts.length));
66
+ parts.push(MarkdownLines({ id: `${id}-${parts.length}`, lines: styled, emphasis }));
68
67
  styled = [];
69
68
  };
70
- for (const line of lines) {
69
+ for (const line of source) {
71
70
  if (typeof line === 'string' || isCells(line)) {
72
71
  flushStyled();
73
72
  const text = typeof line === 'string' ? line : lineText(line);
74
- parts.push(_jsx("text", { width: "100%", wrapMode: "word", flexShrink: 0, fg: emphasis ? theme.colors.primary : theme.colors.foreground, children: emphasis ? _jsx("b", { children: text }) : text }, parts.length));
73
+ parts.push(paragraphNode({
74
+ id: `${id}-${parts.length}`,
75
+ runs: [plainRun(text, emphasis ? BOLD : 0)],
76
+ fg: emphasis ? FOREGROUND_HIGHLIGHT : FOREGROUND,
77
+ width: '100%',
78
+ flexShrink: 0,
79
+ }));
75
80
  continue;
76
81
  }
77
82
  if (isStyled(line))
78
- styled.push(markdownLineFromStyled(line));
83
+ styled.push(line);
79
84
  }
80
85
  flushStyled();
81
- return (_jsx("box", { flexDirection: "column", width: "100%", children: parts }));
86
+ return column(id, { width: '100%' }, ...parts);
82
87
  };
88
+ /**
89
+ * A press on a region that does nothing. A selectable entry's row id sits on
90
+ * an ENCLOSING node the kernel binds clicks to, so an area that must stay
91
+ * inert has to consume its own press rather than let it bubble there.
92
+ */
93
+ const INERT = () => { };
83
94
  const activate = (entry, select, toggle) => {
84
95
  select(entry.key);
85
96
  if (entry.expandable)
86
97
  toggle(entry.key);
87
98
  };
88
99
  const visibleLines = (entry, expandedKeys) => expandedKeys.has(entry.key) ? entry.expanded : entry.collapsed;
89
- const TechnicalBody = ({ entry }) => {
90
- const theme = useTheme();
91
- return (_jsx(KeyValue, { items: kvItems(entry.expanded), keyColor: theme.colors.foreground, valueColor: theme.colors.primary }));
92
- };
93
- const SectionBody = ({ entry, expandedKeys, }) => {
94
- const theme = useTheme();
95
- if (entry.key === TECHNICAL_KEY) {
96
- return _jsx(TechnicalBody, { entry: entry });
97
- }
98
- if (entry.key === LINKS_KEY) {
99
- return (_jsx(KeyValue, { items: linkItems(visibleLines(entry, expandedKeys)), keyColor: theme.colors.foreground, valueColor: theme.colors.primary }));
100
- }
101
- return (_jsx(Lines, { lines: visibleLines(entry, expandedKeys), emphasis: entry.key.startsWith('section:') }));
100
+ const sectionBody = (id, entry, expandedKeys) => {
101
+ if (entry.key === TECHNICAL_KEY)
102
+ return KeyValue({
103
+ id,
104
+ items: kvItems(entry.expanded),
105
+ keyColor: FOREGROUND,
106
+ valueColor: FOREGROUND_HIGHLIGHT,
107
+ });
108
+ if (entry.key === LINKS_KEY)
109
+ return KeyValue({
110
+ id,
111
+ items: linkItems(visibleLines(entry, expandedKeys)),
112
+ keyColor: FOREGROUND,
113
+ valueColor: FOREGROUND_HIGHLIGHT,
114
+ });
115
+ return lines(id, visibleLines(entry, expandedKeys), entry.key.startsWith('section:'));
102
116
  };
103
- const HeadlineContent = ({ tabs, activeId, selected, onTab, children, }) => {
104
- const theme = useTheme();
117
+ /** A body that activates its entry while collapsed, and nothing once open. */
118
+ const entryBody = (id, entry, props, layout) => {
119
+ const bodyActivates = entry.expandable && !props.expandedKeys.has(entry.key);
120
+ return h(BoxRenderable, {
121
+ id,
122
+ flexDirection: 'column',
123
+ width: '100%',
124
+ ...layout,
125
+ onMouseDown: pressHandler(bodyActivates
126
+ ? () => activate(entry, props.select, props.toggle)
127
+ : undefined),
128
+ }, sectionBody(`${id}-content`, entry, props.expandedKeys));
129
+ };
130
+ const tabLabel = (id, label, active, fg, onPress) => paragraphNode({
131
+ id,
132
+ runs: [plainRun(active ? `[${label}]` : ` ${label} `, active ? BOLD : 0)],
133
+ fg,
134
+ onMouseDown: onPress,
135
+ });
136
+ const headlineContent = (id, tabs, activeId, selected, onTab, body) => {
105
137
  const many = tabs.length > 1;
106
- return (_jsxs("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, marginTop: 1, children: [_jsx("box", { id: ticketContentRowId(activeId), flexDirection: "row", width: "100%", flexShrink: 0, gap: 1, children: many ? (tabs.map((tab) => (
107
- // biome-ignore lint/a11y/noStaticElementInteractions: OpenTUI terminal node; inner tabs are mouse-driven.
108
- _jsx("text", { fg: tab.id === activeId
109
- ? selected
110
- ? theme.colors.primaryForeground
111
- : theme.colors.primary
112
- : theme.colors.foreground, onMouseDown: () => onTab(tab.id), children: tab.id === activeId ? (_jsx("b", { children: `[${tab.label}]` })) : (` ${tab.label} `) }, tab.id)))) : (
113
- // biome-ignore lint/a11y/noStaticElementInteractions: OpenTUI terminal node; keyboard selection stays on the screen.
114
- _jsx("text", { fg: selected ? theme.colors.primaryForeground : theme.colors.primary, onMouseDown: () => onTab(tabs[0]?.id ?? activeId), children: _jsx("b", { children: tabs[0]?.label ?? '' }) })) }), _jsx(Divider, { color: selected ? theme.colors.primary : theme.colors.border }), _jsx("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, paddingLeft: 1, marginTop: 1, children: children })] }));
115
- };
116
- const OverviewDocuments = ({ documents, expandedKeys, select, toggle, }) => {
117
- return (_jsx("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, marginTop: 1, children: documents.map((entry) => {
118
- const expanded = expandedKeys.has(entry.key);
119
- const bodyActivates = entry.expandable && !expanded;
120
- return (_jsx(HeadlineMarkdown, { headline: documentTabLabel(entry.title), id: ticketContentRowId(entry.key), onMouseDown: () => activate(entry, select, toggle), paddingBottom: 1, paddingLeft: 1, children: _jsx("box", { flexDirection: "column", width: "100%", flexShrink: 0, ...(bodyActivates
121
- ? { onMouseDown: () => activate(entry, select, toggle) }
122
- : {}), children: _jsx(SectionBody, { entry: entry, expandedKeys: expandedKeys }) }) }, entry.key));
123
- }) }));
124
- };
125
- const DocumentPane = ({ documents, selectedKey, expandedKeys, select, toggle, }) => {
126
- const descriptionKey = documents.find((entry) => entry.key === 'section:Description')?.key ??
127
- documents[0]?.key ??
128
- '';
129
- const [tab, setTab] = useState(selectedKey !== undefined &&
130
- documents.some((entry) => entry.key === selectedKey)
131
- ? selectedKey
132
- : descriptionKey);
133
- useEffect(() => {
134
- if (selectedKey !== undefined &&
135
- documents.some((entry) => entry.key === selectedKey)) {
136
- setTab(selectedKey);
137
- }
138
- }, [documents, selectedKey]);
139
- const activeKey = documents.some((entry) => entry.key === tab)
140
- ? tab
141
- : descriptionKey;
138
+ return column(id, { width: '100%', flexGrow: 1, flexShrink: 1, marginTop: 1 }, h(BoxRenderable, {
139
+ id: ticketContentRowId(activeId),
140
+ flexDirection: 'row',
141
+ width: '100%',
142
+ flexShrink: 0,
143
+ }, h(BoxRenderable, {
144
+ id: `${id}-tabs`,
145
+ flexDirection: 'row',
146
+ width: '100%',
147
+ flexShrink: 0,
148
+ gap: 1,
149
+ onMouseDown: pressHandler(INERT),
150
+ }, ...(many
151
+ ? tabs.map((tab) => tabLabel(`${id}-tab-${tab.id}`, tab.label, tab.id === activeId, tab.id === activeId
152
+ ? selected
153
+ ? FOREGROUND_ACTIVE
154
+ : FOREGROUND_HIGHLIGHT
155
+ : FOREGROUND, () => onTab(tab.id)))
156
+ : [
157
+ paragraphNode({
158
+ id: `${id}-tab-only`,
159
+ runs: [plainRun(tabs[0]?.label ?? '', BOLD)],
160
+ fg: selected ? FOREGROUND_ACTIVE : FOREGROUND_HIGHLIGHT,
161
+ onMouseDown: () => onTab(tabs[0]?.id ?? activeId),
162
+ }),
163
+ ]))), Divider({
164
+ id: `${id}-divider`,
165
+ color: selected ? FOREGROUND_HIGHLIGHT : BORDER,
166
+ }), column(`${id}-pane`, {
167
+ width: '100%',
168
+ flexGrow: 1,
169
+ flexShrink: 1,
170
+ paddingLeft: 1,
171
+ marginTop: 1,
172
+ }, body));
173
+ };
174
+ const overviewDocuments = (id, documents, props) => column(id, { width: '100%', flexGrow: 1, flexShrink: 1, marginTop: 1 }, ...documents.map((entry) => HeadlineMarkdown({
175
+ id: `${id}-${entry.key}`,
176
+ headline: documentTabLabel(entry.title),
177
+ headlineId: ticketContentRowId(entry.key),
178
+ onMouseDown: () => activate(entry, props.select, props.toggle),
179
+ paddingBottom: 1,
180
+ paddingLeft: 1,
181
+ children: [
182
+ entryBody(`${id}-${entry.key}-entry`, entry, props, {
183
+ flexShrink: 0,
184
+ }),
185
+ ],
186
+ })));
187
+ /** The Planning pane's active document: the selection, the visit's tab, or Description. */
188
+ export const activeDocumentKey = (documents, selectedKey, documentKey) => {
189
+ const isDocument = (key) => key !== undefined && documents.some((entry) => entry.key === key);
190
+ if (isDocument(selectedKey))
191
+ return selectedKey;
192
+ if (isDocument(documentKey))
193
+ return documentKey;
194
+ return (documents.find((entry) => entry.key === 'section:Description')?.key ??
195
+ documents[0]?.key);
196
+ };
197
+ const documentPane = (id, documents, props) => {
198
+ const activeKey = activeDocumentKey(documents, props.selectedKey, props.documentKey);
142
199
  const active = documents.find((entry) => entry.key === activeKey) ?? documents[0];
143
200
  if (active === undefined)
144
- return null;
145
- const expanded = expandedKeys.has(active.key);
146
- const bodyActivates = active.expandable && !expanded;
147
- return (_jsx(HeadlineContent, { tabs: documents.map((entry) => ({
148
- id: entry.key,
149
- label: documentTabLabel(entry.title),
150
- })), activeId: active.key, selected: selectedKey === active.key, onTab: (id) => {
151
- setTab(id);
152
- if (id === active.key)
153
- toggle(id);
154
- else
155
- select(id);
156
- }, children: _jsx("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, ...(bodyActivates
157
- ? { onMouseDown: () => activate(active, select, toggle) }
158
- : {}), children: _jsx(SectionBody, { entry: active, expandedKeys: expandedKeys }) }) }));
159
- };
160
- const EntryCard = ({ entry, selected, expandedKeys, select, toggle, }) => {
161
- const theme = useTheme();
162
- return (_jsxs(Card, { id: ticketContentRowId(entry.key), width: "100%", borderColor: selected ? theme.colors.primary : theme.colors.border, children: [_jsxs("box", { flexDirection: "column", width: "100%", flexShrink: 0, paddingBottom: 1, onMouseDown: () => activate(entry, select, toggle), children: [_jsx("text", { fg: theme.colors.foreground, children: _jsx("b", { children: entry.title }) }), entry.metadata !== undefined ? (_jsx("text", { fg: theme.colors.mutedForeground, children: entry.metadata })) : null] }), _jsx(SectionBody, { entry: entry, expandedKeys: expandedKeys })] }));
163
- };
164
- const Properties = ({ items, activateProperty, }) => {
165
- const theme = useTheme();
166
- return (_jsx(KeyValue, { items: items.map((item) => {
167
- const linked = item.ticketId !== undefined || item.href !== undefined;
168
- return {
169
- key: item.key,
170
- value: linked ? _jsx("u", { children: item.value }) : item.value,
171
- ...(linked && activateProperty !== undefined
172
- ? { onMouseDown: () => activateProperty(item) }
173
- : {}),
174
- };
175
- }), keyColor: theme.colors.foreground, valueColor: theme.colors.primary }));
176
- };
177
- const heatGrid = (grid) => {
201
+ return column(id, {});
202
+ return headlineContent(id, documents.map((entry) => ({
203
+ id: entry.key,
204
+ label: documentTabLabel(entry.title),
205
+ })), active.key, props.selectedKey === active.key, (key) => {
206
+ props.onDocumentTab(key);
207
+ if (key === active.key)
208
+ props.toggle(key);
209
+ else
210
+ props.select(key);
211
+ }, entryBody(`${id}-body`, active, props, { flexGrow: 1, flexShrink: 1 }));
212
+ };
213
+ const entryCard = (entry, selected, props) => {
214
+ const id = ticketContentRowId(entry.key);
215
+ return Card({
216
+ id,
217
+ width: '100%',
218
+ borderColor: selected ? FOREGROUND_HIGHLIGHT : BORDER,
219
+ children: [
220
+ h(BoxRenderable, {
221
+ id: `${id}-header`,
222
+ flexDirection: 'column',
223
+ width: '100%',
224
+ flexShrink: 0,
225
+ paddingBottom: 1,
226
+ onMouseDown: pressHandler(() => activate(entry, props.select, props.toggle)),
227
+ }, paragraphNode({
228
+ id: `${id}-title-text`,
229
+ runs: [plainRun(entry.title, BOLD)],
230
+ fg: FOREGROUND,
231
+ }), ...(entry.metadata !== undefined
232
+ ? [
233
+ paragraphNode({
234
+ id: `${id}-metadata`,
235
+ runs: [plainRun(entry.metadata, DIM)],
236
+ fg: FOREGROUND,
237
+ }),
238
+ ]
239
+ : [])),
240
+ h(BoxRenderable, {
241
+ id: `${id}-body`,
242
+ flexDirection: 'column',
243
+ width: '100%',
244
+ onMouseDown: pressHandler(INERT),
245
+ }, sectionBody(`${id}-body-content`, entry, props.expandedKeys)),
246
+ ],
247
+ });
248
+ };
249
+ const properties = (id, items, activateProperty) => KeyValue({
250
+ id,
251
+ items: items.map((item) => {
252
+ const linked = item.ticketId !== undefined || item.href !== undefined;
253
+ return {
254
+ key: item.key,
255
+ value: item.value,
256
+ underline: linked,
257
+ ...(linked && activateProperty !== undefined
258
+ ? { onMouseDown: () => activateProperty(item) }
259
+ : {}),
260
+ };
261
+ }),
262
+ keyColor: FOREGROUND,
263
+ valueColor: FOREGROUND_HIGHLIGHT,
264
+ });
265
+ const heatGrid = (id, grid) => {
178
266
  if (grid.columns.length === 0 || grid.rows.length === 0)
179
267
  return null;
180
- return (_jsx(HeatMap, { data: grid.rows.map((row) => row.cells.map((cell) => cell.value ?? 0)), rowLabels: grid.rows.map((row) => row.label), colLabels: grid.columns.map((column) => column.label), showValues: true }));
268
+ return HeatMap({
269
+ id,
270
+ data: grid.rows.map((row) => row.cells.map((cell) => cell.value ?? 0)),
271
+ rowLabels: grid.rows.map((row) => row.label),
272
+ colLabels: grid.columns.map((column) => column.label),
273
+ showValues: true,
274
+ });
181
275
  };
182
- const ticketStats = (grid) => {
183
- const theme = useTheme();
276
+ const ticketStats = (id, grid) => {
184
277
  const row = grid.rows[0];
185
278
  if (grid.columns.length === 0 || row === undefined)
186
279
  return null;
187
- return (_jsx(KeyValue, { items: grid.columns.map((column, index) => ({
280
+ return KeyValue({
281
+ id,
282
+ items: grid.columns.map((column, index) => ({
188
283
  key: column.label,
189
284
  value: row.cells[index]?.display ?? 'none',
190
- })), keyColor: theme.colors.foreground, valueColor: theme.colors.primary }));
191
- };
192
- const MetricsMatrix = ({ matrix }) => {
193
- const theme = useTheme();
194
- const ticket = ticketStats(matrix.ticket);
195
- const runs = heatGrid(matrix.runs);
196
- if (ticket === null && runs === null) {
197
- return (_jsx("text", { fg: theme.colors.primary, flexShrink: 0, children: "none" }));
198
- }
199
- return (_jsxs("box", { flexDirection: "column", width: "100%", flexShrink: 0, children: [ticket === null ? null : (_jsx(HeadlineMarkdown, { headline: "ticket", paddingBottom: 1, paddingLeft: 1, children: ticket })), runs === null ? null : (_jsx(HeadlineMarkdown, { headline: "runs", paddingBottom: 1, paddingLeft: 1, children: runs }))] }));
285
+ })),
286
+ keyColor: FOREGROUND,
287
+ valueColor: FOREGROUND_HIGHLIGHT,
288
+ });
200
289
  };
201
- const Sidebar = ({ sidebar, selected, select, activateProperty, }) => {
202
- const theme = useTheme();
290
+ const metricsMatrix = (id, matrix) => {
291
+ const ticket = ticketStats(`${id}-ticket-values`, matrix.ticket);
292
+ const runs = heatGrid(`${id}-runs-values`, matrix.runs);
293
+ if (ticket === null && runs === null)
294
+ return paragraphNode({
295
+ id: `${id}-none`,
296
+ runs: [plainRun('none')],
297
+ fg: FOREGROUND_HIGHLIGHT,
298
+ flexShrink: 0,
299
+ });
300
+ return column(id, { width: '100%', flexShrink: 0 }, ...(ticket === null
301
+ ? []
302
+ : [
303
+ HeadlineMarkdown({
304
+ id: `${id}-ticket`,
305
+ headline: 'ticket',
306
+ children: [ticket],
307
+ }),
308
+ ]), ...(runs === null
309
+ ? []
310
+ : [
311
+ HeadlineMarkdown({
312
+ id: `${id}-runs`,
313
+ headline: 'runs',
314
+ children: [runs],
315
+ }),
316
+ ]));
317
+ };
318
+ const sidebarCard = (id, sidebar, props) => {
203
319
  // The Stats tab only exists once the ticket is done (`showMetrics`); until
204
320
  // then the sidebar opens on Details and never offers a Stats tab.
205
321
  const tabs = sidebar.showMetrics
206
322
  ? SIDEBAR_TABS
207
323
  : SIDEBAR_TABS.filter((item) => item.id !== 'stats');
208
- const [tab, setTab] = useState(sidebar.showMetrics ? 'stats' : 'details');
324
+ const requested = props.sidebarTab ?? defaultSidebarTab(sidebar);
325
+ const tab = tabs.some((item) => item.id === requested)
326
+ ? requested
327
+ : defaultSidebarTab(sidebar);
209
328
  const pane = tab === 'related' ? sidebar.related : sidebar.details;
210
- return (_jsxs(Card, { width: "100%", paddingY: 1, borderColor: selected ? theme.colors.primary : theme.colors.border, children: [_jsx("box", { id: ticketContentRowId(TECHNICAL_KEY), flexDirection: "row", width: "100%", flexShrink: 0, gap: 1, onMouseDown: () => select(TECHNICAL_KEY), children: tabs.map((item) => (
211
- // biome-ignore lint/a11y/noStaticElementInteractions: OpenTUI terminal node; inner tabs are mouse-driven.
212
- _jsx("text", { fg: tab === item.id ? theme.colors.primary : theme.colors.foreground, onMouseDown: () => {
213
- setTab(item.id);
214
- select(TECHNICAL_KEY);
215
- }, children: tab === item.id ? _jsx("b", { children: `[${item.label}]` }) : ` ${item.label} ` }, item.id))) }), _jsx("box", { flexDirection: "column", width: "100%", flexShrink: 0, marginTop: 1, gap: 1, children: tab === 'stats' ? (_jsx(MetricsMatrix, { matrix: sidebar.matrix })) : (_jsx(Properties, { items: pane, ...(activateProperty === undefined ? {} : { activateProperty }) })) })] }));
216
- };
217
- const LinksSection = ({ links, activateProperty, }) => {
329
+ return Card({
330
+ id,
331
+ width: '100%',
332
+ paddingY: 1,
333
+ borderColor: props.selectedKey === TECHNICAL_KEY ? FOREGROUND_HIGHLIGHT : BORDER,
334
+ children: [
335
+ // The row carries the Technical entry's id, which the kernel scrolls to;
336
+ // the inner strip selects the entry and the tab labels pick a pane, each
337
+ // consuming its own press.
338
+ h(BoxRenderable, {
339
+ id: ticketContentRowId(TECHNICAL_KEY),
340
+ flexDirection: 'row',
341
+ width: '100%',
342
+ flexShrink: 0,
343
+ }, h(BoxRenderable, {
344
+ id: `${id}-tabs`,
345
+ flexDirection: 'row',
346
+ width: '100%',
347
+ flexShrink: 0,
348
+ gap: 1,
349
+ onMouseDown: pressHandler(() => props.select(TECHNICAL_KEY)),
350
+ }, ...tabs.map((item) => tabLabel(`${id}-tab-${item.id}`, item.label, tab === item.id, tab === item.id ? FOREGROUND_HIGHLIGHT : FOREGROUND, () => {
351
+ props.onSidebarTab(item.id);
352
+ props.select(TECHNICAL_KEY);
353
+ })))),
354
+ column(`${id}-pane`, { width: '100%', flexShrink: 0, marginTop: 1, gap: 1 }, tab === 'stats'
355
+ ? metricsMatrix(`${id}-metrics`, sidebar.matrix)
356
+ : properties(`${id}-properties-${tab}`, pane, props.activateProperty)),
357
+ ],
358
+ });
359
+ };
360
+ const linksSection = (id, links, activateProperty) => {
218
361
  // Drop the `none` placeholder linkProperties emits for a linkless ticket, so
219
362
  // the section is omitted entirely rather than painting "links : none".
220
363
  const real = links.filter((item) => item.value !== 'none' && item.value !== '');
221
364
  if (real.length === 0)
222
365
  return null;
223
- return (_jsx(HeadlineMarkdown, { headline: "links", paddingBottom: 1, children: _jsx(Properties, { items: real, ...(activateProperty === undefined ? {} : { activateProperty }) }) }));
366
+ return HeadlineMarkdown({
367
+ id,
368
+ headline: 'links',
369
+ paddingBottom: 1,
370
+ children: [properties(`${id}-items`, real, activateProperty)],
371
+ });
224
372
  };
225
- const Overview = ({ model, selectedKey, expandedKeys, select, toggle, activateProperty, }) => {
226
- const { width } = useTerminalDimensions();
227
- const wide = width >= WIDE_OVERVIEW_COLUMNS;
373
+ /**
374
+ * ONE tree for both widths: side by side at 100 columns and wider, stacked
375
+ * below. Only layout props differ between the two, so a resize across the
376
+ * breakpoint patches them instead of rebuilding nodes that keep their row ids.
377
+ */
378
+ const overview = (id, props) => {
379
+ const { model } = props;
380
+ const wide = props.terminalColumns >= WIDE_OVERVIEW_COLUMNS;
228
381
  const main = model.entries.filter((entry) => entry.key !== TECHNICAL_KEY);
229
- const documents = (_jsxs(_Fragment, { children: [_jsx(OverviewDocuments, { documents: main, expandedKeys: expandedKeys, select: select, toggle: toggle }), _jsx(LinksSection, { links: model.sidebar?.links ?? [], ...(activateProperty === undefined ? {} : { activateProperty }) })] }));
230
- const side = model.sidebar === undefined ? null : (_jsx(Sidebar, { sidebar: model.sidebar, selected: selectedKey === TECHNICAL_KEY, select: select, ...(activateProperty === undefined ? {} : { activateProperty }) }));
231
- if (wide && side !== null) {
232
- return (_jsxs("box", { flexDirection: "row", width: "100%", flexGrow: 1, flexShrink: 1, gap: 2, children: [_jsx("box", { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: documents }), _jsx("box", { flexDirection: "column", width: "30%", flexShrink: 0, children: side })] }));
233
- }
234
- return (_jsxs("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, gap: 2, children: [documents, side] }));
382
+ const links = linksSection(`${id}-links`, model.sidebar?.links ?? [], props.activateProperty);
383
+ const side = model.sidebar === undefined
384
+ ? null
385
+ : sidebarCard(`${id}-sidebar`, model.sidebar, props);
386
+ const sideBySide = wide && side !== null;
387
+ return h(BoxRenderable, {
388
+ id,
389
+ flexDirection: sideBySide ? 'row' : 'column',
390
+ width: '100%',
391
+ flexGrow: 1,
392
+ flexShrink: 1,
393
+ gap: 2,
394
+ }, column(`${id}-main`, {
395
+ width: sideBySide ? 'auto' : '100%',
396
+ flexGrow: 1,
397
+ // Side by side it yields WIDTH to the sidebar; stacked, nothing may
398
+ // squeeze its height below the documents it holds.
399
+ flexShrink: sideBySide ? 1 : 0,
400
+ gap: sideBySide ? 0 : 2,
401
+ }, overviewDocuments(`${id}-documents`, main, props), ...(links === null ? [] : [links])), ...(side === null
402
+ ? []
403
+ : [
404
+ column(`${id}-side`, { width: sideBySide ? '30%' : '100%', flexShrink: 0 }, side),
405
+ ]));
235
406
  };
236
- export function TicketContent({ model, tab, selectedKey, expandedKeys, select, toggle, activateProperty, }) {
237
- if (tab === 'comments' && model.entries.length === 0) {
238
- return (_jsx("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, children: _jsx("text", { width: "100%", wrapMode: "word", children: "No comments." }) }));
239
- }
240
- if (tab === 'overview') {
241
- return (_jsx(Overview, { model: model, ...(selectedKey === undefined ? {} : { selectedKey }), expandedKeys: expandedKeys, select: select, ...(activateProperty === undefined ? {} : { activateProperty }), toggle: toggle }));
242
- }
243
- if (tab === 'planning') {
244
- return (_jsx(DocumentPane, { documents: model.entries, ...(selectedKey === undefined ? {} : { selectedKey }), expandedKeys: expandedKeys, select: select, toggle: toggle }));
245
- }
246
- return (_jsx("box", { flexDirection: "column", width: "100%", flexGrow: 1, flexShrink: 1, gap: 1, children: model.entries.map((entry) => (_jsx(EntryCard, { entry: entry, selected: selectedKey === entry.key, expandedKeys: expandedKeys, select: select, toggle: toggle }, entry.key))) }));
407
+ export function TicketContent(props) {
408
+ const { id, model, tab } = props;
409
+ if (tab === 'comments' && model.entries.length === 0)
410
+ return column(id, { width: '100%', flexGrow: 1, flexShrink: 1 }, paragraphNode({
411
+ id: `${id}-empty`,
412
+ runs: [plainRun('No comments.')],
413
+ fg: FOREGROUND,
414
+ width: '100%',
415
+ }));
416
+ if (tab === 'overview')
417
+ return overview(`${id}-overview`, props);
418
+ if (tab === 'planning')
419
+ return documentPane(`${id}-planning`, model.entries, props);
420
+ return column(`${id}-history`, { width: '100%', flexGrow: 1, flexShrink: 1, gap: 1 }, ...model.entries.map((entry) => entryCard(entry, props.selectedKey === entry.key, props)));
247
421
  }
@@ -9,7 +9,7 @@
9
9
  // convenience: it already implements the project filter plus the free-text
10
10
  // search, so the parent picker cannot drift from the ticket list. How WIDE the
11
11
  // search matches is the caller's choice (`match`): the create form keeps the
12
- // builder's identifier+title OR group (GAIA-257 S5), while the parent FILTER
12
+ // builder's server-resolved identifier+title search (GAIA-257 S5), while the parent FILTER
13
13
  // picker matches by identifier only — the operator knows `GAIA-273`, not the
14
14
  // title (GAIA-284, PM steer during coding) — and asks for tickets WITH
15
15
  // children only (`filter[has_children]=1`, GAIA-300 D1, answered server-side
@@ -57,7 +57,7 @@ export declare function describeCriteria(criteria: TicketCriteria): string;
57
57
  /**
58
58
  * Build the JSON:API query for a project's tickets under the given criteria.
59
59
  * project + state + closed + parent + who are AND filters at the top level; the
60
- * free-text search is an OR group matching identifier OR title (substring).
60
+ * free-text search is one `filter[search]` the server resolves (GAIA-544).
61
61
  */
62
62
  /** How a caller narrows the shared builder (GAIA-292 D1/D8). */
63
63
  export interface TicketQueryOptions {
@@ -92,4 +92,4 @@ export declare function buildTeamMemberTicketQueryParams(userId: string, project
92
92
  export declare function buildConductorTicketQueryParams(conductorId: string, page?: {
93
93
  size: number;
94
94
  index: number;
95
- }): DrupalJsonApiParams;
95
+ }, query?: string): DrupalJsonApiParams;