@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
|
@@ -100,10 +100,13 @@ export function buildTeamMemberTicketQueryParams(userId, projectIds, criteria, o
|
|
|
100
100
|
* open only, newest-changed first. Not project-scoped: a conductor may serve
|
|
101
101
|
* more than one project.
|
|
102
102
|
*/
|
|
103
|
-
export function buildConductorTicketQueryParams(conductorId, page = { size: PAGE_SIZE, index: 0 }) {
|
|
103
|
+
export function buildConductorTicketQueryParams(conductorId, page = { size: PAGE_SIZE, index: 0 }, query = '') {
|
|
104
104
|
const params = new DrupalJsonApiParams();
|
|
105
105
|
params.addFilter('conductor_id.id', conductorId);
|
|
106
106
|
params.addFilter('closed', '0');
|
|
107
|
+
// The `/` line, resolved server-side exactly as on the project list.
|
|
108
|
+
if (query)
|
|
109
|
+
params.addFilter('search', query);
|
|
107
110
|
params.addInclude(['parent_id', 'conductor_id']);
|
|
108
111
|
params.addFields('gaia_conductor--gaia_conductor', TICKET_CONDUCTOR_INCLUDE_FIELDS);
|
|
109
112
|
params.addFields('gaia_ticket--gaia_ticket', TICKET_LIST_FIELDS);
|
|
@@ -115,11 +118,12 @@ export function buildConductorTicketQueryParams(conductorId, page = { size: PAGE
|
|
|
115
118
|
return params;
|
|
116
119
|
}
|
|
117
120
|
function applyTicketCriteria(params, criteria, options) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// The typed line goes to the server verbatim (GAIA-544): it resolves
|
|
122
|
+
// `#19`, `gaia#19` and origin URLs to their tickets, and turns anything else
|
|
123
|
+
// into the identifier OR title CONTAINS match this used to build. The grammar
|
|
124
|
+
// lives once, server-side, so the terminal and the web list cannot drift.
|
|
125
|
+
if (criteria.query)
|
|
126
|
+
params.addFilter('search', criteria.query);
|
|
123
127
|
if (criteria.state)
|
|
124
128
|
params.addFilter('state', criteria.state);
|
|
125
129
|
// '1'/'0', never the boolean: the backend's integer-backed boolean storage
|
|
@@ -127,16 +131,16 @@ function applyTicketCriteria(params, criteria, options) {
|
|
|
127
131
|
if (criteria.closed !== null)
|
|
128
132
|
params.addFilter('closed', criteria.closed ? '1' : '0');
|
|
129
133
|
// Direct children only; top level, so it ANDs with project/state while
|
|
130
|
-
// the search
|
|
134
|
+
// the search stays untouched (AC-5).
|
|
131
135
|
if (criteria.parent)
|
|
132
136
|
params.addFilter('parent_id.id', criteria.parent.id);
|
|
133
137
|
// Assigned to this user only; a top-level AND like parent, never part of
|
|
134
|
-
// the search
|
|
138
|
+
// the search (GAIA-299 AC-4). Skipped when the builder itself is
|
|
135
139
|
// already scoped to an assignee (user ticket list).
|
|
136
140
|
if (criteria.who)
|
|
137
141
|
params.addFilter('assignee_user_id.id', criteria.who.id);
|
|
138
142
|
// Owned by (created by) this user only; a top-level AND like who/parent,
|
|
139
|
-
// never part of the search
|
|
143
|
+
// never part of the search (GAIA-416). `owner_user_id` is the
|
|
140
144
|
// entity's owner key — see `ticket-detail/index.ts` — and is unrelated to
|
|
141
145
|
// the web-UI's `owner` exposed-Views facet.
|
|
142
146
|
if (criteria.owner)
|
|
@@ -11,7 +11,7 @@ const ticketKey = (id) => dataKey(`ticket/${id}`);
|
|
|
11
11
|
* requests but this list omits is always "missing", so the store retries a
|
|
12
12
|
* fetch for it on every `enter()` even though the supplied document already
|
|
13
13
|
* has nothing more to give. That retry does not merely waste a round trip:
|
|
14
|
-
* `
|
|
14
|
+
* `TicketContentScreen.enter()`'s `watchTicket` subscription and the
|
|
15
15
|
* retry's own `start()` both react to the same store write and race to bump
|
|
16
16
|
* `this.revision`, and whichever loses leaves `AsyncScreen.busy` stuck TRUE
|
|
17
17
|
* forever — measured as `renderPipe`'s `settledActive` spinning until the
|
|
@@ -330,7 +330,7 @@ export type TicketPage = Page<TicketRow>;
|
|
|
330
330
|
* screen happens to be holding. `null` when the server reports no count, which
|
|
331
331
|
* `readTotal` already treats as the explicit unknown rather than as a zero.
|
|
332
332
|
*
|
|
333
|
-
* It builds the SAME query as {@link loadFilteredTickets} — the same
|
|
333
|
+
* It builds the SAME query as {@link loadFilteredTickets} — the same `filter[search]` over
|
|
334
334
|
* identifier/title, the same project/state/parent/who ANDs — with exactly one
|
|
335
335
|
* criterion removed. That is what makes the number it returns an answer to "how
|
|
336
336
|
* many is `closed` holding back" and not to some other question; a second,
|
|
@@ -298,7 +298,7 @@ export function mapTicketDocument(document) {
|
|
|
298
298
|
* screen happens to be holding. `null` when the server reports no count, which
|
|
299
299
|
* `readTotal` already treats as the explicit unknown rather than as a zero.
|
|
300
300
|
*
|
|
301
|
-
* It builds the SAME query as {@link loadFilteredTickets} — the same
|
|
301
|
+
* It builds the SAME query as {@link loadFilteredTickets} — the same `filter[search]` over
|
|
302
302
|
* identifier/title, the same project/state/parent/who ANDs — with exactly one
|
|
303
303
|
* criterion removed. That is what makes the number it returns an answer to "how
|
|
304
304
|
* many is `closed` holding back" and not to some other question; a second,
|
|
@@ -112,6 +112,18 @@ export declare const EDIT_FORM_TERMINAL: {
|
|
|
112
112
|
apply(s: FormState<EditValues>, options: EditFormOptions, intent: import("../../../Form/form.js").Intent): FormState<EditValues>;
|
|
113
113
|
toObject: (s: FormState<EditValues>, options: EditFormOptions) => EditFormPayload;
|
|
114
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* A closed ticket's popup: read-only, no Save and no Cancel ticket. The server
|
|
117
|
+
* freezes a ticket on its stored `closed` flag and answers any PATCH with 403.
|
|
118
|
+
*/
|
|
119
|
+
export declare const EDIT_FORM_CLOSED: {
|
|
120
|
+
fields: import("../../../Form/field.js").FieldDecl[];
|
|
121
|
+
activeField: (s: FormState<EditValues>) => import("../../../Form/field.js").FieldDecl;
|
|
122
|
+
move: (s: FormState<EditValues>, d: number) => FormState<EditValues>;
|
|
123
|
+
initial(options: EditFormOptions, prefill?: Partial<EditValues>): FormState<EditValues>;
|
|
124
|
+
apply(s: FormState<EditValues>, options: EditFormOptions, intent: import("../../../Form/form.js").Intent): FormState<EditValues>;
|
|
125
|
+
toObject: (s: FormState<EditValues>, options: EditFormOptions) => EditFormPayload;
|
|
126
|
+
};
|
|
115
127
|
export type EditFormDeclaration = typeof EDIT_FORM;
|
|
116
128
|
/** The ticket's state as the popup sees it; `''` when the read carried none. */
|
|
117
129
|
export declare const ticketState: (document: TicketDetailDocument) => string;
|
|
@@ -127,6 +139,7 @@ export declare const editFormFor: (document: TicketDetailDocument) => EditFormDe
|
|
|
127
139
|
/** Field order in the popup, per declaration. */
|
|
128
140
|
export declare const EDIT_FIELDS: FieldDef<EditFieldId>[];
|
|
129
141
|
export declare const EDIT_FIELDS_TERMINAL: FieldDef<EditFieldId>[];
|
|
142
|
+
export declare const EDIT_FIELDS_CLOSED: FieldDef<EditFieldId>[];
|
|
130
143
|
export type EditFormState = FormState<EditValues>;
|
|
131
144
|
/**
|
|
132
145
|
* No lists to OFFER — bags start empty until the adapter / option loader fills
|
|
@@ -102,7 +102,7 @@ const timeAttributes = (v) => {
|
|
|
102
102
|
* every index below it; absence has to be a property of WHICH DECLARATION is in
|
|
103
103
|
* force.
|
|
104
104
|
*/
|
|
105
|
-
const declareEditForm = (cancellable) => declareForm({
|
|
105
|
+
const declareEditForm = (savable, cancellable) => declareForm({
|
|
106
106
|
fields: (f) => [
|
|
107
107
|
f.select('assignee', 'Assignee', { from: 'users', clearable: true }),
|
|
108
108
|
f.select('conductor', 'Conductor', {
|
|
@@ -119,7 +119,7 @@ const declareEditForm = (cancellable) => declareForm({
|
|
|
119
119
|
pageSize: PARENT_PAGE_SIZE,
|
|
120
120
|
}),
|
|
121
121
|
f.multi('labels', 'Labels', { from: 'labels' }),
|
|
122
|
-
f.action('Save', 'submit'),
|
|
122
|
+
...(savable ? [f.action('Save', 'submit')] : []),
|
|
123
123
|
...(cancellable
|
|
124
124
|
? [f.action('Cancel ticket', CANCEL_TICKET_ACTION_ID)]
|
|
125
125
|
: []),
|
|
@@ -136,9 +136,14 @@ const declareEditForm = (cancellable) => declareForm({
|
|
|
136
136
|
}),
|
|
137
137
|
});
|
|
138
138
|
/** The ordinary popup: a non-terminal ticket can be cancelled from it. */
|
|
139
|
-
export const EDIT_FORM = declareEditForm(true);
|
|
139
|
+
export const EDIT_FORM = declareEditForm(true, true);
|
|
140
140
|
/** A terminal ticket's popup: assignment, times, structure — no Cancel ticket. */
|
|
141
|
-
export const EDIT_FORM_TERMINAL = declareEditForm(false);
|
|
141
|
+
export const EDIT_FORM_TERMINAL = declareEditForm(true, false);
|
|
142
|
+
/**
|
|
143
|
+
* A closed ticket's popup: read-only, no Save and no Cancel ticket. The server
|
|
144
|
+
* freezes a ticket on its stored `closed` flag and answers any PATCH with 403.
|
|
145
|
+
*/
|
|
146
|
+
export const EDIT_FORM_CLOSED = declareEditForm(false, false);
|
|
142
147
|
/** The ticket's state as the popup sees it; `''` when the read carried none. */
|
|
143
148
|
export const ticketState = (document) => {
|
|
144
149
|
const value = document.data?.attributes?.state;
|
|
@@ -152,12 +157,17 @@ export const ticketState = (document) => {
|
|
|
152
157
|
* Cancel ticket on a thin read would cost a legitimate affordance; offering it
|
|
153
158
|
* costs at worst the server's 422, which the popup already renders in full.
|
|
154
159
|
*/
|
|
155
|
-
export const editFormFor = (document) =>
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
export const editFormFor = (document) => {
|
|
161
|
+
if (document.data?.attributes?.closed === true)
|
|
162
|
+
return EDIT_FORM_CLOSED;
|
|
163
|
+
return TERMINAL_TICKET_STATES.has(ticketState(document))
|
|
164
|
+
? EDIT_FORM_TERMINAL
|
|
165
|
+
: EDIT_FORM;
|
|
166
|
+
};
|
|
158
167
|
/** Field order in the popup, per declaration. */
|
|
159
168
|
export const EDIT_FIELDS = EDIT_FORM.fields;
|
|
160
169
|
export const EDIT_FIELDS_TERMINAL = EDIT_FORM_TERMINAL.fields;
|
|
170
|
+
export const EDIT_FIELDS_CLOSED = EDIT_FORM_CLOSED.fields;
|
|
161
171
|
/**
|
|
162
172
|
* No lists to OFFER — bags start empty until the adapter / option loader fills
|
|
163
173
|
* them. Prefill names every value, and `clear`/`toObject` read no option list
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FullScreenChrome } from '../../../Screen/full-screen.js';
|
|
1
|
+
import type { FullScreenChrome, ListFilterBadge } from '../../../Screen/full-screen.js';
|
|
2
2
|
import { ListScreen } from '../../../Screen/list-screen.js';
|
|
3
3
|
import type { ScreenContext } from '../../../Screen/screen.js';
|
|
4
4
|
import { type Page } from '../../collection.js';
|
|
@@ -69,16 +69,22 @@ export declare class ConductorTicketsScreen extends ListScreen<TicketRow, void>
|
|
|
69
69
|
}];
|
|
70
70
|
readonly emptyMessage: "No ticket is assigned to this conductor.";
|
|
71
71
|
};
|
|
72
|
+
searchQuery: string;
|
|
73
|
+
private readonly search;
|
|
74
|
+
reloadSearch(context: ScreenContext): Promise<boolean>;
|
|
72
75
|
protected tableContext(): void;
|
|
73
76
|
protected loadRows(context: ScreenContext, page: number): Promise<Page<TicketRow>>;
|
|
74
77
|
protected renderLoading(): string[];
|
|
75
78
|
protected chrome(): FullScreenChrome;
|
|
79
|
+
protected badges(): readonly ListFilterBadge[];
|
|
80
|
+
protected notice(): string | undefined;
|
|
76
81
|
protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
|
|
77
82
|
activate(index: number, context: ScreenContext): boolean;
|
|
78
83
|
select(index: number, context: ScreenContext): boolean;
|
|
79
84
|
handleInput(input: string, context: ScreenContext): boolean;
|
|
80
85
|
private headerDetail;
|
|
81
86
|
protected didLoad(_data: Page<TicketRow>, context: ScreenContext): void;
|
|
87
|
+
leave(): void;
|
|
82
88
|
reset(): void;
|
|
83
89
|
/** The pipe's own text — the same table + rows the drawn tree uses. */
|
|
84
90
|
renderNonInteractive(): string[];
|
|
@@ -7,6 +7,7 @@ import { conductorTitle } from '../../conductor/Screen/conductor-overview.js';
|
|
|
7
7
|
import { LIST_PAGE_SIZE } from '../../cycle.js';
|
|
8
8
|
import { buildConductorTicketQueryParams } from '../Data/query.js';
|
|
9
9
|
import { CONDUCTOR_TICKET_TABLE, mapTicketData, } from '../Data/tickets.js';
|
|
10
|
+
import { TicketSearch } from './ticket-search.js';
|
|
10
11
|
/** Assigned — the open tickets held by one conductor. */
|
|
11
12
|
export class ConductorTicketsScreen extends ListScreen {
|
|
12
13
|
static route = {
|
|
@@ -19,6 +20,13 @@ export class ConductorTicketsScreen extends ListScreen {
|
|
|
19
20
|
id = ConductorTicketsScreen.route.id;
|
|
20
21
|
frameId = 'conductor';
|
|
21
22
|
table = CONDUCTOR_TICKET_TABLE;
|
|
23
|
+
searchQuery = '';
|
|
24
|
+
search = new TicketSearch(this);
|
|
25
|
+
reloadSearch(context) {
|
|
26
|
+
this.page = 0;
|
|
27
|
+
this.selectedIndex = 0;
|
|
28
|
+
return this.reloadInPlace(context);
|
|
29
|
+
}
|
|
22
30
|
tableContext() {
|
|
23
31
|
// No clock/context needed for this table.
|
|
24
32
|
}
|
|
@@ -27,10 +35,7 @@ export class ConductorTicketsScreen extends ListScreen {
|
|
|
27
35
|
throw new Error('Assigned requires services');
|
|
28
36
|
const conductorId = context.params?.conductorId ?? '';
|
|
29
37
|
const window = { offset: page * LIST_PAGE_SIZE, limit: LIST_PAGE_SIZE };
|
|
30
|
-
const params = buildConductorTicketQueryParams(conductorId, {
|
|
31
|
-
size: window.limit,
|
|
32
|
-
index: page,
|
|
33
|
-
});
|
|
38
|
+
const params = buildConductorTicketQueryParams(conductorId, { size: window.limit, index: page }, this.searchQuery);
|
|
34
39
|
return loadPage(context.services.client, 'gaia_ticket/gaia_ticket', params, (data, included) => {
|
|
35
40
|
const index = new Map(included.filter((r) => r.id).map((r) => [r.id, r]));
|
|
36
41
|
return data.map((item) => mapTicketData(item, index));
|
|
@@ -45,11 +50,22 @@ export class ConductorTicketsScreen extends ListScreen {
|
|
|
45
50
|
selectedIndex: this.selectedIndex,
|
|
46
51
|
rowIds: this.rowNodeIds,
|
|
47
52
|
title: conductorTitle(this.headerDetail),
|
|
48
|
-
meta: [
|
|
53
|
+
meta: [
|
|
54
|
+
[this.countLabel(), ...this.pagingSegments()]
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.join(' · '),
|
|
57
|
+
this.search.hint(),
|
|
58
|
+
]
|
|
49
59
|
.filter(Boolean)
|
|
50
|
-
.join('
|
|
60
|
+
.join(' · '),
|
|
51
61
|
};
|
|
52
62
|
}
|
|
63
|
+
badges() {
|
|
64
|
+
return [this.search.badge()];
|
|
65
|
+
}
|
|
66
|
+
notice() {
|
|
67
|
+
return this.search.status || undefined;
|
|
68
|
+
}
|
|
53
69
|
actions() {
|
|
54
70
|
return [
|
|
55
71
|
...(this.rows.length > 0
|
|
@@ -76,6 +92,8 @@ export class ConductorTicketsScreen extends ListScreen {
|
|
|
76
92
|
handleInput(input, context) {
|
|
77
93
|
if (super.handleInput(input, context))
|
|
78
94
|
return true;
|
|
95
|
+
if (this.search.handleKey(input, context))
|
|
96
|
+
return true;
|
|
79
97
|
if (this.handlePagingInput(input, context))
|
|
80
98
|
return true;
|
|
81
99
|
if (this.handleCursorInput(input, context))
|
|
@@ -94,8 +112,14 @@ export class ConductorTicketsScreen extends ListScreen {
|
|
|
94
112
|
context.requestDraw();
|
|
95
113
|
});
|
|
96
114
|
}
|
|
115
|
+
leave() {
|
|
116
|
+
this.search.close();
|
|
117
|
+
super.leave();
|
|
118
|
+
}
|
|
97
119
|
reset() {
|
|
98
120
|
this.resetList();
|
|
121
|
+
this.searchQuery = '';
|
|
122
|
+
this.search.reset();
|
|
99
123
|
this.headerDetail = undefined;
|
|
100
124
|
super.reset();
|
|
101
125
|
}
|
|
@@ -33,7 +33,7 @@ export declare class EditAssignmentFormScreen extends AsyncModalScreen<EditAssig
|
|
|
33
33
|
* Chosen once, in `didLoad`, and used for BOTH the rendered rows and the key
|
|
34
34
|
* routing — the kernel indexes its field array by `state.active`, so two
|
|
35
35
|
* sources for that array is two ways to disagree about which row the `▸`
|
|
36
|
-
* marker is on. Defaults to the
|
|
36
|
+
* marker is on. Defaults to the closed (read-only) declaration: a screen
|
|
37
37
|
* that somehow renders before its document has arrived offers less rather
|
|
38
38
|
* than more.
|
|
39
39
|
*/
|
|
@@ -86,6 +86,8 @@ export declare class EditAssignmentFormScreen extends AsyncModalScreen<EditAssig
|
|
|
86
86
|
leave(): void;
|
|
87
87
|
reset(): void;
|
|
88
88
|
protected modalChrome(context: ScreenContext): ModalChrome;
|
|
89
|
+
/** Whether this ticket's popup can write at all; a closed one cannot. */
|
|
90
|
+
private get savable();
|
|
89
91
|
protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
|
|
90
92
|
}
|
|
91
93
|
export {};
|
|
@@ -9,7 +9,7 @@ import { activeRunInfo } from '../../run/Data/active-run.js';
|
|
|
9
9
|
import { resolveWhoCandidate } from '../../user/Data/users.js';
|
|
10
10
|
import { EDIT_FORM_REGION, editFormTree, } from '../Component/edit-form/index.js';
|
|
11
11
|
import { loadTicketDetail } from '../Data/detail.js';
|
|
12
|
-
import { CANCEL_TICKET_ACTION_ID, cancelEditPayload,
|
|
12
|
+
import { CANCEL_TICKET_ACTION_ID, cancelEditPayload, EDIT_FORM_CLOSED, EMPTY_EDIT_FORM_OPTIONS, editFormFor, initialEditForm, serializeEdit, } from '../Form/edit.js';
|
|
13
13
|
import { loadEditFormOptions } from '../Form/edit-data.js';
|
|
14
14
|
import { editParentOptionSource } from '../Form/edit-parent-source.js';
|
|
15
15
|
import { keyToIntent } from '../Form/keys.js';
|
|
@@ -44,11 +44,11 @@ export class EditAssignmentFormScreen extends AsyncModalScreen {
|
|
|
44
44
|
* Chosen once, in `didLoad`, and used for BOTH the rendered rows and the key
|
|
45
45
|
* routing — the kernel indexes its field array by `state.active`, so two
|
|
46
46
|
* sources for that array is two ways to disagree about which row the `▸`
|
|
47
|
-
* marker is on. Defaults to the
|
|
47
|
+
* marker is on. Defaults to the closed (read-only) declaration: a screen
|
|
48
48
|
* that somehow renders before its document has arrived offers less rather
|
|
49
49
|
* than more.
|
|
50
50
|
*/
|
|
51
|
-
declaration =
|
|
51
|
+
declaration = EDIT_FORM_CLOSED;
|
|
52
52
|
form;
|
|
53
53
|
action;
|
|
54
54
|
message = '';
|
|
@@ -223,12 +223,19 @@ export class EditAssignmentFormScreen extends AsyncModalScreen {
|
|
|
223
223
|
return true;
|
|
224
224
|
if (intent.kind === 'cancel')
|
|
225
225
|
this.action = { type: 'back' };
|
|
226
|
+
else if (intent.kind === 'submit' && !this.savable) {
|
|
227
|
+
// A closed ticket's popup is read-only: Ctrl+S writes nothing.
|
|
228
|
+
this.message = 'This ticket is closed and read-only.';
|
|
229
|
+
}
|
|
226
230
|
else if (intent.kind === 'submit') {
|
|
227
231
|
// D10: Ctrl+S ALWAYS Save, even when the cursor is on Cancel ticket.
|
|
228
232
|
// Only Enter/submit while standing on the cancelTicket action cancels.
|
|
229
233
|
const cancelTicket = input !== 'ctrl+s' && field.id === CANCEL_TICKET_ACTION_ID;
|
|
230
234
|
this.submit(context, data, cancelTicket);
|
|
231
235
|
}
|
|
236
|
+
else if (!this.savable && intent.kind !== 'move') {
|
|
237
|
+
// A closed ticket's values stay as they are; only ↑↓ moves.
|
|
238
|
+
}
|
|
232
239
|
else {
|
|
233
240
|
this.form = this.declaration.apply(this.form, data.options, intent);
|
|
234
241
|
if (field.query !== undefined &&
|
|
@@ -258,7 +265,7 @@ export class EditAssignmentFormScreen extends AsyncModalScreen {
|
|
|
258
265
|
super.leave();
|
|
259
266
|
}
|
|
260
267
|
reset() {
|
|
261
|
-
this.declaration =
|
|
268
|
+
this.declaration = EDIT_FORM_CLOSED;
|
|
262
269
|
this.form = undefined;
|
|
263
270
|
this.action = undefined;
|
|
264
271
|
this.message = '';
|
|
@@ -279,12 +286,20 @@ export class EditAssignmentFormScreen extends AsyncModalScreen {
|
|
|
279
286
|
''),
|
|
280
287
|
};
|
|
281
288
|
}
|
|
289
|
+
/** Whether this ticket's popup can write at all; a closed one cannot. */
|
|
290
|
+
get savable() {
|
|
291
|
+
return this.declaration.fields.some((f) => f.id === 'submit');
|
|
292
|
+
}
|
|
282
293
|
actions() {
|
|
283
294
|
// GAIA-360 D12 — Esc:close (not cancel); Cancel ticket is lifecycle.
|
|
284
295
|
return [
|
|
285
296
|
actionItem('edit-field', '↑↓', 'field'),
|
|
286
|
-
|
|
287
|
-
|
|
297
|
+
...(this.savable
|
|
298
|
+
? [
|
|
299
|
+
actionItem('edit-change', '←→', 'change'),
|
|
300
|
+
actionItem('edit-save', 'Ctrl+S', 'save'),
|
|
301
|
+
]
|
|
302
|
+
: []),
|
|
288
303
|
actionItem('edit-esc', 'Esc', 'close'),
|
|
289
304
|
];
|
|
290
305
|
}
|
|
@@ -24,7 +24,12 @@ export declare class MyWorkScreen extends AsyncScreen<MyWorkResult> {
|
|
|
24
24
|
private readonly cursor;
|
|
25
25
|
private currentCriteria;
|
|
26
26
|
private readonly filter;
|
|
27
|
-
private
|
|
27
|
+
private readonly search;
|
|
28
|
+
get rows(): readonly TicketRow[];
|
|
29
|
+
get searchQuery(): string;
|
|
30
|
+
set searchQuery(query: string);
|
|
31
|
+
showRows(rows: readonly TicketRow[]): void;
|
|
32
|
+
reloadSearch(context: ScreenContext): Promise<boolean>;
|
|
28
33
|
reload(context: ScreenContext): void;
|
|
29
34
|
protected load(context: ScreenContext): Promise<MyWorkResult>;
|
|
30
35
|
protected renderLoading(): string[];
|
|
@@ -38,9 +43,11 @@ export declare class MyWorkScreen extends AsyncScreen<MyWorkResult> {
|
|
|
38
43
|
* parent · project · closed · clear).
|
|
39
44
|
*/
|
|
40
45
|
protected badges(): readonly ListFilterBadge[];
|
|
46
|
+
protected notice(): string | undefined;
|
|
41
47
|
protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
|
|
42
48
|
activate(index: number, context: ScreenContext): boolean;
|
|
43
49
|
handleInput(input: string, context: ScreenContext): boolean;
|
|
50
|
+
leave(): void;
|
|
44
51
|
reset(): void;
|
|
45
52
|
get criteria(): TicketCriteria;
|
|
46
53
|
/** Reload through `retry`, mirroring `TicketsScreen.setCriteria`. */
|
|
@@ -6,6 +6,7 @@ import { resolveWhoCandidate } from '../../user/Data/users.js';
|
|
|
6
6
|
import { DEFAULT_TICKET_CRITERIA, describeCriteria, } from '../Data/query.js';
|
|
7
7
|
import { loadFilteredUserTickets, TICKET_TABLE, } from '../Data/tickets.js';
|
|
8
8
|
import { TicketFilterBar } from './ticket-filter-bar.js';
|
|
9
|
+
import { TicketSearch } from './ticket-search.js';
|
|
9
10
|
const MY_WORK_TABLE = {
|
|
10
11
|
...TICKET_TABLE,
|
|
11
12
|
emptyMessage: 'No open tickets.',
|
|
@@ -23,13 +24,33 @@ export class MyWorkScreen extends AsyncScreen {
|
|
|
23
24
|
// GAIA-540: a single bar shared with the project ticket list, disabled for
|
|
24
25
|
// `who` (My work = my tickets, the criterion is implicit) and `mine` (the
|
|
25
26
|
// shortcut makes no sense when the assignee is fixed). The bar still
|
|
26
|
-
// dispatches `s`/`x`/`p`/`r
|
|
27
|
-
// project
|
|
28
|
-
//
|
|
27
|
+
// dispatches `s`/`x`/`p`/`r`/`c`. The bar's `applyTo` still guards
|
|
28
|
+
// state/closed/parent/project on a cached re-entry; the search line is
|
|
29
|
+
// the server's.
|
|
29
30
|
filter = new TicketFilterBar(this, new Set(['who', 'mine']));
|
|
31
|
+
search = new TicketSearch(this);
|
|
30
32
|
get rows() {
|
|
31
33
|
return this.readyValue?.page.rows ?? [];
|
|
32
34
|
}
|
|
35
|
+
get searchQuery() {
|
|
36
|
+
return this.currentCriteria.query;
|
|
37
|
+
}
|
|
38
|
+
set searchQuery(query) {
|
|
39
|
+
this.currentCriteria = { ...this.currentCriteria, query };
|
|
40
|
+
}
|
|
41
|
+
showRows(rows) {
|
|
42
|
+
const current = this.readyValue;
|
|
43
|
+
if (!current)
|
|
44
|
+
return;
|
|
45
|
+
this.replaceReady({
|
|
46
|
+
...current,
|
|
47
|
+
page: { ...current.page, rows: [...rows], total: null, window: null },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
reloadSearch(context) {
|
|
51
|
+
this.cursor.reset();
|
|
52
|
+
return this.reloadInPlace(context);
|
|
53
|
+
}
|
|
33
54
|
reload(context) {
|
|
34
55
|
this.retry(context);
|
|
35
56
|
}
|
|
@@ -77,6 +98,7 @@ export class MyWorkScreen extends AsyncScreen {
|
|
|
77
98
|
`${this.rows.length} open ticket(s)`,
|
|
78
99
|
describe,
|
|
79
100
|
context.services?.workspace ?? '',
|
|
101
|
+
this.search.hint(),
|
|
80
102
|
]
|
|
81
103
|
.filter(Boolean)
|
|
82
104
|
.join(' · ');
|
|
@@ -97,6 +119,9 @@ export class MyWorkScreen extends AsyncScreen {
|
|
|
97
119
|
badges() {
|
|
98
120
|
return this.filter.badges();
|
|
99
121
|
}
|
|
122
|
+
notice() {
|
|
123
|
+
return this.search.status || undefined;
|
|
124
|
+
}
|
|
100
125
|
actions() {
|
|
101
126
|
return [
|
|
102
127
|
actionItem('my-work-open', 'Enter', 'open'),
|
|
@@ -113,7 +138,10 @@ export class MyWorkScreen extends AsyncScreen {
|
|
|
113
138
|
handleInput(input, context) {
|
|
114
139
|
if (super.handleInput(input, context))
|
|
115
140
|
return true;
|
|
116
|
-
// The
|
|
141
|
+
// The open search field takes every key, so it goes before the bar.
|
|
142
|
+
if (this.search.handleKey(input, context))
|
|
143
|
+
return true;
|
|
144
|
+
// The bar next: its key dispatch covers `s`/`x`/`p`/`r`/`c`. The
|
|
117
145
|
// cursor/enter branches stay below so the bar claims only the keys it
|
|
118
146
|
// names.
|
|
119
147
|
if (this.filter.handleKey(input, context))
|
|
@@ -126,7 +154,12 @@ export class MyWorkScreen extends AsyncScreen {
|
|
|
126
154
|
return this.activate(this.cursor.index, context);
|
|
127
155
|
return false;
|
|
128
156
|
}
|
|
157
|
+
leave() {
|
|
158
|
+
this.search.close();
|
|
159
|
+
super.leave();
|
|
160
|
+
}
|
|
129
161
|
reset() {
|
|
162
|
+
this.search.reset();
|
|
130
163
|
this.cursor.reset();
|
|
131
164
|
this.currentCriteria = { ...DEFAULT_TICKET_CRITERIA };
|
|
132
165
|
super.reset();
|
|
@@ -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 TicketCommentsController extends TicketContentController {
|
|
6
|
-
readonly id: string;
|
|
7
|
-
readonly tab = "comments";
|
|
8
|
-
protected readonly includes: string[];
|
|
9
|
-
protected renderLoading(): string[];
|
|
10
|
-
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
11
|
-
}
|
|
12
|
-
/** Public History route: ReactScreen wrapper around the comments controller. */
|
|
3
|
+
import { TicketContentScreen } from './ticket-content-screen.js';
|
|
4
|
+
/** Public History route: the ticket's comments view and its interaction state. */
|
|
13
5
|
export declare class TicketCommentsScreen extends TicketContentScreen {
|
|
14
6
|
static readonly route: {
|
|
15
7
|
id: string;
|
|
@@ -27,6 +19,8 @@ export declare class TicketCommentsScreen 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 = "comments";
|
|
23
|
+
protected readonly includes: string[];
|
|
24
|
+
protected renderLoading(): string[];
|
|
25
|
+
protected fullNonInteractive(document: TicketDetailDocument, context: ScreenContext): string[];
|
|
31
26
|
}
|
|
32
|
-
export {};
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
import { flattenSections } from '../../../Component/section-list/index.js';
|
|
2
2
|
import { detailSections } 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
|
const INCLUDES = ['comments'];
|
|
6
|
-
/**
|
|
7
|
-
class TicketCommentsController extends TicketContentController {
|
|
8
|
-
id = TicketCommentsScreen.route.id;
|
|
9
|
-
tab = 'comments';
|
|
10
|
-
includes = INCLUDES;
|
|
11
|
-
renderLoading() {
|
|
12
|
-
return ['Loading comments…'];
|
|
13
|
-
}
|
|
14
|
-
fullNonInteractive(document, context) {
|
|
15
|
-
const nowSeconds = context.nowSeconds?.() ?? Math.floor(Date.now() / 1000);
|
|
16
|
-
return flattenSections(detailSections(document, this.labels, nowSeconds).filter((section) => section.heading === 'Comments')).lines;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/** Public History route: ReactScreen wrapper around the comments controller. */
|
|
6
|
+
/** Public History route: the ticket's comments view and its interaction state. */
|
|
20
7
|
export class TicketCommentsScreen extends TicketContentScreen {
|
|
21
8
|
static route = {
|
|
22
9
|
id: 'ticket.comments',
|
|
@@ -27,5 +14,13 @@ export class TicketCommentsScreen extends TicketContentScreen {
|
|
|
27
14
|
context: ticketInputContext,
|
|
28
15
|
};
|
|
29
16
|
id = TicketCommentsScreen.route.id;
|
|
30
|
-
|
|
17
|
+
tab = 'comments';
|
|
18
|
+
includes = INCLUDES;
|
|
19
|
+
renderLoading() {
|
|
20
|
+
return ['Loading comments…'];
|
|
21
|
+
}
|
|
22
|
+
fullNonInteractive(document, context) {
|
|
23
|
+
const nowSeconds = context.nowSeconds?.() ?? Math.floor(Date.now() / 1000);
|
|
24
|
+
return flattenSections(detailSections(document, this.labels, nowSeconds).filter((section) => section.heading === 'Comments')).lines;
|
|
25
|
+
}
|
|
31
26
|
}
|