@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,14 +1,15 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
1
|
import { type ActionItem } from '../../../Component/footer-actions/index.js';
|
|
3
2
|
import { AsyncScreen, type FullScreenChrome } from '../../../Screen/async-screen.js';
|
|
4
|
-
import {
|
|
5
|
-
import type { ScreenAction, ScreenContext, ScreenId, ScreenPresentation } from '../../../Screen/screen.js';
|
|
3
|
+
import type { ScreenAction, ScreenContext, ScreenId } from '../../../Screen/screen.js';
|
|
6
4
|
import type { TicketDetailDocument, UiViewMode } from '../../../types.js';
|
|
7
5
|
import { type TicketContentProps } from '../Component/ticket-content/index.js';
|
|
8
6
|
import { type TicketContentTab } from '../Component/ticket-content/model.js';
|
|
9
7
|
import { type AssignmentLabels } from '../Component/ticket-detail/index.js';
|
|
10
|
-
/**
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Owns ticket content load, selection, chrome and paint for the three ticket
|
|
10
|
+
* document routes. Route subclasses supply the tab, includes and pipe output.
|
|
11
|
+
*/
|
|
12
|
+
export declare abstract class TicketContentScreen extends AsyncScreen<TicketDetailDocument> {
|
|
12
13
|
abstract readonly id: ScreenId;
|
|
13
14
|
abstract readonly tab: TicketContentTab;
|
|
14
15
|
readonly frameId = "ticket";
|
|
@@ -20,9 +21,19 @@ export declare abstract class TicketContentController extends AsyncScreen<Ticket
|
|
|
20
21
|
private releaseStore;
|
|
21
22
|
private expanded;
|
|
22
23
|
protected viewMode: UiViewMode;
|
|
24
|
+
/** Visit-local: the sidebar pane and Planning document tab last chosen. */
|
|
25
|
+
private sidebarTab;
|
|
26
|
+
private documentKey;
|
|
27
|
+
private modelMemo;
|
|
23
28
|
compact(): boolean;
|
|
24
29
|
get document(): TicketDetailDocument | undefined;
|
|
25
30
|
message(context: ScreenContext): string[] | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* What the content tree is built from. Every callback is guarded by the
|
|
33
|
+
* visit it was built for — a click that lands after the route was left
|
|
34
|
+
* changes nothing — and one press that calls several of them (select, then
|
|
35
|
+
* toggle) paints once.
|
|
36
|
+
*/
|
|
26
37
|
contentProps(context: ScreenContext): TicketContentProps;
|
|
27
38
|
reload(context: ScreenContext): void;
|
|
28
39
|
enter(context: ScreenContext): void;
|
|
@@ -41,6 +52,8 @@ export declare abstract class TicketContentController extends AsyncScreen<Ticket
|
|
|
41
52
|
actionForInput(input: string, context: ScreenContext): ScreenAction | undefined;
|
|
42
53
|
receiveResult(result: unknown, context: ScreenContext): void;
|
|
43
54
|
protected renderReady(document: TicketDetailDocument, context: ScreenContext): import("@opentui/core").VNode<any, import("@opentui/core").VChild[]>;
|
|
55
|
+
/** The full document reads as content inside the frame; compact is flush. */
|
|
56
|
+
protected flushBody(): boolean;
|
|
44
57
|
protected chrome(context: ScreenContext): FullScreenChrome;
|
|
45
58
|
protected actions(context: ScreenContext): readonly ActionItem[];
|
|
46
59
|
protected notice(): string | undefined;
|
|
@@ -49,44 +62,12 @@ export declare abstract class TicketContentController extends AsyncScreen<Ticket
|
|
|
49
62
|
protected abstract fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
50
63
|
private initialize;
|
|
51
64
|
private syncModel;
|
|
65
|
+
/**
|
|
66
|
+
* The projection of one document, built once per document, labels and
|
|
67
|
+
* second. A keypress reads it from input handling, selection, chrome,
|
|
68
|
+
* actions and the body; parsing every body that many times per frame was
|
|
69
|
+
* most of a keypress's cost on a long ticket.
|
|
70
|
+
*/
|
|
71
|
+
private modelOf;
|
|
52
72
|
private selectedIndexOf;
|
|
53
73
|
}
|
|
54
|
-
/** Ticket-local ReactScreen adapter. Forwards AsyncScreen lifecycle by delegation. */
|
|
55
|
-
export declare abstract class TicketContentScreen extends ReactScreen {
|
|
56
|
-
abstract readonly id: ScreenId;
|
|
57
|
-
readonly frameId = "ticket";
|
|
58
|
-
protected abstract readonly controller: TicketContentController;
|
|
59
|
-
get document(): TicketDetailDocument | undefined;
|
|
60
|
-
get state(): import("../../../Screen/async-screen.js").AsyncScreenState;
|
|
61
|
-
get busy(): boolean;
|
|
62
|
-
enter(context: ScreenContext): void;
|
|
63
|
-
leave(): void;
|
|
64
|
-
reset(): void;
|
|
65
|
-
handleInput(input: string, context?: ScreenContext): boolean;
|
|
66
|
-
reload(context: ScreenContext): void;
|
|
67
|
-
setLabels(labels: AssignmentLabels | undefined): void;
|
|
68
|
-
select(index: number, context: ScreenContext): boolean;
|
|
69
|
-
activate(index: number, context: ScreenContext): boolean;
|
|
70
|
-
saveState(): {
|
|
71
|
-
readonly selectedKey?: string;
|
|
72
|
-
};
|
|
73
|
-
restoreState(token: unknown): void;
|
|
74
|
-
commandForInput(input: string): string | undefined;
|
|
75
|
-
actionForInput(input: string, context: ScreenContext): ScreenAction | undefined;
|
|
76
|
-
receiveResult(result: unknown, context: ScreenContext): void;
|
|
77
|
-
renderNonInteractive(context: ScreenContext): string[];
|
|
78
|
-
present(context: ScreenContext): ScreenPresentation;
|
|
79
|
-
protected render(context: ScreenContext): ReactNode;
|
|
80
|
-
protected chrome(context: ScreenContext): {
|
|
81
|
-
selectable: number;
|
|
82
|
-
selectedIndex: number;
|
|
83
|
-
rowIds?: readonly string[];
|
|
84
|
-
cursorMode?: "select" | "scroll";
|
|
85
|
-
title?: string;
|
|
86
|
-
meta?: string;
|
|
87
|
-
header?: import("@opentui/core").VNode;
|
|
88
|
-
status?: string;
|
|
89
|
-
toast?: string;
|
|
90
|
-
actions?: readonly ActionItem[];
|
|
91
|
-
};
|
|
92
|
-
}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { createElement } from 'react';
|
|
2
1
|
import { actionItem, } from '../../../Component/footer-actions/index.js';
|
|
3
2
|
import { copyThrough } from '../../../lib/clipboard.js';
|
|
4
|
-
import { BORDER,
|
|
3
|
+
import { BORDER, textNode } from '../../../lib/vnode.js';
|
|
5
4
|
import { AsyncScreen, } from '../../../Screen/async-screen.js';
|
|
6
|
-
import { ReactScreen } from '../../../Screen/react-screen.js';
|
|
7
5
|
import { TicketContent, } from '../Component/ticket-content/index.js';
|
|
8
6
|
import { initialExpandedKeys, resolveSelectedKey, retainExpandedKeys, ticketContentModel, ticketContentRowId, } from '../Component/ticket-content/model.js';
|
|
9
7
|
import { handleTicketCopy, ticketCopyActions, ticketEditAction, ticketHeaderTree, ticketTitleOf, } from '../Component/ticket-detail/index.js';
|
|
10
8
|
import { ticketTeaserLines, ticketTeaserTree, } from '../Component/ticket-teaser/index.js';
|
|
11
9
|
import { ticketDetailInputContext } from '../Data/input.js';
|
|
12
10
|
import { loadTicketView, readTicket, refreshTicket, saveTicket, ticketLoaded, watchTicket, } from '../Data/store.js';
|
|
13
|
-
/**
|
|
14
|
-
|
|
11
|
+
/** Overview width when the context carries none — a pipe has no terminal. */
|
|
12
|
+
const DEFAULT_COLUMNS = 80;
|
|
13
|
+
/**
|
|
14
|
+
* Owns ticket content load, selection, chrome and paint for the three ticket
|
|
15
|
+
* document routes. Route subclasses supply the tab, includes and pipe output.
|
|
16
|
+
*/
|
|
17
|
+
export class TicketContentScreen extends AsyncScreen {
|
|
15
18
|
frameId = 'ticket';
|
|
16
19
|
selectedKey;
|
|
17
20
|
initializedKey;
|
|
@@ -20,6 +23,10 @@ export class TicketContentController extends AsyncScreen {
|
|
|
20
23
|
releaseStore;
|
|
21
24
|
expanded = new Set();
|
|
22
25
|
viewMode = 'full';
|
|
26
|
+
/** Visit-local: the sidebar pane and Planning document tab last chosen. */
|
|
27
|
+
sidebarTab;
|
|
28
|
+
documentKey;
|
|
29
|
+
modelMemo;
|
|
23
30
|
compact() {
|
|
24
31
|
return this.viewMode !== 'full';
|
|
25
32
|
}
|
|
@@ -29,28 +36,59 @@ export class TicketContentController extends AsyncScreen {
|
|
|
29
36
|
message(context) {
|
|
30
37
|
return this.noticeRows(context);
|
|
31
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* What the content tree is built from. Every callback is guarded by the
|
|
41
|
+
* visit it was built for — a click that lands after the route was left
|
|
42
|
+
* changes nothing — and one press that calls several of them (select, then
|
|
43
|
+
* toggle) paints once.
|
|
44
|
+
*/
|
|
32
45
|
contentProps(context) {
|
|
33
46
|
const model = this.syncModel(context);
|
|
34
47
|
const selectedKey = this.selectedKey;
|
|
48
|
+
let drawQueued = false;
|
|
49
|
+
const live = (action) => {
|
|
50
|
+
if (!context.isActive())
|
|
51
|
+
return;
|
|
52
|
+
action();
|
|
53
|
+
if (drawQueued)
|
|
54
|
+
return;
|
|
55
|
+
drawQueued = true;
|
|
56
|
+
queueMicrotask(() => {
|
|
57
|
+
drawQueued = false;
|
|
58
|
+
context.requestDraw();
|
|
59
|
+
});
|
|
60
|
+
};
|
|
35
61
|
return {
|
|
62
|
+
id: 'ticket-content',
|
|
36
63
|
model,
|
|
37
64
|
tab: this.tab,
|
|
38
65
|
...(selectedKey === undefined ? {} : { selectedKey }),
|
|
39
66
|
expandedKeys: this.expanded,
|
|
40
|
-
|
|
67
|
+
terminalColumns: context.terminalColumns ?? DEFAULT_COLUMNS,
|
|
68
|
+
...(this.sidebarTab === undefined ? {} : { sidebarTab: this.sidebarTab }),
|
|
69
|
+
...(this.documentKey === undefined
|
|
70
|
+
? {}
|
|
71
|
+
: { documentKey: this.documentKey }),
|
|
72
|
+
onSidebarTab: (tab) => live(() => {
|
|
73
|
+
this.sidebarTab = tab;
|
|
74
|
+
}),
|
|
75
|
+
onDocumentTab: (key) => live(() => {
|
|
76
|
+
this.documentKey = key;
|
|
77
|
+
}),
|
|
78
|
+
select: (key) => live(() => {
|
|
41
79
|
this.selectedKey = key;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
toggle: (key) => {
|
|
80
|
+
}),
|
|
81
|
+
toggle: (key) => live(() => {
|
|
45
82
|
const next = new Set(this.expanded);
|
|
46
83
|
if (next.has(key))
|
|
47
84
|
next.delete(key);
|
|
48
85
|
else
|
|
49
86
|
next.add(key);
|
|
50
87
|
this.expanded = next;
|
|
51
|
-
|
|
52
|
-
},
|
|
88
|
+
}),
|
|
53
89
|
activateProperty: (item) => {
|
|
90
|
+
if (!context.isActive())
|
|
91
|
+
return;
|
|
54
92
|
if (item.ticketId !== undefined) {
|
|
55
93
|
context.navigate?.('ticket.detail', { ticketId: item.ticketId });
|
|
56
94
|
}
|
|
@@ -69,6 +107,8 @@ export class TicketContentController extends AsyncScreen {
|
|
|
69
107
|
}
|
|
70
108
|
enter(context) {
|
|
71
109
|
this.releaseStore?.();
|
|
110
|
+
this.sidebarTab = undefined;
|
|
111
|
+
this.documentKey = undefined;
|
|
72
112
|
super.enter(context);
|
|
73
113
|
if (context.contexts?.has(ticketDetailInputContext)) {
|
|
74
114
|
const document = readTicket(context);
|
|
@@ -195,7 +235,11 @@ export class TicketContentController extends AsyncScreen {
|
|
|
195
235
|
this.initialize(document, context);
|
|
196
236
|
return this.viewMode !== 'full'
|
|
197
237
|
? ticketTeaserTree(document, this.viewMode)
|
|
198
|
-
:
|
|
238
|
+
: TicketContent(this.contentProps(context));
|
|
239
|
+
}
|
|
240
|
+
/** The full document reads as content inside the frame; compact is flush. */
|
|
241
|
+
flushBody() {
|
|
242
|
+
return this.viewMode !== 'full';
|
|
199
243
|
}
|
|
200
244
|
chrome(context) {
|
|
201
245
|
const document = this.document;
|
|
@@ -247,6 +291,9 @@ export class TicketContentController extends AsyncScreen {
|
|
|
247
291
|
this.releaseStore?.();
|
|
248
292
|
this.releaseStore = undefined;
|
|
249
293
|
super.reset();
|
|
294
|
+
this.modelMemo = undefined;
|
|
295
|
+
this.sidebarTab = undefined;
|
|
296
|
+
this.documentKey = undefined;
|
|
250
297
|
this.selectedKey = undefined;
|
|
251
298
|
this.initializedKey = undefined;
|
|
252
299
|
this.labels = undefined;
|
|
@@ -264,7 +311,7 @@ export class TicketContentController extends AsyncScreen {
|
|
|
264
311
|
}
|
|
265
312
|
initialize(document, context) {
|
|
266
313
|
const identity = document.data?.id ?? document;
|
|
267
|
-
const model =
|
|
314
|
+
const model = this.modelOf(document, context);
|
|
268
315
|
if (this.initializedKey === identity) {
|
|
269
316
|
this.selectedKey = resolveSelectedKey(model.selectableKeys, this.selectedKey);
|
|
270
317
|
this.expanded = retainExpandedKeys(model.selectableKeys, this.expanded);
|
|
@@ -278,7 +325,25 @@ export class TicketContentController extends AsyncScreen {
|
|
|
278
325
|
syncModel(context) {
|
|
279
326
|
const document = this.document ?? {};
|
|
280
327
|
this.initialize(document, context);
|
|
281
|
-
return
|
|
328
|
+
return this.modelOf(document, context);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The projection of one document, built once per document, labels and
|
|
332
|
+
* second. A keypress reads it from input handling, selection, chrome,
|
|
333
|
+
* actions and the body; parsing every body that many times per frame was
|
|
334
|
+
* most of a keypress's cost on a long ticket.
|
|
335
|
+
*/
|
|
336
|
+
modelOf(document, context) {
|
|
337
|
+
const now = context.nowSeconds?.() ?? Math.floor(Date.now() / 1000);
|
|
338
|
+
const memo = this.modelMemo;
|
|
339
|
+
if (memo !== undefined &&
|
|
340
|
+
memo.document === document &&
|
|
341
|
+
memo.labels === this.labels &&
|
|
342
|
+
memo.now === now)
|
|
343
|
+
return memo.model;
|
|
344
|
+
const model = ticketContentModel(document, this.tab, this.labels, now);
|
|
345
|
+
this.modelMemo = { document, labels: this.labels, now, model };
|
|
346
|
+
return model;
|
|
282
347
|
}
|
|
283
348
|
selectedIndexOf(keys) {
|
|
284
349
|
if (this.selectedKey === undefined)
|
|
@@ -287,76 +352,3 @@ export class TicketContentController extends AsyncScreen {
|
|
|
287
352
|
return index < 0 ? 0 : index;
|
|
288
353
|
}
|
|
289
354
|
}
|
|
290
|
-
/** Ticket-local ReactScreen adapter. Forwards AsyncScreen lifecycle by delegation. */
|
|
291
|
-
export class TicketContentScreen extends ReactScreen {
|
|
292
|
-
frameId = 'ticket';
|
|
293
|
-
get document() {
|
|
294
|
-
return this.controller.document;
|
|
295
|
-
}
|
|
296
|
-
get state() {
|
|
297
|
-
return this.controller.state;
|
|
298
|
-
}
|
|
299
|
-
get busy() {
|
|
300
|
-
return this.controller.busy;
|
|
301
|
-
}
|
|
302
|
-
// ReactScreen.enter only requestDraw; load/store guards stay on the controller.
|
|
303
|
-
enter(context) {
|
|
304
|
-
this.controller.enter(context);
|
|
305
|
-
}
|
|
306
|
-
leave() {
|
|
307
|
-
this.controller.leave();
|
|
308
|
-
}
|
|
309
|
-
reset() {
|
|
310
|
-
this.controller.reset();
|
|
311
|
-
}
|
|
312
|
-
handleInput(input, context) {
|
|
313
|
-
if (super.handleInput(input))
|
|
314
|
-
return true;
|
|
315
|
-
return context ? this.controller.handleInput(input, context) : false;
|
|
316
|
-
}
|
|
317
|
-
reload(context) {
|
|
318
|
-
this.controller.reload(context);
|
|
319
|
-
}
|
|
320
|
-
setLabels(labels) {
|
|
321
|
-
this.controller.setLabels(labels);
|
|
322
|
-
}
|
|
323
|
-
select(index, context) {
|
|
324
|
-
return this.controller.select(index, context);
|
|
325
|
-
}
|
|
326
|
-
activate(index, context) {
|
|
327
|
-
return this.controller.activate(index, context);
|
|
328
|
-
}
|
|
329
|
-
saveState() {
|
|
330
|
-
return this.controller.saveState();
|
|
331
|
-
}
|
|
332
|
-
restoreState(token) {
|
|
333
|
-
this.controller.restoreState(token);
|
|
334
|
-
}
|
|
335
|
-
commandForInput(input) {
|
|
336
|
-
return this.controller.commandForInput(input);
|
|
337
|
-
}
|
|
338
|
-
actionForInput(input, context) {
|
|
339
|
-
return this.controller.actionForInput(input, context);
|
|
340
|
-
}
|
|
341
|
-
receiveResult(result, context) {
|
|
342
|
-
this.controller.receiveResult(result, context);
|
|
343
|
-
}
|
|
344
|
-
renderNonInteractive(context) {
|
|
345
|
-
return this.controller.renderNonInteractive(context);
|
|
346
|
-
}
|
|
347
|
-
present(context) {
|
|
348
|
-
if (this.controller.compact())
|
|
349
|
-
return this.controller.present(context);
|
|
350
|
-
return super.present(context);
|
|
351
|
-
}
|
|
352
|
-
render(context) {
|
|
353
|
-
const message = this.controller.message(context);
|
|
354
|
-
return message
|
|
355
|
-
? createElement('text', { wrapMode: 'word' }, message.join('\n'))
|
|
356
|
-
: createElement(TicketContent, this.controller.contentProps(context));
|
|
357
|
-
}
|
|
358
|
-
chrome(context) {
|
|
359
|
-
const { body, reactBody, ...chrome } = this.controller.present(context);
|
|
360
|
-
return chrome;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import type { ScreenContext } from '../../../Screen/screen.js';
|
|
2
2
|
import type { TicketDetailDocument } from '../../../types.js';
|
|
3
|
-
import {
|
|
3
|
+
import { TicketContentScreen } from './ticket-content-screen.js';
|
|
4
4
|
export type { TicketDetailInput } from '../Data/input.js';
|
|
5
5
|
export { ticketDetailInputContext } from '../Data/input.js';
|
|
6
|
-
/**
|
|
7
|
-
declare class TicketOverviewController extends TicketContentController {
|
|
8
|
-
readonly id: string;
|
|
9
|
-
readonly tab = "overview";
|
|
10
|
-
protected readonly includes: string[];
|
|
11
|
-
protected renderLoading(): string[];
|
|
12
|
-
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
13
|
-
}
|
|
14
|
-
/** Public Overview route: ReactScreen wrapper around the overview controller. */
|
|
6
|
+
/** Public Overview route: the ticket's overview view and its interaction state. */
|
|
15
7
|
export declare class TicketDetailScreen extends TicketContentScreen {
|
|
16
8
|
static readonly route: {
|
|
17
9
|
id: string;
|
|
@@ -34,5 +26,8 @@ export declare class TicketDetailScreen extends TicketContentScreen {
|
|
|
34
26
|
context: (params: Readonly<Record<string, string>>, state: unknown, base: import("../../../Routing/context.js").ContextBag) => import("../../../Routing/context.js").ContextBag;
|
|
35
27
|
};
|
|
36
28
|
readonly id: string;
|
|
37
|
-
|
|
29
|
+
readonly tab = "overview";
|
|
30
|
+
protected readonly includes: string[];
|
|
31
|
+
protected renderLoading(): string[];
|
|
32
|
+
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
38
33
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { flattenSections } from '../../../Component/section-list/index.js';
|
|
2
2
|
import { detailSections, sectionsForTab, } from '../Component/ticket-detail/index.js';
|
|
3
3
|
import { ticketInputContext } from '../Data/input.js';
|
|
4
|
-
import {
|
|
4
|
+
import { TicketContentScreen } from './ticket-content-screen.js';
|
|
5
5
|
export { ticketDetailInputContext } from '../Data/input.js';
|
|
6
6
|
const INCLUDES = [
|
|
7
7
|
'labels',
|
|
@@ -18,23 +18,7 @@ const INCLUDES = [
|
|
|
18
18
|
'sub_tickets',
|
|
19
19
|
'referenced_tickets',
|
|
20
20
|
];
|
|
21
|
-
/**
|
|
22
|
-
class TicketOverviewController extends TicketContentController {
|
|
23
|
-
id = TicketDetailScreen.route.id;
|
|
24
|
-
tab = 'overview';
|
|
25
|
-
includes = INCLUDES;
|
|
26
|
-
renderLoading() {
|
|
27
|
-
return ['Loading ticket…'];
|
|
28
|
-
}
|
|
29
|
-
fullNonInteractive(document, context) {
|
|
30
|
-
const nowSeconds = context.nowSeconds?.() ?? Math.floor(Date.now() / 1000);
|
|
31
|
-
return flattenSections([
|
|
32
|
-
...detailSections(document, this.labels, nowSeconds).filter((section) => section.heading === 'State' || section.heading === 'Labels'),
|
|
33
|
-
...sectionsForTab(document, 0, this.labels, nowSeconds),
|
|
34
|
-
]).lines;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/** Public Overview route: ReactScreen wrapper around the overview controller. */
|
|
21
|
+
/** Public Overview route: the ticket's overview view and its interaction state. */
|
|
38
22
|
export class TicketDetailScreen extends TicketContentScreen {
|
|
39
23
|
static route = {
|
|
40
24
|
id: 'ticket.detail',
|
|
@@ -49,5 +33,16 @@ export class TicketDetailScreen extends TicketContentScreen {
|
|
|
49
33
|
context: ticketInputContext,
|
|
50
34
|
};
|
|
51
35
|
id = TicketDetailScreen.route.id;
|
|
52
|
-
|
|
36
|
+
tab = 'overview';
|
|
37
|
+
includes = INCLUDES;
|
|
38
|
+
renderLoading() {
|
|
39
|
+
return ['Loading ticket…'];
|
|
40
|
+
}
|
|
41
|
+
fullNonInteractive(document, context) {
|
|
42
|
+
const nowSeconds = context.nowSeconds?.() ?? Math.floor(Date.now() / 1000);
|
|
43
|
+
return flattenSections([
|
|
44
|
+
...detailSections(document, this.labels, nowSeconds).filter((section) => section.heading === 'State' || section.heading === 'Labels'),
|
|
45
|
+
...sectionsForTab(document, 0, this.labels, nowSeconds),
|
|
46
|
+
]).lines;
|
|
47
|
+
}
|
|
53
48
|
}
|
|
@@ -105,18 +105,11 @@ export class TicketFilterBar {
|
|
|
105
105
|
}
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
|
-
if (!this.disable.has('search') && input === '/') {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
108
|
return false;
|
|
112
109
|
}
|
|
113
110
|
applyTo(row) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
row.identifier.toLocaleLowerCase().includes(query) ||
|
|
117
|
-
row.title.toLocaleLowerCase().includes(query)) &&
|
|
118
|
-
(this.host.criteria.state === null ||
|
|
119
|
-
row.state === this.host.criteria.state) &&
|
|
111
|
+
return ((this.host.criteria.state === null ||
|
|
112
|
+
row.state === this.host.criteria.state) &&
|
|
120
113
|
(this.host.criteria.closed === null ||
|
|
121
114
|
row.closed === this.host.criteria.closed) &&
|
|
122
115
|
(this.host.criteria.parent === null ||
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import type { ScreenContext } from '../../../Screen/screen.js';
|
|
2
2
|
import type { TicketDetailDocument } from '../../../types.js';
|
|
3
|
-
import {
|
|
4
|
-
/**
|
|
5
|
-
declare class TicketPlanningController extends TicketContentController {
|
|
6
|
-
readonly id: string;
|
|
7
|
-
readonly tab = "planning";
|
|
8
|
-
protected readonly includes: string[];
|
|
9
|
-
protected renderLoading(): string[];
|
|
10
|
-
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
11
|
-
}
|
|
12
|
-
/** Public Planning route: ReactScreen wrapper around the planning controller. */
|
|
3
|
+
import { TicketContentScreen } from './ticket-content-screen.js';
|
|
4
|
+
/** Public Planning route: the ticket's planning view and its interaction state. */
|
|
13
5
|
export declare class TicketPlanningScreen extends TicketContentScreen {
|
|
14
6
|
static readonly route: {
|
|
15
7
|
id: string;
|
|
@@ -27,6 +19,8 @@ export declare class TicketPlanningScreen extends TicketContentScreen {
|
|
|
27
19
|
context: (params: Readonly<Record<string, string>>, state: unknown, base: import("../../../Routing/context.js").ContextBag) => import("../../../Routing/context.js").ContextBag;
|
|
28
20
|
};
|
|
29
21
|
readonly id: string;
|
|
30
|
-
|
|
22
|
+
readonly tab = "planning";
|
|
23
|
+
protected readonly includes: string[];
|
|
24
|
+
protected renderLoading(): string[];
|
|
25
|
+
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
31
26
|
}
|
|
32
|
-
export {};
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { flattenSections } from '../../../Component/section-list/index.js';
|
|
2
2
|
import { ticketContentModel } from '../Component/ticket-content/model.js';
|
|
3
3
|
import { ticketInputContext } from '../Data/input.js';
|
|
4
|
-
import {
|
|
4
|
+
import { TicketContentScreen } from './ticket-content-screen.js';
|
|
5
5
|
const INCLUDES = ['comments', 'labels'];
|
|
6
|
-
/**
|
|
7
|
-
class
|
|
6
|
+
/** Public Planning route: the ticket's planning view and its interaction state. */
|
|
7
|
+
export class TicketPlanningScreen extends TicketContentScreen {
|
|
8
|
+
static route = {
|
|
9
|
+
id: 'ticket.planning',
|
|
10
|
+
path: '/tickets/:ticketId/planning',
|
|
11
|
+
parent: 'project.tickets',
|
|
12
|
+
tab: { id: 'planning', label: 'Planning', scope: 'ticket', weight: 15 },
|
|
13
|
+
fallback: { routeId: 'my.work' },
|
|
14
|
+
context: ticketInputContext,
|
|
15
|
+
};
|
|
8
16
|
id = TicketPlanningScreen.route.id;
|
|
9
17
|
tab = 'planning';
|
|
10
18
|
includes = INCLUDES;
|
|
@@ -19,16 +27,3 @@ class TicketPlanningController extends TicketContentController {
|
|
|
19
27
|
}))).lines;
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
|
-
/** Public Planning route: ReactScreen wrapper around the planning controller. */
|
|
23
|
-
export class TicketPlanningScreen extends TicketContentScreen {
|
|
24
|
-
static route = {
|
|
25
|
-
id: 'ticket.planning',
|
|
26
|
-
path: '/tickets/:ticketId/planning',
|
|
27
|
-
parent: 'project.tickets',
|
|
28
|
-
tab: { id: 'planning', label: 'Planning', scope: 'ticket', weight: 15 },
|
|
29
|
-
fallback: { routeId: 'my.work' },
|
|
30
|
-
context: ticketInputContext,
|
|
31
|
-
};
|
|
32
|
-
id = TicketPlanningScreen.route.id;
|
|
33
|
-
controller = new TicketPlanningController();
|
|
34
|
-
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type VNode } from '@opentui/core';
|
|
2
|
+
import { AsyncScreen, type FullScreenChrome } from '../../../Screen/async-screen.js';
|
|
2
3
|
import type { ScreenContext } from '../../../Screen/screen.js';
|
|
3
4
|
/** A separate document screen using the kernel's existing scrolling viewport. */
|
|
4
|
-
export declare class TicketReactMarkdownScreen extends
|
|
5
|
+
export declare class TicketReactMarkdownScreen extends AsyncScreen<true> {
|
|
5
6
|
static readonly route: {
|
|
6
7
|
id: string;
|
|
7
8
|
path: string;
|
|
@@ -19,10 +20,11 @@ export declare class TicketReactMarkdownScreen extends ReactScreen {
|
|
|
19
20
|
};
|
|
20
21
|
readonly id: string;
|
|
21
22
|
readonly frameId = "ticket";
|
|
22
|
-
protected
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
protected load(): Promise<true>;
|
|
24
|
+
enter(context: ScreenContext): void;
|
|
25
|
+
protected renderLoading(): string[];
|
|
26
|
+
protected flushBody(): boolean;
|
|
27
|
+
protected renderReady(_data: true, context: ScreenContext): VNode;
|
|
28
|
+
protected chrome(context: ScreenContext): FullScreenChrome;
|
|
27
29
|
renderNonInteractive(context: ScreenContext): string[];
|
|
28
30
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { BoxRenderable, h } from '@opentui/core';
|
|
2
|
+
import { Markdown } from '../../../Component/markdown/index.js';
|
|
3
|
+
import { FOREGROUND, paragraphNode, plainRun } from '../../../lib/vnode.js';
|
|
4
|
+
import { AsyncScreen, } from '../../../Screen/async-screen.js';
|
|
5
5
|
import { ticketHeaderTree, ticketTitleOf, } from '../Component/ticket-detail/index.js';
|
|
6
6
|
import { ticketInputContext } from '../Data/input.js';
|
|
7
7
|
import { readTicket } from '../Data/store.js';
|
|
8
|
+
const ID = 'ticket-markdown-demo';
|
|
8
9
|
function ticketDescription(context) {
|
|
9
10
|
const description = readTicket(context).data?.attributes?.description;
|
|
10
11
|
if (typeof description === 'string')
|
|
@@ -24,10 +25,10 @@ const EXAMPLE = [
|
|
|
24
25
|
'> The native ticket header and tabs stay visible while the document scrolls.',
|
|
25
26
|
'',
|
|
26
27
|
'- **Strong emphasis**, *italic text* and `inline code`.',
|
|
27
|
-
'- A [
|
|
28
|
+
'- A [documentation link](https://example.test/docs) remains visible with its destination.',
|
|
28
29
|
'',
|
|
29
30
|
'```ts',
|
|
30
|
-
'const screen = "
|
|
31
|
+
'const screen = "NativeScreen";',
|
|
31
32
|
'render({ statistics: true, markdown: true });',
|
|
32
33
|
'```',
|
|
33
34
|
'',
|
|
@@ -44,12 +45,8 @@ const EXAMPLE = [
|
|
|
44
45
|
'',
|
|
45
46
|
'You reached the bottom. Scroll back up to the actual ticket description.',
|
|
46
47
|
].join('\n');
|
|
47
|
-
function Preview({ description }) {
|
|
48
|
-
const { width } = useTerminalDimensions();
|
|
49
|
-
return (_jsxs("box", { flexDirection: "column", gap: 1, children: [_jsx("text", { children: "Markdown preview \u00B7 \u2191\u2193 / j,k / mouse wheel: scroll" }), _jsx(Markdown, { width: Math.max(16, width - 12), children: `# Ticket description\n\n${description}\n\n---\n\n${EXAMPLE}` })] }));
|
|
50
|
-
}
|
|
51
48
|
/** A separate document screen using the kernel's existing scrolling viewport. */
|
|
52
|
-
export class TicketReactMarkdownScreen extends
|
|
49
|
+
export class TicketReactMarkdownScreen extends AsyncScreen {
|
|
53
50
|
static route = {
|
|
54
51
|
id: 'ticket.react-markdown',
|
|
55
52
|
path: '/tickets/:ticketId/react-markdown',
|
|
@@ -65,8 +62,34 @@ export class TicketReactMarkdownScreen extends ReactScreen {
|
|
|
65
62
|
};
|
|
66
63
|
id = TicketReactMarkdownScreen.route.id;
|
|
67
64
|
frameId = 'ticket';
|
|
68
|
-
|
|
69
|
-
return
|
|
65
|
+
load() {
|
|
66
|
+
return Promise.resolve(true);
|
|
67
|
+
}
|
|
68
|
+
enter(context) {
|
|
69
|
+
super.enter(context);
|
|
70
|
+
// The document is the ticket already in context: ready at once.
|
|
71
|
+
if (this.state !== 'ready') {
|
|
72
|
+
this.replaceReady(true);
|
|
73
|
+
context.requestDraw();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
renderLoading() {
|
|
77
|
+
return ['Loading Markdown preview…'];
|
|
78
|
+
}
|
|
79
|
+
flushBody() {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
renderReady(_data, context) {
|
|
83
|
+
const width = context.terminalColumns ?? 80;
|
|
84
|
+
return h(BoxRenderable, { id: ID, flexDirection: 'column', gap: 1 }, paragraphNode({
|
|
85
|
+
id: `${ID}-hint`,
|
|
86
|
+
runs: [plainRun('Markdown preview · ↑↓ / j,k / mouse wheel: scroll')],
|
|
87
|
+
fg: FOREGROUND,
|
|
88
|
+
}), Markdown({
|
|
89
|
+
id: `${ID}-document`,
|
|
90
|
+
width: Math.max(16, width - 12),
|
|
91
|
+
source: `# Ticket description\n\n${ticketDescription(context)}\n\n---\n\n${EXAMPLE}`,
|
|
92
|
+
}));
|
|
70
93
|
}
|
|
71
94
|
chrome(context) {
|
|
72
95
|
const document = readTicket(context);
|