Line data Source code
1 : import type { LoggerLike } from '../../platform/logger/logger.js';
2 : import { chartStatementId } from '../scripts/script_compilation.js';
3 : import type { ModifySessionScripts } from '../scripts/session_scripts_registry.js';
4 : import { SET_SCRIPT_TEXT, type ScriptData } from '../scripts/session_scripts.js';
5 : import type { DashboardPlacement } from './dashboard_layout.js';
6 :
7 1 : const LOG_CTX = 'dashboard';
8 :
9 : /// The renderers of a card
10 : export type DashboardRenderer = 'table' | 'vegalite' | 'markdown';
11 :
12 : /// The statement that a card shows: the visualized statement, the statement with the `@board` tag, or the last one
13 1 : function cardStatementId(script: ScriptData): number | null {
14 1 : return script.annotations.visualizeQuery?.statementId
15 1 : ?? script.annotations.boardPosition?.statementId
16 1 : ?? chartStatementId(script.scriptSession);
17 1 : }
18 :
19 : /// Write a placement into the `@board` tag of the statement that the card shows.
20 : /// A placement is not staged, but it joins a diff that the card already stages, rejecting the diff moves the card back.
21 1 : export function persistDashboardPlacement(
22 1 : script: ScriptData,
23 1 : placement: DashboardPlacement,
24 1 : modifySessionScripts: ModifySessionScripts,
25 1 : ): void {
26 1 : const statementId = cardStatementId(script);
27 1 : if (statementId == null) return;
28 1 : modifySessionScripts({
29 1 : type: SET_SCRIPT_TEXT,
30 1 : value: {
31 1 : scriptKey: script.scriptKey,
32 1 : text: script.scriptSession.rewriteVisBoard(
33 1 : statementId,
34 1 : placement.row,
35 1 : placement.column,
36 1 : placement.width,
37 1 : placement.height,
38 1 : ),
39 1 : withDiff: script.pendingDiff != null,
40 1 : },
41 1 : });
42 1 : }
43 :
44 : /// Give the card of a script a renderer, its `@vis` tag. Without a renderer, the tag is removed and the card collapses
45 : /// to its script. A card that changes the section loses its `@board` tag and flows into the other section. The rewrite
46 : /// is staged as a diff to accept or reject, like in the feed. Returns false if the tag could not be written.
47 1 : export function setDashboardRenderer(
48 1 : script: ScriptData,
49 1 : renderer: DashboardRenderer | null,
50 1 : body: string,
51 1 : modifySessionScripts: ModifySessionScripts,
52 1 : logger?: LoggerLike,
53 1 : ): boolean {
54 1 : const statementId = cardStatementId(script);
55 1 : if (statementId == null) return false;
56 1 : let text: string;
57 1 : try {
58 1 : text = script.scriptSession.rewriteVisRenderer(statementId, renderer, body);
59 1 : } catch (e: unknown) {
60 1 : logger?.warn('Failed to write the renderer of a dashboard card', { renderer, error: String(e) }, LOG_CTX);
61 1 : return false;
62 1 : }
63 1 : modifySessionScripts({ type: SET_SCRIPT_TEXT, value: { scriptKey: script.scriptKey, text, withDiff: true } });
64 1 : return true;
65 1 : }
66 :
67 : /// A starter Markdown row template: the first column as heading, the others in a line below
68 1 : export function markdownTemplate(columns: readonly string[]): string | null {
69 1 : if (columns.length === 0) return null;
70 1 : const [first, ...rest] = columns;
71 1 : const lines = [`### {{${first}}}`];
72 1 : if (rest.length > 0) lines.push(rest.map(column => `{{${column}}}`).join(' ยท '));
73 1 : return lines.join('\n');
74 1 : }
|