@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.
- package/dist/src/Component/badge/index.d.ts +11 -0
- package/dist/src/Component/badge/index.js +10 -0
- package/dist/src/Component/bar-chart/index.d.ts +16 -0
- package/dist/src/Component/bar-chart/index.js +63 -0
- package/dist/src/Component/card/index.d.ts +16 -0
- package/dist/src/Component/card/index.js +39 -0
- package/dist/src/Component/divider/index.d.ts +7 -0
- package/dist/src/Component/divider/index.js +13 -0
- package/dist/src/Component/heat-map/index.d.ts +21 -0
- package/dist/src/Component/heat-map/index.js +86 -0
- package/dist/src/Component/key-value/index.d.ts +18 -0
- package/dist/src/Component/key-value/index.js +30 -0
- package/dist/src/Component/markdown/index.d.ts +35 -5
- package/dist/src/Component/markdown/index.js +72 -16
- package/dist/src/Entity/team/Data/workload.d.ts +3 -1
- package/dist/src/Entity/team/Data/workload.js +6 -4
- package/dist/src/Entity/team/Screen/team-work.d.ts +12 -1
- package/dist/src/Entity/team/Screen/team-work.js +47 -2
- package/dist/src/Entity/ticket/Component/demo-statistics.d.ts +14 -0
- package/dist/src/Entity/ticket/Component/demo-statistics.js +88 -0
- package/dist/src/Entity/ticket/Component/react-statistics.d.ts +14 -22
- package/dist/src/Entity/ticket/Component/react-statistics.js +21 -42
- package/dist/src/Entity/ticket/Component/ticket-content/index.d.ts +28 -3
- package/dist/src/Entity/ticket/Component/ticket-content/index.js +331 -157
- package/dist/src/Entity/ticket/Data/parents.js +1 -1
- package/dist/src/Entity/ticket/Data/query.d.ts +2 -2
- package/dist/src/Entity/ticket/Data/query.js +13 -9
- package/dist/src/Entity/ticket/Data/store.js +1 -1
- package/dist/src/Entity/ticket/Data/tickets.d.ts +1 -1
- package/dist/src/Entity/ticket/Data/tickets.js +1 -1
- package/dist/src/Entity/ticket/Form/edit.d.ts +13 -0
- package/dist/src/Entity/ticket/Form/edit.js +17 -7
- package/dist/src/Entity/ticket/Screen/conductor-tickets.d.ts +7 -1
- package/dist/src/Entity/ticket/Screen/conductor-tickets.js +30 -6
- package/dist/src/Entity/ticket/Screen/edit-assignment-form.d.ts +3 -1
- package/dist/src/Entity/ticket/Screen/edit-assignment-form.js +21 -6
- package/dist/src/Entity/ticket/Screen/my-work.d.ts +8 -1
- package/dist/src/Entity/ticket/Screen/my-work.js +37 -4
- package/dist/src/Entity/ticket/Screen/ticket-comments.d.ts +6 -12
- package/dist/src/Entity/ticket/Screen/ticket-comments.js +11 -16
- package/dist/src/Entity/ticket/Screen/ticket-content-screen.d.ts +25 -44
- package/dist/src/Entity/ticket/Screen/ticket-content-screen.js +79 -87
- package/dist/src/Entity/ticket/Screen/ticket-detail.d.ts +6 -11
- package/dist/src/Entity/ticket/Screen/ticket-detail.js +14 -19
- package/dist/src/Entity/ticket/Screen/ticket-filter-bar.js +2 -9
- package/dist/src/Entity/ticket/Screen/ticket-planning.d.ts +6 -12
- package/dist/src/Entity/ticket/Screen/ticket-planning.js +11 -16
- package/dist/src/Entity/ticket/Screen/ticket-react-markdown.d.ts +9 -7
- package/dist/src/Entity/ticket/Screen/ticket-react-markdown.js +36 -13
- package/dist/src/Entity/ticket/Screen/ticket-react.d.ts +21 -8
- package/dist/src/Entity/ticket/Screen/ticket-react.js +109 -34
- package/dist/src/Entity/ticket/Screen/ticket-search.d.ts +44 -0
- package/dist/src/Entity/ticket/Screen/ticket-search.js +97 -0
- package/dist/src/Entity/ticket/Screen/tickets.d.ts +9 -7
- package/dist/src/Entity/ticket/Screen/tickets.js +25 -85
- package/dist/src/Entity/ticket/Screen/user-tickets.d.ts +7 -0
- package/dist/src/Entity/ticket/Screen/user-tickets.js +30 -2
- package/dist/src/Kernel/renderer.d.ts +1 -3
- package/dist/src/Kernel/renderer.js +2 -5
- package/dist/src/Kernel/tui-kernel.js +7 -16
- package/dist/src/Screen/async-screen.d.ts +13 -0
- package/dist/src/Screen/async-screen.js +34 -5
- package/dist/src/Screen/list-screen.d.ts +11 -2
- package/dist/src/Screen/list-screen.js +20 -2
- package/dist/src/Screen/screen.d.ts +6 -2
- package/dist/src/Statistics/comparison-chart.d.ts +4 -2
- package/dist/src/Statistics/comparison-chart.js +14 -6
- package/dist/src/Statistics/figures.d.ts +17 -3
- package/dist/src/Statistics/figures.js +104 -41
- package/dist/src/Statistics/presentation.d.ts +3 -5
- package/dist/src/Statistics/presentation.js +3 -5
- package/dist/src/Statistics/screen.d.ts +16 -5
- package/dist/src/Statistics/screen.js +59 -26
- package/dist/src/lib/theme.d.ts +0 -56
- package/dist/src/lib/theme.js +0 -42
- package/dist/src/lib/vnode.d.ts +29 -0
- package/dist/src/lib/vnode.js +69 -0
- package/dist/src/route.js +37 -0
- package/dist/src/types.d.ts +5 -1
- package/dist/src/ui.d.ts +0 -1
- package/dist/src/ui.js +0 -1
- package/package.json +2 -2
- package/dist/src/Agent/Component/agent-list/index.d.ts +0 -6
- package/dist/src/Agent/Component/agent-list/index.js +0 -14
- package/dist/src/Component/agent-list/index.d.ts +0 -6
- package/dist/src/Component/agent-list/index.js +0 -14
- package/dist/src/Component/comment-item/index.d.ts +0 -21
- package/dist/src/Component/comment-item/index.js +0 -39
- package/dist/src/Component/create-form/index.d.ts +0 -3
- package/dist/src/Component/create-form/index.js +0 -26
- package/dist/src/Component/dashboard-list/index.d.ts +0 -8
- package/dist/src/Component/dashboard-list/index.js +0 -7
- package/dist/src/Component/project-picker/index.d.ts +0 -15
- package/dist/src/Component/project-picker/index.js +0 -42
- package/dist/src/Component/run-table/index.d.ts +0 -10
- package/dist/src/Component/run-table/index.js +0 -20
- package/dist/src/Component/tab-bar/index.d.ts +0 -20
- package/dist/src/Component/tab-bar/index.js +0 -42
- package/dist/src/Component/ticket-detail/index.d.ts +0 -38
- package/dist/src/Component/ticket-detail/index.js +0 -193
- package/dist/src/Component/ticket-table/index.d.ts +0 -5
- package/dist/src/Component/ticket-table/index.js +0 -14
- package/dist/src/Component/ticket-teaser/index.d.ts +0 -7
- package/dist/src/Component/ticket-teaser/index.js +0 -76
- package/dist/src/Deriver/liveness.d.ts +0 -12
- package/dist/src/Deriver/liveness.js +0 -34
- package/dist/src/Deriver/run-status.d.ts +0 -12
- package/dist/src/Deriver/run-status.js +0 -36
- package/dist/src/Entity/conductor/Component/conductor-list/index.d.ts +0 -25
- package/dist/src/Entity/conductor/Component/conductor-list/index.js +0 -60
- package/dist/src/Entity/project/Component/dashboard-list/index.d.ts +0 -8
- package/dist/src/Entity/project/Component/dashboard-list/index.js +0 -7
- package/dist/src/Entity/project/Component/project-list/index.d.ts +0 -8
- package/dist/src/Entity/project/Component/project-list/index.js +0 -7
- package/dist/src/Entity/project/Component/project-picker/index.d.ts +0 -15
- package/dist/src/Entity/project/Component/project-picker/index.js +0 -42
- package/dist/src/Entity/project/Screen/project-work.d.ts +0 -33
- package/dist/src/Entity/project/Screen/project-work.js +0 -114
- package/dist/src/Entity/run/Component/run-table/index.d.ts +0 -8
- package/dist/src/Entity/run/Component/run-table/index.js +0 -11
- package/dist/src/Entity/statistics/Data/statistics.d.ts +0 -147
- package/dist/src/Entity/statistics/Data/statistics.js +0 -235
- package/dist/src/Entity/statistics/Screen/dashboard.d.ts +0 -70
- package/dist/src/Entity/statistics/Screen/dashboard.js +0 -216
- package/dist/src/Entity/statistics/render.d.ts +0 -6
- package/dist/src/Entity/statistics/render.js +0 -71
- package/dist/src/Entity/ticket/Component/tab-bar/index.d.ts +0 -20
- package/dist/src/Entity/ticket/Component/tab-bar/index.js +0 -71
- package/dist/src/Entity/ticket/Component/ticket-table/index.d.ts +0 -7
- package/dist/src/Entity/ticket/Component/ticket-table/index.js +0 -10
- package/dist/src/Entity/user/Screen/user-overview.d.ts +0 -33
- package/dist/src/Entity/user/Screen/user-overview.js +0 -80
- package/dist/src/Extension/contract.d.ts +0 -204
- package/dist/src/Extension/contract.js +0 -1
- package/dist/src/Kernel/react-body.d.ts +0 -9
- package/dist/src/Kernel/react-body.js +0 -42
- package/dist/src/Screen/async-react-screen.d.ts +0 -45
- package/dist/src/Screen/async-react-screen.js +0 -120
- package/dist/src/Screen/dashboard.d.ts +0 -1
- package/dist/src/Screen/dashboard.js +0 -1
- package/dist/src/Screen/project.d.ts +0 -1
- package/dist/src/Screen/project.js +0 -1
- package/dist/src/Screen/projects.d.ts +0 -1
- package/dist/src/Screen/projects.js +0 -1
- package/dist/src/Screen/react-screen.d.ts +0 -14
- package/dist/src/Screen/react-screen.js +0 -34
- package/dist/src/Screen/ticket.d.ts +0 -1
- package/dist/src/Screen/ticket.js +0 -1
- package/dist/src/Service/agent.d.ts +0 -17
- package/dist/src/Service/agent.js +0 -28
- package/dist/src/Service/create-form-data.d.ts +0 -10
- package/dist/src/Service/create-form-data.js +0 -52
- package/dist/src/Service/create-form.d.ts +0 -52
- package/dist/src/Service/create-form.js +0 -98
- package/dist/src/Service/project-data.d.ts +0 -48
- package/dist/src/Service/project-data.js +0 -92
- package/dist/src/Service/projects.d.ts +0 -21
- package/dist/src/Service/projects.js +0 -80
- package/dist/src/Service/route.d.ts +0 -11
- package/dist/src/Service/route.js +0 -215
- package/dist/src/Service/run-data.d.ts +0 -35
- package/dist/src/Service/run-data.js +0 -62
- package/dist/src/Service/ticket-data.d.ts +0 -6
- package/dist/src/Service/ticket-data.js +0 -7
- package/dist/src/Tui/controller.d.ts +0 -13
- package/dist/src/Tui/controller.js +0 -1794
- package/dist/src/Vendor/termcn/hooks/use-motion.d.ts +0 -5
- package/dist/src/Vendor/termcn/hooks/use-motion.js +0 -7
- package/dist/src/Vendor/termcn/hooks/use-theme.d.ts +0 -5
- package/dist/src/Vendor/termcn/hooks/use-theme.js +0 -10
- package/dist/src/Vendor/termcn/hooks/use-unicode.d.ts +0 -5
- package/dist/src/Vendor/termcn/hooks/use-unicode.js +0 -34
- package/dist/src/Vendor/termcn/lib/dither-chart-utils.d.ts +0 -130
- package/dist/src/Vendor/termcn/lib/dither-chart-utils.js +0 -357
- package/dist/src/Vendor/termcn/lib/dither-line-chart-utils.d.ts +0 -2
- package/dist/src/Vendor/termcn/lib/dither-line-chart-utils.js +0 -72
- package/dist/src/Vendor/termcn/lib/dither-radar-chart-utils.d.ts +0 -2
- package/dist/src/Vendor/termcn/lib/dither-radar-chart-utils.js +0 -113
- package/dist/src/Vendor/termcn/themes/default.d.ts +0 -1
- package/dist/src/Vendor/termcn/themes/default.js +0 -3
- package/dist/src/Vendor/termcn/ui/badge.d.ts +0 -13
- package/dist/src/Vendor/termcn/ui/badge.js +0 -33
- package/dist/src/Vendor/termcn/ui/bar-chart.d.ts +0 -16
- package/dist/src/Vendor/termcn/ui/bar-chart.js +0 -61
- package/dist/src/Vendor/termcn/ui/card.d.ts +0 -18
- package/dist/src/Vendor/termcn/ui/card.js +0 -7
- package/dist/src/Vendor/termcn/ui/dither-chart.d.ts +0 -118
- package/dist/src/Vendor/termcn/ui/dither-chart.js +0 -418
- package/dist/src/Vendor/termcn/ui/dither-line-chart.d.ts +0 -10
- package/dist/src/Vendor/termcn/ui/dither-line-chart.js +0 -11
- package/dist/src/Vendor/termcn/ui/dither-radar-chart.d.ts +0 -21
- package/dist/src/Vendor/termcn/ui/dither-radar-chart.js +0 -11
- package/dist/src/Vendor/termcn/ui/divider.d.ts +0 -14
- package/dist/src/Vendor/termcn/ui/divider.js +0 -25
- package/dist/src/Vendor/termcn/ui/gauge.d.ts +0 -12
- package/dist/src/Vendor/termcn/ui/gauge.js +0 -48
- package/dist/src/Vendor/termcn/ui/heat-map.d.ts +0 -13
- package/dist/src/Vendor/termcn/ui/heat-map.js +0 -59
- package/dist/src/Vendor/termcn/ui/key-value.d.ts +0 -16
- package/dist/src/Vendor/termcn/ui/key-value.js +0 -24
- package/dist/src/Vendor/termcn/ui/line-chart.d.ts +0 -15
- package/dist/src/Vendor/termcn/ui/line-chart.js +0 -102
- package/dist/src/Vendor/termcn/ui/markdown.d.ts +0 -24
- package/dist/src/Vendor/termcn/ui/markdown.js +0 -39
- package/dist/src/Vendor/termcn/ui/progress-bar.d.ts +0 -13
- package/dist/src/Vendor/termcn/ui/progress-bar.js +0 -13
- package/dist/src/Vendor/termcn/ui/sparkline.d.ts +0 -8
- package/dist/src/Vendor/termcn/ui/sparkline.js +0 -30
- package/dist/src/Vendor/termcn/ui/types.d.ts +0 -82
- package/dist/src/Vendor/termcn/ui/types.js +0 -1
- package/dist/src/lib/ansi.d.ts +0 -34
- package/dist/src/lib/ansi.js +0 -97
- package/dist/src/lib/hit-test.d.ts +0 -138
- package/dist/src/lib/hit-test.js +0 -138
- package/dist/src/lib/mouse.d.ts +0 -35
- package/dist/src/lib/mouse.js +0 -89
- package/dist/src/lib/table.d.ts +0 -37
- package/dist/src/lib/table.js +0 -20
- package/dist/src/lib/ticket-query.d.ts +0 -21
- package/dist/src/lib/ticket-query.js +0 -72
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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 {
|
|
9
|
-
import {
|
|
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
|
|
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
|
-
|
|
61
|
-
|
|
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(
|
|
66
|
+
parts.push(MarkdownLines({ id: `${id}-${parts.length}`, lines: styled, emphasis }));
|
|
68
67
|
styled = [];
|
|
69
68
|
};
|
|
70
|
-
for (const line of
|
|
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(
|
|
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(
|
|
83
|
+
styled.push(line);
|
|
79
84
|
}
|
|
80
85
|
flushStyled();
|
|
81
|
-
return (
|
|
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
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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 (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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 (
|
|
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
|
|
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
|
-
})),
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
|
202
|
-
const
|
|
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
|
|
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
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
366
|
+
return HeadlineMarkdown({
|
|
367
|
+
id,
|
|
368
|
+
headline: 'links',
|
|
369
|
+
paddingBottom: 1,
|
|
370
|
+
children: [properties(`${id}-items`, real, activateProperty)],
|
|
371
|
+
});
|
|
224
372
|
};
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
230
|
-
const side = model.sidebar === undefined
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return (
|
|
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(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
|
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
|
|
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;
|