@trilogy-data/trilogy-studio-components 0.1.25 → 0.1.27
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/AssetAutoImporter-OHphsfW9.js +403 -0
- package/dist/ChatCreatorModal-CuXha6Dg.js +218 -0
- package/dist/ChatModelSelect-Cz7axWjP.js +40 -0
- package/dist/{CodeBlock-PT4no49I.js → CodeBlock-BBsaC6hX.js} +4 -4
- package/dist/{CommunityModels-D7zWnHgG.js → CommunityModels-CIQQhO-y.js} +106 -75
- package/dist/{ConnectionErrorPopup-FSs7U-Yl.js → ConnectionErrorPopup-7vpqgF0s.js} +1 -1
- package/dist/{ConnectionView-COnTTuA4.js → ConnectionView-7Jj_Ggdi.js} +49 -49
- package/dist/{CreateEditorFromDatasourcePopup-snOh1d5h.js → CreateEditorFromDatasourcePopup-CrVHUWFl.js} +4 -4
- package/dist/{Dashboard-D1ZCTw5r.js → Dashboard-DxSi9W6Q.js} +276 -280
- package/dist/{DashboardImportSelector-CNxibXlS.js → DashboardImportSelector-kuDRDYi8.js} +2 -2
- package/dist/{DashboardMobile-D_m0xv17.js → DashboardMobile-CZEgTb0R.js} +39 -39
- package/dist/{DrilldownPane-CBs5ZojS.js → DrilldownPane-BheRHJMs.js} +5 -7
- package/dist/{Editor-DhsP18KE.js → Editor-D6tdutTm.js} +106 -104
- package/dist/{ErrorMessage-XMn_08gJ.js → ErrorMessage-D5JeF3Iz.js} +4 -4
- package/dist/{GlobalChatPanel-DFx9A4yP.js → GlobalChatPanel-BXZh0sdD.js} +169 -134
- package/dist/{IDE-BRMLxTfP.js → IDE-T8PmyAQ_.js} +200 -203
- package/dist/{JobsView-C9PYS6pZ.js → JobsView-Ca97MiSd.js} +12 -13
- package/dist/{LLMChat-Cqg6pTgC.js → LLMChat-Cch33Yd_.js} +3 -3
- package/dist/{LLMView-VkJpP-49.js → LLMView-BDb6wD74.js} +26 -26
- package/dist/{LoadingView-s1uznGwG.js → LoadingView-B-xFwd2N.js} +2 -2
- package/dist/{MarkdownRenderer-BNDuEyG-.js → MarkdownRenderer-BWvdx0k3.js} +531 -430
- package/dist/MobileIDE-DpdEQEqc.js +783 -0
- package/dist/{ModelCard-D8tKkK9-.js → ModelCard-DkAMP4X9.js} +19 -20
- package/dist/{ModelView-rAurf9n8.js → ModelView-DomyhN8g.js} +7 -7
- package/dist/PageLoading-BAvKGo9h.js +5937 -0
- package/dist/{ResultComponent-_-1qZCfv.js → ResultComponent-zoOSoRLe.js} +8 -8
- package/dist/{Results-CQGpFmPQ.js → Results-dq-SlJbU.js} +17 -19
- package/dist/{StatusIcon-BylPx2EO.js → StatusIcon-AbxNvJ6p.js} +2 -2
- package/dist/{StoreTokenModal-zCSYhfrw.js → StoreTokenModal-CM8WXdu1.js} +2 -2
- package/dist/{SymbolsPane-BpmL___H.js → SymbolsPane-DfaxeaPS.js} +6 -3
- package/dist/{TrilogyEmbedProvider-WA_dlv9e.js → TrilogyEmbedProvider-D3h0gYnX.js} +9 -9
- package/dist/{TutorialPage-CZGBRJdq.js → TutorialPage-BtEJG7cT.js} +27 -28
- package/dist/{VegaLiteChart-CmkOw6yD.js → VegaLiteChart-BVyAab-o.js} +12191 -10975
- package/dist/{WelcomePage-CLKvAvk-.js → WelcomePage-BoqzYBLr.js} +5 -5
- package/dist/{embedTheme-Bub46ILG.js → _plugin-vue_export-helper-f9Rw-Il4.js} +14 -6
- package/dist/assets/{css.worker-9aDGcEUy.js → css.worker-niORQtzO.js} +14 -14
- package/dist/assets/{html.worker-D2LKDpnG.js → html.worker-CO5LvJpF.js} +17 -17
- package/dist/assets/json.worker-BezHzWUV.js +58 -0
- package/dist/assets/{ts.worker-Bz0-EaKK.js → ts.worker-CYhxGg0r.js} +107 -107
- package/dist/{results-DTgAKr5j.js → base-DuKnVD-A.js} +216 -45
- package/dist/components/AssetAutoImporter.vue.d.ts.map +1 -1
- package/dist/components/FeedbackBanner.vue.d.ts +4 -0
- package/dist/components/FeedbackBanner.vue.d.ts.map +1 -0
- package/dist/components/TipsCTA.vue.d.ts +1 -1
- package/dist/components/VegaLiteChart.vue.d.ts.map +1 -1
- package/dist/components/chartHelpers.d.ts +9 -1
- package/dist/components/chartHelpers.d.ts.map +1 -1
- package/dist/components/chartRenderManager.d.ts +4 -1
- package/dist/components/chartRenderManager.d.ts.map +1 -1
- package/dist/components/community/AddStoreModal.vue.d.ts +1 -1
- package/dist/components/community/AddStoreModal.vue.d.ts.map +1 -1
- package/dist/components/community/CommunityModelCard.vue.d.ts.map +1 -1
- package/dist/components/dashboard/DashboardCreatorIcon.vue.d.ts +54 -0
- package/dist/components/dashboard/DashboardCreatorIcon.vue.d.ts.map +1 -0
- package/dist/components/dashboard/DashboardProvenance.vue.d.ts +30 -0
- package/dist/components/dashboard/DashboardProvenance.vue.d.ts.map +1 -0
- package/dist/components/dashboard/ReportLayout.vue.d.ts +19 -0
- package/dist/components/dashboard/ReportLayout.vue.d.ts.map +1 -0
- package/dist/components/editor/Editor.vue.d.ts +3 -3
- package/dist/components/editor/Editor.vue.d.ts.map +1 -1
- package/dist/components/editor/EditorCreatorIcon.vue.d.ts +62 -0
- package/dist/components/editor/EditorCreatorIcon.vue.d.ts.map +1 -0
- package/dist/components/editor/ValidationComponent.vue.d.ts +50 -0
- package/dist/components/editor/ValidationComponent.vue.d.ts.map +1 -0
- package/dist/components/jobs/JobsAddStoreModal.vue.d.ts.map +1 -1
- package/dist/components/llm/ChatCreatorModal.vue.d.ts +17 -1
- package/dist/components/llm/ChatCreatorModal.vue.d.ts.map +1 -1
- package/dist/components/llm/ChatModelSelect.vue.d.ts +13 -0
- package/dist/components/llm/ChatModelSelect.vue.d.ts.map +1 -0
- package/dist/components/llm/GlobalChatPanel.vue.d.ts.map +1 -1
- package/dist/components/model/ModelCard.vue.d.ts +3 -3
- package/dist/components/sidebar/CommunityModelList.vue.d.ts +33 -50
- package/dist/components/sidebar/CommunityModelList.vue.d.ts.map +1 -1
- package/dist/components/sidebar/CommunityModelListItem.vue.d.ts.map +1 -1
- package/dist/components/sidebar/EditorList.vue.d.ts +32 -49
- package/dist/components/sidebar/EditorList.vue.d.ts.map +1 -1
- package/dist/components/sidebar/LLMConnectionList.vue.d.ts.map +1 -1
- package/dist/components/sidebar/Sidebar.vue.d.ts +65 -99
- package/dist/components/sidebar/Sidebar.vue.d.ts.map +1 -1
- package/dist/components/tutorial/TutorialPrompt.vue.d.ts +3 -3
- package/dist/components/tutorial/TutorialPrompt.vue.d.ts.map +1 -1
- package/dist/{remoteWorker-Dkv3TJ0j.js → connections-CWH3zwH2.js} +4544 -4126
- package/dist/connections.js +3 -4
- package/dist/{cssMode-D4Rzr1Cu.js → cssMode-zpO2ap2B.js} +5 -6
- package/dist/dashboard.js +54 -57
- package/dist/dashboards/layerSpec.d.ts +38 -4
- package/dist/dashboards/layerSpec.d.ts.map +1 -1
- package/dist/dashboards/lineAreaSpec.d.ts +8 -80
- package/dist/dashboards/lineAreaSpec.d.ts.map +1 -1
- package/dist/dashboards/mapSpec.d.ts +1 -0
- package/dist/dashboards/mapSpec.d.ts.map +1 -1
- package/dist/dashboards/spec.d.ts.map +1 -1
- package/dist/data/tutorial/documentation.d.ts.map +1 -1
- package/dist/data/tutorial/startupScripts.d.ts +3 -0
- package/dist/data/tutorial/startupScripts.d.ts.map +1 -0
- package/dist/{dist-CXoL8kXK.js → dist-1z5KURzS.js} +55 -50
- package/dist/{dist-DKkuvbPb.js → dist-Bv3D2p5A.js} +20 -18
- package/dist/{editor.main-Cl8i7rHY.js → editor.main-BQh6DxDB.js} +33 -33
- package/dist/{editorRefinementRuntime-C_YmXRy4.js → editorStore-CAlMJftt.js} +2084 -946
- package/dist/embed.js +2 -2
- package/dist/entry.dashboard.d.ts +1 -0
- package/dist/entry.dashboard.d.ts.map +1 -1
- package/dist/{freemarker2-fW5NBILf.js → freemarker2-DQBqlEXc.js} +1 -1
- package/dist/{globalChatRuntime-oMLiPLNC.js → globalChatRuntime-CyS7vH51.js} +18 -18
- package/dist/{handlebars-dG4w8UUY.js → handlebars-tgYxaM70.js} +1 -1
- package/dist/{helpers-DcWCa6bX.js → helpers-BbVlA3Pf.js} +39 -39
- package/dist/{html-1Dq70BdU.js → html-jJahD3Mi.js} +1 -1
- package/dist/{htmlMode--IQmLBeh.js → htmlMode-BA1-8l2e.js} +5 -6
- package/dist/{javascript-CTzBM4sF.js → javascript-Cypfo7va.js} +1 -1
- package/dist/{jsonMode-DzeJjIEH.js → jsonMode-xJye8PWS.js} +25 -25
- package/dist/{liquid-DlHThiki.js → liquid-BGDrv5da.js} +1 -1
- package/dist/llm/data/constants.d.ts +1 -1
- package/dist/llm/data/constants.d.ts.map +1 -1
- package/dist/llm/data/trilogySyntax.generated.d.ts +7 -1
- package/dist/llm/data/trilogySyntax.generated.d.ts.map +1 -1
- package/dist/llm/docsIndex.d.ts.map +1 -1
- package/dist/llm/openai.d.ts +2 -1
- package/dist/llm/openai.d.ts.map +1 -1
- package/dist/llm-ClU-2rgk.js +18493 -0
- package/dist/llm.js +2 -3
- package/dist/{localStorage-CSuYS7QE.js → localStorage-CGQ1iJXt.js} +39 -42
- package/dist/{lspLanguageFeatures-Cdfs3EKq.js → lspLanguageFeatures-V3e_p9oN.js} +32 -32
- package/dist/{mdx-fn3g4PH5.js → mdx-BUR1aImW.js} +1 -1
- package/dist/models/helpers.d.ts.map +1 -1
- package/dist/monaco.js +3 -3
- package/dist/{python-CCVj0pFt.js → python-YLkl0pc6.js} +1 -1
- package/dist/{razor-Cj3flYnk.js → razor-BP8TRMDY.js} +1 -1
- package/dist/{reconcile-Bk7M797_.js → reconcile-DXIvGwBk.js} +1 -1
- package/dist/{remoteStoreSync-CLvZJrTK.js → remoteStoreSync-CuQBWpWf.js} +3 -3
- package/dist/remotes/displayHelpers.d.ts.map +1 -1
- package/dist/remotes/genericStoreMetadata.d.ts +1 -0
- package/dist/remotes/genericStoreMetadata.d.ts.map +1 -1
- package/dist/remotes/models.d.ts +37 -5
- package/dist/remotes/models.d.ts.map +1 -1
- package/dist/remotes/staticStorePresets.d.ts +22 -0
- package/dist/remotes/staticStorePresets.d.ts.map +1 -0
- package/dist/remotes/storeService.d.ts +25 -4
- package/dist/remotes/storeService.d.ts.map +1 -1
- package/dist/{rolldown-runtime-Dqa2HsxW.js → rolldown-runtime-B0aSnxlc.js} +2 -2
- package/dist/static/test_import.vue.d.ts +4 -0
- package/dist/static/test_import.vue.d.ts.map +1 -0
- package/dist/stores/communityApiStore.d.ts +32 -60
- package/dist/stores/communityApiStore.d.ts.map +1 -1
- package/dist/stores/connectionStore.d.ts.map +1 -1
- package/dist/stores/resolver.d.ts +5 -0
- package/dist/stores/resolver.d.ts.map +1 -1
- package/dist/stores/urlStore.d.ts +1 -0
- package/dist/stores/urlStore.d.ts.map +1 -1
- package/dist/stores-LlyiwSbK.js +2604 -0
- package/dist/stores.js +4 -7
- package/dist/trilogy-studio-components.css +1 -1
- package/dist/{tsMode-GI4xMYAl.js → tsMode-BH9HS_sH.js} +64 -66
- package/dist/{typescript-CPibXi3J.js → typescript-BM-ynfk9.js} +1 -1
- package/dist/{useChatWithTools-GV1ufcqw.js → useChatWithTools-m3Jn_SV-.js} +11 -11
- package/dist/{useDashboard-OoBKkkuQ.js → useDashboard-BOAuvVEw.js} +1013 -1021
- package/dist/{tabulator_esm-CxLvGDp8.js → useGlobalChatPanel-DuP1q7_f.js} +1729 -711
- package/dist/{useResizableDialog-B0ePSts4.js → useResizableDialog-Cs90WJdF.js} +2 -2
- package/dist/views/MobileIDE.vue.d.ts.map +1 -1
- package/dist/views/ModelView.vue.d.ts +6 -6
- package/dist/views/ModelView.vue.d.ts.map +1 -1
- package/dist/views/TutorialPage.vue.d.ts +41 -58
- package/dist/views/TutorialPage.vue.d.ts.map +1 -1
- package/dist/views.js +193 -195
- package/dist/{editor.api2-ClD5pp8H.js → workers-B9Eybl-M.js} +16252 -15926
- package/dist/{xml-BNyphceI.js → xml-M5WFPSpA.js} +1 -1
- package/dist/{yaml-DE5Vz0PH.js → yaml-CEeFwjz9.js} +1 -1
- package/package.json +29 -20
- package/dist/AssetAutoImporter-DfMd_DSk.js +0 -403
- package/dist/ChatCreatorModal-BTqY06B6.js +0 -177
- package/dist/DashboardCreatorInline-LWvf--2x.js +0 -129
- package/dist/DataTable-DoRDynP1.js +0 -365
- package/dist/EditorCreatorInline-D6_y1H_h.js +0 -125
- package/dist/LoadingButton-OH3frQuO.js +0 -138
- package/dist/MobileIDE-CHGJoh05.js +0 -781
- package/dist/ModalDialog-D1EOG4rl.js +0 -42
- package/dist/ModelCreator-DrxLxeyH.js +0 -253
- package/dist/PageLoading-I6mr-7NB.js +0 -2666
- package/dist/Tooltip-Dihir4zs.js +0 -103
- package/dist/_plugin-vue_export-helper-B3ysoDQm.js +0 -8
- package/dist/assets/json.worker-CJ5MmO5Q.js +0 -58
- package/dist/base-C8IuZWqY.js +0 -164
- package/dist/connectionHistoryStorage-DKJHiKJY.js +0 -111
- package/dist/connectionHistoryStore-DQeBvStZ.js +0 -61
- package/dist/connections-CJSb1TZl.js +0 -229
- package/dist/constants-DgFEYN2b.js +0 -7
- package/dist/dashboardStore-CNkWQ4r7.js +0 -641
- package/dist/demoSetup-DiW3ROFQ.js +0 -2941
- package/dist/editorRefinementToolExecutor-mX8ClQ63.js +0 -4498
- package/dist/editorStore-Ch7k-gse.js +0 -972
- package/dist/formatting-BbJ5ICgh.js +0 -6
- package/dist/llm-_807I79k.js +0 -11965
- package/dist/llmStore-CSzM1IZd.js +0 -153
- package/dist/monaco.contribution-ikesdolO.js +0 -128
- package/dist/stores-C1wUWiFm.js +0 -1708
- package/dist/trilogy-BroD2Qmp.js +0 -4
- package/dist/urlStore-Dgmwx1YI.js +0 -54
- package/dist/useGlobalChatPanel-CIeUyZba.js +0 -85
- package/dist/useIsMobile-CNpUQAvk.js +0 -8
- package/dist/usePrismHighlight-DVyDiDAL.js +0 -183
- package/dist/workers-Br7ThUKL.js +0 -47
|
@@ -1,4498 +0,0 @@
|
|
|
1
|
-
import { a as e, n as t, t as n } from "./results-DTgAKr5j.js";
|
|
2
|
-
import { t as r } from "./formatting-BbJ5ICgh.js";
|
|
3
|
-
import { computed as i, ref as a, toValue as o } from "vue";
|
|
4
|
-
import { defineStore as s } from "pinia";
|
|
5
|
-
//#region models/model.ts
|
|
6
|
-
var c = class e {
|
|
7
|
-
address;
|
|
8
|
-
name;
|
|
9
|
-
namespace;
|
|
10
|
-
datatype;
|
|
11
|
-
purpose;
|
|
12
|
-
description;
|
|
13
|
-
lineage;
|
|
14
|
-
keys;
|
|
15
|
-
constructor(e, t, n, r, i, a, o = [], s = []) {
|
|
16
|
-
this.address = e, this.name = t, this.namespace = n, this.datatype = r, this.purpose = i, this.description = a || null, this.lineage = o, this.keys = s;
|
|
17
|
-
}
|
|
18
|
-
toJSON() {
|
|
19
|
-
return {
|
|
20
|
-
address: this.address,
|
|
21
|
-
name: this.name,
|
|
22
|
-
namespace: this.namespace,
|
|
23
|
-
datatype: this.datatype,
|
|
24
|
-
purpose: this.purpose,
|
|
25
|
-
description: this.description,
|
|
26
|
-
lineage: this.lineage,
|
|
27
|
-
keys: this.keys
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
static fromJSON(t) {
|
|
31
|
-
return new e(t.address, t.name, t.namespace, t.datatype, t.purpose, t.description, t.lineage, t.keys);
|
|
32
|
-
}
|
|
33
|
-
}, l = class e {
|
|
34
|
-
name;
|
|
35
|
-
address;
|
|
36
|
-
concepts;
|
|
37
|
-
grain;
|
|
38
|
-
constructor(e, t, n, r) {
|
|
39
|
-
this.name = e, this.address = t, this.concepts = n, this.grain = r;
|
|
40
|
-
}
|
|
41
|
-
toJSON() {
|
|
42
|
-
return {
|
|
43
|
-
name: this.name,
|
|
44
|
-
address: this.address,
|
|
45
|
-
concepts: this.concepts.map((e) => e.toJSON()),
|
|
46
|
-
grain: this.grain.map((e) => e.toJSON())
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
static fromJSON(t) {
|
|
50
|
-
return new e(t.name, t.address, t.concepts.map((e) => c.fromJSON(e)), t.grain.map((e) => c.fromJSON(e)));
|
|
51
|
-
}
|
|
52
|
-
}, u = class e {
|
|
53
|
-
editor;
|
|
54
|
-
alias;
|
|
55
|
-
concepts;
|
|
56
|
-
datasources;
|
|
57
|
-
constructor(t, n, r, i) {
|
|
58
|
-
this.editor = t, this.alias = e.normalizeAlias(n), this.concepts = r || [], this.datasources = i || [];
|
|
59
|
-
}
|
|
60
|
-
static normalizeAlias(e) {
|
|
61
|
-
return e.replace(/\.(preql|sql|py)$/i, "");
|
|
62
|
-
}
|
|
63
|
-
toJSON() {
|
|
64
|
-
return {
|
|
65
|
-
editor: this.editor,
|
|
66
|
-
alias: this.alias,
|
|
67
|
-
concepts: this.concepts.map((e) => e.toJSON()),
|
|
68
|
-
datasources: this.datasources.map((e) => e.toJSON())
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
static fromJSON(t) {
|
|
72
|
-
return new e(t.editor, t.alias, (t.concepts || []).map((e) => new c(e.address, e.name, e.namespace, e.datatype, e.purpose, e.description, e.lineage, e.keys || [])), (t.datasources || []).map((e) => new l(e.name, e.address, (e.concepts || []).map((e) => new c(e.address, e.name, e.namespace, e.datatype, e.purpose, e.description, e.lineage, e.keys || [])), (e.grain || []).map((e) => new c(e.address, e.name, e.namespace, e.datatype, e.purpose, e.description, e.lineage, e.keys || [])))));
|
|
73
|
-
}
|
|
74
|
-
}, d = class e {
|
|
75
|
-
name;
|
|
76
|
-
storage;
|
|
77
|
-
sources;
|
|
78
|
-
parseError = null;
|
|
79
|
-
changed = !0;
|
|
80
|
-
description = null;
|
|
81
|
-
deleted = !1;
|
|
82
|
-
constructor({ name: e, sources: t, storage: n, description: r }) {
|
|
83
|
-
this.name = e, this.sources = t, this.storage = n, this.changed = !0, this.description = r || null;
|
|
84
|
-
}
|
|
85
|
-
delete() {
|
|
86
|
-
this.deleted = !0, this.changed = !0;
|
|
87
|
-
}
|
|
88
|
-
setParseResults(e) {
|
|
89
|
-
this.changed = !0, this.parseError = null;
|
|
90
|
-
for (let t of this.sources) {
|
|
91
|
-
let n = e.sources.find((e) => e.alias === t.alias);
|
|
92
|
-
n ? (t.concepts = n.concepts, t.datasources = n.datasources) : this.parseError = `No parse results found for source ${t.alias}`;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
setSources(e) {
|
|
96
|
-
this.sources = e, this.changed = !0;
|
|
97
|
-
}
|
|
98
|
-
addModelSource(e) {
|
|
99
|
-
let t = this.sources.find((t) => t.alias === e.alias);
|
|
100
|
-
if (t) {
|
|
101
|
-
if (t.editor === e.editor) return !0;
|
|
102
|
-
this.sources = this.sources.filter((t) => t.alias !== e.alias);
|
|
103
|
-
}
|
|
104
|
-
this.sources.push(e), this.changed = !0;
|
|
105
|
-
}
|
|
106
|
-
addModelSourceSimple(e, t) {
|
|
107
|
-
this.addModelSource(new u(e, t, [], []));
|
|
108
|
-
}
|
|
109
|
-
removeModelSourceSimple(e) {
|
|
110
|
-
this.sources = this.sources.filter((t) => t.editor !== e), this.changed = !0;
|
|
111
|
-
}
|
|
112
|
-
updateModelSourceName(e, t) {
|
|
113
|
-
let n = this.sources.find((t) => t.editor === e);
|
|
114
|
-
n && (n.alias = u.normalizeAlias(t), this.changed = !0);
|
|
115
|
-
}
|
|
116
|
-
setParseError(e) {
|
|
117
|
-
this.parseError = e, this.changed = !0;
|
|
118
|
-
}
|
|
119
|
-
getEditorByName(e) {
|
|
120
|
-
for (let t of this.sources) if (t.alias === e) return t.editor;
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
static fromJSON(t) {
|
|
124
|
-
let n = new e({
|
|
125
|
-
name: t.name,
|
|
126
|
-
storage: t.storage,
|
|
127
|
-
description: t.description,
|
|
128
|
-
sources: t.sources.map((e) => u.fromJSON(e))
|
|
129
|
-
});
|
|
130
|
-
return n.changed = !1, n;
|
|
131
|
-
}
|
|
132
|
-
toJSON() {
|
|
133
|
-
return {
|
|
134
|
-
name: this.name,
|
|
135
|
-
storage: this.storage,
|
|
136
|
-
description: this.description,
|
|
137
|
-
sources: this.sources.map((e) => e.toJSON())
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
}, f = s("analytics", {
|
|
141
|
-
state: () => ({
|
|
142
|
-
isEnabled: !0,
|
|
143
|
-
sendTelemetry: !0
|
|
144
|
-
}),
|
|
145
|
-
actions: {
|
|
146
|
-
log(e, t, n = !0) {
|
|
147
|
-
if (this.isEnabled) {
|
|
148
|
-
if (!this.sendTelemetry) {
|
|
149
|
-
console.debug("Telemetry disabled. Would have sent:", {
|
|
150
|
-
path: e,
|
|
151
|
-
title: t,
|
|
152
|
-
isEvent: n
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
window.goatcounter && (console.debug("Sending telemetry event:", {
|
|
158
|
-
path: e,
|
|
159
|
-
title: t,
|
|
160
|
-
isEvent: n
|
|
161
|
-
}), window.goatcounter.count({
|
|
162
|
-
path: e,
|
|
163
|
-
title: t,
|
|
164
|
-
event: n
|
|
165
|
-
}));
|
|
166
|
-
} catch (e) {
|
|
167
|
-
console.warn("Telemetry send failed:", e);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
setEnabled(e) {
|
|
172
|
-
this.isEnabled = e;
|
|
173
|
-
},
|
|
174
|
-
setSendTelemetry(e) {
|
|
175
|
-
this.sendTelemetry = e;
|
|
176
|
-
},
|
|
177
|
-
init({ enabled: e = !0, sendTelemetry: t = !0 }) {
|
|
178
|
-
this.isEnabled = e, this.sendTelemetry = t;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}), p = "userSettings", m = s("userSettings", {
|
|
182
|
-
state: () => ({
|
|
183
|
-
settings: {
|
|
184
|
-
theme: "",
|
|
185
|
-
trilogyResolver: "",
|
|
186
|
-
telemetryEnabled: null,
|
|
187
|
-
tipsRead: [],
|
|
188
|
-
skipAllTips: !1
|
|
189
|
-
},
|
|
190
|
-
defaults: {
|
|
191
|
-
theme: "dark",
|
|
192
|
-
trilogyResolver: "https://trilogy-service.fly.dev",
|
|
193
|
-
telemetryEnabled: !0,
|
|
194
|
-
tipsRead: [],
|
|
195
|
-
skipAllTips: !1
|
|
196
|
-
},
|
|
197
|
-
isLoading: !1,
|
|
198
|
-
hasChanges: !1,
|
|
199
|
-
hasLoaded: !1
|
|
200
|
-
}),
|
|
201
|
-
getters: {
|
|
202
|
-
getSettings: (e) => e.settings,
|
|
203
|
-
getDefaults: (e) => e.defaults,
|
|
204
|
-
hasUnsavedChanges: (e) => e.hasChanges
|
|
205
|
-
},
|
|
206
|
-
actions: {
|
|
207
|
-
updateSetting(e, t) {
|
|
208
|
-
this.settings[e] = t, e === "theme" ? this.toggleTheme() : e === "telemetryEnabled" && f().setEnabled(t === !0), this.hasChanges = !0;
|
|
209
|
-
},
|
|
210
|
-
getUnreadTips(e) {
|
|
211
|
-
return this.settings.skipAllTips ? [] : (this.settings.tipsRead || (this.settings.tipsRead = []), e.filter((e) => !this.settings.tipsRead.includes(e.id)));
|
|
212
|
-
},
|
|
213
|
-
clearDismissedTips() {
|
|
214
|
-
this.settings.tipsRead = [], this.hasChanges = !0, this.saveSettings(), this.settings.skipAllTips = !1;
|
|
215
|
-
},
|
|
216
|
-
markTipRead(e) {
|
|
217
|
-
this.settings.tipsRead.includes(e) || (this.settings.tipsRead.push(e), this.hasChanges = !0, this.saveSettings());
|
|
218
|
-
},
|
|
219
|
-
clearReadTips() {
|
|
220
|
-
this.settings.tipsRead = [], this.hasChanges = !0;
|
|
221
|
-
},
|
|
222
|
-
toggleTheme() {
|
|
223
|
-
document.documentElement.classList.remove("dark-theme", "light-theme"), this.settings.theme === "light" ? document.documentElement.classList.add("light-theme") : document.documentElement.classList.add("dark-theme");
|
|
224
|
-
},
|
|
225
|
-
setHasChanges(e) {
|
|
226
|
-
this.hasChanges = e;
|
|
227
|
-
},
|
|
228
|
-
updateSettings(e) {
|
|
229
|
-
this.settings = {
|
|
230
|
-
...this.settings,
|
|
231
|
-
...e
|
|
232
|
-
}, this.hasChanges = !0;
|
|
233
|
-
},
|
|
234
|
-
resetToDefaults() {
|
|
235
|
-
let e = this.settings.theme;
|
|
236
|
-
this.settings = { ...this.defaults }, this.settings.theme = e, this.hasChanges = !0;
|
|
237
|
-
},
|
|
238
|
-
async saveSettings() {
|
|
239
|
-
this.isLoading = !0;
|
|
240
|
-
try {
|
|
241
|
-
return localStorage.setItem(p, JSON.stringify(this.settings)), this.hasChanges = !1, !0;
|
|
242
|
-
} catch (e) {
|
|
243
|
-
return console.error("Failed to save settings:", e), !1;
|
|
244
|
-
} finally {
|
|
245
|
-
this.isLoading = !1;
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
loadSettings() {
|
|
249
|
-
this.isLoading = !0;
|
|
250
|
-
try {
|
|
251
|
-
let e = localStorage.getItem(p);
|
|
252
|
-
if (e) {
|
|
253
|
-
this.settings = {
|
|
254
|
-
...this.settings,
|
|
255
|
-
...JSON.parse(e)
|
|
256
|
-
};
|
|
257
|
-
let t = f();
|
|
258
|
-
this.settings.telemetryEnabled === !1 && t.setEnabled(this.settings.telemetryEnabled), this.settings.tipsRead || (this.settings.tipsRead = []), "disableEditorHints" in this.settings && delete this.settings.disableEditorHints;
|
|
259
|
-
}
|
|
260
|
-
} catch (e) {
|
|
261
|
-
console.error("Failed to load settings:", e);
|
|
262
|
-
} finally {
|
|
263
|
-
this.isLoading = !1, this.hasLoaded = !0;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}), h = /* @__PURE__ */ new Set(), g = /* @__PURE__ */ new Map(), _ = {
|
|
268
|
-
query: "select 1 as resolver_warmup;",
|
|
269
|
-
dialect: "duckdb",
|
|
270
|
-
full_model: {
|
|
271
|
-
name: "",
|
|
272
|
-
sources: []
|
|
273
|
-
},
|
|
274
|
-
imports: [],
|
|
275
|
-
extra_filters: [],
|
|
276
|
-
parameters: {},
|
|
277
|
-
current_filename: "__resolver_warmup__.preql"
|
|
278
|
-
}, v = class {
|
|
279
|
-
capacity;
|
|
280
|
-
cache;
|
|
281
|
-
keyOrder;
|
|
282
|
-
constructor(e = 100) {
|
|
283
|
-
this.capacity = e, this.cache = /* @__PURE__ */ new Map(), this.keyOrder = [];
|
|
284
|
-
}
|
|
285
|
-
get(e) {
|
|
286
|
-
if (this.cache.has(e)) return this.keyOrder = this.keyOrder.filter((t) => t !== e), this.keyOrder.push(e), this.cache.get(e);
|
|
287
|
-
}
|
|
288
|
-
set(e, t) {
|
|
289
|
-
if (this.cache.has(e)) this.keyOrder = this.keyOrder.filter((t) => t !== e);
|
|
290
|
-
else if (this.keyOrder.length >= this.capacity) {
|
|
291
|
-
let e = this.keyOrder.shift();
|
|
292
|
-
e && this.cache.delete(e);
|
|
293
|
-
}
|
|
294
|
-
this.keyOrder.push(e), this.cache.set(e, t);
|
|
295
|
-
}
|
|
296
|
-
clear() {
|
|
297
|
-
this.cache.clear(), this.keyOrder = [];
|
|
298
|
-
}
|
|
299
|
-
size() {
|
|
300
|
-
return this.cache.size;
|
|
301
|
-
}
|
|
302
|
-
}, y = class {
|
|
303
|
-
settingStore;
|
|
304
|
-
validateCache;
|
|
305
|
-
formatCache;
|
|
306
|
-
queryCache;
|
|
307
|
-
batchQueryCache;
|
|
308
|
-
modelCache;
|
|
309
|
-
constructor(e, t = 100) {
|
|
310
|
-
this.settingStore = e, this.validateCache = new v(t), this.formatCache = new v(t), this.queryCache = new v(t), this.batchQueryCache = new v(t), this.modelCache = new v(t);
|
|
311
|
-
}
|
|
312
|
-
createHash(e) {
|
|
313
|
-
let t = JSON.stringify(e), n = 5381;
|
|
314
|
-
for (let e = 0; e < t.length; e++) n = n * 33 ^ t.charCodeAt(e);
|
|
315
|
-
return (n >>> 0).toString(16);
|
|
316
|
-
}
|
|
317
|
-
createQueryCacheKey(e, t, n, r, i, a, o, s = null, c = null) {
|
|
318
|
-
let l = {
|
|
319
|
-
query: e,
|
|
320
|
-
dialect: t,
|
|
321
|
-
full_model: {
|
|
322
|
-
name: "",
|
|
323
|
-
sources: n || []
|
|
324
|
-
},
|
|
325
|
-
imports: r || [],
|
|
326
|
-
extra_filters: i || [],
|
|
327
|
-
parameters: a || {},
|
|
328
|
-
current_filename: o || null,
|
|
329
|
-
files: s && s.length > 0 ? [...s].sort() : [],
|
|
330
|
-
working_path: c || null
|
|
331
|
-
};
|
|
332
|
-
return this.createHash(l);
|
|
333
|
-
}
|
|
334
|
-
getErrorMessage(e) {
|
|
335
|
-
let t = "An error occurred.";
|
|
336
|
-
return e instanceof Error && (t = e.message), e.response && e.response.data && (t = e.response.data.detail), t;
|
|
337
|
-
}
|
|
338
|
-
buildResolverUrl(e) {
|
|
339
|
-
return `${this.settingStore.settings.trilogyResolver.replace(/\/+$/, "")}/${e}`;
|
|
340
|
-
}
|
|
341
|
-
async fetchWithErrorHandling(e, t) {
|
|
342
|
-
try {
|
|
343
|
-
let n = await fetch(e, t);
|
|
344
|
-
if (!n.ok) {
|
|
345
|
-
let e = await n.json().catch(() => ({}));
|
|
346
|
-
throw {
|
|
347
|
-
message: `HTTP error ${n.status}`,
|
|
348
|
-
response: { data: e }
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
return { data: await n.json() };
|
|
352
|
-
} catch (e) {
|
|
353
|
-
throw console.log(e), Error(this.getErrorMessage(e));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
async validate_query(e, t = null, n = null, r = null, i = null, a = null, o = null, s = null, c = null) {
|
|
357
|
-
let l = {
|
|
358
|
-
query: e,
|
|
359
|
-
sources: t || [],
|
|
360
|
-
imports: n || [],
|
|
361
|
-
extra_filters: r || [],
|
|
362
|
-
extra_content: i || {},
|
|
363
|
-
current_filename: a || null,
|
|
364
|
-
parameters: o || {},
|
|
365
|
-
files: s || null,
|
|
366
|
-
working_path: c || null
|
|
367
|
-
}, u = this.createHash(l), d = this.validateCache.get(u);
|
|
368
|
-
if (d) return d;
|
|
369
|
-
let f = await this.fetchWithErrorHandling(this.buildResolverUrl("validate_query"), {
|
|
370
|
-
method: "POST",
|
|
371
|
-
headers: { "Content-Type": "application/json" },
|
|
372
|
-
body: JSON.stringify(l)
|
|
373
|
-
});
|
|
374
|
-
return this.validateCache.set(u, f), f;
|
|
375
|
-
}
|
|
376
|
-
async drilldown_query(e, t, n, r, i, a, o = null, s = null, c = null, l = null, u = null, d = null, f = null) {
|
|
377
|
-
console.log("TrilogyResolver.drilldown_query called"), console.log(a);
|
|
378
|
-
let p = {
|
|
379
|
-
query: e,
|
|
380
|
-
dialect: t,
|
|
381
|
-
type: n,
|
|
382
|
-
drilldown_remove: r,
|
|
383
|
-
drilldown_add: i,
|
|
384
|
-
drilldown_filter: a,
|
|
385
|
-
full_model: {
|
|
386
|
-
name: "",
|
|
387
|
-
sources: o || []
|
|
388
|
-
},
|
|
389
|
-
imports: s || [],
|
|
390
|
-
extra_filters: c || [],
|
|
391
|
-
parameters: l || {},
|
|
392
|
-
current_filename: u || null,
|
|
393
|
-
files: d || null,
|
|
394
|
-
working_path: f || null
|
|
395
|
-
};
|
|
396
|
-
return await this.fetchWithErrorHandling(this.buildResolverUrl("drilldown_query"), {
|
|
397
|
-
method: "POST",
|
|
398
|
-
headers: { "Content-Type": "application/json" },
|
|
399
|
-
body: JSON.stringify(p)
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
async format_query(e, t, n, r = null, i = null, a = null, o = null, s = null, c = null, l = null) {
|
|
403
|
-
if (n === "sql") return { data: { text: e } };
|
|
404
|
-
let u = {
|
|
405
|
-
query: e,
|
|
406
|
-
dialect: t,
|
|
407
|
-
full_model: {
|
|
408
|
-
name: "",
|
|
409
|
-
sources: r || []
|
|
410
|
-
},
|
|
411
|
-
imports: i || [],
|
|
412
|
-
extra_filters: a || [],
|
|
413
|
-
parameters: o || {},
|
|
414
|
-
current_filename: s || null,
|
|
415
|
-
files: c || null,
|
|
416
|
-
working_path: l || null
|
|
417
|
-
}, d = this.createHash(u), f = this.formatCache.get(d);
|
|
418
|
-
if (f) return f;
|
|
419
|
-
let p = await this.fetchWithErrorHandling(this.buildResolverUrl("format_query"), {
|
|
420
|
-
method: "POST",
|
|
421
|
-
headers: { "Content-Type": "application/json" },
|
|
422
|
-
body: JSON.stringify(u)
|
|
423
|
-
});
|
|
424
|
-
return this.formatCache.set(d, p), p;
|
|
425
|
-
}
|
|
426
|
-
async resolve_query(e, t, n, r = null, i = null, a = null, o = null, s = null, c = null, l = null) {
|
|
427
|
-
if (n === "sql") return { data: {
|
|
428
|
-
generated_sql: e,
|
|
429
|
-
columns: [],
|
|
430
|
-
error: null
|
|
431
|
-
} };
|
|
432
|
-
let u = this.createQueryCacheKey(e, t, r, i, a, o, s, c, l), d = this.queryCache.get(u);
|
|
433
|
-
if (d) return d;
|
|
434
|
-
let f = {
|
|
435
|
-
query: e,
|
|
436
|
-
dialect: t,
|
|
437
|
-
full_model: {
|
|
438
|
-
name: "",
|
|
439
|
-
sources: r || []
|
|
440
|
-
},
|
|
441
|
-
imports: i || [],
|
|
442
|
-
extra_filters: a || [],
|
|
443
|
-
parameters: o || {},
|
|
444
|
-
current_filename: s || null,
|
|
445
|
-
files: c || null,
|
|
446
|
-
working_path: l || null
|
|
447
|
-
}, p = await this.fetchWithErrorHandling(this.buildResolverUrl("generate_query"), {
|
|
448
|
-
method: "POST",
|
|
449
|
-
headers: { "Content-Type": "application/json" },
|
|
450
|
-
body: JSON.stringify(f)
|
|
451
|
-
});
|
|
452
|
-
return this.queryCache.set(u, p), p;
|
|
453
|
-
}
|
|
454
|
-
async resolve_queries_batch(e, t, n = null, r = null, i = null, a = null, o = null, s = null) {
|
|
455
|
-
let c = {
|
|
456
|
-
queries: e,
|
|
457
|
-
dialect: t,
|
|
458
|
-
full_model: {
|
|
459
|
-
name: "",
|
|
460
|
-
sources: n || []
|
|
461
|
-
},
|
|
462
|
-
imports: r || [],
|
|
463
|
-
extra_filters: i || [],
|
|
464
|
-
parameters: a || {},
|
|
465
|
-
files: o && o.length > 0 ? [...o].sort() : [],
|
|
466
|
-
working_path: s || null
|
|
467
|
-
}, l = this.createHash(c), u = this.batchQueryCache.get(l);
|
|
468
|
-
if (u) return u;
|
|
469
|
-
let d = [], f = [];
|
|
470
|
-
if (e.forEach((e, c) => {
|
|
471
|
-
let l = [...i || [], ...e.extra_filters || []], u = {
|
|
472
|
-
...a || {},
|
|
473
|
-
...e.parameters || {}
|
|
474
|
-
}, p = this.createQueryCacheKey(e.query, t, n, r, l.length > 0 ? l : null, Object.keys(u).length > 0 ? u : null, null, o, s), m = this.queryCache.get(p);
|
|
475
|
-
m ? d.push({
|
|
476
|
-
index: c,
|
|
477
|
-
result: {
|
|
478
|
-
...m.data,
|
|
479
|
-
label: e.label
|
|
480
|
-
}
|
|
481
|
-
}) : f.push({
|
|
482
|
-
index: c,
|
|
483
|
-
component: e
|
|
484
|
-
});
|
|
485
|
-
}), f.length === 0) {
|
|
486
|
-
let e = { data: { queries: d.sort((e, t) => e.index - t.index).map((e) => e.result) } };
|
|
487
|
-
return this.batchQueryCache.set(l, e), e;
|
|
488
|
-
}
|
|
489
|
-
let p = {
|
|
490
|
-
queries: f.map((e) => e.component),
|
|
491
|
-
dialect: t,
|
|
492
|
-
full_model: {
|
|
493
|
-
name: "",
|
|
494
|
-
sources: n || []
|
|
495
|
-
},
|
|
496
|
-
imports: r || [],
|
|
497
|
-
extra_filters: i || [],
|
|
498
|
-
parameters: a || {},
|
|
499
|
-
files: o || null,
|
|
500
|
-
working_path: s || null
|
|
501
|
-
};
|
|
502
|
-
(await this.fetchWithErrorHandling(this.buildResolverUrl("generate_queries"), {
|
|
503
|
-
method: "POST",
|
|
504
|
-
headers: { "Content-Type": "application/json" },
|
|
505
|
-
body: JSON.stringify(p)
|
|
506
|
-
})).data.queries.forEach((e, c) => {
|
|
507
|
-
let l = f[c].index, u = f[c].component, p = [...i || [], ...u.extra_filters || []], m = {
|
|
508
|
-
...a || {},
|
|
509
|
-
...u.parameters || {}
|
|
510
|
-
}, h = this.createQueryCacheKey(u.query, t, n, r, p.length > 0 ? p : null, Object.keys(m).length > 0 ? m : null, null, o, s);
|
|
511
|
-
this.queryCache.set(h, { data: e }), d.push({
|
|
512
|
-
index: l,
|
|
513
|
-
result: {
|
|
514
|
-
...e,
|
|
515
|
-
label: u.label
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
let m = { data: { queries: d.sort((e, t) => e.index - t.index).map((e) => e.result) } };
|
|
520
|
-
return this.batchQueryCache.set(l, m), m;
|
|
521
|
-
}
|
|
522
|
-
async resolveModel(e, t) {
|
|
523
|
-
let n = {
|
|
524
|
-
name: e,
|
|
525
|
-
sources: t
|
|
526
|
-
}, r = this.createHash(n), i = this.modelCache.get(r);
|
|
527
|
-
if (i) return i;
|
|
528
|
-
let a = await this.fetchWithErrorHandling(this.buildResolverUrl("parse_model"), {
|
|
529
|
-
method: "POST",
|
|
530
|
-
headers: { "Content-Type": "application/json" },
|
|
531
|
-
body: JSON.stringify(n)
|
|
532
|
-
}), o = d.fromJSON(a.data);
|
|
533
|
-
return this.modelCache.set(r, o), o;
|
|
534
|
-
}
|
|
535
|
-
async warmResolver() {
|
|
536
|
-
let e = this.settingStore.settings.trilogyResolver.replace(/\/+$/, "");
|
|
537
|
-
if (!e || h.has(e)) return;
|
|
538
|
-
let t = g.get(e);
|
|
539
|
-
if (t) return t;
|
|
540
|
-
let n = this.fetchWithErrorHandling(`${e}/generate_query`, {
|
|
541
|
-
method: "POST",
|
|
542
|
-
headers: { "Content-Type": "application/json" },
|
|
543
|
-
body: JSON.stringify(_)
|
|
544
|
-
}).then(() => {
|
|
545
|
-
h.add(e);
|
|
546
|
-
}).catch((e) => {
|
|
547
|
-
console.warn("Resolver warm-up request failed:", e);
|
|
548
|
-
}).finally(() => {
|
|
549
|
-
g.delete(e);
|
|
550
|
-
});
|
|
551
|
-
return g.set(e, n), n;
|
|
552
|
-
}
|
|
553
|
-
clearAllCaches() {
|
|
554
|
-
this.validateCache.clear(), this.formatCache.clear(), this.queryCache.clear(), this.batchQueryCache.clear(), this.modelCache.clear();
|
|
555
|
-
}
|
|
556
|
-
getCacheStats() {
|
|
557
|
-
return {
|
|
558
|
-
validate: this.validateCache.size(),
|
|
559
|
-
format: this.formatCache.size(),
|
|
560
|
-
query: this.queryCache.size(),
|
|
561
|
-
batchQuery: this.batchQueryCache.size(),
|
|
562
|
-
model: this.modelCache.size()
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
}, ee = "<style>\n /* Every color comes from the theme contract, so the widget follows the\n host's light/dark mode instead of pinning one of them. */\n .widget { padding: 12px 14px; color: var(--widget-text); }\n .row {\n display: flex; align-items: center; gap: 10px;\n padding: 6px 8px; border-radius: 8px; cursor: pointer;\n }\n .row:hover { background: rgba(var(--widget-accent-rgb), 0.08); }\n .row.selected { background: rgba(var(--widget-accent-rgb), 0.18); }\n .label { flex: 0 0 30%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .bar { height: 10px; border-radius: 999px; background: var(--widget-accent); min-width: 2px; }\n .value {\n margin-left: auto;\n font-variant-numeric: tabular-nums;\n color: var(--widget-text-muted);\n }\n .empty { color: var(--widget-text-muted); padding: 12px 14px; }\n</style>\n\n<div class=\"widget\" id=\"root\"></div>\n\n<script>\n var root = document.getElementById('root');\n var selected = null;\n\n trilogy.subscribe(function (state) {\n if (state.status === 'loading' && !state.rows.length) return;\n if (!state.rows.length) {\n root.innerHTML = '<div class=\"empty\">No rows.</div>';\n return;\n }\n\n // Convention: first column is the dimension, second is the measure.\n var dim = state.columns[0] && state.columns[0].name;\n var measure = state.columns[1] && state.columns[1].name;\n if (!dim || !measure) {\n root.innerHTML = '<div class=\"empty\">Needs a dimension and a measure column.</div>';\n return;\n }\n\n var max = 0;\n state.rows.forEach(function (row) {\n var n = Number(row[measure]);\n if (isFinite(n) && n > max) max = n;\n });\n\n root.innerHTML = '';\n state.rows.slice(0, 25).forEach(function (row) {\n var value = Number(row[measure]) || 0;\n var label = String(row[dim]);\n\n var el = document.createElement('div');\n el.className = 'row' + (selected === label ? ' selected' : '');\n\n var name = document.createElement('div');\n name.className = 'label';\n name.textContent = label;\n\n var bar = document.createElement('div');\n bar.className = 'bar';\n bar.style.width = (max ? (value / max) * 55 : 0) + '%';\n\n var num = document.createElement('div');\n num.className = 'value';\n num.textContent = value.toLocaleString();\n\n el.appendChild(name);\n el.appendChild(bar);\n el.appendChild(num);\n\n el.addEventListener('click', function () {\n if (selected === label) {\n selected = null;\n trilogy.filters.clear();\n } else {\n selected = label;\n trilogy.filters.eq(dim, row[dim]);\n }\n });\n\n root.appendChild(el);\n });\n });\n\n trilogy.ready();\n<\/script>", b = [
|
|
566
|
-
{
|
|
567
|
-
value: "default",
|
|
568
|
-
label: "Default",
|
|
569
|
-
hint: "Rounded cards, tinted headers, a hairline ring. The standard look."
|
|
570
|
-
},
|
|
571
|
-
{
|
|
572
|
-
value: "flat",
|
|
573
|
-
label: "Flat",
|
|
574
|
-
hint: "Square corners, no shadow, untinted headers. Reads as one surface."
|
|
575
|
-
},
|
|
576
|
-
{
|
|
577
|
-
value: "paper",
|
|
578
|
-
label: "Paper",
|
|
579
|
-
hint: "Borderless cards floating on the canvas with roomy spacing. Best for reports and presentations."
|
|
580
|
-
},
|
|
581
|
-
{
|
|
582
|
-
value: "dense",
|
|
583
|
-
label: "Dense",
|
|
584
|
-
hint: "Tight gutters and short headers, to fit more panels on one screen."
|
|
585
|
-
}
|
|
586
|
-
], te = [
|
|
587
|
-
{
|
|
588
|
-
value: "square",
|
|
589
|
-
label: "Square",
|
|
590
|
-
hint: "No rounding."
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
value: "soft",
|
|
594
|
-
label: "Soft",
|
|
595
|
-
hint: "Lightly rounded."
|
|
596
|
-
},
|
|
597
|
-
{
|
|
598
|
-
value: "round",
|
|
599
|
-
label: "Round",
|
|
600
|
-
hint: "Fully rounded cards."
|
|
601
|
-
}
|
|
602
|
-
], ne = [
|
|
603
|
-
{
|
|
604
|
-
value: "compact",
|
|
605
|
-
label: "Compact",
|
|
606
|
-
hint: "Tight gutters and padding."
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
value: "comfortable",
|
|
610
|
-
label: "Comfortable",
|
|
611
|
-
hint: "Balanced spacing."
|
|
612
|
-
},
|
|
613
|
-
{
|
|
614
|
-
value: "spacious",
|
|
615
|
-
label: "Spacious",
|
|
616
|
-
hint: "Generous gutters and padding."
|
|
617
|
-
}
|
|
618
|
-
], re = [
|
|
619
|
-
{
|
|
620
|
-
value: "none",
|
|
621
|
-
label: "None",
|
|
622
|
-
hint: "Cards sit flat on the canvas."
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
value: "subtle",
|
|
626
|
-
label: "Subtle",
|
|
627
|
-
hint: "A faint drop shadow."
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
value: "raised",
|
|
631
|
-
label: "Raised",
|
|
632
|
-
hint: "Cards clearly float."
|
|
633
|
-
}
|
|
634
|
-
], ie = b.map((e) => e.value), ae = te.map((e) => e.value), oe = ne.map((e) => e.value), se = re.map((e) => e.value), ce = [
|
|
635
|
-
"canvasBackground",
|
|
636
|
-
"cardBackground",
|
|
637
|
-
"headerBackground",
|
|
638
|
-
"borderColor",
|
|
639
|
-
"textColor",
|
|
640
|
-
"accentColor"
|
|
641
|
-
], le = [
|
|
642
|
-
{
|
|
643
|
-
key: "canvasBackground",
|
|
644
|
-
label: "Canvas",
|
|
645
|
-
hint: "The page behind the cards.",
|
|
646
|
-
placeholder: {
|
|
647
|
-
light: "#f6f8fb",
|
|
648
|
-
dark: "#0d0f13"
|
|
649
|
-
}
|
|
650
|
-
},
|
|
651
|
-
{
|
|
652
|
-
key: "cardBackground",
|
|
653
|
-
label: "Card",
|
|
654
|
-
hint: "Fill of each panel.",
|
|
655
|
-
placeholder: {
|
|
656
|
-
light: "#ffffff",
|
|
657
|
-
dark: "#121417"
|
|
658
|
-
}
|
|
659
|
-
},
|
|
660
|
-
{
|
|
661
|
-
key: "headerBackground",
|
|
662
|
-
label: "Card header",
|
|
663
|
-
hint: "Title strip at the top of each panel.",
|
|
664
|
-
placeholder: {
|
|
665
|
-
light: "#f6f8fb",
|
|
666
|
-
dark: "#111318"
|
|
667
|
-
}
|
|
668
|
-
},
|
|
669
|
-
{
|
|
670
|
-
key: "borderColor",
|
|
671
|
-
label: "Border",
|
|
672
|
-
hint: "Card ring and header rule.",
|
|
673
|
-
placeholder: {
|
|
674
|
-
light: "#d6dde6",
|
|
675
|
-
dark: "#2a2f37"
|
|
676
|
-
}
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
key: "textColor",
|
|
680
|
-
label: "Text",
|
|
681
|
-
hint: "Body and title text.",
|
|
682
|
-
placeholder: {
|
|
683
|
-
light: "#1f2733",
|
|
684
|
-
dark: "#e6e9ef"
|
|
685
|
-
}
|
|
686
|
-
},
|
|
687
|
-
{
|
|
688
|
-
key: "accentColor",
|
|
689
|
-
label: "Accent",
|
|
690
|
-
hint: "Links, chips, active controls, and chart highlights.",
|
|
691
|
-
placeholder: {
|
|
692
|
-
light: "#2563eb",
|
|
693
|
-
dark: "#60a5fa"
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
], ue = "var(--dashboard-card-bg, var(--trilogy-embed-dashboard-background, var(--dashboard-background, #ffffff)))", de = "var(--dashboard-card-border-color, var(--trilogy-embed-border, var(--border-color, var(--border, #d6dde6))))", fe = {
|
|
697
|
-
square: {
|
|
698
|
-
card: "0px",
|
|
699
|
-
control: "0px",
|
|
700
|
-
chip: "4px"
|
|
701
|
-
},
|
|
702
|
-
soft: {
|
|
703
|
-
card: "8px",
|
|
704
|
-
control: "6px",
|
|
705
|
-
chip: "999px"
|
|
706
|
-
},
|
|
707
|
-
round: {
|
|
708
|
-
card: "14px",
|
|
709
|
-
control: "10px",
|
|
710
|
-
chip: "999px"
|
|
711
|
-
}
|
|
712
|
-
}, pe = {
|
|
713
|
-
compact: {
|
|
714
|
-
gutter: 6,
|
|
715
|
-
rowHeight: 30,
|
|
716
|
-
canvasPadding: "8px 10px 16px",
|
|
717
|
-
headerPadding: "2px 8px 2px",
|
|
718
|
-
headerMinHeight: "24px",
|
|
719
|
-
mobileGap: "8px",
|
|
720
|
-
mobileCanvasPadding: "4px 6px",
|
|
721
|
-
mobileHeaderPadding: "2px 8px 2px",
|
|
722
|
-
mobileHeaderMinHeight: "22px"
|
|
723
|
-
},
|
|
724
|
-
comfortable: {
|
|
725
|
-
gutter: 10,
|
|
726
|
-
rowHeight: 30,
|
|
727
|
-
canvasPadding: "16px 18px 24px",
|
|
728
|
-
headerPadding: "4px 12px 3px",
|
|
729
|
-
headerMinHeight: "27px",
|
|
730
|
-
mobileGap: "15px",
|
|
731
|
-
mobileCanvasPadding: "5px 10px",
|
|
732
|
-
mobileHeaderPadding: "3px 10px 2px",
|
|
733
|
-
mobileHeaderMinHeight: "25px"
|
|
734
|
-
},
|
|
735
|
-
spacious: {
|
|
736
|
-
gutter: 16,
|
|
737
|
-
rowHeight: 32,
|
|
738
|
-
canvasPadding: "24px 28px 32px",
|
|
739
|
-
headerPadding: "7px 16px 6px",
|
|
740
|
-
headerMinHeight: "34px",
|
|
741
|
-
mobileGap: "22px",
|
|
742
|
-
mobileCanvasPadding: "10px 14px",
|
|
743
|
-
mobileHeaderPadding: "6px 14px 5px",
|
|
744
|
-
mobileHeaderMinHeight: "32px"
|
|
745
|
-
}
|
|
746
|
-
}, me = {
|
|
747
|
-
none: {
|
|
748
|
-
light: "none",
|
|
749
|
-
dark: "none"
|
|
750
|
-
},
|
|
751
|
-
subtle: {
|
|
752
|
-
light: "0 1px 2px rgba(15, 23, 42, 0.08)",
|
|
753
|
-
dark: "0 1px 2px rgba(2, 6, 23, 0.35)"
|
|
754
|
-
},
|
|
755
|
-
raised: {
|
|
756
|
-
light: "0 8px 20px rgba(15, 23, 42, 0.12)",
|
|
757
|
-
dark: "0 8px 20px rgba(2, 6, 23, 0.5)"
|
|
758
|
-
}
|
|
759
|
-
}, he = {
|
|
760
|
-
default: {
|
|
761
|
-
corners: "round",
|
|
762
|
-
density: "comfortable",
|
|
763
|
-
elevation: "subtle",
|
|
764
|
-
mobileCards: !1,
|
|
765
|
-
borderWidth: "1px",
|
|
766
|
-
headerTint: !0
|
|
767
|
-
},
|
|
768
|
-
flat: {
|
|
769
|
-
corners: "square",
|
|
770
|
-
density: "comfortable",
|
|
771
|
-
elevation: "none",
|
|
772
|
-
mobileCards: !1,
|
|
773
|
-
borderWidth: "1px",
|
|
774
|
-
headerTint: !1
|
|
775
|
-
},
|
|
776
|
-
paper: {
|
|
777
|
-
corners: "round",
|
|
778
|
-
density: "spacious",
|
|
779
|
-
elevation: "raised",
|
|
780
|
-
mobileCards: !0,
|
|
781
|
-
borderWidth: "0px",
|
|
782
|
-
headerTint: !0
|
|
783
|
-
},
|
|
784
|
-
dense: {
|
|
785
|
-
corners: "soft",
|
|
786
|
-
density: "compact",
|
|
787
|
-
elevation: "subtle",
|
|
788
|
-
mobileCards: !1,
|
|
789
|
-
borderWidth: "1px",
|
|
790
|
-
headerTint: !0
|
|
791
|
-
}
|
|
792
|
-
}, ge = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i, _e = /^(?:rgb|rgba|hsl|hsla)\(\s*[0-9a-z.,%/\s-]+\)$/i, ve = /^[a-z]+$/i;
|
|
793
|
-
function ye(e) {
|
|
794
|
-
if (typeof e != "string") return !1;
|
|
795
|
-
let t = e.trim();
|
|
796
|
-
return !t || t.length > 64 || /[;{}\\<>]|\/\*|url\(|var\(|expression|@import/i.test(t) ? !1 : ge.test(t) || _e.test(t) || ve.test(t);
|
|
797
|
-
}
|
|
798
|
-
function be(e) {
|
|
799
|
-
let t = e.trim(), n = t.match(/^#([0-9a-f]{3,8})$/i)?.[1];
|
|
800
|
-
if (n) {
|
|
801
|
-
let e = (e) => e.length === 3 || e.length === 4 ? e.slice(0, 3).split("").map((e) => e + e).join("") : e.slice(0, 6);
|
|
802
|
-
if (n.length === 5 || n.length === 7) return null;
|
|
803
|
-
let t = e(n), r = parseInt(t, 16);
|
|
804
|
-
return Number.isNaN(r) ? null : `${r >> 16 & 255}, ${r >> 8 & 255}, ${r & 255}`;
|
|
805
|
-
}
|
|
806
|
-
let r = t.match(/^rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)/i);
|
|
807
|
-
if (r) {
|
|
808
|
-
let e = [
|
|
809
|
-
r[1],
|
|
810
|
-
r[2],
|
|
811
|
-
r[3]
|
|
812
|
-
].map((e) => Math.round(Number(e)));
|
|
813
|
-
return e.some((e) => !Number.isFinite(e) || e < 0 || e > 255) ? null : e.join(", ");
|
|
814
|
-
}
|
|
815
|
-
return null;
|
|
816
|
-
}
|
|
817
|
-
function x(e) {
|
|
818
|
-
if (!e || typeof e != "object" || Array.isArray(e)) return;
|
|
819
|
-
let t = e, n = {}, r = (e, t) => typeof e == "string" && t.includes(e) ? e : void 0, i = r(t.preset, ie);
|
|
820
|
-
i && (n.preset = i);
|
|
821
|
-
let a = r(t.corners, ae);
|
|
822
|
-
a && (n.corners = a);
|
|
823
|
-
let o = r(t.density, oe);
|
|
824
|
-
o && (n.density = o);
|
|
825
|
-
let s = r(t.elevation, se);
|
|
826
|
-
s && (n.elevation = s), typeof t.mobileCards == "boolean" && (n.mobileCards = t.mobileCards);
|
|
827
|
-
for (let e of ce) ye(t[e]) && (n[e] = t[e].trim());
|
|
828
|
-
return Object.keys(n).length > 0 ? n : void 0;
|
|
829
|
-
}
|
|
830
|
-
function xe(e) {
|
|
831
|
-
if (!e || Object.keys(e).length === 0) return "default (inherits the app light/dark theme)";
|
|
832
|
-
let t = [`preset ${e.preset || "default"}`];
|
|
833
|
-
e.corners && t.push(`corners ${e.corners}`), e.density && t.push(`density ${e.density}`), e.elevation && t.push(`elevation ${e.elevation}`), e.mobileCards !== void 0 && t.push(e.mobileCards ? "cards kept on mobile" : "cards flattened on mobile");
|
|
834
|
-
let n = ce.filter((t) => e[t]).map((t) => `${t}=${e[t]}`);
|
|
835
|
-
return t.push(n.length > 0 ? `colors: ${n.join(", ")}` : "colors inherited"), t.join(", ");
|
|
836
|
-
}
|
|
837
|
-
function Se(e) {
|
|
838
|
-
let { mode: t } = e, n = e.theme || {}, r = he[n.preset || "default"], i = fe[n.corners || r.corners], a = pe[n.density || r.density], o = n.elevation || r.elevation, s = n.mobileCards ?? r.mobileCards, c = me[o][t], l = `inset 0 0 0 ${r.borderWidth} ${de}` + (c === "none" ? "" : `, ${c}`), u = {
|
|
839
|
-
"--dashboard-card-radius": i.card,
|
|
840
|
-
"--dashboard-control-radius": i.control,
|
|
841
|
-
"--dashboard-chip-radius": i.chip,
|
|
842
|
-
"--dashboard-card-border-width": r.borderWidth,
|
|
843
|
-
"--dashboard-header-border-width": r.borderWidth,
|
|
844
|
-
"--dashboard-card-shadow": c,
|
|
845
|
-
"--dashboard-canvas-padding": a.canvasPadding,
|
|
846
|
-
"--dashboard-header-padding": a.headerPadding,
|
|
847
|
-
"--dashboard-header-min-height": a.headerMinHeight,
|
|
848
|
-
"--dashboard-gutter": `${a.gutter}px`,
|
|
849
|
-
"--dashboard-card-radius-mobile": s ? i.card : "0px",
|
|
850
|
-
"--dashboard-card-bg-mobile": s ? ue : "transparent",
|
|
851
|
-
"--dashboard-card-shadow-mobile": s ? l : "none",
|
|
852
|
-
"--dashboard-header-border-width-mobile": s ? r.borderWidth : "0px",
|
|
853
|
-
"--dashboard-mobile-item-bg": s ? "transparent" : "var(--result-window-bg, transparent)",
|
|
854
|
-
"--dashboard-mobile-gap": a.mobileGap,
|
|
855
|
-
"--dashboard-mobile-canvas-padding": a.mobileCanvasPadding,
|
|
856
|
-
"--dashboard-header-padding-mobile": a.mobileHeaderPadding,
|
|
857
|
-
"--dashboard-header-min-height-mobile": a.mobileHeaderMinHeight
|
|
858
|
-
};
|
|
859
|
-
if (!r.headerTint && !n.headerBackground && (u["--dashboard-header-bg"] = ue), n.cardBackground && (u["--dashboard-card-bg"] = n.cardBackground), n.headerBackground && (u["--dashboard-header-bg"] = n.headerBackground), n.canvasBackground && (u["--dashboard-canvas-bg"] = n.canvasBackground), n.borderColor && (u["--dashboard-card-border-color"] = n.borderColor), n.textColor && (u["--text-color"] = n.textColor), n.accentColor) {
|
|
860
|
-
u["--special-text"] = n.accentColor;
|
|
861
|
-
let e = be(n.accentColor);
|
|
862
|
-
e && (u["--special-text-rgb"] = e);
|
|
863
|
-
}
|
|
864
|
-
return {
|
|
865
|
-
vars: u,
|
|
866
|
-
gridMargin: [a.gutter, a.gutter],
|
|
867
|
-
rowHeight: a.rowHeight
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
function Ce(e, t) {
|
|
871
|
-
if (!t) return e;
|
|
872
|
-
let n = {};
|
|
873
|
-
for (let [r, i] of Object.entries(e)) r in t || (n[r] = i);
|
|
874
|
-
return n;
|
|
875
|
-
}
|
|
876
|
-
//#endregion
|
|
877
|
-
//#region dashboards/conditions.ts
|
|
878
|
-
function we(e) {
|
|
879
|
-
return e.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
880
|
-
}
|
|
881
|
-
function Te(e) {
|
|
882
|
-
let t = 0;
|
|
883
|
-
for (let n = 0; n < e.length; n++) t = Math.imul(31, t) + e.charCodeAt(n) | 0;
|
|
884
|
-
return Math.abs(t).toString(36).slice(0, 5);
|
|
885
|
-
}
|
|
886
|
-
function S(e) {
|
|
887
|
-
return e instanceof Date ? `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}` : typeof e == "object" && e && typeof e.toISODate == "function" ? e.toISODate() : e;
|
|
888
|
-
}
|
|
889
|
-
function Ee(e, t, n = "") {
|
|
890
|
-
let r = we(e) + "_" + Te(e) + n;
|
|
891
|
-
switch (t.op) {
|
|
892
|
-
case "eq": {
|
|
893
|
-
let n = S(t.value);
|
|
894
|
-
return {
|
|
895
|
-
filterString: `${e} = :${r}`,
|
|
896
|
-
parameters: { [`:${r}`]: n }
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
case "range": {
|
|
900
|
-
let n = S(t.value[0]), i = S(t.value[1]);
|
|
901
|
-
return {
|
|
902
|
-
filterString: `${e} between :${r}_min and :${r}_max`,
|
|
903
|
-
parameters: {
|
|
904
|
-
[`:${r}_min`]: n,
|
|
905
|
-
[`:${r}_max`]: i
|
|
906
|
-
}
|
|
907
|
-
};
|
|
908
|
-
}
|
|
909
|
-
case "in": {
|
|
910
|
-
let n = {};
|
|
911
|
-
return {
|
|
912
|
-
filterString: `${e} in (${t.value.map((e, t) => (n[`:${r}_${t}`] = S(e), `:${r}_${t}`)).join(", ")})`,
|
|
913
|
-
parameters: n
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
case "is_null": return {
|
|
917
|
-
filterString: `${e} IS NULL`,
|
|
918
|
-
parameters: {}
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
function De(e) {
|
|
923
|
-
if (Array.isArray(e)) {
|
|
924
|
-
let t = {};
|
|
925
|
-
return e.forEach((e) => {
|
|
926
|
-
Object.entries(e).forEach(([e, n]) => {
|
|
927
|
-
t[e] || (t[e] = []), t[e].push(n);
|
|
928
|
-
});
|
|
929
|
-
}), Object.entries(t).map(([e, t]) => t.length > 1 ? `(${t.map((t) => ke(e, t)).join(" OR ")})` : ke(e, t[0])).join(" AND ");
|
|
930
|
-
}
|
|
931
|
-
return Object.keys(e).length === 0 ? "" : Object.entries(e).map(([e, t]) => ke(e, t)).join(" AND ");
|
|
932
|
-
}
|
|
933
|
-
function Oe(e) {
|
|
934
|
-
if (e instanceof Date) return `'${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}'::date`;
|
|
935
|
-
if (e === null) return "NULL";
|
|
936
|
-
if (typeof e == "string") return `'${e.replace(/'/g, "!`")}'`;
|
|
937
|
-
if (typeof e == "boolean") return e ? "TRUE" : "FALSE";
|
|
938
|
-
if (typeof e == "number") return e.toString();
|
|
939
|
-
}
|
|
940
|
-
function ke(e, t) {
|
|
941
|
-
return t === null ? `${e} IS NULL` : typeof t == "string" ? `${e}='''${t.replace(/'/g, "!`")}'''` : Array.isArray(t) ? `${e} between ${Oe(t[0])} and ${Oe(t[t.length - 1])}` : typeof t == "number" || typeof t == "boolean" ? `${e}=${t}` : t === void 0 ? `${e} IS NULL` : `${e}='${JSON.stringify(t).replace(/'/g, "!`")}'`;
|
|
942
|
-
}
|
|
943
|
-
//#endregion
|
|
944
|
-
//#region dashboards/crossFilters.ts
|
|
945
|
-
function Ae(e = []) {
|
|
946
|
-
let t = /* @__PURE__ */ new Set();
|
|
947
|
-
for (let n of e) n?.label && t.add(n.label);
|
|
948
|
-
return Array.from(t);
|
|
949
|
-
}
|
|
950
|
-
function C(e) {
|
|
951
|
-
return { ...e };
|
|
952
|
-
}
|
|
953
|
-
function w(e) {
|
|
954
|
-
return { ...e };
|
|
955
|
-
}
|
|
956
|
-
function je(e, t) {
|
|
957
|
-
if (e.op !== t.op) return !1;
|
|
958
|
-
switch (e.op) {
|
|
959
|
-
case "is_null": return !0;
|
|
960
|
-
case "eq": return e.value === t.value;
|
|
961
|
-
case "range": {
|
|
962
|
-
let n = t;
|
|
963
|
-
return e.value[0] === n.value[0] && e.value[1] === n.value[1];
|
|
964
|
-
}
|
|
965
|
-
case "in": {
|
|
966
|
-
let n = t;
|
|
967
|
-
return e.value.length === n.value.length && e.value.every((e, t) => e === n.value[t]);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
function T(e, t) {
|
|
972
|
-
let n = Object.keys(e).sort(), r = Object.keys(t).sort();
|
|
973
|
-
return n.length === r.length && n.every((n, i) => n === r[i] && je(e[n], t[n]));
|
|
974
|
-
}
|
|
975
|
-
function Me(e, t) {
|
|
976
|
-
return Array.isArray(e) && Array.isArray(t) ? e.length === t.length && e.every((e, n) => e === t[n]) : e === t;
|
|
977
|
-
}
|
|
978
|
-
function Ne(e, t) {
|
|
979
|
-
let n = Object.keys(e).sort(), r = Object.keys(t).sort();
|
|
980
|
-
return n.length === r.length && n.every((n, i) => n === r[i] && Me(e[n], t[n]));
|
|
981
|
-
}
|
|
982
|
-
function Pe(e, t, n, r) {
|
|
983
|
-
let i = e.filter((e) => e.source !== t), a = e.filter((e) => e.source === t);
|
|
984
|
-
if (r === "remove") return i;
|
|
985
|
-
if (r === "add") return [...i, {
|
|
986
|
-
source: t,
|
|
987
|
-
value: w(n)
|
|
988
|
-
}];
|
|
989
|
-
let o = a.some((e) => Ne(e.value, n)) ? a.filter((e) => !Ne(e.value, n)) : [...a, {
|
|
990
|
-
source: t,
|
|
991
|
-
value: w(n)
|
|
992
|
-
}];
|
|
993
|
-
return [...i, ...o];
|
|
994
|
-
}
|
|
995
|
-
function Fe(e, t, n) {
|
|
996
|
-
if (t.size === 0) return n && e.startsWith("local.") ? e.replace(/^local\./, "") : e;
|
|
997
|
-
if (t.has(e)) return e;
|
|
998
|
-
if (e.startsWith("local.")) {
|
|
999
|
-
let r = e.replace(/^local\./, "");
|
|
1000
|
-
if (t.has(r)) return n ? r : e;
|
|
1001
|
-
}
|
|
1002
|
-
return null;
|
|
1003
|
-
}
|
|
1004
|
-
function Ie(e, t = [], n = {}) {
|
|
1005
|
-
let r = new Set(t), i = n.normalizeLocalFields ?? !1;
|
|
1006
|
-
return Object.entries(e).reduce((e, [t, n]) => {
|
|
1007
|
-
if (typeof n != "object" || !n || ![
|
|
1008
|
-
"eq",
|
|
1009
|
-
"range",
|
|
1010
|
-
"in",
|
|
1011
|
-
"is_null"
|
|
1012
|
-
].includes(n.op)) return e;
|
|
1013
|
-
let a = Fe(t, r, i);
|
|
1014
|
-
return a && (e[a] = n), e;
|
|
1015
|
-
}, {});
|
|
1016
|
-
}
|
|
1017
|
-
function E(e) {
|
|
1018
|
-
if (!e.length) return {
|
|
1019
|
-
filterStrings: [],
|
|
1020
|
-
parameters: {}
|
|
1021
|
-
};
|
|
1022
|
-
let t = {};
|
|
1023
|
-
for (let n of e) for (let [e, r] of Object.entries(n.value)) t[e] || (t[e] = []), t[e].push(r);
|
|
1024
|
-
let n = [], r = {};
|
|
1025
|
-
for (let [e, i] of Object.entries(t)) if (i.length > 1) {
|
|
1026
|
-
let t = [];
|
|
1027
|
-
for (let n = 0; n < i.length; n++) {
|
|
1028
|
-
let { filterString: a, parameters: o } = Ee(e, i[n], `_or${n}`);
|
|
1029
|
-
t.push(a), r = {
|
|
1030
|
-
...r,
|
|
1031
|
-
...o
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
n.push(`(${t.join(" OR ")})`);
|
|
1035
|
-
} else {
|
|
1036
|
-
let { filterString: t, parameters: a } = Ee(e, i[0]);
|
|
1037
|
-
n.push(t), r = {
|
|
1038
|
-
...r,
|
|
1039
|
-
...a
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
return {
|
|
1043
|
-
filterStrings: n,
|
|
1044
|
-
parameters: r
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
function D(e) {
|
|
1048
|
-
let t = e.conceptFilters || [], n = (e.filters || []).filter((e) => e.source !== "cross"), { filterStrings: r, parameters: i } = E(t), a = r.join(" AND ");
|
|
1049
|
-
a && n.push({
|
|
1050
|
-
source: "cross",
|
|
1051
|
-
value: a,
|
|
1052
|
-
parameters: Object.keys(i).length ? i : void 0
|
|
1053
|
-
});
|
|
1054
|
-
let o = JSON.stringify(n) !== JSON.stringify(e.filters || []);
|
|
1055
|
-
return e.filters = n, o;
|
|
1056
|
-
}
|
|
1057
|
-
function Le(e, t, n, r) {
|
|
1058
|
-
let i = e.filter((e) => e.source !== t), a = e.filter((e) => e.source === t);
|
|
1059
|
-
if (r === "remove") return i;
|
|
1060
|
-
if (r === "add") return [...i, {
|
|
1061
|
-
source: t,
|
|
1062
|
-
value: C(n)
|
|
1063
|
-
}];
|
|
1064
|
-
let o = a.some((e) => T(e.value, n)) ? a.filter((e) => !T(e.value, n)) : [...a, {
|
|
1065
|
-
source: t,
|
|
1066
|
-
value: C(n)
|
|
1067
|
-
}];
|
|
1068
|
-
return [...i, ...o];
|
|
1069
|
-
}
|
|
1070
|
-
function Re(e, t, n, r, i) {
|
|
1071
|
-
let a = [];
|
|
1072
|
-
return Object.entries(e).forEach(([e, o]) => {
|
|
1073
|
-
if (e === t) {
|
|
1074
|
-
let e = Pe(o.chartFilters || [], t, r, i);
|
|
1075
|
-
JSON.stringify(e) !== JSON.stringify(o.chartFilters || []) && (o.chartFilters = e);
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
if (!o.allowCrossFilter) return;
|
|
1079
|
-
let s = Le(o.conceptFilters || [], t, n, i), c = JSON.stringify(s) !== JSON.stringify(o.conceptFilters || []);
|
|
1080
|
-
c && (o.conceptFilters = s);
|
|
1081
|
-
let l = D(o);
|
|
1082
|
-
(c || l) && a.push(e);
|
|
1083
|
-
}), a;
|
|
1084
|
-
}
|
|
1085
|
-
function ze(e, t, n) {
|
|
1086
|
-
let r = e[t];
|
|
1087
|
-
if (!r) return !1;
|
|
1088
|
-
let i = (r.conceptFilters || []).filter((e) => e.source !== n), a = JSON.stringify(i) !== JSON.stringify(r.conceptFilters || []);
|
|
1089
|
-
a && (r.conceptFilters = i);
|
|
1090
|
-
let o = D(r);
|
|
1091
|
-
return a || o;
|
|
1092
|
-
}
|
|
1093
|
-
function Be(e, t) {
|
|
1094
|
-
let n = [];
|
|
1095
|
-
return Object.entries(e).forEach(([e, r]) => {
|
|
1096
|
-
if (e === t) {
|
|
1097
|
-
r.chartFilters = [];
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
let i = (r.conceptFilters || []).filter((e) => e.source !== t), a = JSON.stringify(i) !== JSON.stringify(r.conceptFilters || []);
|
|
1101
|
-
a && (r.conceptFilters = i);
|
|
1102
|
-
let o = D(r);
|
|
1103
|
-
(a || o) && n.push(e);
|
|
1104
|
-
}), n;
|
|
1105
|
-
}
|
|
1106
|
-
function Ve(e) {
|
|
1107
|
-
let t = [];
|
|
1108
|
-
return Object.entries(e).forEach(([e, n]) => {
|
|
1109
|
-
let r = !!n.conceptFilters?.length || !!n.chartFilters?.length || !!n.filters?.length;
|
|
1110
|
-
n.conceptFilters = [], n.chartFilters = [], n.filters = [], r && t.push(e);
|
|
1111
|
-
}), t;
|
|
1112
|
-
}
|
|
1113
|
-
function He(e = {}) {
|
|
1114
|
-
let t = /* @__PURE__ */ new Map(), n = () => {
|
|
1115
|
-
let t = e.validFields ? o(e.validFields) : [];
|
|
1116
|
-
return new Set(t);
|
|
1117
|
-
}, r = (t) => {
|
|
1118
|
-
let r = Ie(t.filters, n(), { normalizeLocalFields: e.normalizeLocalFields ?? !0 });
|
|
1119
|
-
return {
|
|
1120
|
-
source: t.source,
|
|
1121
|
-
filters: r,
|
|
1122
|
-
chart: w(t.chart || {}),
|
|
1123
|
-
append: t.append
|
|
1124
|
-
};
|
|
1125
|
-
};
|
|
1126
|
-
return {
|
|
1127
|
-
getSelections() {
|
|
1128
|
-
return Array.from(t.values()).flat().map((e) => ({
|
|
1129
|
-
source: e.source,
|
|
1130
|
-
filters: C(e.filters),
|
|
1131
|
-
chart: w(e.chart || {}),
|
|
1132
|
-
append: e.append
|
|
1133
|
-
}));
|
|
1134
|
-
},
|
|
1135
|
-
getSelectionSources() {
|
|
1136
|
-
return Array.from(t.keys());
|
|
1137
|
-
},
|
|
1138
|
-
applyDimensionClick(e, n) {
|
|
1139
|
-
let i = r(e), a = n ?? (e.append ? "append" : "add");
|
|
1140
|
-
if (Object.keys(i.filters).length === 0) return a !== "append" && t.delete(e.source), {};
|
|
1141
|
-
let o = t.get(e.source) || [];
|
|
1142
|
-
if (a === "remove") return t.delete(e.source), i.filters;
|
|
1143
|
-
if (a === "add") return t.set(e.source, [i]), i.filters;
|
|
1144
|
-
let s = o.some((e) => T(e.filters, i.filters)) ? o.filter((e) => !T(e.filters, i.filters)) : [...o, i];
|
|
1145
|
-
return s.length === 0 ? t.delete(e.source) : t.set(e.source, s), i.filters;
|
|
1146
|
-
},
|
|
1147
|
-
clearSource(e) {
|
|
1148
|
-
t.delete(e);
|
|
1149
|
-
},
|
|
1150
|
-
clearAll() {
|
|
1151
|
-
t.clear();
|
|
1152
|
-
},
|
|
1153
|
-
hasSelectionFrom(e) {
|
|
1154
|
-
return t.has(e);
|
|
1155
|
-
},
|
|
1156
|
-
getSqlFilterInputsFor(e) {
|
|
1157
|
-
return Array.from(t.entries()).filter(([t]) => t !== e).flatMap(([e, t]) => t.map((t) => ({
|
|
1158
|
-
source: e,
|
|
1159
|
-
value: C(t.filters)
|
|
1160
|
-
})));
|
|
1161
|
-
},
|
|
1162
|
-
getChartSelectionsFor(e) {
|
|
1163
|
-
return (t.get(e) || []).map((e) => w(e.chart || {}));
|
|
1164
|
-
},
|
|
1165
|
-
getFilterExpressionFor(e) {
|
|
1166
|
-
let { filterStrings: t } = E(this.getSqlFilterInputsFor(e));
|
|
1167
|
-
return t.join(" AND ");
|
|
1168
|
-
},
|
|
1169
|
-
getSqlFiltersFor(e, t = []) {
|
|
1170
|
-
let n = this.getFilterExpressionFor(e);
|
|
1171
|
-
return n ? [...t, n] : [...t];
|
|
1172
|
-
},
|
|
1173
|
-
getSqlFilterLikesFor(e, t = []) {
|
|
1174
|
-
let n = t.map((e) => ({
|
|
1175
|
-
source: "base",
|
|
1176
|
-
value: e
|
|
1177
|
-
})), { filterStrings: r, parameters: i } = E(this.getSqlFilterInputsFor(e)), a = r.join(" AND ");
|
|
1178
|
-
return a && n.push({
|
|
1179
|
-
source: "cross",
|
|
1180
|
-
value: a,
|
|
1181
|
-
parameters: Object.keys(i).length ? i : void 0
|
|
1182
|
-
}), n;
|
|
1183
|
-
},
|
|
1184
|
-
getSqlParametersFor(e) {
|
|
1185
|
-
let { parameters: t } = E(this.getSqlFilterInputsFor(e));
|
|
1186
|
-
return t;
|
|
1187
|
-
}
|
|
1188
|
-
};
|
|
1189
|
-
}
|
|
1190
|
-
function Ue(e = {}) {
|
|
1191
|
-
let t = a(0), n = He(o(e)), r = () => {
|
|
1192
|
-
t.value += 1;
|
|
1193
|
-
};
|
|
1194
|
-
return {
|
|
1195
|
-
version: i(() => t.value),
|
|
1196
|
-
applyDimensionClick(e, t) {
|
|
1197
|
-
let i = n.applyDimensionClick(e, t);
|
|
1198
|
-
return r(), i;
|
|
1199
|
-
},
|
|
1200
|
-
clearSource(e) {
|
|
1201
|
-
n.clearSource(e), r();
|
|
1202
|
-
},
|
|
1203
|
-
clearAll() {
|
|
1204
|
-
n.clearAll(), r();
|
|
1205
|
-
},
|
|
1206
|
-
hasSelectionFrom(e) {
|
|
1207
|
-
return t.value, n.hasSelectionFrom(e);
|
|
1208
|
-
},
|
|
1209
|
-
getSelections() {
|
|
1210
|
-
return t.value, n.getSelections();
|
|
1211
|
-
},
|
|
1212
|
-
getSelectionSources() {
|
|
1213
|
-
return t.value, n.getSelectionSources();
|
|
1214
|
-
},
|
|
1215
|
-
getSqlFilterInputsFor(e) {
|
|
1216
|
-
return t.value, n.getSqlFilterInputsFor(e);
|
|
1217
|
-
},
|
|
1218
|
-
getChartSelectionsFor(e) {
|
|
1219
|
-
return t.value, n.getChartSelectionsFor(e);
|
|
1220
|
-
},
|
|
1221
|
-
getFilterExpressionFor(e) {
|
|
1222
|
-
return t.value, n.getFilterExpressionFor(e);
|
|
1223
|
-
},
|
|
1224
|
-
getSqlFiltersFor(e, r = []) {
|
|
1225
|
-
return t.value, n.getSqlFiltersFor(e, r);
|
|
1226
|
-
},
|
|
1227
|
-
getSqlFilterLikesFor(e, r = []) {
|
|
1228
|
-
return t.value, n.getSqlFilterLikesFor(e, r);
|
|
1229
|
-
},
|
|
1230
|
-
getSqlParametersFor(e) {
|
|
1231
|
-
return t.value, n.getSqlParametersFor(e);
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
//#endregion
|
|
1236
|
-
//#region dashboards/base.ts
|
|
1237
|
-
var O = {
|
|
1238
|
-
CHART: "chart",
|
|
1239
|
-
MARKDOWN: "markdown",
|
|
1240
|
-
TABLE: "table",
|
|
1241
|
-
FILTER: "filter",
|
|
1242
|
-
SECTION_HEADER: "section-header",
|
|
1243
|
-
MEMO: "memo",
|
|
1244
|
-
CLAIM: "claim",
|
|
1245
|
-
APPENDIX_HEADER: "appendix-header",
|
|
1246
|
-
FREEFORM: "freeform"
|
|
1247
|
-
};
|
|
1248
|
-
function We(e) {
|
|
1249
|
-
return !!e && typeof e == "object" && "markdown" in e;
|
|
1250
|
-
}
|
|
1251
|
-
function Ge(e) {
|
|
1252
|
-
return !!e && typeof e == "object" && "headline" in e && "verdict" in e && "confidence" in e;
|
|
1253
|
-
}
|
|
1254
|
-
function Ke(e) {
|
|
1255
|
-
return !!e && typeof e == "object" && "claim" in e && !("headline" in e);
|
|
1256
|
-
}
|
|
1257
|
-
function qe(e) {
|
|
1258
|
-
return !!e && typeof e == "object" && typeof e.html == "string";
|
|
1259
|
-
}
|
|
1260
|
-
function Je(e) {
|
|
1261
|
-
let t = e.content;
|
|
1262
|
-
if (typeof t == "string") return e.type === O.CHART || e.type === O.TABLE ? t : void 0;
|
|
1263
|
-
if (qe(t) || Ge(t) || Ke(t) || We(t)) return t.query || void 0;
|
|
1264
|
-
}
|
|
1265
|
-
var Ye = class t {
|
|
1266
|
-
id;
|
|
1267
|
-
name;
|
|
1268
|
-
storage;
|
|
1269
|
-
connection;
|
|
1270
|
-
connectionId;
|
|
1271
|
-
layout = [];
|
|
1272
|
-
gridItems = {};
|
|
1273
|
-
nextId = 0;
|
|
1274
|
-
createdAt;
|
|
1275
|
-
updatedAt;
|
|
1276
|
-
filter = null;
|
|
1277
|
-
imports = [];
|
|
1278
|
-
version;
|
|
1279
|
-
state = "editing";
|
|
1280
|
-
description = "";
|
|
1281
|
-
changed = !1;
|
|
1282
|
-
deleted = !1;
|
|
1283
|
-
layoutType = "grid";
|
|
1284
|
-
theme;
|
|
1285
|
-
parentDashboardId;
|
|
1286
|
-
investigationName;
|
|
1287
|
-
investigationCreatedFrom;
|
|
1288
|
-
children;
|
|
1289
|
-
chatId;
|
|
1290
|
-
constructor({ id: e, name: t, storage: n = "local", connection: r, connectionId: i = "", layout: a = [], gridItems: o = {}, nextId: s = 0, createdAt: c, updatedAt: l, filter: u = null, imports: d = [], version: f = 1, state: p = "editing", description: m = "", layoutType: h = "grid", theme: g, parentDashboardId: _ = null, investigationName: v, investigationCreatedFrom: y, children: ee = [], chatId: b = null }) {
|
|
1291
|
-
this.id = e, this.name = t, this.storage = n, this.connection = r, this.connectionId = i, this.layout = a, this.gridItems = o, this.nextId = s, this.createdAt = c || /* @__PURE__ */ new Date(), this.updatedAt = l || /* @__PURE__ */ new Date(), this.filter = u, this.imports = d, this.version = f, this.state = p, this.description = m, this.changed = !1, this.layoutType = h, this.theme = x(g), this.parentDashboardId = _, this.investigationName = v, this.investigationCreatedFrom = y, this.children = ee, this.chatId = b;
|
|
1292
|
-
}
|
|
1293
|
-
setChatId(e) {
|
|
1294
|
-
this.chatId !== e && (this.chatId = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1295
|
-
}
|
|
1296
|
-
get isInvestigation() {
|
|
1297
|
-
return !!this.parentDashboardId;
|
|
1298
|
-
}
|
|
1299
|
-
delete() {
|
|
1300
|
-
this.deleted = !0, this.changed = !0;
|
|
1301
|
-
}
|
|
1302
|
-
updateItemLayoutDimensions(e, t = null, n = null, r = null, i = null) {
|
|
1303
|
-
let a = this.layout.find((t) => t.i === e);
|
|
1304
|
-
a ? (t !== null && (a.x = t), n !== null && (a.y = n), r !== null && (a.w = r), i !== null && (a.h = i), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0) : console.warn(`Layout item with ID "${e}" does not exist in the dashboard.`);
|
|
1305
|
-
}
|
|
1306
|
-
addItem(e, t = 0, n = 0, r = 4, i = null, a = null, o) {
|
|
1307
|
-
let s = this.nextId.toString(), c = 10, l = r;
|
|
1308
|
-
e === O.MARKDOWN ? c = 3 : e === O.SECTION_HEADER || e === O.APPENDIX_HEADER ? c = 1 : e === O.MEMO ? (c = 8, l = 20) : e === O.CLAIM ? (c = 4, l = 20) : e === O.FREEFORM && (c = 10);
|
|
1309
|
-
let u = n;
|
|
1310
|
-
u = this.layout.reduce((e, t) => Math.max(e, t.y + t.h), 0), this.layout.push({
|
|
1311
|
-
x: t,
|
|
1312
|
-
y: u,
|
|
1313
|
-
w: l,
|
|
1314
|
-
h: i || c,
|
|
1315
|
-
i: s,
|
|
1316
|
-
static: !1
|
|
1317
|
-
});
|
|
1318
|
-
let d = `Note ${s}`;
|
|
1319
|
-
e === O.CHART ? d = `Chart ${s}` : e === O.TABLE ? d = `Table ${s}` : e === O.SECTION_HEADER ? d = "### Section Header" : e === O.MEMO ? d = "Executive Memo" : e === O.CLAIM ? d = `Claim ${s}` : e === O.APPENDIX_HEADER ? d = "### Appendix" : e === O.FREEFORM && (d = `Widget ${s}`);
|
|
1320
|
-
let f = o || d, p = "# Markdown Cell\nEnter your markdown content here.";
|
|
1321
|
-
e === O.CHART ? p = "SELECT unnest([1,2,3,4]) as value, 'example' as dim" : e === O.TABLE ? p = "SELECT [1,2,3,4] as value, 'example' as dim" : e === O.SECTION_HEADER || e === O.APPENDIX_HEADER ? p = "" : e === O.MEMO ? p = {
|
|
1322
|
-
headline: "",
|
|
1323
|
-
verdict: "inconclusive",
|
|
1324
|
-
magnitude: "",
|
|
1325
|
-
cause: "",
|
|
1326
|
-
action: "",
|
|
1327
|
-
confidence: "medium"
|
|
1328
|
-
} : e === O.CLAIM ? p = { claim: "" } : e === O.FREEFORM && (p = {
|
|
1329
|
-
html: ee,
|
|
1330
|
-
query: "SELECT unnest(['alpha','beta','gamma']) as dim, random() * 100 as value"
|
|
1331
|
-
});
|
|
1332
|
-
let m = a ?? p;
|
|
1333
|
-
return this.gridItems[s] = {
|
|
1334
|
-
type: e,
|
|
1335
|
-
content: m,
|
|
1336
|
-
name: f,
|
|
1337
|
-
width: 0,
|
|
1338
|
-
height: 0,
|
|
1339
|
-
allowCrossFilter: !(e === O.SECTION_HEADER || e === O.APPENDIX_HEADER || e === O.MEMO)
|
|
1340
|
-
}, this.nextId++, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, s;
|
|
1341
|
-
}
|
|
1342
|
-
setLayoutType(e) {
|
|
1343
|
-
this.layoutType !== e && (this.layoutType = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1344
|
-
}
|
|
1345
|
-
setTheme(e) {
|
|
1346
|
-
let t = e === null ? void 0 : x({
|
|
1347
|
-
...this.theme,
|
|
1348
|
-
...e
|
|
1349
|
-
});
|
|
1350
|
-
JSON.stringify(t ?? null) !== JSON.stringify(this.theme ?? null) && (this.theme = t, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1351
|
-
}
|
|
1352
|
-
copyItem(e) {
|
|
1353
|
-
if (!this.gridItems[e]) throw Error(`Item with ID "${e}" does not exist in the dashboard.`);
|
|
1354
|
-
let t = this.layout.find((t) => t.i === e);
|
|
1355
|
-
if (!t) throw Error(`Layout item with ID "${e}" does not exist in the dashboard.`);
|
|
1356
|
-
let n = this.nextId.toString();
|
|
1357
|
-
return this.gridItems[n] = { ...this.gridItems[e] }, this.layout.push({
|
|
1358
|
-
...t,
|
|
1359
|
-
i: n
|
|
1360
|
-
}), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, this.nextId++, n;
|
|
1361
|
-
}
|
|
1362
|
-
updateItemContent(e, t) {
|
|
1363
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1364
|
-
...this.gridItems[e],
|
|
1365
|
-
content: t
|
|
1366
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1367
|
-
}
|
|
1368
|
-
updateItemCrossFilterEligibility(e, t) {
|
|
1369
|
-
this.gridItems[e] ? (this.gridItems[e] = {
|
|
1370
|
-
...this.gridItems[e],
|
|
1371
|
-
allowCrossFilter: t
|
|
1372
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0) : console.warn(`Item with ID "${e}" does not exist in dashboard "${this.id}". Cannot update cross-filter eligibility.`);
|
|
1373
|
-
}
|
|
1374
|
-
updateItemLoading(e, t) {
|
|
1375
|
-
this.gridItems[e] ? (this.gridItems[e] = {
|
|
1376
|
-
...this.gridItems[e],
|
|
1377
|
-
loading: t
|
|
1378
|
-
}, t && (this.gridItems[e].loadStartTime = Date.now())) : console.warn(`Item with ID "${e}" does not exist in dashboard "${this.id}". Cannot update loading state.`);
|
|
1379
|
-
}
|
|
1380
|
-
updateItemError(e, t) {
|
|
1381
|
-
this.gridItems[e] ? this.gridItems[e] = {
|
|
1382
|
-
...this.gridItems[e],
|
|
1383
|
-
error: t,
|
|
1384
|
-
loading: !1,
|
|
1385
|
-
loadStartTime: null
|
|
1386
|
-
} : console.warn(`Item with ID "${e}" does not exist in dashboard "${this.id}". Cannot update error.`);
|
|
1387
|
-
}
|
|
1388
|
-
updateItemDrilldown(e, t) {
|
|
1389
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1390
|
-
...this.gridItems[e],
|
|
1391
|
-
drilldown: t
|
|
1392
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1393
|
-
}
|
|
1394
|
-
updateItemDrilldownChartConfig(e, t) {
|
|
1395
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1396
|
-
...this.gridItems[e],
|
|
1397
|
-
drilldownChartConfig: t
|
|
1398
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1399
|
-
}
|
|
1400
|
-
updateItemResults(e, t) {
|
|
1401
|
-
if (this.gridItems[e]) {
|
|
1402
|
-
this.gridItems[e] = {
|
|
1403
|
-
...this.gridItems[e],
|
|
1404
|
-
results: t,
|
|
1405
|
-
loading: !1,
|
|
1406
|
-
error: "",
|
|
1407
|
-
loadStartTime: null
|
|
1408
|
-
};
|
|
1409
|
-
let n = this.gridItems[e];
|
|
1410
|
-
if (n.chartFilters && n.chartFilters.length > 0) {
|
|
1411
|
-
if (!(n.chartFilters?.every((e) => e?.value && typeof e.value == "object" ? Object.values(e.value).every((e) => typeof e == "string") : !1) ?? !1)) {
|
|
1412
|
-
console.warn(`Cross filter values in item ${e} are not static strings, skipping cross filter check.`);
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
if (!this.gridItems[e].chartFilters?.some((e) => Object.keys(e.value).some((n) => t?.data.some((t) => t[n] === e.value[n])))) {
|
|
1416
|
-
let t = this.gridItems[e].chartFilters?.map((e) => e.value);
|
|
1417
|
-
console.log("Removing cross filter that was sourced from", n.name, "and is no longer present in the results: ", t), this.removeItemCrossFilterSource(e);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
updateItemType(e, t) {
|
|
1423
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1424
|
-
...this.gridItems[e],
|
|
1425
|
-
type: t
|
|
1426
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1427
|
-
}
|
|
1428
|
-
updateItemFilters(e) {
|
|
1429
|
-
let t = this.gridItems[e];
|
|
1430
|
-
t && D(t) && (this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1431
|
-
}
|
|
1432
|
-
removeItemCrossFilter(e, t) {
|
|
1433
|
-
ze(this.gridItems, e, t) && (this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1434
|
-
}
|
|
1435
|
-
removeItemCrossFilterSource(e) {
|
|
1436
|
-
let t = !!this.gridItems[e]?.chartFilters?.length, n = Be(this.gridItems, e);
|
|
1437
|
-
return (n.length > 0 || t) && (this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0), n;
|
|
1438
|
-
}
|
|
1439
|
-
removeAllFilters() {
|
|
1440
|
-
let e = Ve(this.gridItems);
|
|
1441
|
-
for (let e in this.gridItems) this.gridItems[e].parameters = {};
|
|
1442
|
-
return e.length > 0 && (this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0), e;
|
|
1443
|
-
}
|
|
1444
|
-
updateItemCrossFilters(e, t, n, r) {
|
|
1445
|
-
let i = Re(this.gridItems, e, t, n, r);
|
|
1446
|
-
return this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, i;
|
|
1447
|
-
}
|
|
1448
|
-
updateItemName(e, t) {
|
|
1449
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1450
|
-
...this.gridItems[e],
|
|
1451
|
-
name: t
|
|
1452
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1453
|
-
}
|
|
1454
|
-
updateItemChartConfig(e, t) {
|
|
1455
|
-
this.gridItems[e] && (this.gridItems[e] = {
|
|
1456
|
-
...this.gridItems[e],
|
|
1457
|
-
chartConfig: t
|
|
1458
|
-
}, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1459
|
-
}
|
|
1460
|
-
updateItemMultipleProperties(e, t) {
|
|
1461
|
-
if (!this.gridItems[e]) throw Error(`Item with ID "${e}" does not exist in the dashboard.`);
|
|
1462
|
-
let n = this.gridItems[e], r = !1;
|
|
1463
|
-
if (t.name !== void 0 && t.name !== n.name && (n.name = t.name, r = !0), t.content !== void 0 && t.content !== n.content && (n.content = t.content, r = !0), t.type !== void 0 && t.type !== n.type && (n.type = t.type, r = !0), t.allowCrossFilter !== void 0 && t.allowCrossFilter !== n.allowCrossFilter && (n.allowCrossFilter = t.allowCrossFilter, r = !0), t.width !== void 0 && t.width !== n.width && (n.width = t.width, r = !0), t.height !== void 0 && t.height !== n.height && (n.height = t.height, r = !0), t.chartConfig !== void 0 && JSON.stringify(n.chartConfig) !== JSON.stringify(t.chartConfig) && (n.chartConfig = t.chartConfig, r = !0), t.drilldown !== void 0 && t.drilldown !== n.drilldown && (n.drilldown = t.drilldown, r = !0), t.drilldownChartConfig !== void 0 && JSON.stringify(n.drilldownChartConfig) !== JSON.stringify(t.drilldownChartConfig) && (n.drilldownChartConfig = t.drilldownChartConfig, r = !0), t.conceptFilters !== void 0 && JSON.stringify(n.conceptFilters) !== JSON.stringify(t.conceptFilters) && (n.conceptFilters = t.conceptFilters, r = !0), t.chartFilters !== void 0 && JSON.stringify(n.chartFilters) !== JSON.stringify(t.chartFilters) && (n.chartFilters = t.chartFilters, r = !0), t.filters !== void 0 && JSON.stringify(n.filters) !== JSON.stringify(t.filters) && (n.filters = t.filters, r = !0), t.parameters !== void 0 && JSON.stringify(n.parameters) !== JSON.stringify(t.parameters) && (n.parameters = t.parameters, r = !0), t.results !== void 0 && t.results !== n.results && (n.results = t.results, n.loading = !1, n.error = null, n.loadStartTime = null, r = !0), t.loading !== void 0 && t.loading !== n.loading && (n.loading = t.loading, t.loading && (n.loadStartTime = Date.now()), r = !0), t.error !== void 0 && t.error !== n.error && (n.error = t.error, n.error && (n.loading = !1, n.loadStartTime = null), r = !0), t.layoutDimensions !== void 0) {
|
|
1464
|
-
let n = this.layout.find((t) => t.i === e);
|
|
1465
|
-
if (n) {
|
|
1466
|
-
let e = !1;
|
|
1467
|
-
t.layoutDimensions.x !== void 0 && t.layoutDimensions.x !== null && t.layoutDimensions.x !== n.x && (n.x = t.layoutDimensions.x, e = !0), t.layoutDimensions.y !== void 0 && t.layoutDimensions.y !== null && t.layoutDimensions.y !== n.y && (n.y = t.layoutDimensions.y, e = !0), t.layoutDimensions.w !== void 0 && t.layoutDimensions.w !== null && t.layoutDimensions.w !== n.w && (n.w = t.layoutDimensions.w, e = !0), t.layoutDimensions.h !== void 0 && t.layoutDimensions.h !== null && t.layoutDimensions.h !== n.h && (n.h = t.layoutDimensions.h, e = !0), e && (r = !0);
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
r && (this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
1471
|
-
}
|
|
1472
|
-
updateLayout(e) {
|
|
1473
|
-
this.layout = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
1474
|
-
}
|
|
1475
|
-
updateItemDimensions(e, t, n) {
|
|
1476
|
-
if (this.gridItems[e]) {
|
|
1477
|
-
if (this.gridItems[e].width === t && this.gridItems[e].height === n) return;
|
|
1478
|
-
this.gridItems[e] = {
|
|
1479
|
-
...this.gridItems[e],
|
|
1480
|
-
width: t,
|
|
1481
|
-
height: n
|
|
1482
|
-
}, this.updatedAt = /* @__PURE__ */ new Date();
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
removeItem(e) {
|
|
1486
|
-
this.layout = this.layout.filter((t) => t.i !== e), this.gridItems[e] && delete this.gridItems[e], this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
1487
|
-
}
|
|
1488
|
-
clearItems() {
|
|
1489
|
-
this.layout = [], this.gridItems = {}, this.nextId = 0, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
1490
|
-
}
|
|
1491
|
-
serialize() {
|
|
1492
|
-
let e = {};
|
|
1493
|
-
for (let [t, n] of Object.entries(this.gridItems)) {
|
|
1494
|
-
let { results: r, loading: i, error: a, loadStartTime: o, ...s } = n;
|
|
1495
|
-
e[t] = s;
|
|
1496
|
-
}
|
|
1497
|
-
return {
|
|
1498
|
-
id: this.id,
|
|
1499
|
-
name: this.name,
|
|
1500
|
-
storage: this.storage,
|
|
1501
|
-
connection: this.connection,
|
|
1502
|
-
connectionId: this.connectionId,
|
|
1503
|
-
layout: this.layout,
|
|
1504
|
-
gridItems: e,
|
|
1505
|
-
nextId: this.nextId,
|
|
1506
|
-
createdAt: this.createdAt,
|
|
1507
|
-
updatedAt: this.updatedAt,
|
|
1508
|
-
filter: this.filter,
|
|
1509
|
-
imports: this.imports,
|
|
1510
|
-
version: this.version,
|
|
1511
|
-
state: this.state,
|
|
1512
|
-
description: this.description,
|
|
1513
|
-
layoutType: this.layoutType,
|
|
1514
|
-
theme: this.theme,
|
|
1515
|
-
parentDashboardId: this.parentDashboardId,
|
|
1516
|
-
investigationName: this.investigationName,
|
|
1517
|
-
investigationCreatedFrom: this.investigationCreatedFrom,
|
|
1518
|
-
children: this.children,
|
|
1519
|
-
chatId: this.chatId ?? null
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
static fromSerialized(n) {
|
|
1523
|
-
let r = {};
|
|
1524
|
-
for (let [t, i] of Object.entries(n.gridItems)) r[t] = {
|
|
1525
|
-
...i,
|
|
1526
|
-
results: null,
|
|
1527
|
-
loading: !1,
|
|
1528
|
-
error: null,
|
|
1529
|
-
loadStartTime: null,
|
|
1530
|
-
allowCrossFilter: i.allowCrossFilter !== !1,
|
|
1531
|
-
chartConfig: e(i.chartConfig),
|
|
1532
|
-
drilldownChartConfig: e(i.drilldownChartConfig)
|
|
1533
|
-
};
|
|
1534
|
-
return new t({
|
|
1535
|
-
...n,
|
|
1536
|
-
createdAt: new Date(n.createdAt),
|
|
1537
|
-
updatedAt: new Date(n.updatedAt),
|
|
1538
|
-
gridItems: r,
|
|
1539
|
-
layoutType: n.layoutType || "grid",
|
|
1540
|
-
theme: x(n.theme),
|
|
1541
|
-
parentDashboardId: n.parentDashboardId || null,
|
|
1542
|
-
investigationName: n.investigationName,
|
|
1543
|
-
investigationCreatedFrom: n.investigationCreatedFrom ? {
|
|
1544
|
-
...n.investigationCreatedFrom,
|
|
1545
|
-
timestamp: new Date(n.investigationCreatedFrom.timestamp)
|
|
1546
|
-
} : void 0,
|
|
1547
|
-
children: n.children || []
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1550
|
-
}, Xe = .5, Ze = 1e4, Qe = 2e5, $e = [
|
|
1551
|
-
{
|
|
1552
|
-
value: "demo",
|
|
1553
|
-
label: "Demo (limited messages)"
|
|
1554
|
-
},
|
|
1555
|
-
{
|
|
1556
|
-
value: "anthropic",
|
|
1557
|
-
label: "Anthropic"
|
|
1558
|
-
},
|
|
1559
|
-
{
|
|
1560
|
-
value: "google",
|
|
1561
|
-
label: "Google"
|
|
1562
|
-
},
|
|
1563
|
-
{
|
|
1564
|
-
value: "openai",
|
|
1565
|
-
label: "OpenAI"
|
|
1566
|
-
},
|
|
1567
|
-
{
|
|
1568
|
-
value: "openrouter",
|
|
1569
|
-
label: "OpenRouter"
|
|
1570
|
-
},
|
|
1571
|
-
{
|
|
1572
|
-
value: "deepseek",
|
|
1573
|
-
label: "DeepSeek"
|
|
1574
|
-
}
|
|
1575
|
-
], et = Object.fromEntries($e.map((e) => [e.value, e.label])), tt = {
|
|
1576
|
-
anthropic: "sk-ant-...",
|
|
1577
|
-
openai: "sk-...",
|
|
1578
|
-
google: "AIza...",
|
|
1579
|
-
openrouter: "sk-or-...",
|
|
1580
|
-
deepseek: "sk-..."
|
|
1581
|
-
}, k = "# Trilogy Syntax\n\nTrilogy statements define a semantic model or a query; collections of statements\nare written as `.preql` files. A statement returns data (SELECT) or defines\nconcepts (key | property | auto | metric), datasources, or parameters.\n\nimport <model> as <alias>; makes a model's fields available. <model> is a DOT-SEPARATED MODULE PATH relative to the project root (where trilogy.toml lives), never a file path: the file `raw/store_sales.preql` is imported as `import raw.store_sales as ss;` — replace each `/` with `.`, drop the `.preql`, keep the folder segment. When an imported model imports others (a fact with imported dimensions), those are dot paths: `enroll.student.name`. Typical usage imports ONE fact and reaches dimensions through it; nested dimensions carry ALL values (order.customers includes customers without orders).\n\nkey | property | auto | metric; define new concepts. `auto x <- ...` is a DEFINITION, not a precomputed value: each reference expands and re-evaluates in the consuming query's scope.\n\nparameter NAME TYPE [default <literal>]; — a runtime value supplied via `--param NAME=VALUE` (repeatable); append `?` to the type to allow null.\n\n## Combining models\n\n| Goal | Use |\n|---|---|\n| Typical query | no merge, no join: access all fields through dot-paths |\n| Blend two models on shared keys inside one query | scoped `subset\\|union join` |\n| Make a connection universal to a whole file | `merge` |\n| Stack subsets/channels as rows | `union(...)` |\n| Rows in A but never in B (set difference) | `except(...)` |\n| Rows present in every source (set intersection) | `intersect(...)` |\n\n### Query-scoped join\n\nA typical fact already has its dimensions merged in, so no join is needed. Blending fact models or rowset outputs takes a scoped join, placed right after the select list, which DECLARES how the key domains relate: `subset join a = b` (a's values are contained in b's, a ⊆ b; b authoritative for the key) or `union join a = b` (neither contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept).\n\nTwo rules decide whether the numbers are right, so apply them before reaching for the example:\n\n- Joins NEVER drop a row and NULL keys match null-safely; there is NO inner join. An intersection is an explicit `where <optional-side attr> is not null`.\n- JOIN ON THE FULL GRAIN: `explore` prints each fact's grain as @<k1, k2>; write one clause PER key. Matching only one key of a multi-key grain causes duplication.\n\nChaining, expression keys, union/subset mixing, multi-key and self-pair shapes: trilogy agent-info syntax example scoped-join.\n\nmerge <a> into ~<b>; is the persistent (whole-file) equivalent of `subset join a = b`; plain `merge a into b;` declares EXACT domain equivalence. Standalone statements; prefer a scoped join unless the connection is universal.\n\n### union / except / intersect (row set operations)\n\n`union(...)` row-stacks self-contained select arms positionally (SQL UNION ALL) into one named rowset (`with combined as union((armA), (armB), ...) -> (out1, out2, ...)`); `except(...)` / `intersect(...)` share that arm shape but are SQL SET operators (DISTINCT rows, null-safe whole-row compare, and except subtracts later arms from the FIRST, so arm order matters). Prefer except over a multi-column `not in` for \"in A but never in B\". Each arm dedups to its own output grain BEFORE stacking, so aggregate INSIDE each arm or the total silently undersums. Examples: trilogy agent-info syntax example union-stack-channels / except-intersect-setops.\n\n## Query structure\n\nTop-level statements first (each `;`-terminated), then a query with clauses in this EXACT order — all optional except select:\n\n```\n<top-level statements>; # import / key / auto / rowset / merge / def / parameter\nwith <name> as # optional: name the select as a reusable rowset (CTE)\nwhere <row condition> # 1. filters INPUT rows, BEFORE aggregation\nselect <col>, <agg> as name, # 2. projection — grouping is AUTOMATIC by the\n # non-aggregated columns; never write GROUP BY\n subset|union join a = b (= c)? # 3. blend models; one clause per key, right after the select list\nby rollup|cube|grouping sets (...) # 4. optional multi-level grouping for the whole select\nhaving <result condition> # 5. filters aggregated/joined RESULTS\norder by <col> asc|desc # 6. sort\nlimit <n>; # 7. cap rows\n```\n\nA rowset (`with <name> as where ... select ...;`) is a standalone statement, evaluated in isolation — it does NOT respond to the consuming query's context. All its outputs are namespaced: output `abc.def` of rowset `foo` is referenced as `foo.abc.def`, and joined back like any concept (`subset join foo.key = other.key`). Alias every reused expression with `as`.\n\nFull annotated example: trilogy agent-info syntax example query-structure.\n\n### Not SQL — what to never write\n\n- **No FROM, GROUP BY, DISTINCT, SELECT \\*, or SQL-style set operators between selects.** Stack rows with `union(...)`; set difference/intersection with `except(...)`/`intersect(...)`; blend fact models with a scoped join.\n- **Grouping is automatic** by the non-aggregated fields in the SELECT — never write GROUP BY. Aggregates inherit the select's grain wherever they appear (where/select/having). Override per-aggregate with `agg(x) by <dims>`; `by *` aggregates across all data (single row). To weight a related dimension property once per fact row, project it to the fact grain first: `auto row_birth_year <- group(enroll.student.birth_year) by enroll.student_id, enroll.course_id;` then aggregate that.\n- **Output rows are deduplicated to the select grain.** To preserve legitimate duplicates (one row per matching fact), include the fact's grain keys in the select — hidden with the PREFIX `--` if they shouldn't appear in the output.\n- **Never write `distinct`.** `count(<key>)` is already distinct because keys are unique; `count_distinct(<property>)` counts distinct values of a non-key property.\n- **Count a COMPOSITE grain with `grain(...)`.** `count(grain(order_id, item.id))` counts order+item combinations; `grain(...)` is NEVER NULL. Never count one column of a multi-key grain — a coarser key counts its own distinct values and undercounts. `count_distinct(a, b)` is accepted as sugar for `count(grain(a, b))` (distinct combinations, NULL members included).\n- **An aggregate over a group with no qualifying rows is NULL, never 0.** `sum(x ? cond) by k` yields NULL for groups where nothing matches, so `= 0` matches nothing. Test emptiness with `count(key ? cond) by k = 0` or wrap: `coalesce(sum(x ? cond), 0)`.\n- **`count(1)` is invalid** — a constant does not identify rows. Use the row key, `count(grain(...))`, or `sum(1) by <grain>`.\n- **One-column expression subqueries only.** `(select ...)` is allowed where a scalar or membership set is expected (exactly one projected column) — never as a SQL-style FROM-subquery. For related-entity filters prefer the dot-path: `where enrollments.student.state = 'TN'`, not a subselect.\n- **`--` is a HIDDEN-field prefix, not a comment** (it still changes query structure). Comments use `#` only.\n- **Aliases**: always use the full dot-path (`enroll.student.id`); alias every new expression with `as`; a select alias is usable in `having`/`order by` but NOT inside other select expressions or `where`, and must not rename a field back to an existing concept name.\n\n## Filtering\n\n`where` filters input rows before aggregation; `having` filters results after aggregation/windows. The inline filter `x ? cond` filters the immediate prior expression: `sum(credits ? enrolled = true)`.\n\nAggregates/windows in WHERE do not filter each other's inputs. Use inline filters, or a staged `then where` chain: each `then where` stage's aggregates compute over only the rows passing earlier stages (`where x = 5 then where sum(y) > 10` ≡ `where x = 5 and sum(y ? x = 5) > 10`). One rule: the SAME cross-row expression cannot gate two different stages — give one an inline filter.\n\nWindows need all rows in their range: filter AFTER the window (in `having`) rather than in `where` when the window must see the full set.\n\n## Membership (semijoins)\n\n`in` / `not in` cross models without any declared relationship — the semijoin IS a scoped intersection. The right side is a concept or expression (never a subselect); build computed sets with an inline filter: `auto big_zip <- student.zip ? (count(student.id ? student.honors = true) by student.zip) > 10; ... where school.zip in big_zip`.\n\nMembership is IDENTITY matching, not SQL three-valued logic: NULL matches NULL; the result is always TRUE or FALSE (safe as a projected flag); `not in` is the exact complement (a NULL in the set never empties the result). For strict SQL behavior, add `x is not null`.\n\nA fact model contains ALL dimensional members, so `where students.id not in enroll.student_id` is typically a tautology — use `where enroll.id is null` instead. Tuple membership `(a, b) in (m.a, m.b)` requires both right-side concepts to resolve to ONE source (model or rowset); to test against a cross-model pair, stage it through a rowset first. Examples: existence-anti-join, staged-membership.\n\n## Aggregation\n\nAn aggregate without an explicit `by` is RESPONSIVE — its grain is set where it is consumed, not where it is declared (`auto avg_credits <- avg(enroll.credits);` becomes per-department when selected with `enroll.department`). Pin a grain inline: `sum(metric) by dim1, dim2 as name`; `by` accepts bare identifiers or parenthesized expressions: `avg(price) by (substring(phone, 1, 2))`.\n\nMulti-level grouping (`by rollup|cube|grouping sets (...)`) is a clause of the WHOLE select, placed before `having`: it computes every no-explicit-grain aggregate at every level in one pass (`by rollup (d1, d2)` → leaf, per-d1 subtotal, grand total). `grouping(<field>)` = 1 on rolled-up rows — use it to label levels rather than testing for NULL. Full detail: trilogy agent-info syntax example rollup.\n\n## Window functions\n\nDefault to windows for self-referential queries (period-over-period, running totals, rank, share of group). SQL-style syntax: `rank(<key>) over (partition by <g> order by <expr> desc)` (`dense_rank`/`row_number` same shape; multi-key `rank(a, b)`); `sum(x) over (partition by g order by t)` for running totals; `lag(<field>, <offset>) over (...)` / `lead(...)` for offsets (default 1). `partition by` is optional and accepts expressions.\n\n## Data types\n\nScalars: `string`, `bytes`, `bool`, `int`, `bigint`, `float`, `double`, `number`, `numeric(p,s)` (alias `decimal`; use for exact money), `date`, `datetime`, `timestamp`, `geography`, `any`. Composites: `array<T>`, `map<K, V>`, `struct<name: T, ...>`, `enum<T>[v1, v2, ...]`. Cast with `::type` or `cast(x as type)`: `\"2020-01-01\"::date`.\n\n`?` after a type marks it nullable (`property user.middle_name string?;`). `~` prefixing a concept marks the reference as a PARTIAL subset of the concept's domain — on a select item (`~customer.id`) or in `merge a into ~b` (a ⊆ b); it tells the planner this side is not authoritative.\n\n## Expression gotchas\n\n- `x ? cond` binds to a primary — wrap arithmetic: `(a - b) ? cond`, NOT `a - b ? cond`.\n- `a || b` is NULL if either side is NULL; `concat(...)` skips NULL arguments; `concat_ws(sep, ...)` joins with sep, skipping NULLs.\n- Date parts are unquoted: `date_part(d, year)`, never `'year'`; prefer `year(d)`. `date_diff(start, end, unit)` = end − start (a shipping lag is `date_diff(sold_date, ship_date, day)`).\n- Zero-argument functions still take parentheses: `current_date()`.\n- Factor repeated calculations into a `def` macro (invoked `@name(...)`) or reusable `auto` concepts.\n\n\nFunctions (the `aggregate` family doubles as the Aggregate Functions list):\naggregate: count|count_distinct|sum|max|min|avg|stddev|variance|array_agg|bool_or|bool_and|any|grouping(<arg1>) ; grouping_id(<arg1>, <arg2>, ..., <argN>)\nstring: concat|concat_strict|concat_ws(<arg1>, <arg2>, ..., <argN>) ; split|strpos|contains|trim|regexp_contains|format_time|parse_time(<arg1>, <arg2>) ; len|lower|upper|ltrim|rtrim|hex(<arg1>) ; substring|replace|regexp_extract|regexp_replace(<arg1>, <arg2>, <arg3>)\ndate/time: date|datetime|timestamp|second|minute|hour|day|day_of_week|week|month|quarter|year|month_name|day_name|unix_to_timestamp(<arg1>) ; date_spine(<arg1>, <arg2>) ; current_date|current_datetime()\n date_part(<arg1>, <arg2>) e.g. date_part('2020-01-01'::date, year)\n date_truncate(<arg1>, <arg2>) e.g. date_trunc('2020-01-01'::date, month)\n date_add(<arg1>, <arg2>, <arg3>) e.g. date_add('2020-01-01'::date, month, 1)\n date_sub(<arg1>, <arg2>, <arg3>) e.g. date_sub('2020-01-01'::date, day, 1)\n date_diff(<arg1>, <arg2>, <arg3>) e.g. date_diff('2020-01-01'::date, '2020-01-02'::date, day)\n current_timestamp() e.g. now()\narray/map/struct: unnest|array_distinct|array_sum|map_keys|map_values(<arg1>) ; struct|array(<arg1>, <arg2>, ..., <argN>) ; array_sort|array_to_string(<arg1>, <arg2>) ; array_transform|array_filter|generate_array(<arg1>, <arg2>, <arg3>)\nmath: mod|round|log|power|hash(<arg1>, <arg2>) ; abs|sqrt|random|floor|ceil(<arg1>)\nconditional/cast: case|simple_case|coalesce|greatest|least(<arg1>, <arg2>, ..., <argN>) ; cast|nullif(<arg1>, <arg2>) ; isnull(<arg1>)\ngeo: geo_from_text|geo_x|geo_y|geo_centroid(<arg1>) ; geo_point|geo_distance(<arg1>, <arg2>) ; geo_transform(<arg1>, <arg2>, <arg3>)\nother: is_not_distinct(<arg1>, <arg2>)\n\nSome types carry trait metadata that adds meaning: 'latitude', 'longitude' and 'currency' are all 'float' with extra semantics.\n\nAdditional syntax examples:\nThese less-common patterns have complete, copy-pasteable examples. Do NOT guess\nthe syntax — print the full example on demand with\n`trilogy agent-info syntax example <name>`:\n- `python-datasource` - run a local Python script as a datasource: wrap a function in `trilogy.io.run`, which writes the Arrow IPC stream to stdout for you from a table, dataframe, or list of dicts; declare concepts, map script columns in `datasource (...)`, use `grain (...) file `path.py`;`, then reference locally declared concepts WITHOUT the datasource name as a prefix\n- `query-structure` - the exact clause order of a query, and how to define a rowset\n- `chart` - drawing a result rather than tabulating it: `chart layer <type> ( <role> <- <expr> as <name>, ... )` is a STATEMENT that wraps its own query - the bindings ARE the select; layers, roles, scales, reference lines and `from <select>`\n- `filtered-aggregate` - aggregating only the rows matching a condition, and counting rows correctly\n- `row-level-where-vs-having` - choosing between WHERE and HAVING for a threshold condition\n- `nested-aggregate-group-average` - the \"above 1.2x the group norm\" ask: inner `sum(x) by entity, group`, outer `avg(inner) by group`; use WHERE for the comparison when a separate output-only filter must not narrow the benchmark\n- `pivot-columns` - turn distinct values of a dimension into columns with a reusable `def` macro + filtered aggregate\n- `case-when` - `case when <cond> then <val> ... else <val> end` to relabel codes or bucket a measure into a derived value, then group by it\n- `window-period-over-period` - `lead`/`lag` over (order by ...) to compare a row to an offset period; build a scoped set with `<col> ? <cond>` and filter with `in`\n- `union-stack-channels` - stacking several sources/channels together as rows\n- `except-intersect-setops` - set difference or co-occurrence across sources\n- `scoped-join` - blending a second fact model or rowset into one query\n- `existence-anti-join` - keeping or excluding rows by whether a key matches another model\n- `set-intersect-difference` - count tuples present in / absent from other groups via per-group presence flags - the multi-column INTERSECT/EXCEPT idiom\n- `dedup-before-aggregate` - a `rowset <- select <cols>` collapses identical tuples to one row (SELECT-grain group by) before a downstream sum - the `distinct`/UNION substitute\n- `rollup` - subtotals and a grand total in one pass, and labeling the levels\n- `rank-over-rollup` - rank rollup subtotals/leaves with a SINGLE `rank(a,b) over (partition by level, parent ...)` - not separate ranks per level\n- `staged-membership` - filtering a fine-grain query by a set computed at a coarser grain\n- `correlated-exists-via-grouped-counts` - translate `EXISTS other` / `NOT EXISTS other matching` over the same model into two `count(...) by <grain>` compared in `where` (`> 1` = another exists, `= 1` = no other matches) - pin the correlation grain with `by`", nt = "# Trilogy Syntax\n\nTrilogy statements define a semantic model or a query; collections of statements\nare written as `.preql` files. A statement returns data (SELECT) or defines\nconcepts (key | property | auto | metric), datasources, or parameters.\n\nimport <model> as <alias>; makes a model's fields available. <model> is a DOT-SEPARATED MODULE PATH relative to the project root (where trilogy.toml lives), never a file path: the file `raw/store_sales.preql` is imported as `import raw.store_sales as ss;` — replace each `/` with `.`, drop the `.preql`, keep the folder segment. When an imported model imports others (a fact with imported dimensions), those are dot paths: `enroll.student.name`. Typical usage imports ONE fact and reaches dimensions through it; nested dimensions carry ALL values (order.customers includes customers without orders).\n\nkey | property | auto | metric; define new concepts. `auto x <- ...` is a DEFINITION, not a precomputed value: each reference expands and re-evaluates in the consuming query's scope.\n\nparameter NAME TYPE [default <literal>]; — a runtime value supplied via `--param NAME=VALUE` (repeatable); append `?` to the type to allow null.\n\n## Combining models\n\n| Goal | Use |\n|---|---|\n| Typical query | no merge, no join: access all fields through dot-paths |\n| Blend two models on shared keys inside one query | scoped `subset\\|union join` |\n| Make a connection universal to a whole file | `merge` |\n| Stack subsets/channels as rows | `union(...)` |\n| Rows in A but never in B (set difference) | `except(...)` |\n| Rows present in every source (set intersection) | `intersect(...)` |\n\n### Query-scoped join\n\nA typical fact already has its dimensions merged in, so no join is needed. Blending fact models or rowset outputs takes a scoped join, placed right after the select list, which DECLARES how the key domains relate: `subset join a = b` (a's values are contained in b's, a ⊆ b; b authoritative for the key) or `union join a = b` (neither contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept).\n\nTwo rules decide whether the numbers are right, so apply them before reaching for the example:\n\n- Joins NEVER drop a row and NULL keys match null-safely; there is NO inner join. An intersection is an explicit `where <optional-side attr> is not null`.\n- JOIN ON THE FULL GRAIN: `explore` prints each fact's grain as @<k1, k2>; write one clause PER key. Matching only one key of a multi-key grain causes duplication.\n\nChaining, expression keys, union/subset mixing, multi-key and self-pair shapes: trilogy agent-info syntax example scoped-join.\n\nmerge <a> into ~<b>; is the persistent (whole-file) equivalent of `subset join a = b`; plain `merge a into b;` declares EXACT domain equivalence. Standalone statements; prefer a scoped join unless the connection is universal.\n\n### union / except / intersect (row set operations)\n\n`union(...)` row-stacks self-contained select arms positionally (SQL UNION ALL) into one named rowset (`with combined as union((armA), (armB), ...) -> (out1, out2, ...)`); `except(...)` / `intersect(...)` share that arm shape but are SQL SET operators (DISTINCT rows, null-safe whole-row compare, and except subtracts later arms from the FIRST, so arm order matters). Prefer except over a multi-column `not in` for \"in A but never in B\". Each arm dedups to its own output grain BEFORE stacking, so aggregate INSIDE each arm or the total silently undersums. Examples: trilogy agent-info syntax example union-stack-channels / except-intersect-setops.\n\n## Query structure\n\nTop-level statements first (each `;`-terminated), then a query with clauses in this EXACT order — all optional except select:\n\n```\n<top-level statements>; # import / key / auto / rowset / merge / def / parameter\nwith <name> as # optional: name the select as a reusable rowset (CTE)\nwhere <row condition> # 1. filters INPUT rows, BEFORE aggregation\nselect <col>, <agg> as name, # 2. projection — grouping is AUTOMATIC by the\n # non-aggregated columns; never write GROUP BY\n subset|union join a = b (= c)? # 3. blend models; one clause per key, right after the select list\nby rollup|cube|grouping sets (...) # 4. optional multi-level grouping for the whole select\nhaving <result condition> # 5. filters aggregated/joined RESULTS\norder by <col> asc|desc # 6. sort\nlimit <n>; # 7. cap rows\n```\n\nA rowset (`with <name> as where ... select ...;`) is a standalone statement, evaluated in isolation — it does NOT respond to the consuming query's context. All its outputs are namespaced: output `abc.def` of rowset `foo` is referenced as `foo.abc.def`, and joined back like any concept (`subset join foo.key = other.key`). Alias every reused expression with `as`.\n\nFull annotated example: trilogy agent-info syntax example query-structure.\n\n### Not SQL — what to never write\n\n- **No FROM, GROUP BY, DISTINCT, SELECT \\*, or SQL-style set operators between selects.** Stack rows with `union(...)`; set difference/intersection with `except(...)`/`intersect(...)`; blend fact models with a scoped join.\n- **Grouping is automatic** by the non-aggregated fields in the SELECT — never write GROUP BY. Aggregates inherit the select's grain wherever they appear (where/select/having). Override per-aggregate with `agg(x) by <dims>`; `by *` aggregates across all data (single row). To weight a related dimension property once per fact row, project it to the fact grain first: `auto row_birth_year <- group(enroll.student.birth_year) by enroll.student_id, enroll.course_id;` then aggregate that.\n- **Output rows are deduplicated to the select grain.** To preserve legitimate duplicates (one row per matching fact), include the fact's grain keys in the select — hidden with the PREFIX `--` if they shouldn't appear in the output.\n- **Never write `distinct`.** `count(<key>)` is already distinct because keys are unique; `count_distinct(<property>)` counts distinct values of a non-key property.\n- **Count a COMPOSITE grain with `grain(...)`.** `count(grain(order_id, item.id))` counts order+item combinations; `grain(...)` is NEVER NULL. Never count one column of a multi-key grain — a coarser key counts its own distinct values and undercounts. `count_distinct(a, b)` is accepted as sugar for `count(grain(a, b))` (distinct combinations, NULL members included).\n- **An aggregate over a group with no qualifying rows is NULL, never 0.** `sum(x ? cond) by k` yields NULL for groups where nothing matches, so `= 0` matches nothing. Test emptiness with `count(key ? cond) by k = 0` or wrap: `coalesce(sum(x ? cond), 0)`.\n- **`count(1)` is invalid** — a constant does not identify rows. Use the row key, `count(grain(...))`, or `sum(1) by <grain>`.\n- **One-column expression subqueries only.** `(select ...)` is allowed where a scalar or membership set is expected (exactly one projected column) — never as a SQL-style FROM-subquery. For related-entity filters prefer the dot-path: `where enrollments.student.state = 'TN'`, not a subselect.\n- **`--` is a HIDDEN-field prefix, not a comment** (it still changes query structure). Comments use `#` only.\n- **Aliases**: always use the full dot-path (`enroll.student.id`); alias every new expression with `as`; a select alias is usable in `having`/`order by` but NOT inside other select expressions or `where`, and must not rename a field back to an existing concept name.\n\n## Filtering\n\n`where` filters input rows before aggregation; `having` filters results after aggregation/windows. The inline filter `x ? cond` filters the immediate prior expression: `sum(credits ? enrolled = true)`.\n\nAggregates/windows in WHERE do not filter each other's inputs. Use inline filters, or a staged `then where` chain: each `then where` stage's aggregates compute over only the rows passing earlier stages (`where x = 5 then where sum(y) > 10` ≡ `where x = 5 and sum(y ? x = 5) > 10`). One rule: the SAME cross-row expression cannot gate two different stages — give one an inline filter.\n\nWindows need all rows in their range: filter AFTER the window (in `having`) rather than in `where` when the window must see the full set.\n\n## Membership (semijoins)\n\n`in` / `not in` cross models without any declared relationship — the semijoin IS a scoped intersection. The right side is a concept or expression (never a subselect); build computed sets with an inline filter: `auto big_zip <- student.zip ? (count(student.id ? student.honors = true) by student.zip) > 10; ... where school.zip in big_zip`.\n\nMembership is IDENTITY matching, not SQL three-valued logic: NULL matches NULL; the result is always TRUE or FALSE (safe as a projected flag); `not in` is the exact complement (a NULL in the set never empties the result). For strict SQL behavior, add `x is not null`.\n\nA fact model contains ALL dimensional members, so `where students.id not in enroll.student_id` is typically a tautology — use `where enroll.id is null` instead. Tuple membership `(a, b) in (m.a, m.b)` requires both right-side concepts to resolve to ONE source (model or rowset); to test against a cross-model pair, stage it through a rowset first. Examples: existence-anti-join, staged-membership.\n\n## Aggregation\n\nAn aggregate without an explicit `by` is RESPONSIVE — its grain is set where it is consumed, not where it is declared (`auto avg_credits <- avg(enroll.credits);` becomes per-department when selected with `enroll.department`). Pin a grain inline: `sum(metric) by dim1, dim2 as name`; `by` accepts bare identifiers or parenthesized expressions: `avg(price) by (substring(phone, 1, 2))`.\n\nMulti-level grouping (`by rollup|cube|grouping sets (...)`) is a clause of the WHOLE select, placed before `having`: it computes every no-explicit-grain aggregate at every level in one pass (`by rollup (d1, d2)` → leaf, per-d1 subtotal, grand total). `grouping(<field>)` = 1 on rolled-up rows — use it to label levels rather than testing for NULL. Full detail: trilogy agent-info syntax example rollup.\n\n## Window functions\n\nDefault to windows for self-referential queries (period-over-period, running totals, rank, share of group). SQL-style syntax: `rank(<key>) over (partition by <g> order by <expr> desc)` (`dense_rank`/`row_number` same shape; multi-key `rank(a, b)`); `sum(x) over (partition by g order by t)` for running totals; `lag(<field>, <offset>) over (...)` / `lead(...)` for offsets (default 1). `partition by` is optional and accepts expressions.\n\n## Data types\n\nScalars: `string`, `bytes`, `bool`, `int`, `bigint`, `float`, `double`, `number`, `numeric(p,s)` (alias `decimal`; use for exact money), `date`, `datetime`, `timestamp`, `geography`, `any`. Composites: `array<T>`, `map<K, V>`, `struct<name: T, ...>`, `enum<T>[v1, v2, ...]`. Cast with `::type` or `cast(x as type)`: `\"2020-01-01\"::date`.\n\n`?` after a type marks it nullable (`property user.middle_name string?;`). `~` prefixing a concept marks the reference as a PARTIAL subset of the concept's domain — on a select item (`~customer.id`) or in `merge a into ~b` (a ⊆ b); it tells the planner this side is not authoritative.\n\n## Expression gotchas\n\n- `x ? cond` binds to a primary — wrap arithmetic: `(a - b) ? cond`, NOT `a - b ? cond`.\n- `a || b` is NULL if either side is NULL; `concat(...)` skips NULL arguments; `concat_ws(sep, ...)` joins with sep, skipping NULLs.\n- Date parts are unquoted: `date_part(d, year)`, never `'year'`; prefer `year(d)`. `date_diff(start, end, unit)` = end − start (a shipping lag is `date_diff(sold_date, ship_date, day)`).\n- Zero-argument functions still take parentheses: `current_date()`.\n- Factor repeated calculations into a `def` macro (invoked `@name(...)`) or reusable `auto` concepts.", rt = ["aggregate: count|count_distinct|sum|max|min|avg|stddev|variance|array_agg|bool_or|bool_and|any|grouping(<arg1>) ; grouping_id(<arg1>, <arg2>, ..., <argN>)"], it = [
|
|
1582
|
-
"aggregate: count|count_distinct|sum|max|min|avg|stddev|variance|array_agg|bool_or|bool_and|any|grouping(<arg1>) ; grouping_id(<arg1>, <arg2>, ..., <argN>)",
|
|
1583
|
-
"string: concat|concat_strict|concat_ws(<arg1>, <arg2>, ..., <argN>) ; split|strpos|contains|trim|regexp_contains|format_time|parse_time(<arg1>, <arg2>) ; len|lower|upper|ltrim|rtrim|hex(<arg1>) ; substring|replace|regexp_extract|regexp_replace(<arg1>, <arg2>, <arg3>)",
|
|
1584
|
-
"date/time: date|datetime|timestamp|second|minute|hour|day|day_of_week|week|month|quarter|year|month_name|day_name|unix_to_timestamp(<arg1>) ; date_spine(<arg1>, <arg2>) ; current_date|current_datetime()",
|
|
1585
|
-
" date_part(<arg1>, <arg2>) e.g. date_part('2020-01-01'::date, year)",
|
|
1586
|
-
" date_truncate(<arg1>, <arg2>) e.g. date_trunc('2020-01-01'::date, month)",
|
|
1587
|
-
" date_add(<arg1>, <arg2>, <arg3>) e.g. date_add('2020-01-01'::date, month, 1)",
|
|
1588
|
-
" date_sub(<arg1>, <arg2>, <arg3>) e.g. date_sub('2020-01-01'::date, day, 1)",
|
|
1589
|
-
" date_diff(<arg1>, <arg2>, <arg3>) e.g. date_diff('2020-01-01'::date, '2020-01-02'::date, day)",
|
|
1590
|
-
" current_timestamp() e.g. now()",
|
|
1591
|
-
"array/map/struct: unnest|array_distinct|array_sum|map_keys|map_values(<arg1>) ; struct|array(<arg1>, <arg2>, ..., <argN>) ; array_sort|array_to_string(<arg1>, <arg2>) ; array_transform|array_filter|generate_array(<arg1>, <arg2>, <arg3>)",
|
|
1592
|
-
"math: mod|round|log|power|hash(<arg1>, <arg2>) ; abs|sqrt|random|floor|ceil(<arg1>)",
|
|
1593
|
-
"conditional/cast: case|simple_case|coalesce|greatest|least(<arg1>, <arg2>, ..., <argN>) ; cast|nullif(<arg1>, <arg2>) ; isnull(<arg1>)",
|
|
1594
|
-
"geo: geo_from_text|geo_x|geo_y|geo_centroid(<arg1>) ; geo_point|geo_distance(<arg1>, <arg2>) ; geo_transform(<arg1>, <arg2>, <arg3>)",
|
|
1595
|
-
"other: is_not_distinct(<arg1>, <arg2>)"
|
|
1596
|
-
], at = [
|
|
1597
|
-
"string",
|
|
1598
|
-
"bytes",
|
|
1599
|
-
"bool",
|
|
1600
|
-
"map",
|
|
1601
|
-
"number",
|
|
1602
|
-
"float",
|
|
1603
|
-
"double",
|
|
1604
|
-
"numeric",
|
|
1605
|
-
"int",
|
|
1606
|
-
"bigint",
|
|
1607
|
-
"date",
|
|
1608
|
-
"datetime",
|
|
1609
|
-
"timestamp",
|
|
1610
|
-
"array",
|
|
1611
|
-
"date_part",
|
|
1612
|
-
"struct",
|
|
1613
|
-
"geography",
|
|
1614
|
-
"null",
|
|
1615
|
-
"unix_seconds",
|
|
1616
|
-
"unknown",
|
|
1617
|
-
"any"
|
|
1618
|
-
];
|
|
1619
|
-
//#endregion
|
|
1620
|
-
//#region dashboards/prompts.ts
|
|
1621
|
-
function ot(e) {
|
|
1622
|
-
let t;
|
|
1623
|
-
try {
|
|
1624
|
-
t = JSON.parse(e);
|
|
1625
|
-
} catch (e) {
|
|
1626
|
-
throw Error(`Invalid JSON format: ${e.message}`);
|
|
1627
|
-
}
|
|
1628
|
-
if (!t.name || typeof t.name != "string") throw Error("Dashboard must have a name property of type string");
|
|
1629
|
-
if (!t.description || typeof t.description != "string") throw Error("Dashboard must have a description property of type string");
|
|
1630
|
-
if (!Array.isArray(t.layout)) throw Error("Dashboard must have a layout property of type array");
|
|
1631
|
-
if (!t.gridItems || typeof t.gridItems != "object") throw Error("Dashboard must have a gridItems property of type object");
|
|
1632
|
-
let n = /* @__PURE__ */ new Set();
|
|
1633
|
-
for (let e = 0; e < t.layout.length; e++) {
|
|
1634
|
-
let r = t.layout[e];
|
|
1635
|
-
if (!r.id || typeof r.id != "string") throw Error(`Layout item at index ${e} must have an id property of type string`);
|
|
1636
|
-
if (typeof r.x != "number") throw Error(`Layout item with id '${r.id}' must have an x property of type number`);
|
|
1637
|
-
if (typeof r.y != "number") throw Error(`Layout item with id '${r.id}' must have a y property of type number`);
|
|
1638
|
-
if (typeof r.w != "number") throw Error(`Layout item with id '${r.id}' must have a w property of type number`);
|
|
1639
|
-
if (typeof r.h != "number") throw Error(`Layout item with id '${r.id}' must have an h property of type number`);
|
|
1640
|
-
n.add(r.id);
|
|
1641
|
-
}
|
|
1642
|
-
for (let [e, r] of Object.entries(t.gridItems)) {
|
|
1643
|
-
if (!n.has(e)) throw Error(`Grid item with id '${e}' does not have a corresponding layout item`);
|
|
1644
|
-
if (!r.type || typeof r.type != "string") throw Error(`Grid item with id '${e}' must have a type property of type string`);
|
|
1645
|
-
if (!r.content || typeof r.content != "string") throw Error(`Grid item with id '${e}' must have a content property of type string`);
|
|
1646
|
-
if (!r.name || typeof r.name != "string") throw Error(`Grid item with id '${e}' must have a name property of type string`);
|
|
1647
|
-
if ("width" in r && typeof r.width != "number") throw Error(`Grid item with id '${e}' has an invalid width property (must be a number)`);
|
|
1648
|
-
}
|
|
1649
|
-
for (let e of n) if (!(e in t.gridItems)) throw Error(`Layout item with id '${e}' does not have a corresponding grid item`);
|
|
1650
|
-
return t;
|
|
1651
|
-
}
|
|
1652
|
-
var st = "You are a world-class dashboard designer and analyst who produces striking insights. Given this typescript template format for a dashboard config, and a list of available fields,\ngenerate a JSON spec that can be imported into these typescript objects that will appropriately visualize data for the provided prompt.\n\nYou build information dense by clear dashboards, in the style of the New York Times or Edward Tufte. Focus on laying out content for an interactive, click based exploration; do not\nmention anything related to global dashboard filters, however.\n\nAppropriately mix in description and markdown to explain the data and the visualizations and how the dashboard should be used. \n\nThe horizontal grid components are sized on a 0-20 scale, which will respond to width. Rows are 30 pixels high. Markdown components should be at least 3 rows high, but make them higher\nif you judge appropriate. \n\nMake the dashboard comprehensive to explore the user question. If the user asks for something detailed, it should typically be 5-8 rows (5-10 cells); otherwise 3-6 is appropriate (4-6 cells). \n\nFor the chart and table types, in the content, write a a prompt for the data you want to visualize. A data engineer\nwill transform this into a real SQL query based on knowledge of the underlying database.\n\nThe prompt should be descriptive and precise to ensure they understand your intent, but should avoid being too 'SQL' - speak business.\n\nThey only have access to the same general concepts as you will be given below, so plan appropriately\nand do not ask them for something they will be unable to answer with that data.\n\nFor markdown, you can directly fill in the appropriate markdown syntax. Markdown cells are static and will not run/fetch data. The other\ntwo cells will be populated by queries. \n\nTypescript format \"\nexport const CELL_TYPES = {\n CHART: 'chart',\n MARKDOWN: 'markdown',\n TABLE: 'table',\n SECTION_HEADER: 'section-header',\n } as const\n \nexport type CellType = (typeof CELL_TYPES)[keyof typeof CELL_TYPES]\n\nexport interface PromptLayoutItem {\n x: number\n y: number\n w: number\n h: number\n id: string\n}\n\n// This contains details about the layout\n// the \nexport interface PromptGridItemData {\n type: CellType\n content: string\n name: string\n width?: number\n height?: number\n}\n\nexport interface PromptDashboard {\n name: string\n layout: PromptLayoutItem[]\n // the key here will associate a grid item with a layout item (in the id field)\n gridItems: Record<string, PromptGridItemData>\n description: string\n}\n\n\"\n\n";
|
|
1653
|
-
function ct(e, t) {
|
|
1654
|
-
return `
|
|
1655
|
-
${st}
|
|
1656
|
-
The prompt is: "${e}"
|
|
1657
|
-
The available concepts are:
|
|
1658
|
-
${t}
|
|
1659
|
-
|
|
1660
|
-
Return your answer as a JSON object surrounded by triple backticks. Include your reasoning before the object.
|
|
1661
|
-
`;
|
|
1662
|
-
}
|
|
1663
|
-
//#endregion
|
|
1664
|
-
//#region llm/data/conceptFilters.ts
|
|
1665
|
-
var lt = [
|
|
1666
|
-
".year",
|
|
1667
|
-
".quarter",
|
|
1668
|
-
".month",
|
|
1669
|
-
".week",
|
|
1670
|
-
".day",
|
|
1671
|
-
".day_of_week",
|
|
1672
|
-
".year_start",
|
|
1673
|
-
".month_start",
|
|
1674
|
-
".hour",
|
|
1675
|
-
".minute",
|
|
1676
|
-
".second"
|
|
1677
|
-
];
|
|
1678
|
-
function ut(e) {
|
|
1679
|
-
return lt.some((t) => e.endsWith(t));
|
|
1680
|
-
}
|
|
1681
|
-
function dt(e) {
|
|
1682
|
-
return e.filter((e) => !ut(e.name || e.label || ""));
|
|
1683
|
-
}
|
|
1684
|
-
//#endregion
|
|
1685
|
-
//#region llm/data/prompts.ts
|
|
1686
|
-
function ft(e) {
|
|
1687
|
-
return dt(e);
|
|
1688
|
-
}
|
|
1689
|
-
var pt = `You are a world-class assistant for generating queries in Trilogy, a SQL inspired language with similar syntax, Use the the syntax description below and field information to answer the user request. Return your answer with a short reasoning and a valid Trilogy query in triple double quotes.
|
|
1690
|
-
|
|
1691
|
-
${k}
|
|
1692
|
-
|
|
1693
|
-
For any response to the user, use this format -> put your actual response within triple double quotes with thinking and justification before it, in this format (replace placeholders with relevant content): Reasoning: {{reasoning}} """{{ response }}"""
|
|
1694
|
-
`;
|
|
1695
|
-
function A(e) {
|
|
1696
|
-
return ft(e).map((e) => `[name: ${e.name} | type:${e.type}${e.calculation ? " | alias_for:" + e.calculation : ""}${e.description ? " | description:" + e.description : ""}]`).join(", ");
|
|
1697
|
-
}
|
|
1698
|
-
function mt(e, t) {
|
|
1699
|
-
return `${pt}. Using these base and aliased calculations, derivations thereof created with valid Trilogy, and any extra context you have: ${A(t)}, create the best valid Trilogy query to answer the following user input: "${e}" Return the query within triple double quotes with your thinking and justification before it, so of this form as a jinja template: Reasoning: {{reasoning_placeholder}} """{{ trilogy }}""". Example: Because the user asked for sales by year, and revenue is the best sales related field available, we can aggregate revenue by year: """SELECT order.year, sum(revenue) as year_revenue order by order.year asc;"""`;
|
|
1700
|
-
}
|
|
1701
|
-
function ht(e, t) {
|
|
1702
|
-
return `${pt}. Using these base and aliased calculations, derivations thereof created with valid Trilogy, and any extra context you have: ${A(t)}, create the closest matching syntactically valid WHERE CLAUSE to filter a dashboard from this request """${e}""". Return only the portion of a SQL query representing the where clause, excluding any ordering. Do not include comments. After you generate the code, review it carefully to make sure it is only the partial where clause of a select, starting with WHERE (imagine if you put a "select 1 ..." in front of it.), with no semicolon at the end. Return your generated code within triple double quotes with thinking and justification before it in the form (as a jinja example) Reasoning: {{reasoning}} """{{ trilogy }}""". Example: Reasoning: Because the user asked for rainbow colors, we can filter to where the color is a primary color """where color in ('red', 'blue', 'violet')"""`;
|
|
1703
|
-
}
|
|
1704
|
-
function gt(e, t) {
|
|
1705
|
-
return ct(e, A(t));
|
|
1706
|
-
}
|
|
1707
|
-
//#endregion
|
|
1708
|
-
//#region llm/sharedToolSchemas.ts
|
|
1709
|
-
var _t = [
|
|
1710
|
-
"line",
|
|
1711
|
-
"bar",
|
|
1712
|
-
"barh",
|
|
1713
|
-
"point",
|
|
1714
|
-
"geo-map",
|
|
1715
|
-
"tree",
|
|
1716
|
-
"area",
|
|
1717
|
-
"headline",
|
|
1718
|
-
"donut",
|
|
1719
|
-
"heatmap",
|
|
1720
|
-
"boxplot",
|
|
1721
|
-
"treemap",
|
|
1722
|
-
"beeswarm"
|
|
1723
|
-
], vt = {
|
|
1724
|
-
chartType: "bar",
|
|
1725
|
-
xField: "category",
|
|
1726
|
-
yField: "revenue",
|
|
1727
|
-
yField2: "cost",
|
|
1728
|
-
colorField: "region",
|
|
1729
|
-
sizeField: "quantity",
|
|
1730
|
-
groupField: "year",
|
|
1731
|
-
trellisField: "department",
|
|
1732
|
-
trellisRowField: "quarter",
|
|
1733
|
-
geoField: "state_code",
|
|
1734
|
-
annotationField: "notes",
|
|
1735
|
-
hideLegend: !1,
|
|
1736
|
-
showTitle: !0,
|
|
1737
|
-
scaleX: "linear",
|
|
1738
|
-
scaleY: "linear",
|
|
1739
|
-
linkY2: !1
|
|
1740
|
-
}, yt = {
|
|
1741
|
-
type: "object",
|
|
1742
|
-
description: "One layer of a layered chart, drawn over the same result set.",
|
|
1743
|
-
properties: {
|
|
1744
|
-
chartType: {
|
|
1745
|
-
type: "string",
|
|
1746
|
-
enum: _t,
|
|
1747
|
-
description: "Type of chart to render"
|
|
1748
|
-
},
|
|
1749
|
-
xField: {
|
|
1750
|
-
type: "string",
|
|
1751
|
-
description: "Field name for x-axis. Longitude for geo-map charts if geofield not provided."
|
|
1752
|
-
},
|
|
1753
|
-
yField: {
|
|
1754
|
-
type: "string",
|
|
1755
|
-
description: "Field name for y-axis. Latitude for geo-map charts if geofield not provided."
|
|
1756
|
-
},
|
|
1757
|
-
colorField: {
|
|
1758
|
-
type: "string",
|
|
1759
|
-
description: "Field for color encoding (optional)"
|
|
1760
|
-
},
|
|
1761
|
-
sizeField: {
|
|
1762
|
-
type: "string",
|
|
1763
|
-
description: "Field for size encoding (optional)"
|
|
1764
|
-
},
|
|
1765
|
-
annotationField: {
|
|
1766
|
-
type: "string",
|
|
1767
|
-
description: "Field for data point annotations/labels (optional)"
|
|
1768
|
-
},
|
|
1769
|
-
layerLabel: {
|
|
1770
|
-
type: "string",
|
|
1771
|
-
description: "Name for this layer in the chart's legend (optional; defaults to the y field name)"
|
|
1772
|
-
},
|
|
1773
|
-
yAxisOrient: {
|
|
1774
|
-
type: "string",
|
|
1775
|
-
enum: ["left", "right"],
|
|
1776
|
-
description: "Which side to draw this layer value axis on (optional)"
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
}, bt = {
|
|
1780
|
-
chartType: "bar",
|
|
1781
|
-
showTitle: !0,
|
|
1782
|
-
layers: [{
|
|
1783
|
-
chartType: "bar",
|
|
1784
|
-
xField: "category",
|
|
1785
|
-
yField: "revenue"
|
|
1786
|
-
}, {
|
|
1787
|
-
chartType: "line",
|
|
1788
|
-
xField: "category",
|
|
1789
|
-
yField: "avg_revenue"
|
|
1790
|
-
}],
|
|
1791
|
-
placements: [{
|
|
1792
|
-
kind: "hline",
|
|
1793
|
-
value: 1e3,
|
|
1794
|
-
label: "target"
|
|
1795
|
-
}]
|
|
1796
|
-
}, j = {
|
|
1797
|
-
type: "object",
|
|
1798
|
-
description: "Chart configuration object",
|
|
1799
|
-
properties: {
|
|
1800
|
-
chartType: {
|
|
1801
|
-
type: "string",
|
|
1802
|
-
enum: _t,
|
|
1803
|
-
description: "Type of chart to render"
|
|
1804
|
-
},
|
|
1805
|
-
xField: {
|
|
1806
|
-
type: "string",
|
|
1807
|
-
description: "Field name for x-axis. Longitude for geo-map charts if geofield not provided."
|
|
1808
|
-
},
|
|
1809
|
-
yField: {
|
|
1810
|
-
type: "string",
|
|
1811
|
-
description: "Field name for y-axis. Latitude for geo-map charts if geofield not provided."
|
|
1812
|
-
},
|
|
1813
|
-
yField2: {
|
|
1814
|
-
type: "string",
|
|
1815
|
-
description: "Secondary y-axis field (optional)"
|
|
1816
|
-
},
|
|
1817
|
-
colorField: {
|
|
1818
|
-
type: "string",
|
|
1819
|
-
description: "Field for color encoding (optional)"
|
|
1820
|
-
},
|
|
1821
|
-
sizeField: {
|
|
1822
|
-
type: "string",
|
|
1823
|
-
description: "Field for size encoding (optional)"
|
|
1824
|
-
},
|
|
1825
|
-
groupField: {
|
|
1826
|
-
type: "string",
|
|
1827
|
-
description: "Field for grouping data (optional)"
|
|
1828
|
-
},
|
|
1829
|
-
trellisField: {
|
|
1830
|
-
type: "string",
|
|
1831
|
-
description: "Field for small multiples/faceting columns (optional)"
|
|
1832
|
-
},
|
|
1833
|
-
trellisRowField: {
|
|
1834
|
-
type: "string",
|
|
1835
|
-
description: "Field for small multiples/faceting rows (optional)"
|
|
1836
|
-
},
|
|
1837
|
-
geoField: {
|
|
1838
|
-
type: "string",
|
|
1839
|
-
description: "Field for geographic data (optional)"
|
|
1840
|
-
},
|
|
1841
|
-
annotationField: {
|
|
1842
|
-
type: "string",
|
|
1843
|
-
description: "Field for data point annotations/labels (optional)"
|
|
1844
|
-
},
|
|
1845
|
-
hideLegend: {
|
|
1846
|
-
type: "boolean",
|
|
1847
|
-
description: "Whether to hide the legend (optional)"
|
|
1848
|
-
},
|
|
1849
|
-
showTitle: {
|
|
1850
|
-
type: "boolean",
|
|
1851
|
-
description: "Whether to show the chart title (optional)"
|
|
1852
|
-
},
|
|
1853
|
-
scaleX: {
|
|
1854
|
-
type: "string",
|
|
1855
|
-
enum: [
|
|
1856
|
-
"linear",
|
|
1857
|
-
"log",
|
|
1858
|
-
"sqrt"
|
|
1859
|
-
],
|
|
1860
|
-
description: "Scale type for x-axis (optional)"
|
|
1861
|
-
},
|
|
1862
|
-
scaleY: {
|
|
1863
|
-
type: "string",
|
|
1864
|
-
enum: [
|
|
1865
|
-
"linear",
|
|
1866
|
-
"log",
|
|
1867
|
-
"sqrt"
|
|
1868
|
-
],
|
|
1869
|
-
description: "Scale type for y-axis (optional)"
|
|
1870
|
-
},
|
|
1871
|
-
linkY2: {
|
|
1872
|
-
type: "boolean",
|
|
1873
|
-
description: "Whether to link the secondary y-axis scale to the primary y-axis (optional)"
|
|
1874
|
-
},
|
|
1875
|
-
layers: {
|
|
1876
|
-
type: "array",
|
|
1877
|
-
items: yt,
|
|
1878
|
-
description: "Draw several marks over one result set, e.g. bars for a total with a line for an average. When set, the chart type and field bindings above are ignored and each layer supplies its own; the settings above (title, legend, scales) still apply to the chart as a whole. Only line, bar, barh, area, point, boxplot, donut and heatmap can be layers. Cannot be combined with trellisField/trellisRowField. Leave unset for an ordinary single-mark chart."
|
|
1879
|
-
},
|
|
1880
|
-
placements: {
|
|
1881
|
-
type: "array",
|
|
1882
|
-
description: "Constant reference lines drawn over the chart (optional)",
|
|
1883
|
-
items: {
|
|
1884
|
-
type: "object",
|
|
1885
|
-
properties: {
|
|
1886
|
-
kind: {
|
|
1887
|
-
type: "string",
|
|
1888
|
-
enum: ["hline", "vline"]
|
|
1889
|
-
},
|
|
1890
|
-
value: {
|
|
1891
|
-
type: "number",
|
|
1892
|
-
description: "Where on the axis to draw the line"
|
|
1893
|
-
},
|
|
1894
|
-
label: {
|
|
1895
|
-
type: "string",
|
|
1896
|
-
description: "Optional text label pinned to the line"
|
|
1897
|
-
}
|
|
1898
|
-
},
|
|
1899
|
-
required: ["kind", "value"]
|
|
1900
|
-
}
|
|
1901
|
-
},
|
|
1902
|
-
linkLayerY: {
|
|
1903
|
-
type: "boolean",
|
|
1904
|
-
description: "Force layers to share one y-axis (true) or get independent ones (false). Omit to let the chart decide from the layers value formats (optional)"
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
}, xt = _t.map((e) => `'${e}'`).join(", "), M = `Chart type is auto-detected based on data shape unless you specify a chartConfig. Only provide chartConfig if the user specifically requests a chart type or configuration; otherwise let auto-detection handle it.
|
|
1908
|
-
|
|
1909
|
-
[Important!] Hiding fields used only for filtering/query structure from output - such as ranks - with the "--" trilogy select syntax may be useful to get the right auto-formatting.
|
|
1910
|
-
|
|
1911
|
-
[Important] To get deterministic coloring, if there is a hex field available that maps to a dimension it can be pulled in to automatically be used as the relevant color when dimension is set as colorField.
|
|
1912
|
-
You DO NOT need to specify colorField as the hexField if it is included; it will automatically be used to populate the color range for the dimension field.
|
|
1913
|
-
You can also add a default available Trilogy import "import std.color;" at the top of a query and cast a string case statement of hex values to ::string::hex to create mappings yourself.
|
|
1914
|
-
Do this if the user asks for specific coloring.
|
|
1915
|
-
|
|
1916
|
-
Example chartConfig: ${JSON.stringify(vt)}
|
|
1917
|
-
|
|
1918
|
-
To draw more than one mark over the same results — bars for a total with a line for an average, say — set 'layers' instead of the top-level chart type and fields. Each layer names its own chartType and fields; title, legend and scale settings stay on the parent. Add 'placements' for constant reference lines.
|
|
1919
|
-
Example layered chartConfig: ${JSON.stringify(bt)}
|
|
1920
|
-
|
|
1921
|
-
Available chartTypes: ${xt}`, N = {
|
|
1922
|
-
name: "connect_data_connection",
|
|
1923
|
-
description: "Connect or reconnect a data connection that is not currently active. Use this when a query fails because the connection is not active, or when you need to establish a connection before running queries.",
|
|
1924
|
-
input_schema: {
|
|
1925
|
-
type: "object",
|
|
1926
|
-
properties: { connection: {
|
|
1927
|
-
type: "string",
|
|
1928
|
-
description: "The name of the data connection to connect"
|
|
1929
|
-
} },
|
|
1930
|
-
required: ["connection"]
|
|
1931
|
-
}
|
|
1932
|
-
};
|
|
1933
|
-
//#endregion
|
|
1934
|
-
//#region llm/chatAgentPrompt.ts
|
|
1935
|
-
function St(e) {
|
|
1936
|
-
return e({
|
|
1937
|
-
trilogySyntaxReference: k,
|
|
1938
|
-
rulesInput: nt,
|
|
1939
|
-
aggFunctions: rt,
|
|
1940
|
-
functions: it,
|
|
1941
|
-
datatypes: at
|
|
1942
|
-
});
|
|
1943
|
-
}
|
|
1944
|
-
var Ct = {
|
|
1945
|
-
name: "return_to_user",
|
|
1946
|
-
description: "Signal that you are done and return control to the user. You MUST call this tool when you have completed all requested tasks and are ready for the user's next input. Provide a brief summary of what was accomplished. Never end a turn with plain text — always call this tool when finished.",
|
|
1947
|
-
input_schema: {
|
|
1948
|
-
type: "object",
|
|
1949
|
-
properties: { message: {
|
|
1950
|
-
type: "string",
|
|
1951
|
-
description: "A brief summary of what was accomplished or a response to the user."
|
|
1952
|
-
} },
|
|
1953
|
-
required: ["message"]
|
|
1954
|
-
}
|
|
1955
|
-
}, wt = [
|
|
1956
|
-
{
|
|
1957
|
-
name: "run_trilogy_query",
|
|
1958
|
-
description: "Execute a Trilogy query and return tabular results. Use this for data exploration, aggregations, and when the user wants to see raw data in a table format.",
|
|
1959
|
-
input_schema: {
|
|
1960
|
-
type: "object",
|
|
1961
|
-
properties: {
|
|
1962
|
-
query: {
|
|
1963
|
-
type: "string",
|
|
1964
|
-
description: "The Trilogy query to execute"
|
|
1965
|
-
},
|
|
1966
|
-
connection: {
|
|
1967
|
-
type: "string",
|
|
1968
|
-
description: "Data connection name to run the query against"
|
|
1969
|
-
}
|
|
1970
|
-
},
|
|
1971
|
-
required: ["query", "connection"]
|
|
1972
|
-
}
|
|
1973
|
-
},
|
|
1974
|
-
{
|
|
1975
|
-
name: "chart_trilogy_query",
|
|
1976
|
-
description: `Execute a Trilogy query and display results as a chart. ${M}`,
|
|
1977
|
-
input_schema: {
|
|
1978
|
-
type: "object",
|
|
1979
|
-
properties: {
|
|
1980
|
-
query: {
|
|
1981
|
-
type: "string",
|
|
1982
|
-
description: "The Trilogy query to execute"
|
|
1983
|
-
},
|
|
1984
|
-
connection: {
|
|
1985
|
-
type: "string",
|
|
1986
|
-
description: "Data connection name to run the query against"
|
|
1987
|
-
},
|
|
1988
|
-
chartConfig: {
|
|
1989
|
-
...j,
|
|
1990
|
-
description: "Optional chart configuration. Only provide if user specifically requests a chart type or configuration."
|
|
1991
|
-
}
|
|
1992
|
-
},
|
|
1993
|
-
required: ["query", "connection"]
|
|
1994
|
-
}
|
|
1995
|
-
},
|
|
1996
|
-
{
|
|
1997
|
-
name: "select_active_import",
|
|
1998
|
-
description: "Select a single data source import to use for queries. This replaces any previously selected import. Only one import can be active at a time. After selecting an import, the tool will return the full list of available fields/concepts from that data source including their descriptions. Use list_available_imports first to see what data sources are available.",
|
|
1999
|
-
input_schema: {
|
|
2000
|
-
type: "object",
|
|
2001
|
-
properties: { import_name: {
|
|
2002
|
-
type: "string",
|
|
2003
|
-
description: "The name of the import to select (e.g., \"sales.orders\" or \"finance.revenue\"). Use list_available_imports to see available options. Pass an empty string or null to clear the current selection."
|
|
2004
|
-
} },
|
|
2005
|
-
required: ["import_name"]
|
|
2006
|
-
}
|
|
2007
|
-
},
|
|
2008
|
-
{
|
|
2009
|
-
name: "list_available_imports",
|
|
2010
|
-
description: "List all available data source imports for the current connection. Use this to discover what data models are available before adding an import.",
|
|
2011
|
-
input_schema: {
|
|
2012
|
-
type: "object",
|
|
2013
|
-
properties: {},
|
|
2014
|
-
required: []
|
|
2015
|
-
}
|
|
2016
|
-
},
|
|
2017
|
-
N,
|
|
2018
|
-
{
|
|
2019
|
-
name: "create_markdown",
|
|
2020
|
-
description: "Create a rich markdown artifact to display formatted text, summaries, reports, or data-driven content. Supports standard markdown syntax (headers, lists, bold, italic, links, tables, code blocks). When a query is provided, data from the query results can be referenced in the markdown template. Use this for narrative reports, executive summaries, annotated insights, or any rich text content.",
|
|
2021
|
-
input_schema: {
|
|
2022
|
-
type: "object",
|
|
2023
|
-
properties: {
|
|
2024
|
-
markdown: {
|
|
2025
|
-
type: "string",
|
|
2026
|
-
description: "Markdown content to display. Supports standard markdown syntax.\n\nIf a query is also provided, inject query results using these template expressions:\n\nBASIC SUBSTITUTION:\n- {field_name} — value from the first result row (e.g. {total_flights})\n- {data[N].field_name} — value from row N (e.g. {data[0].airline})\n- {data.length} — total number of result rows\n- {field_name || \"fallback\"} — value with a fallback if null/missing\n- {{#each data limit=N}} ...{field}... {{/each}} — loop over rows\n\nFORMAT SPECIFIERS (numeric fields only):\n- {field_name:,} — thousands separator (e.g. {total_flights:,} → \"5,797\")\n- {field_name:.2f} — fixed decimal places (e.g. {rate:.2f} → \"1.43\")\n- {field_name:,.2f} — both (e.g. {revenue:,.2f} → \"1,234.56\")\n- {field_name:.1%} — multiply by 100 and show as percentage (e.g. {rate:.1%} where rate=0.014 → \"1.4%\")\n\nARITHMETIC WITH FORMAT:\n- {(expr):format} — evaluate arithmetic then format; only field names and + - * / are allowed\n- Example: {(cancelled/total*100):.1f} computes the ratio and shows 1 decimal place\n\nLIMITATIONS — what the template engine cannot do:\n- No comparisons or conditional logic: {{#if (avg < 500)}} is NOT supported\n- No string functions, date arithmetic, or complex expressions\n- No nested loops or grouping logic\nIf you need conditional output (e.g. \"Regional\" vs \"Major/National\" based on a threshold), compute it in SQL/Trilogy using a CASE expression and return it as a field, then reference the field in the template."
|
|
2027
|
-
},
|
|
2028
|
-
title: {
|
|
2029
|
-
type: "string",
|
|
2030
|
-
description: "Optional title for the artifact"
|
|
2031
|
-
},
|
|
2032
|
-
query: {
|
|
2033
|
-
type: "string",
|
|
2034
|
-
description: "Optional Trilogy query to execute. Results will be available for template substitution in the markdown."
|
|
2035
|
-
},
|
|
2036
|
-
connection: {
|
|
2037
|
-
type: "string",
|
|
2038
|
-
description: "Data connection name for executing the query (required if query is provided)"
|
|
2039
|
-
}
|
|
2040
|
-
},
|
|
2041
|
-
required: ["markdown"]
|
|
2042
|
-
}
|
|
2043
|
-
},
|
|
2044
|
-
{
|
|
2045
|
-
name: "list_artifacts",
|
|
2046
|
-
description: "List all artifacts in the current chat session with their IDs, types, and summaries. Use this to see what artifacts exist before updating or removing them.",
|
|
2047
|
-
input_schema: {
|
|
2048
|
-
type: "object",
|
|
2049
|
-
properties: {},
|
|
2050
|
-
required: []
|
|
2051
|
-
}
|
|
2052
|
-
},
|
|
2053
|
-
{
|
|
2054
|
-
name: "get_artifact",
|
|
2055
|
-
description: "Get the full contents and metadata of an artifact by ID. Returns the artifact type, configuration, and data. Large result sets are truncated; use get_artifact_rows to fetch specific row ranges.",
|
|
2056
|
-
input_schema: {
|
|
2057
|
-
type: "object",
|
|
2058
|
-
properties: { artifact_id: {
|
|
2059
|
-
type: "string",
|
|
2060
|
-
description: "The ID of the artifact to retrieve"
|
|
2061
|
-
} },
|
|
2062
|
-
required: ["artifact_id"]
|
|
2063
|
-
}
|
|
2064
|
-
},
|
|
2065
|
-
{
|
|
2066
|
-
name: "get_artifact_rows",
|
|
2067
|
-
description: "Fetch a specific range of rows from a query result or chart artifact. Use this to inspect data in large result sets that were truncated in the initial response. Rows are 0-indexed.",
|
|
2068
|
-
input_schema: {
|
|
2069
|
-
type: "object",
|
|
2070
|
-
properties: {
|
|
2071
|
-
artifact_id: {
|
|
2072
|
-
type: "string",
|
|
2073
|
-
description: "The ID of the results or chart artifact to fetch rows from"
|
|
2074
|
-
},
|
|
2075
|
-
start_row: {
|
|
2076
|
-
type: "number",
|
|
2077
|
-
description: "First row to return (0-indexed, inclusive)"
|
|
2078
|
-
},
|
|
2079
|
-
end_row: {
|
|
2080
|
-
type: "number",
|
|
2081
|
-
description: "Last row to return (0-indexed, inclusive)"
|
|
2082
|
-
}
|
|
2083
|
-
},
|
|
2084
|
-
required: [
|
|
2085
|
-
"artifact_id",
|
|
2086
|
-
"start_row",
|
|
2087
|
-
"end_row"
|
|
2088
|
-
]
|
|
2089
|
-
}
|
|
2090
|
-
},
|
|
2091
|
-
{
|
|
2092
|
-
name: "update_artifact",
|
|
2093
|
-
description: "Update an existing artifact by ID. Can update markdown content, title, or chart configuration. Use list_artifacts first to find artifact IDs.",
|
|
2094
|
-
input_schema: {
|
|
2095
|
-
type: "object",
|
|
2096
|
-
properties: {
|
|
2097
|
-
artifact_id: {
|
|
2098
|
-
type: "string",
|
|
2099
|
-
description: "The ID of the artifact to update (from list_artifacts or tool results)"
|
|
2100
|
-
},
|
|
2101
|
-
markdown: {
|
|
2102
|
-
type: "string",
|
|
2103
|
-
description: "New markdown content (for markdown artifacts)"
|
|
2104
|
-
},
|
|
2105
|
-
title: {
|
|
2106
|
-
type: "string",
|
|
2107
|
-
description: "New title for the artifact"
|
|
2108
|
-
},
|
|
2109
|
-
chartConfig: {
|
|
2110
|
-
...j,
|
|
2111
|
-
description: "New chart configuration (for chart/results artifacts)"
|
|
2112
|
-
}
|
|
2113
|
-
},
|
|
2114
|
-
required: ["artifact_id"]
|
|
2115
|
-
}
|
|
2116
|
-
},
|
|
2117
|
-
{
|
|
2118
|
-
name: "hide_artifact",
|
|
2119
|
-
description: "Hide one or more artifacts from the main view. Hidden artifacts are soft-deleted: they move to a collapsed \"Hidden\" section the user can expand, and you can still reference them by ID. Use this to remove stale, intermediate, or superseded artifacts during curation. Use list_artifacts first to find artifact IDs.",
|
|
2120
|
-
input_schema: {
|
|
2121
|
-
type: "object",
|
|
2122
|
-
properties: { artifact_ids: {
|
|
2123
|
-
type: "array",
|
|
2124
|
-
items: { type: "string" },
|
|
2125
|
-
description: "One or more artifact IDs to hide."
|
|
2126
|
-
} },
|
|
2127
|
-
required: ["artifact_ids"]
|
|
2128
|
-
}
|
|
2129
|
-
},
|
|
2130
|
-
{
|
|
2131
|
-
name: "reorder_artifacts",
|
|
2132
|
-
description: "Reorder artifacts in the chat session by providing the desired order of artifact IDs. The artifacts panel displays artifacts in order, so arrange them for maximum clarity and impact (e.g., summary/overview first, supporting details after). Any artifact IDs not included will be appended at the end in their original order.",
|
|
2133
|
-
input_schema: {
|
|
2134
|
-
type: "object",
|
|
2135
|
-
properties: { artifact_ids: {
|
|
2136
|
-
type: "array",
|
|
2137
|
-
items: { type: "string" },
|
|
2138
|
-
description: "Ordered list of artifact IDs representing the desired display order. Use list_artifacts to find IDs."
|
|
2139
|
-
} },
|
|
2140
|
-
required: ["artifact_ids"]
|
|
2141
|
-
}
|
|
2142
|
-
},
|
|
2143
|
-
Ct
|
|
2144
|
-
];
|
|
2145
|
-
function Tt(e, t) {
|
|
2146
|
-
if (!t || t.length === 0) return e;
|
|
2147
|
-
let n = new Set(t);
|
|
2148
|
-
return e.filter((e) => !n.has(e.name));
|
|
2149
|
-
}
|
|
2150
|
-
function Et(e, t) {
|
|
2151
|
-
if (!t || t.length === 0) return e;
|
|
2152
|
-
let n = new Set(e.map((e) => e.name)), r = /* @__PURE__ */ new Set(), i = t.map((e) => {
|
|
2153
|
-
let t = e.definition.name;
|
|
2154
|
-
if (n.has(t)) throw Error(`Host tool '${t}' shadows a built-in chat tool`);
|
|
2155
|
-
if (r.has(t)) throw Error(`Host tool '${t}' is declared twice`);
|
|
2156
|
-
return r.add(t), e.definition;
|
|
2157
|
-
}), a = e.findIndex((e) => e.name === Ct.name);
|
|
2158
|
-
return a === -1 ? [...e, ...i] : [
|
|
2159
|
-
...e.slice(0, a),
|
|
2160
|
-
...i,
|
|
2161
|
-
...e.slice(a)
|
|
2162
|
-
];
|
|
2163
|
-
}
|
|
2164
|
-
var Dt = [
|
|
2165
|
-
{ text: "- Every query and chart tool call returns an artifact ID. Use these IDs to reference, update, or remove artifacts later." },
|
|
2166
|
-
{
|
|
2167
|
-
tool: "create_markdown",
|
|
2168
|
-
text: "- Use create_markdown to create rich formatted content: reports, summaries, annotated insights, data-driven narratives.\n - Markdown supports template expressions when a query is provided: {field_name}, {data[0].field}, {{#each data limit=5}} {field} {{/each}}"
|
|
2169
|
-
},
|
|
2170
|
-
{
|
|
2171
|
-
tool: "list_artifacts",
|
|
2172
|
-
text: "- Use list_artifacts to see all artifacts with their IDs, types, and metadata."
|
|
2173
|
-
},
|
|
2174
|
-
{
|
|
2175
|
-
tool: "get_artifact",
|
|
2176
|
-
text: "- Use get_artifact to inspect the full contents and configuration of a specific artifact."
|
|
2177
|
-
},
|
|
2178
|
-
{
|
|
2179
|
-
tool: "update_artifact",
|
|
2180
|
-
text: "- Use update_artifact to modify existing artifacts (change markdown content, title, or chart configuration)."
|
|
2181
|
-
},
|
|
2182
|
-
{
|
|
2183
|
-
tool: "hide_artifact",
|
|
2184
|
-
text: "- Use hide_artifact to remove stale or superseded artifacts from the main view. Hidden artifacts are preserved and accessible to both you and the user — they are not deleted."
|
|
2185
|
-
},
|
|
2186
|
-
{
|
|
2187
|
-
tool: "create_markdown",
|
|
2188
|
-
text: "- When the user asks for a summary, report, or narrative, prefer create_markdown over just text responses - it renders in the artifacts panel."
|
|
2189
|
-
}
|
|
2190
|
-
], Ot = [{
|
|
2191
|
-
tool: "search_docs",
|
|
2192
|
-
text: "- When you are unsure how to express something in Trilogy — window functions, date handling, filtering on aggregates, an unfamiliar keyword — call search_docs (kind: language or function) and then read_doc, rather than guessing at syntax. The reference above is a summary; the docs carry the full idioms."
|
|
2193
|
-
}, {
|
|
2194
|
-
tool: "read_doc",
|
|
2195
|
-
text: "- read_doc returns the full article for an id from search_docs; quote the relevant part back to the user when they ask how the language works."
|
|
2196
|
-
}], kt = [
|
|
2197
|
-
{
|
|
2198
|
-
tool: "list_artifacts",
|
|
2199
|
-
text: "Call list_artifacts to see everything currently in the panel."
|
|
2200
|
-
},
|
|
2201
|
-
{
|
|
2202
|
-
tool: "hide_artifact",
|
|
2203
|
-
text: "Hide stale or superseded artifacts using hide_artifact — failed queries, test runs, intermediate steps, or results from earlier questions that are no longer relevant to the current ask. Hidden artifacts are preserved (the user can restore them) and you can still reference them by ID."
|
|
2204
|
-
},
|
|
2205
|
-
{
|
|
2206
|
-
tool: "update_artifact",
|
|
2207
|
-
text: "Update titles: give each remaining artifact a clear, descriptive title that explains what it shows (via update_artifact)."
|
|
2208
|
-
},
|
|
2209
|
-
{
|
|
2210
|
-
tool: "reorder_artifacts",
|
|
2211
|
-
text: "Reorder artifacts for maximum impact — put the most important artifact first (e.g., a summary markdown or key chart), followed by supporting detail. The artifacts panel is the primary view the user sees."
|
|
2212
|
-
},
|
|
2213
|
-
{ text: "The artifact panel should tell a coherent story that directly answers the user's latest request — not accumulate a growing pile from every prior turn." }
|
|
2214
|
-
];
|
|
2215
|
-
function P(e, t) {
|
|
2216
|
-
return e.filter((e) => !e.tool || !t.includes(e.tool));
|
|
2217
|
-
}
|
|
2218
|
-
function At(e) {
|
|
2219
|
-
let { dataConnectionName: t, availableConnections: n, availableConcepts: r, activeImports: i = [], availableImportsForConnection: a = [], isDataConnectionActive: o = !0, disabledTools: s = [] } = e, c = P(Dt, s).map((e) => e.text).join("\n"), l = P(kt, s).map((e, t) => `${t + 1}. ${e.text}`).join("\n"), u = P(Ot, s), d = u.length > 0 ? `\n\nDOCUMENTATION:\n${u.map((e) => e.text).join("\n")}` : "", f = r && r.length > 0 ? `\n\nAVAILABLE FIELDS FOR QUERIES:\n${A(r)}` : "", p = !s.includes("connect_data_connection"), m = t && !o ? p ? " (NOT CONNECTED - use connect_data_connection tool to connect before running queries)" : " (NOT CONNECTED - queries will fail; tell the user the data connection is not available and call return_to_user)" : "", h = p ? "\n8. If the data connection is not active, use connect_data_connection to establish the connection before running queries" : "", g = t ? `ACTIVE DATA CONNECTION: ${t}${m}` : "No data connection currently selected. Ask the user which connection to use.", _ = i.length > 0 ? `\nACTIVE DATA SOURCE: ${i[0].name}` : "\nNo data source currently selected. Use select_active_import to select a data source, or use list_available_imports to see what is available.", v = a.length > 0 ? `\n\nAVAILABLE DATA SOURCES:\n${a.map((e) => `- ${e.name}${i.some((t) => t.id === e.id) ? " (active)" : ""}`).join("\n")}` : "";
|
|
2220
|
-
return `You are a data analysis assistant with access to Trilogy query capabilities.
|
|
2221
|
-
|
|
2222
|
-
You have access to tools that can select datasources, execute queries and generate visualizations. When a user asks about data, analyze their request, make sure you are looking at the right source, write a valid Trilogy query, and use the appropriate tool.
|
|
2223
|
-
|
|
2224
|
-
${g}
|
|
2225
|
-
AVAILABLE DATA CONNECTIONS: ${n.length > 0 ? n.join(", ") : "None configured - user needs to set up a data connection first"}
|
|
2226
|
-
${_}${v}
|
|
2227
|
-
|
|
2228
|
-
TRILOGY LANGUAGE REFERENCE:
|
|
2229
|
-
${k}
|
|
2230
|
-
${f}
|
|
2231
|
-
|
|
2232
|
-
IMPORTANT GUIDELINES:
|
|
2233
|
-
1. Always use a reasonable LIMIT (e.g., 100-1000) unless the request is specifically for a time series, line chart, or the user asks for all data
|
|
2234
|
-
2. For charts, let auto-detection choose the chart type unless the user specifies one (e.g., "show me a bar chart", "as a line graph")
|
|
2235
|
-
3. If a query fails, explain the error clearly and try a corrected version
|
|
2236
|
-
4. When showing data, prefer tables for detailed exploration and charts for trends/comparisons
|
|
2237
|
-
5. Use the full field path (e.g., 'order.product.id') - never use FROM clauses
|
|
2238
|
-
6. Remember: No GROUP BY clause - grouping is implicit by non-aggregated fields in SELECT
|
|
2239
|
-
7. If the user question needs fields that are not in the same source, use select_active_import to switch to a different data source (only one can be active at a time). Always consider this when they change topics.${h}${d}
|
|
2240
|
-
|
|
2241
|
-
ARTIFACT MANAGEMENT:
|
|
2242
|
-
${c}
|
|
2243
|
-
|
|
2244
|
-
ARTIFACT CURATION (required before every return_to_user call):
|
|
2245
|
-
Before calling return_to_user, you MUST curate the artifact panel so it reflects a clean, coherent answer to the user's current request:
|
|
2246
|
-
${l}
|
|
2247
|
-
|
|
2248
|
-
COMPLETING YOUR RESPONSE:
|
|
2249
|
-
- When you have finished addressing the user's request AND curated the artifact panel, call return_to_user with a brief summary.
|
|
2250
|
-
- Never end a turn with plain text only — you must always call a tool. return_to_user is always your final tool call.
|
|
2251
|
-
- The return_to_user message should be concise — the artifacts panel carries the detail.
|
|
2252
|
-
`;
|
|
2253
|
-
}
|
|
2254
|
-
//#endregion
|
|
2255
|
-
//#region llm/subchatSummarize.ts
|
|
2256
|
-
var jt = "You are summarizing a subchat that has just finished. Read the transcript below (messages and tool calls) and produce a 2–4 sentence summary of what was accomplished, what (if anything) failed or remains, and any concrete artifacts (file names, queries, errors). Be specific. The overseer will use this report to update the user — there is no other source of truth, so do not omit important results.", Mt = "You are summarizing a subchat's progress for an overseer agent. Read the transcript below (messages and tool calls) and produce a concise 2–4 sentence summary of what has happened so far, what has been accomplished, and what (if anything) remains. Be specific about file names, queries, or errors. Do not editorialize.";
|
|
2257
|
-
async function Nt(e, t, n = "completion") {
|
|
2258
|
-
let r = Pt(t.messages), i = n === "completion" ? jt : Mt, a = e.getFastModel(), o = e.model, s = !!a && a !== o;
|
|
2259
|
-
try {
|
|
2260
|
-
return s && (e.model = a), (await e.generateCompletion({
|
|
2261
|
-
prompt: "",
|
|
2262
|
-
systemPrompt: i
|
|
2263
|
-
}, [{
|
|
2264
|
-
role: "user",
|
|
2265
|
-
content: `Subchat kind: ${t.kind}\nName: ${t.name}\n\n--- TRANSCRIPT ---\n${r}`
|
|
2266
|
-
}])).text.trim();
|
|
2267
|
-
} finally {
|
|
2268
|
-
s && (e.model = o);
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
function Pt(e) {
|
|
2272
|
-
return e.map((e, t) => {
|
|
2273
|
-
let n = [`[${t}] ${e.role}: ${Ft(e.content || "", 800)}`];
|
|
2274
|
-
if (e.toolCalls && e.toolCalls.length > 0) for (let t of e.toolCalls) n.push(` → ${t.name}(${Ft(JSON.stringify(t.input), 200)})`);
|
|
2275
|
-
if (e.toolResults && e.toolResults.length > 0) for (let t of e.toolResults) n.push(` ← ${t.toolName}: ${Ft(t.result, 300)}`);
|
|
2276
|
-
return n.join("\n");
|
|
2277
|
-
}).join("\n\n");
|
|
2278
|
-
}
|
|
2279
|
-
function Ft(e, t) {
|
|
2280
|
-
return e.length <= t ? e : e.slice(0, t - 1) + "…";
|
|
2281
|
-
}
|
|
2282
|
-
var It = 4, Lt = 8, Rt = 1600;
|
|
2283
|
-
function F(e) {
|
|
2284
|
-
return e ? Math.ceil(e.length / 4) : 0;
|
|
2285
|
-
}
|
|
2286
|
-
function zt(e) {
|
|
2287
|
-
let t = It + F(e.content);
|
|
2288
|
-
for (let n of e.toolCalls ?? []) {
|
|
2289
|
-
t += Lt + F(n.name);
|
|
2290
|
-
try {
|
|
2291
|
-
t += F(JSON.stringify(n.input));
|
|
2292
|
-
} catch {}
|
|
2293
|
-
}
|
|
2294
|
-
for (let n of e.toolResults ?? []) t += Lt + F(n.toolName), t += F(n.result), n.imageData && (t += Rt);
|
|
2295
|
-
return t;
|
|
2296
|
-
}
|
|
2297
|
-
function Bt(e) {
|
|
2298
|
-
return e.reduce((e, t) => e + zt(t), 0);
|
|
2299
|
-
}
|
|
2300
|
-
//#endregion
|
|
2301
|
-
//#region llm/toolLoopCore.ts
|
|
2302
|
-
var Vt = "<user_input>", Ht = "</user_input>", I = "<system_input>", L = "</system_input>";
|
|
2303
|
-
function R(e) {
|
|
2304
|
-
return e.replace(/<\/?(?:user_input|system_input)>/gi, "");
|
|
2305
|
-
}
|
|
2306
|
-
function Ut(e) {
|
|
2307
|
-
let t = e?.data;
|
|
2308
|
-
return !Array.isArray(t) || t.length <= 100 ? {
|
|
2309
|
-
head: t ?? [],
|
|
2310
|
-
tail: [],
|
|
2311
|
-
totalRows: t?.length ?? 0,
|
|
2312
|
-
cutCount: 0
|
|
2313
|
-
} : {
|
|
2314
|
-
head: t.slice(0, 50),
|
|
2315
|
-
tail: t.slice(t.length - 50),
|
|
2316
|
-
totalRows: t.length,
|
|
2317
|
-
cutCount: t.length - 100
|
|
2318
|
-
};
|
|
2319
|
-
}
|
|
2320
|
-
function Wt(e) {
|
|
2321
|
-
if (e.success) if (e.artifact) {
|
|
2322
|
-
let t = e.artifact.config, n = e.artifact.data, r = e.artifact.id, i = "";
|
|
2323
|
-
if (n) {
|
|
2324
|
-
let e = typeof n.toJSON == "function" ? n.toJSON() : n, a = t?.resultSize ?? (Array.isArray(e?.data) ? e.data.length : 0), { head: o, tail: s, cutCount: c } = Ut(e);
|
|
2325
|
-
if (c > 0) {
|
|
2326
|
-
let t = JSON.stringify({
|
|
2327
|
-
...e,
|
|
2328
|
-
data: o
|
|
2329
|
-
}, null, 2), n = JSON.stringify({
|
|
2330
|
-
headers: e.headers,
|
|
2331
|
-
data: s
|
|
2332
|
-
}, null, 2);
|
|
2333
|
-
i = `\n\nQuery results (${a} rows total — showing first ${o.length} and last ${s.length}, use get_artifact_rows to fetch any range):\n${t}\n...(${c} of ${a} rows cut off — use get_artifact_rows with artifact ID: ${r})...\n${n}`;
|
|
2334
|
-
} else i = `\n\nQuery results (${a} rows):\n${JSON.stringify(e, null, 2)}`;
|
|
2335
|
-
}
|
|
2336
|
-
let a = t && typeof t.executionTime == "number" ? ` in ${t.executionTime}ms` : "", o = t ? `Results: ${t.resultSize || 0} rows, ${t.columnCount || 0} columns${a}.` : "";
|
|
2337
|
-
return `Success. ${r ? `Artifact ID: ${r}. ` : ""}${e.message || o}${i}`;
|
|
2338
|
-
} else if (e.message) return e.message;
|
|
2339
|
-
else return "Success.";
|
|
2340
|
-
else return `Error: ${e.error}`;
|
|
2341
|
-
}
|
|
2342
|
-
function Gt(e) {
|
|
2343
|
-
if (e instanceof Error) return e.message;
|
|
2344
|
-
if (typeof e == "string") return e;
|
|
2345
|
-
try {
|
|
2346
|
-
return JSON.stringify(e);
|
|
2347
|
-
} catch {
|
|
2348
|
-
return String(e);
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
async function Kt(e, t, n, r, i, a, o) {
|
|
2352
|
-
let s = o.maxIterations ?? 20, c = r.getMessages().slice(0, -1).map((e) => e.role === "user" && !e.hidden && e.content ? {
|
|
2353
|
-
...e,
|
|
2354
|
-
content: `${Vt}${R(e.content)}${Ht}`
|
|
2355
|
-
} : e), l = `${Vt}${R(e)}${Ht}`, u = l, d = !1, f = 0;
|
|
2356
|
-
for (let e = 0; e < s; e++) {
|
|
2357
|
-
if (a.checkAborted()) return e === 0 && r.addMessage({
|
|
2358
|
-
role: "assistant",
|
|
2359
|
-
content: "(Response in progress when stopped)"
|
|
2360
|
-
}), r.addMessage({
|
|
2361
|
-
role: "user",
|
|
2362
|
-
content: `${I}[User requested pause - conversation can be continued]${L}`,
|
|
2363
|
-
hidden: !0
|
|
2364
|
-
}), {
|
|
2365
|
-
terminated: !1,
|
|
2366
|
-
stopped: !0,
|
|
2367
|
-
finalMessage: "Stopped by user"
|
|
2368
|
-
};
|
|
2369
|
-
for (; a.isPaused?.() && !a.checkAborted();) await new Promise((e) => setTimeout(e, 200));
|
|
2370
|
-
if (a.checkAborted()) return e === 0 && r.addMessage({
|
|
2371
|
-
role: "assistant",
|
|
2372
|
-
content: "(Response in progress when stopped)"
|
|
2373
|
-
}), r.addMessage({
|
|
2374
|
-
role: "user",
|
|
2375
|
-
content: `${I}[User requested pause - conversation can be continued]${L}`,
|
|
2376
|
-
hidden: !0
|
|
2377
|
-
}), {
|
|
2378
|
-
terminated: !1,
|
|
2379
|
-
stopped: !0,
|
|
2380
|
-
finalMessage: "Stopped by user"
|
|
2381
|
-
};
|
|
2382
|
-
let p = i.getToolExecutor(), m = {
|
|
2383
|
-
prompt: u,
|
|
2384
|
-
systemPrompt: o.buildSystemPrompt(),
|
|
2385
|
-
tools: o.tools
|
|
2386
|
-
}, h = await n.generateCompletion(t, m, c), g = h.text, _ = h.toolCalls ?? [];
|
|
2387
|
-
if (a.checkAborted()) return r.addMessage({
|
|
2388
|
-
role: "assistant",
|
|
2389
|
-
content: g
|
|
2390
|
-
}), r.addMessage({
|
|
2391
|
-
role: "user",
|
|
2392
|
-
content: `${I}[User requested pause - conversation can be continued]${L}`,
|
|
2393
|
-
hidden: !0
|
|
2394
|
-
}), {
|
|
2395
|
-
terminated: !1,
|
|
2396
|
-
stopped: !0,
|
|
2397
|
-
finalMessage: "Stopped by user"
|
|
2398
|
-
};
|
|
2399
|
-
if (_.length === 0) {
|
|
2400
|
-
if (r.addMessage({
|
|
2401
|
-
role: "assistant",
|
|
2402
|
-
content: g
|
|
2403
|
-
}), o.terminateOnNoToolCall) return {
|
|
2404
|
-
terminated: !0,
|
|
2405
|
-
finalMessage: g
|
|
2406
|
-
};
|
|
2407
|
-
if (f++, f >= 3) return console.log("[toolLoopCore] Model ignored repeated tool reminders — ending turn"), {
|
|
2408
|
-
terminated: !0,
|
|
2409
|
-
finalMessage: g
|
|
2410
|
-
};
|
|
2411
|
-
let e = o.noToolCallReminder ?? "You must call a tool to proceed. If you are finished, call the appropriate completion tool to return control to the user. Do not respond with text only.";
|
|
2412
|
-
console.log("[toolLoopCore] No tool call — re-prompting agent to use a tool");
|
|
2413
|
-
let t = `${I}${e}${L}`;
|
|
2414
|
-
r.addMessage({
|
|
2415
|
-
role: "user",
|
|
2416
|
-
content: t,
|
|
2417
|
-
hidden: !0
|
|
2418
|
-
}), c = [
|
|
2419
|
-
...c,
|
|
2420
|
-
...d ? [] : [{
|
|
2421
|
-
role: "user",
|
|
2422
|
-
content: l
|
|
2423
|
-
}],
|
|
2424
|
-
{
|
|
2425
|
-
role: "assistant",
|
|
2426
|
-
content: g
|
|
2427
|
-
},
|
|
2428
|
-
{
|
|
2429
|
-
role: "user",
|
|
2430
|
-
content: t,
|
|
2431
|
-
hidden: !0
|
|
2432
|
-
}
|
|
2433
|
-
], d = !0, u = "";
|
|
2434
|
-
continue;
|
|
2435
|
-
}
|
|
2436
|
-
f = 0;
|
|
2437
|
-
let v = [], y = [];
|
|
2438
|
-
for (let e of _) {
|
|
2439
|
-
if (a.checkAborted()) return r.addMessage({
|
|
2440
|
-
role: "assistant",
|
|
2441
|
-
content: g,
|
|
2442
|
-
toolCalls: _.slice(0, y.length),
|
|
2443
|
-
executedToolCalls: y.length > 0 ? y : void 0
|
|
2444
|
-
}), v.length > 0 && r.addMessage({
|
|
2445
|
-
role: "user",
|
|
2446
|
-
content: "",
|
|
2447
|
-
toolResults: v,
|
|
2448
|
-
hidden: !0
|
|
2449
|
-
}), r.addMessage({
|
|
2450
|
-
role: "user",
|
|
2451
|
-
content: `${I}[User requested pause - conversation can be continued]${L}`,
|
|
2452
|
-
hidden: !0
|
|
2453
|
-
}), {
|
|
2454
|
-
terminated: !1,
|
|
2455
|
-
stopped: !0,
|
|
2456
|
-
finalMessage: "Stopped by user"
|
|
2457
|
-
};
|
|
2458
|
-
a.setActiveToolName(e.name);
|
|
2459
|
-
let t;
|
|
2460
|
-
try {
|
|
2461
|
-
t = await p.executeToolCall(e.name, e.input);
|
|
2462
|
-
} catch (n) {
|
|
2463
|
-
t = {
|
|
2464
|
-
success: !1,
|
|
2465
|
-
error: `Tool "${e.name}" failed: ${Gt(n)}`
|
|
2466
|
-
};
|
|
2467
|
-
}
|
|
2468
|
-
let n = {
|
|
2469
|
-
id: e.id,
|
|
2470
|
-
name: e.name,
|
|
2471
|
-
input: e.input,
|
|
2472
|
-
result: {
|
|
2473
|
-
success: t.success,
|
|
2474
|
-
message: t.message,
|
|
2475
|
-
error: t.error,
|
|
2476
|
-
subchatId: t.subchatId
|
|
2477
|
-
}
|
|
2478
|
-
};
|
|
2479
|
-
if (y.push(n), o.onToolResult?.(e.name, t), t.artifact && r.addArtifact(t.artifact), t.terminatesLoop) {
|
|
2480
|
-
v.push({
|
|
2481
|
-
toolCallId: e.id,
|
|
2482
|
-
toolName: e.name,
|
|
2483
|
-
result: ""
|
|
2484
|
-
});
|
|
2485
|
-
let n = g?.trim() ? g : t.message ?? "";
|
|
2486
|
-
return r.addMessage({
|
|
2487
|
-
role: "assistant",
|
|
2488
|
-
content: n,
|
|
2489
|
-
toolCalls: _.slice(0, y.length),
|
|
2490
|
-
executedToolCalls: y
|
|
2491
|
-
}), r.addMessage({
|
|
2492
|
-
role: "user",
|
|
2493
|
-
content: "",
|
|
2494
|
-
toolResults: v,
|
|
2495
|
-
hidden: !0
|
|
2496
|
-
}), {
|
|
2497
|
-
terminated: !0,
|
|
2498
|
-
finalMessage: t.message
|
|
2499
|
-
};
|
|
2500
|
-
}
|
|
2501
|
-
if (t.awaitsUserInput) {
|
|
2502
|
-
let n = t.message || "Awaiting user input.";
|
|
2503
|
-
return v.push({
|
|
2504
|
-
toolCallId: e.id,
|
|
2505
|
-
toolName: e.name,
|
|
2506
|
-
result: n
|
|
2507
|
-
}), r.addMessage({
|
|
2508
|
-
role: "assistant",
|
|
2509
|
-
content: t.message || "",
|
|
2510
|
-
toolCalls: _.slice(0, y.length),
|
|
2511
|
-
executedToolCalls: y
|
|
2512
|
-
}), r.addMessage({
|
|
2513
|
-
role: "user",
|
|
2514
|
-
content: "",
|
|
2515
|
-
toolResults: v,
|
|
2516
|
-
hidden: !0
|
|
2517
|
-
}), o.onAwaitsUserInput?.(t, y), {
|
|
2518
|
-
terminated: !1,
|
|
2519
|
-
finalMessage: t.message
|
|
2520
|
-
};
|
|
2521
|
-
}
|
|
2522
|
-
let i = Wt(t);
|
|
2523
|
-
v.push({
|
|
2524
|
-
toolCallId: e.id,
|
|
2525
|
-
toolName: e.name,
|
|
2526
|
-
result: i,
|
|
2527
|
-
imageData: t.imageData
|
|
2528
|
-
});
|
|
2529
|
-
}
|
|
2530
|
-
if (a.setActiveToolName(""), r.addMessage({
|
|
2531
|
-
role: "assistant",
|
|
2532
|
-
content: g,
|
|
2533
|
-
toolCalls: _,
|
|
2534
|
-
executedToolCalls: y
|
|
2535
|
-
}), r.addMessage({
|
|
2536
|
-
role: "user",
|
|
2537
|
-
content: "",
|
|
2538
|
-
toolResults: v,
|
|
2539
|
-
hidden: !0
|
|
2540
|
-
}), c = [
|
|
2541
|
-
...c,
|
|
2542
|
-
...d ? [] : [{
|
|
2543
|
-
role: "user",
|
|
2544
|
-
content: l
|
|
2545
|
-
}],
|
|
2546
|
-
{
|
|
2547
|
-
role: "assistant",
|
|
2548
|
-
content: g,
|
|
2549
|
-
toolCalls: _
|
|
2550
|
-
},
|
|
2551
|
-
{
|
|
2552
|
-
role: "user",
|
|
2553
|
-
content: "",
|
|
2554
|
-
toolResults: v,
|
|
2555
|
-
hidden: !0
|
|
2556
|
-
}
|
|
2557
|
-
], d = !0, u = "", e === s - 1) return r.addMessage({
|
|
2558
|
-
role: "assistant",
|
|
2559
|
-
content: "(Max tool iterations reached)"
|
|
2560
|
-
}), {
|
|
2561
|
-
terminated: !1,
|
|
2562
|
-
finalMessage: g + "\n\n(Max tool iterations reached)"
|
|
2563
|
-
};
|
|
2564
|
-
}
|
|
2565
|
-
return { terminated: !1 };
|
|
2566
|
-
}
|
|
2567
|
-
//#endregion
|
|
2568
|
-
//#region llm/compaction.ts
|
|
2569
|
-
var qt = 2e4, Jt = 6, Yt = 20, Xt = 6, Zt = "You are a context summarization assistant. You are given the earlier portion of an assistant conversation that is about to fall out of the context window. Produce a structured summary that the assistant will rely on INSTEAD of those messages.\n\nUse exactly these sections:\n## Goal — what the user is ultimately trying to accomplish.\n## Progress — what was built, changed, or discovered, with exact names and ids (editors, dashboards, jobs, connections, queries, fields).\n## Key decisions — choices made and why, including approaches tried and rejected.\n## Current state — where the work stands right now.\n## Open items — unresolved questions, known failures, and obvious next steps.\n\nBe concrete: prefer exact identifiers, query text and error messages over paraphrase. Aim for 300-600 words. Omit nothing the assistant would need to continue seamlessly. Do not editorialize and do not add recommendations of your own.";
|
|
2570
|
-
function Qt(e) {
|
|
2571
|
-
return e.role === "user" && !(e.toolResults && e.toolResults.length > 0);
|
|
2572
|
-
}
|
|
2573
|
-
function $t(e, t) {
|
|
2574
|
-
let n = t.keepRecentTokens ?? 2e4, r = t.minKeepRecentCount ?? Jt, i = t.maxKeepRecentCount ?? Yt, a = t.minArchiveCount ?? Xt, o = 0, s = 0;
|
|
2575
|
-
for (let t = e.length - 1; t >= 0 && !(o >= i || o >= r && s >= n); t--) s += zt(e[t]), o++;
|
|
2576
|
-
let c = e.length - o;
|
|
2577
|
-
for (; c > 0 && !Qt(e[c]);) c--;
|
|
2578
|
-
return c < a ? -1 : c;
|
|
2579
|
-
}
|
|
2580
|
-
function en(e, t, n) {
|
|
2581
|
-
return !t || t <= 0 ? !1 : (n ?? Bt(e.getLLMMessages())) > t;
|
|
2582
|
-
}
|
|
2583
|
-
async function tn(e, t, n) {
|
|
2584
|
-
let r = Pt(t), i = e.getFastModel(), a = e.model, o = !!i && i !== a;
|
|
2585
|
-
try {
|
|
2586
|
-
return o && (e.model = i), (await e.generateCompletion({
|
|
2587
|
-
prompt: "",
|
|
2588
|
-
systemPrompt: n ? `${Zt}\n\nAdditional emphasis requested: ${n}` : Zt
|
|
2589
|
-
}, [{
|
|
2590
|
-
role: "user",
|
|
2591
|
-
content: `--- TRANSCRIPT ---\n${r}`
|
|
2592
|
-
}])).text.trim();
|
|
2593
|
-
} finally {
|
|
2594
|
-
o && (e.model = a);
|
|
2595
|
-
}
|
|
2596
|
-
}
|
|
2597
|
-
function nn(e) {
|
|
2598
|
-
return {
|
|
2599
|
-
role: "user",
|
|
2600
|
-
hidden: !0,
|
|
2601
|
-
content: e
|
|
2602
|
-
};
|
|
2603
|
-
}
|
|
2604
|
-
async function rn(e, t, n = {}) {
|
|
2605
|
-
let r = t.getLLMMessages(), i = $t(r, n);
|
|
2606
|
-
if (i < 0) return null;
|
|
2607
|
-
let a = r.slice(0, i), o = await tn(e, a, n.focus), s = t.messages.indexOf(r[i]);
|
|
2608
|
-
if (s < 0) return null;
|
|
2609
|
-
a.forEach((e) => {
|
|
2610
|
-
e.archived = !0;
|
|
2611
|
-
});
|
|
2612
|
-
let c = n.createSummaryMessage ?? nn, l = `${I}[Conversation compacted. Summary of the earlier conversation:]\n\n${o}${n.appendix ?? ""}${L}`;
|
|
2613
|
-
t.messages.splice(s, 0, c(l));
|
|
2614
|
-
let u = {
|
|
2615
|
-
archivedCount: a.length,
|
|
2616
|
-
summary: o
|
|
2617
|
-
};
|
|
2618
|
-
return n.onCompacted?.(u), u;
|
|
2619
|
-
}
|
|
2620
|
-
function an(e) {
|
|
2621
|
-
let t = e.artifacts.filter((e) => !e.hidden);
|
|
2622
|
-
return t.length === 0 ? "" : `\n\nArtifacts still available via get_artifact/get_artifact_rows:\n${t.map((e) => {
|
|
2623
|
-
let t = e.config?.title || e.config?.query?.slice(0, 60) || "", n = e.config?.resultSize == null ? "" : `, ${e.config.resultSize} rows`;
|
|
2624
|
-
return `- [${e.id}] ${e.type}${t ? ` "${t}"` : ""}${n}`;
|
|
2625
|
-
}).join("\n")}`;
|
|
2626
|
-
}
|
|
2627
|
-
async function on(e, t, n = {}) {
|
|
2628
|
-
return rn(e, t, {
|
|
2629
|
-
...n,
|
|
2630
|
-
appendix: n.appendix ?? an(t),
|
|
2631
|
-
createSummaryMessage: n.createSummaryMessage ?? ((e) => ({
|
|
2632
|
-
role: "user",
|
|
2633
|
-
hidden: !0,
|
|
2634
|
-
compaction: !0,
|
|
2635
|
-
content: e
|
|
2636
|
-
})),
|
|
2637
|
-
onCompacted: (e) => {
|
|
2638
|
-
t.updatedAt = /* @__PURE__ */ new Date(), t.changed = !0, n.onCompacted?.(e);
|
|
2639
|
-
}
|
|
2640
|
-
});
|
|
2641
|
-
}
|
|
2642
|
-
async function sn(e, t, n = {}) {
|
|
2643
|
-
if (!en(t, e.getCompactionThresholdTokens(), t.lastContextTokens)) return null;
|
|
2644
|
-
try {
|
|
2645
|
-
let r = await on(e, t, n);
|
|
2646
|
-
return r && (t.lastContextTokens = void 0), r;
|
|
2647
|
-
} catch (e) {
|
|
2648
|
-
return console.error("Automatic conversation compaction failed:", e), null;
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
//#endregion
|
|
2652
|
-
//#region llm/editorRefinementTools.ts
|
|
2653
|
-
function z(e) {
|
|
2654
|
-
return e.filter((e) => e.trilogyType === "concept").map((e) => ({
|
|
2655
|
-
name: e.label,
|
|
2656
|
-
type: e.datatype || e.type,
|
|
2657
|
-
description: e.description || void 0,
|
|
2658
|
-
calculation: e.calculation || void 0,
|
|
2659
|
-
keys: e.keys || void 0
|
|
2660
|
-
}));
|
|
2661
|
-
}
|
|
2662
|
-
function cn(e) {
|
|
2663
|
-
return A(z(e));
|
|
2664
|
-
}
|
|
2665
|
-
var ln = [
|
|
2666
|
-
{
|
|
2667
|
-
name: "validate_query",
|
|
2668
|
-
description: "Validate a Trilogy query without executing it. Returns validation errors or confirms the query is valid, along with the list of available symbols/fields that can be used in the query. Use this to check your work before or after writing to the editor. IMPORTANT: Always validate after changing import statements, as this will refresh the available symbols from the imported sources.",
|
|
2669
|
-
input_schema: {
|
|
2670
|
-
type: "object",
|
|
2671
|
-
properties: { query: {
|
|
2672
|
-
type: "string",
|
|
2673
|
-
description: "The Trilogy query to validate"
|
|
2674
|
-
} },
|
|
2675
|
-
required: ["query"]
|
|
2676
|
-
}
|
|
2677
|
-
},
|
|
2678
|
-
{
|
|
2679
|
-
name: "run_query",
|
|
2680
|
-
description: "Execute a Trilogy query and return results to you. Use this to test queries and see what data they return before writing to the editor.",
|
|
2681
|
-
input_schema: {
|
|
2682
|
-
type: "object",
|
|
2683
|
-
properties: { query: {
|
|
2684
|
-
type: "string",
|
|
2685
|
-
description: "The Trilogy query to execute"
|
|
2686
|
-
} },
|
|
2687
|
-
required: ["query"]
|
|
2688
|
-
}
|
|
2689
|
-
},
|
|
2690
|
-
{
|
|
2691
|
-
name: "format_query",
|
|
2692
|
-
description: "Format/prettify a Trilogy query. Returns the formatted query string. Use this to clean up query formatting.",
|
|
2693
|
-
input_schema: {
|
|
2694
|
-
type: "object",
|
|
2695
|
-
properties: { query: {
|
|
2696
|
-
type: "string",
|
|
2697
|
-
description: "The Trilogy query to format"
|
|
2698
|
-
} },
|
|
2699
|
-
required: ["query"]
|
|
2700
|
-
}
|
|
2701
|
-
},
|
|
2702
|
-
{
|
|
2703
|
-
name: "edit_chart_config",
|
|
2704
|
-
description: `Update the chart configuration for visualizing query results. Use this when the user wants to change how results are displayed.
|
|
2705
|
-
|
|
2706
|
-
${M}`,
|
|
2707
|
-
input_schema: {
|
|
2708
|
-
type: "object",
|
|
2709
|
-
properties: { chartConfig: j },
|
|
2710
|
-
required: ["chartConfig"]
|
|
2711
|
-
}
|
|
2712
|
-
},
|
|
2713
|
-
{
|
|
2714
|
-
name: "edit_editor",
|
|
2715
|
-
description: "Write content to the editor and automatically validate it. Returns validation results (errors or success with available fields). Use this to update the query - no need to call validate_query separately after editing.",
|
|
2716
|
-
input_schema: {
|
|
2717
|
-
type: "object",
|
|
2718
|
-
properties: {
|
|
2719
|
-
content: {
|
|
2720
|
-
type: "string",
|
|
2721
|
-
description: "The new content to write to the editor"
|
|
2722
|
-
},
|
|
2723
|
-
replaceSelection: {
|
|
2724
|
-
type: "boolean",
|
|
2725
|
-
description: "When true and the user has an active selection, replace only the selected text with the content instead of overwriting the whole document. Only use when the user's request targets their selection."
|
|
2726
|
-
}
|
|
2727
|
-
},
|
|
2728
|
-
required: ["content"]
|
|
2729
|
-
}
|
|
2730
|
-
},
|
|
2731
|
-
{
|
|
2732
|
-
name: "run_active_editor_query",
|
|
2733
|
-
description: "Run the current editor query and display results in the main results pane as well as return them to you. Use this when the user asks to \"see results\", \"run it\", \"show me\", or after making changes to the chart configuration. This runs the query that is currently in the editor (not a test query).",
|
|
2734
|
-
input_schema: {
|
|
2735
|
-
type: "object",
|
|
2736
|
-
properties: {},
|
|
2737
|
-
required: []
|
|
2738
|
-
}
|
|
2739
|
-
},
|
|
2740
|
-
{
|
|
2741
|
-
name: "get_artifact_rows",
|
|
2742
|
-
description: "Fetch a specific range of rows from a query result artifact created by run_query or run_active_editor_query in this session. Use this to inspect data in large result sets that were truncated in the initial response. Rows are 0-indexed.",
|
|
2743
|
-
input_schema: {
|
|
2744
|
-
type: "object",
|
|
2745
|
-
properties: {
|
|
2746
|
-
artifact_id: {
|
|
2747
|
-
type: "string",
|
|
2748
|
-
description: "The artifact ID to fetch rows from (shown in the truncation notice)"
|
|
2749
|
-
},
|
|
2750
|
-
start_row: {
|
|
2751
|
-
type: "number",
|
|
2752
|
-
description: "First row to return (0-indexed, inclusive)"
|
|
2753
|
-
},
|
|
2754
|
-
end_row: {
|
|
2755
|
-
type: "number",
|
|
2756
|
-
description: "Last row to return (0-indexed, inclusive)"
|
|
2757
|
-
}
|
|
2758
|
-
},
|
|
2759
|
-
required: [
|
|
2760
|
-
"artifact_id",
|
|
2761
|
-
"start_row",
|
|
2762
|
-
"end_row"
|
|
2763
|
-
]
|
|
2764
|
-
}
|
|
2765
|
-
},
|
|
2766
|
-
{
|
|
2767
|
-
name: "request_close",
|
|
2768
|
-
description: "Request to close the refinement session. Call this when you believe you are done making changes. The user will have a chance to reply with follow-up requests before confirming. Include a summary of what was done.",
|
|
2769
|
-
input_schema: {
|
|
2770
|
-
type: "object",
|
|
2771
|
-
properties: { message: {
|
|
2772
|
-
type: "string",
|
|
2773
|
-
description: "Summary message describing what changes were made"
|
|
2774
|
-
} },
|
|
2775
|
-
required: ["message"]
|
|
2776
|
-
}
|
|
2777
|
-
},
|
|
2778
|
-
{
|
|
2779
|
-
name: "close_session",
|
|
2780
|
-
description: "Immediately close the refinement session. Only call this after the user has confirmed they are satisfied with the changes, or if they explicitly ask to close/finish/done.",
|
|
2781
|
-
input_schema: {
|
|
2782
|
-
type: "object",
|
|
2783
|
-
properties: {},
|
|
2784
|
-
required: []
|
|
2785
|
-
}
|
|
2786
|
-
},
|
|
2787
|
-
N
|
|
2788
|
-
], un = [
|
|
2789
|
-
{
|
|
2790
|
-
name: "browse_database_tree",
|
|
2791
|
-
description: "Browse connection metadata using the same loading pattern as the sidebar tree. Use this to list databases, schemas, tables, and columns before writing SQL. You can optionally scope to a specific database/schema/table and refresh metadata from the connection.",
|
|
2792
|
-
input_schema: {
|
|
2793
|
-
type: "object",
|
|
2794
|
-
properties: {
|
|
2795
|
-
database: {
|
|
2796
|
-
type: "string",
|
|
2797
|
-
description: "Optional database/catalog name to inspect"
|
|
2798
|
-
},
|
|
2799
|
-
schema: {
|
|
2800
|
-
type: "string",
|
|
2801
|
-
description: "Optional schema name (requires database)"
|
|
2802
|
-
},
|
|
2803
|
-
table: {
|
|
2804
|
-
type: "string",
|
|
2805
|
-
description: "Optional table/view name (requires database and schema)"
|
|
2806
|
-
},
|
|
2807
|
-
refresh: {
|
|
2808
|
-
type: "boolean",
|
|
2809
|
-
description: "Whether to refresh metadata from the backend before returning results"
|
|
2810
|
-
}
|
|
2811
|
-
},
|
|
2812
|
-
required: []
|
|
2813
|
-
}
|
|
2814
|
-
},
|
|
2815
|
-
{
|
|
2816
|
-
name: "run_query",
|
|
2817
|
-
description: "Execute a SQL query and return results to you. Use this to test SQL before writing final editor content.",
|
|
2818
|
-
input_schema: {
|
|
2819
|
-
type: "object",
|
|
2820
|
-
properties: { query: {
|
|
2821
|
-
type: "string",
|
|
2822
|
-
description: "The SQL query to execute"
|
|
2823
|
-
} },
|
|
2824
|
-
required: ["query"]
|
|
2825
|
-
}
|
|
2826
|
-
},
|
|
2827
|
-
{
|
|
2828
|
-
name: "edit_editor",
|
|
2829
|
-
description: "Write content to the SQL editor. Use this to update the query in the editor when you are ready.",
|
|
2830
|
-
input_schema: {
|
|
2831
|
-
type: "object",
|
|
2832
|
-
properties: {
|
|
2833
|
-
content: {
|
|
2834
|
-
type: "string",
|
|
2835
|
-
description: "The new SQL content to write to the editor"
|
|
2836
|
-
},
|
|
2837
|
-
replaceSelection: {
|
|
2838
|
-
type: "boolean",
|
|
2839
|
-
description: "When true and the user has an active selection, replace only the selected text with the content instead of overwriting the whole document. Only use when the user's request targets their selection."
|
|
2840
|
-
}
|
|
2841
|
-
},
|
|
2842
|
-
required: ["content"]
|
|
2843
|
-
}
|
|
2844
|
-
},
|
|
2845
|
-
{
|
|
2846
|
-
name: "run_active_editor_query",
|
|
2847
|
-
description: "Run the current editor query and display results in the main results pane as well as return them to you. Use this when the user asks to run or show results from the current editor content.",
|
|
2848
|
-
input_schema: {
|
|
2849
|
-
type: "object",
|
|
2850
|
-
properties: {},
|
|
2851
|
-
required: []
|
|
2852
|
-
}
|
|
2853
|
-
},
|
|
2854
|
-
{
|
|
2855
|
-
name: "get_artifact_rows",
|
|
2856
|
-
description: "Fetch a specific range of rows from a query result artifact created by run_query or run_active_editor_query in this session. Use this when results were truncated.",
|
|
2857
|
-
input_schema: {
|
|
2858
|
-
type: "object",
|
|
2859
|
-
properties: {
|
|
2860
|
-
artifact_id: {
|
|
2861
|
-
type: "string",
|
|
2862
|
-
description: "The artifact ID to fetch rows from"
|
|
2863
|
-
},
|
|
2864
|
-
start_row: {
|
|
2865
|
-
type: "number",
|
|
2866
|
-
description: "First row to return (0-indexed, inclusive)"
|
|
2867
|
-
},
|
|
2868
|
-
end_row: {
|
|
2869
|
-
type: "number",
|
|
2870
|
-
description: "Last row to return (0-indexed, inclusive)"
|
|
2871
|
-
}
|
|
2872
|
-
},
|
|
2873
|
-
required: [
|
|
2874
|
-
"artifact_id",
|
|
2875
|
-
"start_row",
|
|
2876
|
-
"end_row"
|
|
2877
|
-
]
|
|
2878
|
-
}
|
|
2879
|
-
},
|
|
2880
|
-
{
|
|
2881
|
-
name: "request_close",
|
|
2882
|
-
description: "Request to close the refinement session. Call this when you believe you are done making changes. The user will have a chance to reply with follow-up requests before confirming.",
|
|
2883
|
-
input_schema: {
|
|
2884
|
-
type: "object",
|
|
2885
|
-
properties: { message: {
|
|
2886
|
-
type: "string",
|
|
2887
|
-
description: "Summary message describing what changes were made"
|
|
2888
|
-
} },
|
|
2889
|
-
required: ["message"]
|
|
2890
|
-
}
|
|
2891
|
-
},
|
|
2892
|
-
{
|
|
2893
|
-
name: "close_session",
|
|
2894
|
-
description: "Immediately close the refinement session. Only call this after the user has confirmed they are satisfied with the changes, or if they explicitly ask to close/finish/done.",
|
|
2895
|
-
input_schema: {
|
|
2896
|
-
type: "object",
|
|
2897
|
-
properties: {},
|
|
2898
|
-
required: []
|
|
2899
|
-
}
|
|
2900
|
-
},
|
|
2901
|
-
N
|
|
2902
|
-
], dn = ln;
|
|
2903
|
-
function fn(e) {
|
|
2904
|
-
return e === "sql" ? un : ln;
|
|
2905
|
-
}
|
|
2906
|
-
function pn(e) {
|
|
2907
|
-
let { editorType: t, connectionName: n, editorContents: r, selectedText: i, chartConfig: a, completionSymbols: o = [] } = e, s = i ? `
|
|
2908
|
-
SELECTED TEXT (user wants to modify this specifically):
|
|
2909
|
-
\`\`\`
|
|
2910
|
-
${i}
|
|
2911
|
-
\`\`\`
|
|
2912
|
-
` : "", c = a ? `
|
|
2913
|
-
CURRENT CHART CONFIG:
|
|
2914
|
-
${JSON.stringify(a, null, 2)}
|
|
2915
|
-
` : "", l = z(o), u = l.length > 0 ? `
|
|
2916
|
-
AVAILABLE FIELDS FOR QUERIES (${l.length} concepts):
|
|
2917
|
-
${cn(o)}
|
|
2918
|
-
` : "";
|
|
2919
|
-
return t === "sql" ? `You are a SQL refinement assistant helping the user edit and test SQL queries.
|
|
2920
|
-
|
|
2921
|
-
CURRENT EDITOR CONTENTS:
|
|
2922
|
-
\`\`\`sql
|
|
2923
|
-
${r}
|
|
2924
|
-
\`\`\`
|
|
2925
|
-
${s}
|
|
2926
|
-
DATA CONNECTION: ${n}
|
|
2927
|
-
|
|
2928
|
-
AVAILABLE TOOLS:
|
|
2929
|
-
- browse_database_tree: Explore databases/schemas/tables/columns using the same metadata loading methods as the sidebar
|
|
2930
|
-
- run_query: Execute SQL privately to test your changes
|
|
2931
|
-
- run_active_editor_query: Run the current editor query and show results in the main pane
|
|
2932
|
-
- get_artifact_rows: Fetch a row range from a truncated result artifact
|
|
2933
|
-
- edit_editor: Write changes to the editor
|
|
2934
|
-
- request_close: Request to close the session (user can reply with follow-ups)
|
|
2935
|
-
- close_session: Immediately close (only after user confirms or says "done")
|
|
2936
|
-
|
|
2937
|
-
WORKFLOW:
|
|
2938
|
-
1. Understand what the user wants to change
|
|
2939
|
-
2. Use browse_database_tree when you need metadata context (tables/columns)
|
|
2940
|
-
3. Use run_query to test candidate SQL
|
|
2941
|
-
4. Use edit_editor to apply final SQL changes
|
|
2942
|
-
5. Use run_active_editor_query when the user asks to run/show current editor results
|
|
2943
|
-
6. Always call request_close with a summary when done
|
|
2944
|
-
|
|
2945
|
-
IMPORTANT:
|
|
2946
|
-
- You MUST always call a tool; never respond with text only
|
|
2947
|
-
- Use browse_database_tree instead of guessing table/column names
|
|
2948
|
-
- Always use edit_editor for final query updates
|
|
2949
|
-
- request_close gives the user a chance to ask for more changes before closing
|
|
2950
|
-
- Only use close_session after the user explicitly confirms (e.g., says "done", "looks good", "close it")` : `You are a query refinement assistant helping the user edit their Trilogy query.
|
|
2951
|
-
|
|
2952
|
-
CURRENT EDITOR CONTENTS:
|
|
2953
|
-
\`\`\`trilogy
|
|
2954
|
-
${r}
|
|
2955
|
-
\`\`\`
|
|
2956
|
-
${s}${c}
|
|
2957
|
-
DATA CONNECTION: ${n}
|
|
2958
|
-
|
|
2959
|
-
AVAILABLE TOOLS:
|
|
2960
|
-
- validate_query: Check if a query is valid without running it (also returns available fields)
|
|
2961
|
-
- run_query: Execute a query to see results (returns results privately to you)
|
|
2962
|
-
- run_active_editor_query: Run the current editor query and show results in the main results pane
|
|
2963
|
-
- get_artifact_rows: Fetch a row range from a truncated result artifact (use when results were cut off)
|
|
2964
|
-
- format_query: Format/prettify a query
|
|
2965
|
-
- edit_chart_config: Update chart visualization settings
|
|
2966
|
-
- edit_editor: Write changes to the editor
|
|
2967
|
-
- request_close: Request to close the session (user can reply with follow-ups)
|
|
2968
|
-
- close_session: Immediately close (only after user confirms or says "done")
|
|
2969
|
-
${u}
|
|
2970
|
-
TRILOGY LANGUAGE REFERENCE:
|
|
2971
|
-
${k}
|
|
2972
|
-
|
|
2973
|
-
WORKFLOW:
|
|
2974
|
-
1. Understand what the user wants to change
|
|
2975
|
-
2. Use edit_editor to write your changes (this automatically validates and returns errors/available fields)
|
|
2976
|
-
3. Optionally use run_query to test and see results privately
|
|
2977
|
-
4. Use format_query to clean up formatting if needed
|
|
2978
|
-
5. Always call request_close with a summary when done — you MUST call a tool, never end with text only
|
|
2979
|
-
|
|
2980
|
-
IMPORTANT:
|
|
2981
|
-
- Always use edit_editor to write your final answer - don't just show the query in text
|
|
2982
|
-
- edit_editor automatically validates, so you don't need to call validate_query separately after editing
|
|
2983
|
-
- You can iterate: write → fix based on validation errors → write again
|
|
2984
|
-
- You MUST always call a tool — never respond with text only. When done, call request_close.
|
|
2985
|
-
- request_close gives the user a chance to ask for more changes before closing
|
|
2986
|
-
- Only use close_session after the user explicitly confirms (e.g., says "done", "looks good", "close it")
|
|
2987
|
-
- If the user selected specific text, use replaceSelection: true to only modify that part
|
|
2988
|
-
- After updating chart configuration with edit_chart_config, use run_active_editor_query to show the user the updated visualization
|
|
2989
|
-
- When the user asks to "run it", "see the results", "show me", or similar, use run_active_editor_query to execute and display in the main results pane`;
|
|
2990
|
-
}
|
|
2991
|
-
//#endregion
|
|
2992
|
-
//#region chats/chat.ts
|
|
2993
|
-
function B() {
|
|
2994
|
-
return `art-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 6)}`;
|
|
2995
|
-
}
|
|
2996
|
-
function V() {
|
|
2997
|
-
return `Chat ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`;
|
|
2998
|
-
}
|
|
2999
|
-
var mn = class e {
|
|
3000
|
-
id;
|
|
3001
|
-
name;
|
|
3002
|
-
dataConnectionName;
|
|
3003
|
-
dataConnectionId;
|
|
3004
|
-
llmConnectionName;
|
|
3005
|
-
messages;
|
|
3006
|
-
artifacts;
|
|
3007
|
-
activeArtifactIndex;
|
|
3008
|
-
imports;
|
|
3009
|
-
createdAt;
|
|
3010
|
-
updatedAt;
|
|
3011
|
-
storage;
|
|
3012
|
-
source;
|
|
3013
|
-
sourceRefId;
|
|
3014
|
-
kind;
|
|
3015
|
-
parentChatId;
|
|
3016
|
-
parentProjectId;
|
|
3017
|
-
pendingInjections;
|
|
3018
|
-
pendingContextNote;
|
|
3019
|
-
lastContextTokens;
|
|
3020
|
-
changed;
|
|
3021
|
-
deleted;
|
|
3022
|
-
constructor(e = {}) {
|
|
3023
|
-
this.id = e.id || `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, this.name = e.name || V(), this.dataConnectionName = e.dataConnectionName || "", this.dataConnectionId = e.dataConnectionId || "", this.llmConnectionName = e.llmConnectionName || "", this.messages = e.messages || [], this.artifacts = e.artifacts || [], this.activeArtifactIndex = e.activeArtifactIndex ?? -1, this.imports = e.imports || [], this.createdAt = e.createdAt || /* @__PURE__ */ new Date(), this.updatedAt = e.updatedAt || /* @__PURE__ */ new Date(), this.storage = e.storage || "local", this.source = e.source || "user", this.sourceRefId = e.sourceRefId ?? null, this.kind = e.kind || "user", this.parentChatId = e.parentChatId ?? null, this.parentProjectId = e.parentProjectId ?? null, this.pendingInjections = e.pendingInjections || [], this.pendingContextNote = e.pendingContextNote ?? null, this.lastContextTokens = e.lastContextTokens ?? void 0, this.changed = e.changed ?? !0, this.deleted = e.deleted ?? !1;
|
|
3024
|
-
}
|
|
3025
|
-
setName(e) {
|
|
3026
|
-
this.name !== e && (this.name = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
3027
|
-
}
|
|
3028
|
-
setLLMConnection(e) {
|
|
3029
|
-
this.llmConnectionName !== e && (this.llmConnectionName = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
3030
|
-
}
|
|
3031
|
-
setDataConnection(e, t = "") {
|
|
3032
|
-
(this.dataConnectionName !== e || t && this.dataConnectionId !== t) && (this.dataConnectionName = e, this.dataConnectionId = t, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0);
|
|
3033
|
-
}
|
|
3034
|
-
addMessage(e) {
|
|
3035
|
-
this.messages.push(e), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
3036
|
-
}
|
|
3037
|
-
addArtifact(e) {
|
|
3038
|
-
return e.id ||= B(), this.artifacts.push(e), this.activeArtifactIndex = this.artifacts.length - 1, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, this.activeArtifactIndex;
|
|
3039
|
-
}
|
|
3040
|
-
getArtifactById(e) {
|
|
3041
|
-
return this.artifacts.find((t) => t.id === e) || null;
|
|
3042
|
-
}
|
|
3043
|
-
updateArtifact(e, t) {
|
|
3044
|
-
let n = this.artifacts.find((t) => t.id === e);
|
|
3045
|
-
return n ? (t.data !== void 0 && (n.data = t.data), t.config !== void 0 && (n.config = {
|
|
3046
|
-
...n.config,
|
|
3047
|
-
...t.config
|
|
3048
|
-
}), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0) : !1;
|
|
3049
|
-
}
|
|
3050
|
-
removeArtifact(e) {
|
|
3051
|
-
let t = this.artifacts.findIndex((t) => t.id === e);
|
|
3052
|
-
return t === -1 ? !1 : (this.artifacts.splice(t, 1), this.activeArtifactIndex >= this.artifacts.length && (this.activeArtifactIndex = this.artifacts.length - 1), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0);
|
|
3053
|
-
}
|
|
3054
|
-
hideArtifact(e) {
|
|
3055
|
-
let t = this.artifacts.find((t) => t.id === e);
|
|
3056
|
-
if (!t) return !1;
|
|
3057
|
-
t.hidden = !0;
|
|
3058
|
-
let n = this.artifacts.indexOf(t);
|
|
3059
|
-
return this.activeArtifactIndex === n && (this.activeArtifactIndex = -1), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0;
|
|
3060
|
-
}
|
|
3061
|
-
unhideArtifact(e) {
|
|
3062
|
-
let t = this.artifacts.find((t) => t.id === e);
|
|
3063
|
-
return t ? (t.hidden = !1, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0) : !1;
|
|
3064
|
-
}
|
|
3065
|
-
setActiveArtifact(e) {
|
|
3066
|
-
e >= -1 && e < this.artifacts.length && (this.activeArtifactIndex = e);
|
|
3067
|
-
}
|
|
3068
|
-
getActiveArtifact() {
|
|
3069
|
-
return this.activeArtifactIndex >= 0 && this.activeArtifactIndex < this.artifacts.length ? this.artifacts[this.activeArtifactIndex] : null;
|
|
3070
|
-
}
|
|
3071
|
-
clearMessages() {
|
|
3072
|
-
this.messages = [], this.artifacts = [], this.activeArtifactIndex = -1, this.lastContextTokens = void 0, this.name = V(), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
3073
|
-
}
|
|
3074
|
-
addImport(e) {
|
|
3075
|
-
return this.imports.some((t) => t.id === e.id) ? !1 : (this.imports.push(e), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0);
|
|
3076
|
-
}
|
|
3077
|
-
removeImport(e) {
|
|
3078
|
-
let t = this.imports.findIndex((t) => t.id === e);
|
|
3079
|
-
return t === -1 ? !1 : (this.imports.splice(t, 1), this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0, !0);
|
|
3080
|
-
}
|
|
3081
|
-
setImports(e) {
|
|
3082
|
-
this.imports = e, this.updatedAt = /* @__PURE__ */ new Date(), this.changed = !0;
|
|
3083
|
-
}
|
|
3084
|
-
getLastMessage() {
|
|
3085
|
-
return this.messages.length > 0 ? this.messages[this.messages.length - 1] : null;
|
|
3086
|
-
}
|
|
3087
|
-
getVisibleMessages() {
|
|
3088
|
-
return this.messages.filter((e) => !e.hidden);
|
|
3089
|
-
}
|
|
3090
|
-
getLLMMessages() {
|
|
3091
|
-
return this.messages.filter((e) => !e.archived && !(e.artifact && !e.content && !e.toolCalls?.length));
|
|
3092
|
-
}
|
|
3093
|
-
serialize() {
|
|
3094
|
-
return {
|
|
3095
|
-
id: this.id,
|
|
3096
|
-
name: this.name,
|
|
3097
|
-
dataConnectionName: this.dataConnectionName,
|
|
3098
|
-
dataConnectionId: this.dataConnectionId,
|
|
3099
|
-
llmConnectionName: this.llmConnectionName,
|
|
3100
|
-
messages: this.messages,
|
|
3101
|
-
artifacts: this.artifacts,
|
|
3102
|
-
activeArtifactIndex: this.activeArtifactIndex,
|
|
3103
|
-
imports: this.imports,
|
|
3104
|
-
createdAt: this.createdAt.toISOString(),
|
|
3105
|
-
updatedAt: this.updatedAt.toISOString(),
|
|
3106
|
-
storage: this.storage,
|
|
3107
|
-
source: this.source,
|
|
3108
|
-
sourceRefId: this.sourceRefId ?? null,
|
|
3109
|
-
kind: this.kind,
|
|
3110
|
-
parentChatId: this.parentChatId ?? null,
|
|
3111
|
-
parentProjectId: this.parentProjectId ?? null,
|
|
3112
|
-
pendingInjections: this.pendingInjections,
|
|
3113
|
-
pendingContextNote: this.pendingContextNote ?? null,
|
|
3114
|
-
lastContextTokens: this.lastContextTokens
|
|
3115
|
-
};
|
|
3116
|
-
}
|
|
3117
|
-
static fromSerialized(t) {
|
|
3118
|
-
return new e({
|
|
3119
|
-
...t,
|
|
3120
|
-
createdAt: new Date(t.createdAt),
|
|
3121
|
-
updatedAt: new Date(t.updatedAt),
|
|
3122
|
-
changed: !1
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3125
|
-
}, hn = [
|
|
3126
|
-
"line",
|
|
3127
|
-
"area",
|
|
3128
|
-
"bar",
|
|
3129
|
-
"barh",
|
|
3130
|
-
"point",
|
|
3131
|
-
"heatmap"
|
|
3132
|
-
], gn = [
|
|
3133
|
-
"geo-map",
|
|
3134
|
-
"tree",
|
|
3135
|
-
"donut",
|
|
3136
|
-
"headline"
|
|
3137
|
-
], _n = [
|
|
3138
|
-
"bar",
|
|
3139
|
-
"barh",
|
|
3140
|
-
"line",
|
|
3141
|
-
"area",
|
|
3142
|
-
"point",
|
|
3143
|
-
"boxplot",
|
|
3144
|
-
"donut",
|
|
3145
|
-
"heatmap"
|
|
3146
|
-
], vn = [
|
|
3147
|
-
{
|
|
3148
|
-
id: "group-by",
|
|
3149
|
-
label: "Group By",
|
|
3150
|
-
field: "groupField",
|
|
3151
|
-
columnFilter: "categorical",
|
|
3152
|
-
allowEmpty: !1,
|
|
3153
|
-
visibleFor: ["boxplot"],
|
|
3154
|
-
filterGroup: "axes"
|
|
3155
|
-
},
|
|
3156
|
-
{
|
|
3157
|
-
id: "category-axis",
|
|
3158
|
-
label: "Category Axis",
|
|
3159
|
-
field: "yField",
|
|
3160
|
-
columnFilter: "categorical",
|
|
3161
|
-
allowEmpty: !1,
|
|
3162
|
-
visibleFor: ["barh", "donut"],
|
|
3163
|
-
filterGroup: "axes"
|
|
3164
|
-
},
|
|
3165
|
-
{
|
|
3166
|
-
id: "value-axis",
|
|
3167
|
-
label: "Value Axis",
|
|
3168
|
-
field: "xField",
|
|
3169
|
-
columnFilter: "numeric",
|
|
3170
|
-
allowEmpty: !1,
|
|
3171
|
-
visibleFor: ["barh", "donut"],
|
|
3172
|
-
filterGroup: "axes"
|
|
3173
|
-
},
|
|
3174
|
-
{
|
|
3175
|
-
id: "x-axis",
|
|
3176
|
-
label: "X Axis",
|
|
3177
|
-
field: "xField",
|
|
3178
|
-
columnFilter: "all",
|
|
3179
|
-
allowEmpty: !1,
|
|
3180
|
-
visibleFor: [
|
|
3181
|
-
"bar",
|
|
3182
|
-
"line",
|
|
3183
|
-
"point",
|
|
3184
|
-
"area",
|
|
3185
|
-
"heatmap",
|
|
3186
|
-
"beeswarm"
|
|
3187
|
-
],
|
|
3188
|
-
filterGroup: "axes"
|
|
3189
|
-
},
|
|
3190
|
-
{
|
|
3191
|
-
id: "y-axis-numeric",
|
|
3192
|
-
label: "Y Axis",
|
|
3193
|
-
field: "yField",
|
|
3194
|
-
columnFilter: "numeric",
|
|
3195
|
-
allowEmpty: !1,
|
|
3196
|
-
visibleFor: [
|
|
3197
|
-
"bar",
|
|
3198
|
-
"line",
|
|
3199
|
-
"area"
|
|
3200
|
-
],
|
|
3201
|
-
filterGroup: "axes"
|
|
3202
|
-
},
|
|
3203
|
-
{
|
|
3204
|
-
id: "y-axis-numeric-two",
|
|
3205
|
-
label: "Secondary Y Axis",
|
|
3206
|
-
field: "yField2",
|
|
3207
|
-
columnFilter: "numeric",
|
|
3208
|
-
allowEmpty: !0,
|
|
3209
|
-
visibleFor: [
|
|
3210
|
-
"bar",
|
|
3211
|
-
"line",
|
|
3212
|
-
"area"
|
|
3213
|
-
],
|
|
3214
|
-
filterGroup: "axes"
|
|
3215
|
-
},
|
|
3216
|
-
{
|
|
3217
|
-
id: "y-axis-all",
|
|
3218
|
-
label: "Y Axis",
|
|
3219
|
-
field: "yField",
|
|
3220
|
-
columnFilter: "all",
|
|
3221
|
-
allowEmpty: !1,
|
|
3222
|
-
visibleFor: ["heatmap", "point"],
|
|
3223
|
-
filterGroup: "axes"
|
|
3224
|
-
},
|
|
3225
|
-
{
|
|
3226
|
-
id: "color-field",
|
|
3227
|
-
label: "Color Scale",
|
|
3228
|
-
field: "colorField",
|
|
3229
|
-
columnFilter: "all",
|
|
3230
|
-
allowEmpty: !0,
|
|
3231
|
-
visibleFor: ["heatmap", "geo-map"],
|
|
3232
|
-
filterGroup: "appearance"
|
|
3233
|
-
},
|
|
3234
|
-
{
|
|
3235
|
-
id: "color-by",
|
|
3236
|
-
label: "Color By",
|
|
3237
|
-
field: "colorField",
|
|
3238
|
-
columnFilter: "all",
|
|
3239
|
-
allowEmpty: !0,
|
|
3240
|
-
visibleFor: [
|
|
3241
|
-
"bar",
|
|
3242
|
-
"barh",
|
|
3243
|
-
"point",
|
|
3244
|
-
"donut"
|
|
3245
|
-
],
|
|
3246
|
-
filterGroup: "appearance"
|
|
3247
|
-
},
|
|
3248
|
-
{
|
|
3249
|
-
id: "color-by",
|
|
3250
|
-
label: "Color By",
|
|
3251
|
-
field: "colorField",
|
|
3252
|
-
columnFilter: "categorical",
|
|
3253
|
-
allowEmpty: !0,
|
|
3254
|
-
visibleFor: [
|
|
3255
|
-
"line",
|
|
3256
|
-
"area",
|
|
3257
|
-
"beeswarm"
|
|
3258
|
-
],
|
|
3259
|
-
filterGroup: "appearance"
|
|
3260
|
-
},
|
|
3261
|
-
{
|
|
3262
|
-
id: "size",
|
|
3263
|
-
label: "Size",
|
|
3264
|
-
field: "sizeField",
|
|
3265
|
-
columnFilter: "numeric",
|
|
3266
|
-
allowEmpty: !0,
|
|
3267
|
-
visibleFor: [
|
|
3268
|
-
"point",
|
|
3269
|
-
"geo-map",
|
|
3270
|
-
"tree",
|
|
3271
|
-
"beeswarm"
|
|
3272
|
-
],
|
|
3273
|
-
filterGroup: "appearance"
|
|
3274
|
-
},
|
|
3275
|
-
{
|
|
3276
|
-
id: "trellis-field",
|
|
3277
|
-
label: "Split Columns By",
|
|
3278
|
-
field: "trellisField",
|
|
3279
|
-
columnFilter: "categorical",
|
|
3280
|
-
allowEmpty: !0,
|
|
3281
|
-
visibleFor: hn,
|
|
3282
|
-
filterGroup: "appearance"
|
|
3283
|
-
},
|
|
3284
|
-
{
|
|
3285
|
-
id: "trellis-row-field",
|
|
3286
|
-
label: "Split Rows By",
|
|
3287
|
-
field: "trellisRowField",
|
|
3288
|
-
columnFilter: "categorical",
|
|
3289
|
-
allowEmpty: !0,
|
|
3290
|
-
visibleFor: hn,
|
|
3291
|
-
filterGroup: "appearance"
|
|
3292
|
-
},
|
|
3293
|
-
{
|
|
3294
|
-
id: "geo-field",
|
|
3295
|
-
label: "Geo Field",
|
|
3296
|
-
field: "geoField",
|
|
3297
|
-
visibleFor: ["geo-map"],
|
|
3298
|
-
allowEmpty: !0,
|
|
3299
|
-
columnFilter: "categorical",
|
|
3300
|
-
filterGroup: "axes"
|
|
3301
|
-
},
|
|
3302
|
-
{
|
|
3303
|
-
id: "latitude",
|
|
3304
|
-
label: "Latitude",
|
|
3305
|
-
field: "yField",
|
|
3306
|
-
visibleFor: ["geo-map"],
|
|
3307
|
-
allowEmpty: !0,
|
|
3308
|
-
columnFilter: "latitude",
|
|
3309
|
-
filterGroup: "axes"
|
|
3310
|
-
},
|
|
3311
|
-
{
|
|
3312
|
-
id: "longitude",
|
|
3313
|
-
label: "Longtitude",
|
|
3314
|
-
field: "xField",
|
|
3315
|
-
visibleFor: ["geo-map"],
|
|
3316
|
-
allowEmpty: !0,
|
|
3317
|
-
columnFilter: "longitude",
|
|
3318
|
-
filterGroup: "axes"
|
|
3319
|
-
},
|
|
3320
|
-
{
|
|
3321
|
-
id: "tree",
|
|
3322
|
-
label: "Split Field",
|
|
3323
|
-
field: "xField",
|
|
3324
|
-
visibleFor: ["tree"],
|
|
3325
|
-
allowEmpty: !1,
|
|
3326
|
-
columnFilter: "categorical",
|
|
3327
|
-
filterGroup: "axes"
|
|
3328
|
-
},
|
|
3329
|
-
{
|
|
3330
|
-
id: "annotation",
|
|
3331
|
-
label: "Annotation",
|
|
3332
|
-
field: "annotationField",
|
|
3333
|
-
columnFilter: "all",
|
|
3334
|
-
allowEmpty: !0,
|
|
3335
|
-
visibleFor: [
|
|
3336
|
-
"geo-map",
|
|
3337
|
-
"point",
|
|
3338
|
-
"heatmap",
|
|
3339
|
-
"beeswarm",
|
|
3340
|
-
"line"
|
|
3341
|
-
],
|
|
3342
|
-
filterGroup: "appearance"
|
|
3343
|
-
},
|
|
3344
|
-
{
|
|
3345
|
-
id: "scale-x",
|
|
3346
|
-
label: "X Axis Scale",
|
|
3347
|
-
field: "scaleX",
|
|
3348
|
-
columnFilter: "numeric",
|
|
3349
|
-
allowEmpty: !0,
|
|
3350
|
-
visibleFor: ["point", "barh"],
|
|
3351
|
-
options: ["linear", "log"],
|
|
3352
|
-
filterGroup: "appearance"
|
|
3353
|
-
},
|
|
3354
|
-
{
|
|
3355
|
-
id: "scale-y",
|
|
3356
|
-
label: "Y Axis Scale",
|
|
3357
|
-
field: "scaleY",
|
|
3358
|
-
columnFilter: "numeric",
|
|
3359
|
-
allowEmpty: !0,
|
|
3360
|
-
visibleFor: [
|
|
3361
|
-
"point",
|
|
3362
|
-
"area",
|
|
3363
|
-
"line"
|
|
3364
|
-
],
|
|
3365
|
-
options: ["linear", "log"],
|
|
3366
|
-
filterGroup: "appearance"
|
|
3367
|
-
},
|
|
3368
|
-
{
|
|
3369
|
-
id: "hide-legend",
|
|
3370
|
-
label: "Hide Legend",
|
|
3371
|
-
field: "hideLegend",
|
|
3372
|
-
columnFilter: "all",
|
|
3373
|
-
allowEmpty: !0,
|
|
3374
|
-
visibleFor: [
|
|
3375
|
-
"geo-map",
|
|
3376
|
-
"bar",
|
|
3377
|
-
"barh",
|
|
3378
|
-
"line",
|
|
3379
|
-
"point",
|
|
3380
|
-
"area",
|
|
3381
|
-
"heatmap"
|
|
3382
|
-
],
|
|
3383
|
-
filterGroup: "appearance"
|
|
3384
|
-
},
|
|
3385
|
-
{
|
|
3386
|
-
id: "hide-label",
|
|
3387
|
-
label: "Hide Label",
|
|
3388
|
-
field: "hideLegend",
|
|
3389
|
-
columnFilter: "all",
|
|
3390
|
-
allowEmpty: !0,
|
|
3391
|
-
visibleFor: ["headline"],
|
|
3392
|
-
filterGroup: "appearance"
|
|
3393
|
-
},
|
|
3394
|
-
{
|
|
3395
|
-
id: "linky2",
|
|
3396
|
-
label: "Link Secondary Y Axis",
|
|
3397
|
-
field: "linkY2",
|
|
3398
|
-
columnFilter: "all",
|
|
3399
|
-
allowEmpty: !0,
|
|
3400
|
-
visibleFor: ["bar", "line"],
|
|
3401
|
-
filterGroup: "appearance"
|
|
3402
|
-
},
|
|
3403
|
-
{
|
|
3404
|
-
id: "show-title",
|
|
3405
|
-
label: "Show Title",
|
|
3406
|
-
field: "showTitle",
|
|
3407
|
-
columnFilter: "all",
|
|
3408
|
-
allowEmpty: !0,
|
|
3409
|
-
visibleFor: [
|
|
3410
|
-
"geo-map",
|
|
3411
|
-
"bar",
|
|
3412
|
-
"barh",
|
|
3413
|
-
"line",
|
|
3414
|
-
"point",
|
|
3415
|
-
"area",
|
|
3416
|
-
"headline",
|
|
3417
|
-
"beeswarm"
|
|
3418
|
-
],
|
|
3419
|
-
filterGroup: "appearance"
|
|
3420
|
-
}
|
|
3421
|
-
], yn = [
|
|
3422
|
-
{
|
|
3423
|
-
value: "bar",
|
|
3424
|
-
label: "Bar Chart",
|
|
3425
|
-
icon: "mdi mdi-chart-bar"
|
|
3426
|
-
},
|
|
3427
|
-
{
|
|
3428
|
-
value: "barh",
|
|
3429
|
-
label: "Horizontal Bar",
|
|
3430
|
-
icon: "mdi mdi-chart-timeline"
|
|
3431
|
-
},
|
|
3432
|
-
{
|
|
3433
|
-
value: "line",
|
|
3434
|
-
label: "Line Chart",
|
|
3435
|
-
icon: "mdi mdi-chart-line"
|
|
3436
|
-
},
|
|
3437
|
-
{
|
|
3438
|
-
value: "point",
|
|
3439
|
-
label: "Scatter Plot",
|
|
3440
|
-
icon: "mdi mdi-chart-scatter-plot"
|
|
3441
|
-
},
|
|
3442
|
-
{
|
|
3443
|
-
value: "area",
|
|
3444
|
-
label: "Area Chart",
|
|
3445
|
-
icon: "mdi mdi-chart-areaspline"
|
|
3446
|
-
},
|
|
3447
|
-
{
|
|
3448
|
-
value: "heatmap",
|
|
3449
|
-
label: "Heatmap",
|
|
3450
|
-
icon: "mdi mdi-sun-thermometer-outline"
|
|
3451
|
-
},
|
|
3452
|
-
{
|
|
3453
|
-
value: "boxplot",
|
|
3454
|
-
label: "Box Plot",
|
|
3455
|
-
icon: "mdi mdi-chart-box"
|
|
3456
|
-
},
|
|
3457
|
-
{
|
|
3458
|
-
value: "geo-map",
|
|
3459
|
-
label: "Map",
|
|
3460
|
-
icon: "mdi mdi-map"
|
|
3461
|
-
},
|
|
3462
|
-
{
|
|
3463
|
-
value: "headline",
|
|
3464
|
-
label: "Headline",
|
|
3465
|
-
icon: "mdi mdi-numeric-1-box-outline"
|
|
3466
|
-
},
|
|
3467
|
-
{
|
|
3468
|
-
value: "tree",
|
|
3469
|
-
label: "Tree",
|
|
3470
|
-
icon: "mdi mdi-tree"
|
|
3471
|
-
},
|
|
3472
|
-
{
|
|
3473
|
-
value: "donut",
|
|
3474
|
-
label: "Donut",
|
|
3475
|
-
icon: "mdi mdi-chart-donut"
|
|
3476
|
-
},
|
|
3477
|
-
{
|
|
3478
|
-
value: "beeswarm",
|
|
3479
|
-
label: "Beeswarm",
|
|
3480
|
-
icon: "mdi mdi-chart-bubble"
|
|
3481
|
-
}
|
|
3482
|
-
], bn = "#1f77b4", xn = "#9467bd", Sn = "#FF7F7F", H = (e, t) => e[t], Cn = [
|
|
3483
|
-
"year",
|
|
3484
|
-
"week",
|
|
3485
|
-
"day",
|
|
3486
|
-
"hour",
|
|
3487
|
-
"minute",
|
|
3488
|
-
"second",
|
|
3489
|
-
"quarter"
|
|
3490
|
-
], wn = [
|
|
3491
|
-
"decade",
|
|
3492
|
-
"year",
|
|
3493
|
-
"month",
|
|
3494
|
-
"week",
|
|
3495
|
-
"day",
|
|
3496
|
-
"hour",
|
|
3497
|
-
"minute",
|
|
3498
|
-
"second",
|
|
3499
|
-
"day_of_week"
|
|
3500
|
-
], U = (e) => e.traits ? e.traits.some((e) => wn.some((t) => e === t || e.endsWith("_" + t))) : !1, Tn = (e, t) => {
|
|
3501
|
-
let n = t.get(e);
|
|
3502
|
-
return n ? U(n) : !1;
|
|
3503
|
-
}, En = [
|
|
3504
|
-
"rank",
|
|
3505
|
-
"index",
|
|
3506
|
-
"grade",
|
|
3507
|
-
"flag",
|
|
3508
|
-
"letter_grade"
|
|
3509
|
-
], Dn = [
|
|
3510
|
-
...Cn,
|
|
3511
|
-
...En,
|
|
3512
|
-
"identifier",
|
|
3513
|
-
"decade"
|
|
3514
|
-
];
|
|
3515
|
-
function On(e) {
|
|
3516
|
-
return new Date(e);
|
|
3517
|
-
}
|
|
3518
|
-
var W = (e, t, n) => {
|
|
3519
|
-
if (!e || !t.get(e)) return !1;
|
|
3520
|
-
let r = t.get(e);
|
|
3521
|
-
return r ? kn(r, n) : !1;
|
|
3522
|
-
}, kn = (e, t) => !!(e.traits && e.traits.some((e) => e.endsWith(t))), G = (e) => e.purpose === "key" || U(e) ? !1 : [
|
|
3523
|
-
n.NUMBER,
|
|
3524
|
-
n.INTEGER,
|
|
3525
|
-
n.FLOAT
|
|
3526
|
-
].includes(e.type) && !e.traits?.some((e) => e.endsWith("latitude") || e.endsWith("longitude")), An = (e) => !!(e.traits && En.some((t) => e.traits?.includes(t))), jn = (e) => !!([n.STRING].includes(e.type) && e.traits?.some((e) => e.endsWith("url_image"))), K = (e) => !!([
|
|
3527
|
-
n.DATE,
|
|
3528
|
-
n.DATETIME,
|
|
3529
|
-
n.TIME,
|
|
3530
|
-
n.TIMESTAMP
|
|
3531
|
-
].includes(e.type) || e.traits && Cn.some((t) => e.traits?.includes(t))), Mn = (e) => !!([n.STRING, n.BOOLEAN].includes(e.type) || e.purpose === "key" || e.traits && Dn.some((t) => e.traits?.includes(t))), Nn = (e) => e.traits?.includes("hex") ?? !1, q = (e, t) => e.traits ? e.traits.some((e) => e.endsWith(t)) : !1, J = (e, t) => {
|
|
3532
|
-
let n = [];
|
|
3533
|
-
return t.forEach((t, r) => {
|
|
3534
|
-
(e === "all" || e === "numeric" && G(t) && !K(t) || e === "categorical" && Mn(t) || e === "temporal" && K(t) || e === "latitude" && q(t, "latitude") || e === "longitude" && q(t, "longitude") || e === "geographic" && t.traits?.some((e) => e.endsWith("state") || e.endsWith("state_short") || e.endsWith("country"))) && n.push(t);
|
|
3535
|
-
}), n;
|
|
3536
|
-
}, Pn = (e, t) => {
|
|
3537
|
-
let n = t.filter((t) => t.name !== e.xField && t.name !== e.yField);
|
|
3538
|
-
return n.length > 0 ? n[0] : t[0];
|
|
3539
|
-
}, Fn = (e, t, n) => {
|
|
3540
|
-
let r = {
|
|
3541
|
-
showTitle: !1,
|
|
3542
|
-
hideLegend: !1
|
|
3543
|
-
}, i = J("numeric", t), a = J("categorical", t).filter((e) => !Nn(e)), o = J("temporal", t), s = J("latitude", t), c = J("longitude", t), l = J("geographic", t);
|
|
3544
|
-
if (t.size === 0) return {};
|
|
3545
|
-
if (!n && i.length === 0 && l.length === 0 && c.length === 0 && s.length === 0) return r.chartType = "headline", r;
|
|
3546
|
-
let u = a.filter((e) => U(e));
|
|
3547
|
-
if (n) r.chartType = n;
|
|
3548
|
-
else if (c.length > 0 && s.length > 0) r.chartType = "geo-map";
|
|
3549
|
-
else if (l.length > 0) r.chartType = "geo-map";
|
|
3550
|
-
else if (o.length > 0 && i.length > 0) r.chartType = "line";
|
|
3551
|
-
else if (u.length > 0 && i.length > 0) r.chartType = "bar";
|
|
3552
|
-
else if (a.length > 0 && i.length > 0) {
|
|
3553
|
-
let t = a[0].name, n = /* @__PURE__ */ new Set();
|
|
3554
|
-
for (let r = 0; r < Math.min(e.length, 50); r++) e[r] && e[r][t] !== void 0 && n.add(e[r][t]);
|
|
3555
|
-
n.size > 7 ? r.chartType = "barh" : r.chartType = "bar";
|
|
3556
|
-
} else i.length >= 2 ? e.length === 1 ? r.chartType = "headline" : r.chartType = "point" : a.length >= 2 && i.length > 0 ? r.chartType = "heatmap" : i.length > 0 && a.length == 0 && (r.chartType = "headline");
|
|
3557
|
-
if (r.chartType === "barh") {
|
|
3558
|
-
r.yField = H(a, 0)?.name, i.length > 0 && (r.xField = Pn(r, i).name);
|
|
3559
|
-
let e = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3560
|
-
e.length > 0 && (r.colorField = e[0].name), i.length > 1 && !r.colorField && (r.colorField = i[1].name);
|
|
3561
|
-
let t = a.filter((e) => e.name !== r.yField && e.name !== r.xField && e.name !== r.colorField);
|
|
3562
|
-
t.length > 0 && (r.trellisRowField = t[0].name), t.length > 1 && (r.trellisField = t[1].name);
|
|
3563
|
-
} else if (r.chartType === "donut") {
|
|
3564
|
-
r.yField = H(a, 0)?.name, r.xField = H(i, 0)?.name;
|
|
3565
|
-
let e = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3566
|
-
e.length > 0 && (r.colorField = e[0].name), i.length > 1 && !r.colorField && (r.colorField = i[1].name);
|
|
3567
|
-
} else if (r.chartType === "point") {
|
|
3568
|
-
r.xField = H(i, 0)?.name, r.yField = H(i, 1)?.name;
|
|
3569
|
-
let e = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3570
|
-
e.length > 0 && (r.colorField = e[0].name);
|
|
3571
|
-
let t = i.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3572
|
-
t.length > 0 && (r.sizeField = t[0].name), !r.colorField && t.length > 1 && (r.colorField = t[1].name);
|
|
3573
|
-
let n = a.filter((e) => e.name !== r.yField && e.name !== r.xField && e.name !== r.colorField);
|
|
3574
|
-
n.length > 0 && (r.trellisRowField = n[0].name), n.length > 1 && (r.trellisField = n[1].name);
|
|
3575
|
-
} else if (r.chartType === "heatmap") {
|
|
3576
|
-
r.xField = H(a, 0)?.name, r.yField = H(a, 1)?.name, r.colorField = H(i, 0)?.name;
|
|
3577
|
-
let e = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3578
|
-
e.length > 0 && (r.trellisRowField = e[0].name), e.length > 1 && (r.trellisField = e[1].name);
|
|
3579
|
-
} else if (r.chartType === "bar") {
|
|
3580
|
-
r.xField = H(u, 0)?.name ?? H(a, 0)?.name;
|
|
3581
|
-
let e = i.filter((e) => !K(e) && e.name !== r.xField);
|
|
3582
|
-
r.yField = e.length > 0 ? e[0].name : H(i, 0)?.name;
|
|
3583
|
-
let t = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3584
|
-
t.length > 0 && (r.colorField = t[0].name), i.length > 1 && !r.colorField && (r.colorField = i[1].name);
|
|
3585
|
-
let n = a.filter((e) => e.name !== r.yField && e.name !== r.xField && e.name !== r.colorField);
|
|
3586
|
-
n.length > 0 && (r.trellisRowField = n[0].name), n.length > 1 && (r.trellisField = n[1].name);
|
|
3587
|
-
} else if (r.chartType === "headline") r.xField = H(i, 0)?.name;
|
|
3588
|
-
else if (["line", "area"].includes(r.chartType || "")) {
|
|
3589
|
-
let e = H(o, 0) ?? H(u, 0) ?? null;
|
|
3590
|
-
r.xField = e?.name;
|
|
3591
|
-
let t = i.filter((t) => t.name !== e?.name);
|
|
3592
|
-
r.yField = t.length > 0 ? t[0].name : H(i, 0)?.name, r.yField2 = t.length > 1 ? t[1].name : void 0;
|
|
3593
|
-
let n = a.filter((e) => e.name !== r.yField && e.name !== r.xField);
|
|
3594
|
-
n.length > 0 && (r.colorField = n[0].name);
|
|
3595
|
-
let s = a.filter((e) => e.name !== r.yField && e.name !== r.xField && e.name !== r.colorField);
|
|
3596
|
-
s.length > 0 && (r.trellisRowField = s[0].name), s.length > 1 && (r.trellisField = s[1].name);
|
|
3597
|
-
} else if (r.chartType === "geo-map") {
|
|
3598
|
-
let e = !1;
|
|
3599
|
-
s.length > 0 && c.length > 0 && (e = !0, r.yField = s[0].name, r.xField = c[0].name, i.length > 0 && (r.sizeField = i[0].name), i.length > 1 && (r.colorField = i[1].name)), l.length > 0 && (r.geoField = l[0].name, i.length > 0 && !e && (r.colorField = i[0].name));
|
|
3600
|
-
let t = a.filter((e) => e.name !== r.colorField && e.name !== r.xField && e.name !== r.yField && e.name !== r.geoField);
|
|
3601
|
-
t.length > 0 && !r.annotationField && (r.annotationField = t[0].name);
|
|
3602
|
-
let n = a.filter((e) => e.name !== r.geoField && e.name !== r.xField && e.name !== r.yField && e.name !== r.colorField && e.name !== r.annotationField);
|
|
3603
|
-
n.length > 0 && (r.trellisRowField = n[0].name), n.length > 1 && (r.trellisField = n[1].name);
|
|
3604
|
-
}
|
|
3605
|
-
return r;
|
|
3606
|
-
}, In = (e, t) => {
|
|
3607
|
-
let n = J("numeric", t), r = J("categorical", t), i = J("temporal", t), a = J("latitude", t), o = J("longitude", t), s = J("geographic", t), c = [];
|
|
3608
|
-
if (r.length > 0 && c.push("beeswarm"), n.length === 0) return (a.length > 0 && o.length > 0 || s.length > 0) && c.push("geo-map"), c.push("headline"), c;
|
|
3609
|
-
let l = r.filter((e) => U(e));
|
|
3610
|
-
if ((i.length > 0 || l.length > 0) && n.length > 0 && (c.push("line"), c.push("area")), r.length > 0 && n.length > 0) {
|
|
3611
|
-
let t = r[0].name, n = /* @__PURE__ */ new Set();
|
|
3612
|
-
for (let r = 0; r < Math.min(e.length, 50); r++) e[r] && e[r][t] !== void 0 && n.add(e[r][t]);
|
|
3613
|
-
c.push("bar"), c.push("barh"), c.push("donut");
|
|
3614
|
-
}
|
|
3615
|
-
return n.length >= 2 && c.push("point"), r.length >= 2 && n.length > 0 && c.push("heatmap"), n.length > 0 && (c.push("boxplot"), c.push("headline")), (a.length > 0 && o.length > 0 || s.length > 0) && c.push("geo-map"), c.filter((e) => yn.map((e) => e.value).includes(e));
|
|
3616
|
-
}, Ln = (e) => q(e, "latitude") ? "latitude" : q(e, "longitude") ? "longitude" : e.traits?.some((e) => e.endsWith("state") || e.endsWith("state_short") || e.endsWith("country")) ? "geographic" : K(e) ? "temporal" : U(e) ? "categorical" : G(e) ? "numeric" : Mn(e) ? "categorical" : "other", Rn = (e) => {
|
|
3617
|
-
let t = [];
|
|
3618
|
-
return e.forEach((e) => {
|
|
3619
|
-
t.push(`${e.name} (${Ln(e)})`);
|
|
3620
|
-
}), t.length > 0 ? t.join(", ") : "no fields";
|
|
3621
|
-
}, zn = (e, n, r) => {
|
|
3622
|
-
let i = In(e, n), a = [];
|
|
3623
|
-
if (r.layers && r.layers.length > 0) {
|
|
3624
|
-
let e = [], a = Array.from(n.keys());
|
|
3625
|
-
return r.layers.forEach((r, i) => {
|
|
3626
|
-
let o = `Layer ${i + 1}`;
|
|
3627
|
-
_n.includes(r.chartType) || e.push(`${o}: chart type "${r.chartType}" cannot be used as a layer. Layerable types: ${_n.join(", ")}.`);
|
|
3628
|
-
for (let i of t) {
|
|
3629
|
-
let t = r[i];
|
|
3630
|
-
typeof t == "string" && t !== "" && !n.has(t) && e.push(`${o}: field "${t}" (${i}) does not exist in the query results. Available columns: ${a.join(", ")}.`);
|
|
3631
|
-
}
|
|
3632
|
-
!r.xField && !r.yField && e.push(`${o}: needs at least one of xField or yField.`);
|
|
3633
|
-
}), (r.trellisField || r.trellisRowField) && e.push("Trellis roles cannot be combined with multiple layers or reference lines."), {
|
|
3634
|
-
valid: e.length === 0,
|
|
3635
|
-
fieldErrors: e,
|
|
3636
|
-
eligibleChartTypes: i,
|
|
3637
|
-
suggestedConfig: r
|
|
3638
|
-
};
|
|
3639
|
-
}
|
|
3640
|
-
if (!i.includes(r.chartType)) {
|
|
3641
|
-
let t = Rn(n);
|
|
3642
|
-
return {
|
|
3643
|
-
valid: !1,
|
|
3644
|
-
chartTypeError: `Chart type "${r.chartType}" is not compatible with the available fields (${t}). Eligible chart types: ${i.join(", ")}.`,
|
|
3645
|
-
fieldErrors: [],
|
|
3646
|
-
eligibleChartTypes: i,
|
|
3647
|
-
suggestedConfig: Fn(e, n)
|
|
3648
|
-
};
|
|
3649
|
-
}
|
|
3650
|
-
let o = Fn(e, n, [
|
|
3651
|
-
"line",
|
|
3652
|
-
"bar",
|
|
3653
|
-
"barh",
|
|
3654
|
-
"point",
|
|
3655
|
-
"geo-map",
|
|
3656
|
-
"tree",
|
|
3657
|
-
"area",
|
|
3658
|
-
"heatmap",
|
|
3659
|
-
"headline",
|
|
3660
|
-
"donut"
|
|
3661
|
-
].includes(r.chartType) ? r.chartType : void 0), s = Array.from(n.keys());
|
|
3662
|
-
for (let e of [
|
|
3663
|
-
"xField",
|
|
3664
|
-
"yField",
|
|
3665
|
-
"yField2",
|
|
3666
|
-
"colorField",
|
|
3667
|
-
"sizeField",
|
|
3668
|
-
"groupField",
|
|
3669
|
-
"trellisField",
|
|
3670
|
-
"trellisRowField",
|
|
3671
|
-
"geoField",
|
|
3672
|
-
"annotationField"
|
|
3673
|
-
]) {
|
|
3674
|
-
let t = r[e];
|
|
3675
|
-
typeof t == "string" && t !== "" && !n.has(t) && a.push(`Field "${t}" (${e}) does not exist in the query results. Available columns: ${s.join(", ")}.`);
|
|
3676
|
-
}
|
|
3677
|
-
let c = vn.filter((e) => !e.allowEmpty && e.visibleFor.includes(r.chartType));
|
|
3678
|
-
for (let e of c) {
|
|
3679
|
-
let t = r[e.field];
|
|
3680
|
-
(typeof t != "string" || t === "") && a.push(`Chart type "${r.chartType}" requires ${e.label} (${String(e.field)}) to be specified, but it is missing.`);
|
|
3681
|
-
}
|
|
3682
|
-
if (r.chartType === "geo-map") {
|
|
3683
|
-
let e = J("latitude", n), t = J("longitude", n), i = J("geographic", n), o = e.length > 0 && t.length > 0, c = i.length > 0;
|
|
3684
|
-
!o && !c && a.push(`geo-map requires geographic columns (latitude/longitude pairs or state/country codes) but none were found. Available columns: ${s.join(", ")}. Consider using a different chart type or adjusting the query to include geographic fields.`), !r.geoField && !c && (r.xField && t.length > 0 && !t.some((e) => e.name === r.xField) && a.push(`For geo-map, xField should be a longitude column. "${r.xField}" is not a longitude field. Available longitude columns: ${t.map((e) => e.name).join(", ") || "none"}.`), r.yField && e.length > 0 && !e.some((e) => e.name === r.yField) && a.push(`For geo-map, yField should be a latitude column. "${r.yField}" is not a latitude field. Available latitude columns: ${e.map((e) => e.name).join(", ") || "none"}.`));
|
|
3685
|
-
}
|
|
3686
|
-
if ((r.chartType === "line" || r.chartType === "area") && r.xField && n.has(r.xField)) {
|
|
3687
|
-
let e = n.get(r.xField);
|
|
3688
|
-
!K(e) && !Mn(e) && !G(e) && a.push(`For ${r.chartType} charts, xField should typically be a temporal or categorical column.`);
|
|
3689
|
-
}
|
|
3690
|
-
let l = { ...o };
|
|
3691
|
-
for (let [e, t] of Object.entries(r)) t != null && (typeof t == "string" && t === "" || (l[e] = t));
|
|
3692
|
-
return {
|
|
3693
|
-
valid: a.length === 0,
|
|
3694
|
-
fieldErrors: a,
|
|
3695
|
-
eligibleChartTypes: i,
|
|
3696
|
-
suggestedConfig: l
|
|
3697
|
-
};
|
|
3698
|
-
}, Bn = (e) => `Chart configuration is invalid for the data:\n${[e.chartTypeError, ...e.fieldErrors].filter(Boolean).map((e) => ` - ${e}`).join("\n")}\nEligible chart types for this data: ${e.eligibleChartTypes.join(", ") || "none"}.\nSuggested auto-detected config: ${JSON.stringify(e.suggestedConfig)}\nTip: Omit chartConfig to let auto-detection choose the best chart type and field mapping.`, Y = (e, t) => {
|
|
3699
|
-
if (!e || !t.get(e)) return {};
|
|
3700
|
-
let r = t.get(e);
|
|
3701
|
-
if (!r) return {};
|
|
3702
|
-
if (W(e, t, "usd")) return { format: "$,.2f" };
|
|
3703
|
-
if (W(e, t, "percent")) return { format: ".1%" };
|
|
3704
|
-
if (W(e, t, "year")) return {
|
|
3705
|
-
labelAngle: -45,
|
|
3706
|
-
format: "%Y",
|
|
3707
|
-
timeUnit: "year"
|
|
3708
|
-
};
|
|
3709
|
-
if (W(e, t, "month") || W(e, t, "day_of_week")) return { format: "d" };
|
|
3710
|
-
switch (r.type) {
|
|
3711
|
-
case n.DATE: return {
|
|
3712
|
-
timeUnit: "yearmonthdate",
|
|
3713
|
-
labelAngle: -45
|
|
3714
|
-
};
|
|
3715
|
-
case n.TIME: return {
|
|
3716
|
-
timeUnit: "hoursminutesseconds",
|
|
3717
|
-
labelAngle: -45
|
|
3718
|
-
};
|
|
3719
|
-
case n.DATETIME: return { timeUnit: "yearmonthdate-hours" };
|
|
3720
|
-
case n.INTEGER: return {};
|
|
3721
|
-
default: return {};
|
|
3722
|
-
}
|
|
3723
|
-
}, Vn = (e, t, n = null) => {
|
|
3724
|
-
if (!e || !t.get(e)) return {};
|
|
3725
|
-
let r = t.get(e);
|
|
3726
|
-
return r ? W(e, t, "day_of_week_name") ? { sort: [
|
|
3727
|
-
"Sunday",
|
|
3728
|
-
"Monday",
|
|
3729
|
-
"Tuesday",
|
|
3730
|
-
"Wednesday",
|
|
3731
|
-
"Thursday",
|
|
3732
|
-
"Friday",
|
|
3733
|
-
"Saturday"
|
|
3734
|
-
] } : An(r) || U(r) || K(r) ? { sort: {
|
|
3735
|
-
field: e,
|
|
3736
|
-
order: "ascending"
|
|
3737
|
-
} } : G(r) ? n ? { sort: {
|
|
3738
|
-
field: n,
|
|
3739
|
-
op: "sum",
|
|
3740
|
-
order: "descending"
|
|
3741
|
-
} } : { sort: {
|
|
3742
|
-
field: e,
|
|
3743
|
-
order: "descending"
|
|
3744
|
-
} } : n ? { sort: {
|
|
3745
|
-
field: n,
|
|
3746
|
-
op: "sum",
|
|
3747
|
-
order: "descending"
|
|
3748
|
-
} } : { sort: {
|
|
3749
|
-
field: e,
|
|
3750
|
-
order: "ascending"
|
|
3751
|
-
} } : {};
|
|
3752
|
-
}, X = (e, t) => {
|
|
3753
|
-
if (!e || !t.get(e)) return "nominal";
|
|
3754
|
-
let r = t.get(e);
|
|
3755
|
-
return r ? K(r) ? [
|
|
3756
|
-
n.DATETIME,
|
|
3757
|
-
n.TIMESTAMP,
|
|
3758
|
-
n.INTEGER
|
|
3759
|
-
].includes(r.type) || [n.DATE].includes(r.type) ? "temporal" : "ordinal" : An(r) || U(r) ? "ordinal" : G(r) ? "quantitative" : "nominal" : "nominal";
|
|
3760
|
-
}, Hn = (e, t, n = {}, i = !0, a = {}) => e ? {
|
|
3761
|
-
field: e,
|
|
3762
|
-
type: X(e, t),
|
|
3763
|
-
title: r(t.get(e)?.description || e),
|
|
3764
|
-
...Y(e, t),
|
|
3765
|
-
...n,
|
|
3766
|
-
...i ? Vn(e, t) : {},
|
|
3767
|
-
...a.scale !== void 0 || a.zero !== void 0 ? { scale: {
|
|
3768
|
-
...a.scale !== void 0 && { type: a.scale },
|
|
3769
|
-
...a.zero !== void 0 && { zero: a.zero }
|
|
3770
|
-
} } : {}
|
|
3771
|
-
} : {}, Un = (e = 0) => e > 0 ? `_l${e}` : "", Z = (e, t = "") => `${e}${t}`, Wn = (e = "") => ({
|
|
3772
|
-
fillOpacity: {
|
|
3773
|
-
condition: {
|
|
3774
|
-
param: Z("select", e),
|
|
3775
|
-
value: 1
|
|
3776
|
-
},
|
|
3777
|
-
value: .3
|
|
3778
|
-
},
|
|
3779
|
-
strokeWidth: {
|
|
3780
|
-
condition: [{
|
|
3781
|
-
param: Z("select", e),
|
|
3782
|
-
empty: !1,
|
|
3783
|
-
value: 2
|
|
3784
|
-
}, {
|
|
3785
|
-
param: Z("highlight", e),
|
|
3786
|
-
empty: !1,
|
|
3787
|
-
value: 1
|
|
3788
|
-
}],
|
|
3789
|
-
value: 0
|
|
3790
|
-
}
|
|
3791
|
-
}), Gn = (e, t, n, r = "color") => {
|
|
3792
|
-
let i = !1;
|
|
3793
|
-
return n === "quantitative" && r === "color" && (i = !0), e && e.length > 10 ? {
|
|
3794
|
-
orient: t ? "bottom" : "right",
|
|
3795
|
-
titleOrient: t ? "center" : i ? "right" : "top",
|
|
3796
|
-
direction: t ? "horizontal" : "vertical",
|
|
3797
|
-
titleFontSize: 10
|
|
3798
|
-
} : {
|
|
3799
|
-
orient: t ? "bottom" : "right",
|
|
3800
|
-
titleOrient: t ? "bottom" : "top",
|
|
3801
|
-
direction: t ? "horizontal" : "vertical",
|
|
3802
|
-
titleFontSize: t ? 10 : 12
|
|
3803
|
-
};
|
|
3804
|
-
}, Kn = 15, qn = (e, t, n, i = !1, a = "light", o = !1, s = [], c = "") => {
|
|
3805
|
-
let l = { tickCount: Kn }, u = [], d = [], f = s || [], p = Array.from(n.entries()).filter(([e, t]) => t.traits?.includes("hex")).map(([e, t]) => e);
|
|
3806
|
-
if (t) {
|
|
3807
|
-
let e = X(t, n);
|
|
3808
|
-
l = {
|
|
3809
|
-
...l,
|
|
3810
|
-
...Gn(t, i, e)
|
|
3811
|
-
}, (e === "nominal" || e === "ordinal") && (d = Array.from(new Set(f.map((e) => String(e[t] ?? "")))).sort((e, t) => e.localeCompare(t))), u = d.slice(0, Kn);
|
|
3812
|
-
}
|
|
3813
|
-
let m = (e) => (!o && Object.keys(l).length > 0 ? e.legend = l : o && (e.legend = null), e);
|
|
3814
|
-
if (t && n.get(t)) {
|
|
3815
|
-
let e = X(t, n);
|
|
3816
|
-
l = {
|
|
3817
|
-
...l,
|
|
3818
|
-
...Y(t, n),
|
|
3819
|
-
...(e === "nominal" || e === "ordinal") && u.length > 0 ? { values: u } : {}
|
|
3820
|
-
};
|
|
3821
|
-
let i = e === "quantitative" ? { scheme: a === "light" ? "viridis" : "plasma" } : { scheme: a === "light" ? "category20c" : "plasma" };
|
|
3822
|
-
if (p.length > 0) {
|
|
3823
|
-
let e = p[0], n = d.map((n) => {
|
|
3824
|
-
let r = f.find((r) => String(r[t]) === n && r[e] != null);
|
|
3825
|
-
return r ? String(r[e]) : "#999999";
|
|
3826
|
-
});
|
|
3827
|
-
i = {
|
|
3828
|
-
domain: d,
|
|
3829
|
-
range: n
|
|
3830
|
-
};
|
|
3831
|
-
}
|
|
3832
|
-
return m({
|
|
3833
|
-
field: t,
|
|
3834
|
-
type: e,
|
|
3835
|
-
title: r(n.get(t)?.description || t),
|
|
3836
|
-
scale: i,
|
|
3837
|
-
...c === null ? {} : { condition: [{
|
|
3838
|
-
param: Z("highlight", c),
|
|
3839
|
-
empty: !1,
|
|
3840
|
-
value: Sn
|
|
3841
|
-
}, {
|
|
3842
|
-
param: Z("select", c),
|
|
3843
|
-
empty: !1,
|
|
3844
|
-
value: Sn
|
|
3845
|
-
}] },
|
|
3846
|
-
...Y(t, n)
|
|
3847
|
-
});
|
|
3848
|
-
}
|
|
3849
|
-
return m({});
|
|
3850
|
-
}, Jn = (e, t, n = !1, i = !1) => {
|
|
3851
|
-
let a = { tickCount: 5 };
|
|
3852
|
-
if (e) {
|
|
3853
|
-
let r = X(e, t);
|
|
3854
|
-
a = {
|
|
3855
|
-
...a,
|
|
3856
|
-
...Gn(e, n, r, "size")
|
|
3857
|
-
};
|
|
3858
|
-
}
|
|
3859
|
-
return e && t.get(e) ? ((e) => (!i && Object.keys(a).length > 0 ? e.legend = a : i && (e.legend = null), e))({
|
|
3860
|
-
scale: {
|
|
3861
|
-
rangeMin: 30,
|
|
3862
|
-
nice: !0,
|
|
3863
|
-
type: "linear"
|
|
3864
|
-
},
|
|
3865
|
-
field: e,
|
|
3866
|
-
title: r(t.get(e)?.description || e)
|
|
3867
|
-
}) : {};
|
|
3868
|
-
};
|
|
3869
|
-
//#endregion
|
|
3870
|
-
//#region llm/importConcepts.ts
|
|
3871
|
-
async function Yn(e, t, n) {
|
|
3872
|
-
let { connectionStore: r, editorStore: i, queryExecutionService: a } = e;
|
|
3873
|
-
try {
|
|
3874
|
-
if (!i?.editors[t.id]?.contents) return "No fields found in this data source.";
|
|
3875
|
-
let e = r.connections[n] || r.connectionByName(n), o = e?.id || n, s = i && e ? Object.values(i.editors).filter((t) => !t.deleted && t.connectionId === e.id).map((e) => ({
|
|
3876
|
-
alias: e.name,
|
|
3877
|
-
contents: e.contents
|
|
3878
|
-
})) : [], c = r.getConnectionSources(o), l = /* @__PURE__ */ new Map();
|
|
3879
|
-
c.forEach((e) => l.set(e.alias, e.contents)), s.forEach((e) => l.set(e.alias, e.contents));
|
|
3880
|
-
let u = Array.from(l.entries()).map(([e, t]) => ({
|
|
3881
|
-
alias: e,
|
|
3882
|
-
contents: t
|
|
3883
|
-
})), d = {
|
|
3884
|
-
text: "SELECT 1",
|
|
3885
|
-
editorType: "trilogy",
|
|
3886
|
-
imports: [{
|
|
3887
|
-
name: t.name,
|
|
3888
|
-
alias: t.alias || ""
|
|
3889
|
-
}],
|
|
3890
|
-
extraContent: u
|
|
3891
|
-
}, f = await a.validateQuery(o, d, !1);
|
|
3892
|
-
if (f?.data?.completion_items) {
|
|
3893
|
-
let e = f.data.completion_items.filter((e) => e.trilogyType === "concept");
|
|
3894
|
-
if (e.length === 0) return "No fields found in this data source.";
|
|
3895
|
-
let t = e.map((e) => {
|
|
3896
|
-
let t = `- ${e.label} (${e.datatype || e.type})`;
|
|
3897
|
-
return e.description && (t += `: ${e.description}`), e.calculation && (t += ` [calculated: ${e.calculation}]`), t;
|
|
3898
|
-
}).join("\n");
|
|
3899
|
-
return `AVAILABLE FIELDS (${e.length} total):\n${t}`;
|
|
3900
|
-
}
|
|
3901
|
-
return "Unable to fetch field information for this data source.";
|
|
3902
|
-
} catch (e) {
|
|
3903
|
-
return console.error("Failed to fetch concepts for import:", e), "Error fetching field information for this data source.";
|
|
3904
|
-
}
|
|
3905
|
-
}
|
|
3906
|
-
//#endregion
|
|
3907
|
-
//#region llm/sharedToolHelpers.ts
|
|
3908
|
-
function Q(e) {
|
|
3909
|
-
return Object.values(e.connections).map((e) => e.name).join(", ");
|
|
3910
|
-
}
|
|
3911
|
-
function $(e, t) {
|
|
3912
|
-
return e.connections[t] || e.connectionByName(t) || null;
|
|
3913
|
-
}
|
|
3914
|
-
async function Xn(e, t, n) {
|
|
3915
|
-
if (!t || typeof t != "string") return {
|
|
3916
|
-
success: !1,
|
|
3917
|
-
error: `Connection name is required. Available connections: ${Q(e) || "None"}`
|
|
3918
|
-
};
|
|
3919
|
-
let r = $(e, t);
|
|
3920
|
-
if (!r) return {
|
|
3921
|
-
success: !1,
|
|
3922
|
-
error: `Connection "${t}" not found. Available connections: ${Q(e) || "None"}`
|
|
3923
|
-
};
|
|
3924
|
-
if (r.connected) return n?.onConnected?.(r.name, r.id), {
|
|
3925
|
-
success: !0,
|
|
3926
|
-
message: `Connection "${r.name}" is already active.`
|
|
3927
|
-
};
|
|
3928
|
-
try {
|
|
3929
|
-
return await e.connectConnection(r.id), n?.onConnected?.(r.name, r.id), {
|
|
3930
|
-
success: !0,
|
|
3931
|
-
message: `Successfully connected to "${r.name}".`,
|
|
3932
|
-
triggersSymbolRefresh: !0
|
|
3933
|
-
};
|
|
3934
|
-
} catch (e) {
|
|
3935
|
-
return {
|
|
3936
|
-
success: !1,
|
|
3937
|
-
error: `Failed to connect to "${r.name}": ${e instanceof Error ? e.message : "Unknown error"}`
|
|
3938
|
-
};
|
|
3939
|
-
}
|
|
3940
|
-
}
|
|
3941
|
-
function Zn(e, t, n, r) {
|
|
3942
|
-
let i = /* @__PURE__ */ new Map(), a = $(e, n), o = a?.id || n;
|
|
3943
|
-
return e.getConnectionSources(o).forEach((e) => i.set(e.alias, e.contents)), t && a && Object.values(t.editors).filter((e) => !e.deleted && e.connectionId === a.id).forEach((e) => {
|
|
3944
|
-
i.set(e.name, e.contents);
|
|
3945
|
-
}), r && r.forEach((e) => {
|
|
3946
|
-
let n = e.alias || e.name, r = t?.editors[e.id]?.contents || "";
|
|
3947
|
-
r && i.set(n, r);
|
|
3948
|
-
}), Array.from(i.entries()).map(([e, t]) => ({
|
|
3949
|
-
alias: e,
|
|
3950
|
-
contents: t
|
|
3951
|
-
}));
|
|
3952
|
-
}
|
|
3953
|
-
function Qn(e, t, n, r) {
|
|
3954
|
-
let i = typeof t?.toJSON == "function" ? t.toJSON() : t, a = i?.data;
|
|
3955
|
-
if (!Array.isArray(a)) return {
|
|
3956
|
-
success: !1,
|
|
3957
|
-
error: `Artifact "${e}" has no row data.`
|
|
3958
|
-
};
|
|
3959
|
-
let o = Number(n), s = Number(r);
|
|
3960
|
-
if (!Number.isFinite(o) || !Number.isFinite(s)) return {
|
|
3961
|
-
success: !1,
|
|
3962
|
-
error: "start_row and end_row must be numbers (0-indexed, inclusive)."
|
|
3963
|
-
};
|
|
3964
|
-
if (a.length === 0) return {
|
|
3965
|
-
success: !1,
|
|
3966
|
-
error: `Artifact "${e}" has 0 rows.`
|
|
3967
|
-
};
|
|
3968
|
-
let c = a.length, l = Math.max(0, Math.min(o, c - 1)), u = Math.max(l, Math.min(s, c - 1)), d = a.slice(l, u + 1);
|
|
3969
|
-
return {
|
|
3970
|
-
success: !0,
|
|
3971
|
-
message: `Rows ${l}-${u} of ${c} total from artifact "${e}":\n` + JSON.stringify({
|
|
3972
|
-
headers: i.headers,
|
|
3973
|
-
data: d
|
|
3974
|
-
}, null, 2)
|
|
3975
|
-
};
|
|
3976
|
-
}
|
|
3977
|
-
function $n(e, t, n) {
|
|
3978
|
-
if (!e) return [];
|
|
3979
|
-
let r = n ? $(n, t) : null;
|
|
3980
|
-
return Object.values(e.editors).filter((e) => e.deleted ? !1 : r ? e.connectionId === r.id : e.connection === t).sort((e, t) => e.name.localeCompare(t.name)).map((e) => ({
|
|
3981
|
-
id: e.id,
|
|
3982
|
-
name: e.name.replace(/\//g, "."),
|
|
3983
|
-
alias: ""
|
|
3984
|
-
}));
|
|
3985
|
-
}
|
|
3986
|
-
async function er(e, t, n, r, i) {
|
|
3987
|
-
let a = t.getConnectionName(), o = i && a ? $(i, a) : null;
|
|
3988
|
-
if (!e || e.trim() === "") return t.setActiveImports([]), {
|
|
3989
|
-
success: !0,
|
|
3990
|
-
message: "Cleared active data source selection.",
|
|
3991
|
-
triggersSymbolRefresh: !0
|
|
3992
|
-
};
|
|
3993
|
-
if (!a) return {
|
|
3994
|
-
success: !1,
|
|
3995
|
-
error: "No data connection selected. Please select a data connection first."
|
|
3996
|
-
};
|
|
3997
|
-
let s = $n(r, o?.id || a, i), c = s.find((t) => t.name === e || t.name.endsWith(`.${e}`));
|
|
3998
|
-
if (!c) return {
|
|
3999
|
-
success: !1,
|
|
4000
|
-
error: `Import "${e}" not found. Available imports: ${s.map((e) => e.name).join(", ") || "none"}`
|
|
4001
|
-
};
|
|
4002
|
-
let l = t.getActiveImports(), u = l.length === 1 && l[0].id === c.id;
|
|
4003
|
-
u || t.setActiveImports([c]);
|
|
4004
|
-
let d = await Yn(n, c, o?.id || a);
|
|
4005
|
-
return {
|
|
4006
|
-
success: !0,
|
|
4007
|
-
message: `${u ? `"${c.name}" is already the active data source.` : `Successfully selected "${c.name}" as the active data source.`}\n\n${d}`,
|
|
4008
|
-
triggersSymbolRefresh: !u
|
|
4009
|
-
};
|
|
4010
|
-
}
|
|
4011
|
-
function tr(e, t, n) {
|
|
4012
|
-
let r = e.getConnectionName(), i = n && r ? $(n, r) : null, a = i?.name || r;
|
|
4013
|
-
if (!r) return {
|
|
4014
|
-
success: !1,
|
|
4015
|
-
error: "No data connection selected. Please select a data connection first."
|
|
4016
|
-
};
|
|
4017
|
-
let o = $n(t, i?.id || r, n), s = e.getActiveImports(), c = s.length > 0 ? s[0] : null;
|
|
4018
|
-
return o.length === 0 ? {
|
|
4019
|
-
success: !0,
|
|
4020
|
-
message: `No data sources available on connection "${a}".`
|
|
4021
|
-
} : {
|
|
4022
|
-
success: !0,
|
|
4023
|
-
message: `${c ? `Current active data source: ${c.name}\n\n` : "No data source currently selected.\n\n"}Available data sources for connection "${a}":\n${o.map((e) => `- ${e.name}${c?.id === e.id ? " (active)" : ""}`).join("\n")}\n\nUse select_active_import to select a data source.`
|
|
4024
|
-
};
|
|
4025
|
-
}
|
|
4026
|
-
async function nr(e, t, n, r, i, a) {
|
|
4027
|
-
if (!i || typeof i != "string" || i.trim() === "") return {
|
|
4028
|
-
success: !1,
|
|
4029
|
-
error: "Query is required and must be a non-empty string",
|
|
4030
|
-
query: i
|
|
4031
|
-
};
|
|
4032
|
-
if (!r || typeof r != "string") return {
|
|
4033
|
-
success: !1,
|
|
4034
|
-
error: `Connection name is required. Available connections: ${Q(t) || "None"}`,
|
|
4035
|
-
query: i
|
|
4036
|
-
};
|
|
4037
|
-
let o = $(t, r);
|
|
4038
|
-
if (!o) return {
|
|
4039
|
-
success: !1,
|
|
4040
|
-
error: `Connection "${r}" not found. Available connections: ${Q(t) || "None"}`,
|
|
4041
|
-
query: i
|
|
4042
|
-
};
|
|
4043
|
-
if (!o.connected) return {
|
|
4044
|
-
success: !1,
|
|
4045
|
-
error: `Connection "${o.name}" is not connected. Use connect_data_connection first.`,
|
|
4046
|
-
query: i
|
|
4047
|
-
};
|
|
4048
|
-
let s = Zn(t, n, o.id, a), c = (a || []).map((e) => ({
|
|
4049
|
-
name: e.name,
|
|
4050
|
-
alias: e.alias || ""
|
|
4051
|
-
})), l = {
|
|
4052
|
-
text: i.trim(),
|
|
4053
|
-
editorType: "trilogy",
|
|
4054
|
-
imports: c,
|
|
4055
|
-
extraContent: s
|
|
4056
|
-
};
|
|
4057
|
-
try {
|
|
4058
|
-
let t = await (await e.executeQuery(o.id, l)).resultPromise;
|
|
4059
|
-
return t.success ? t.results ? {
|
|
4060
|
-
success: !0,
|
|
4061
|
-
queryResult: t,
|
|
4062
|
-
query: i
|
|
4063
|
-
} : {
|
|
4064
|
-
success: !1,
|
|
4065
|
-
error: "Query returned no results",
|
|
4066
|
-
query: i,
|
|
4067
|
-
generatedSql: t.generatedSql
|
|
4068
|
-
} : {
|
|
4069
|
-
success: !1,
|
|
4070
|
-
error: t.error || "Query execution failed",
|
|
4071
|
-
executionTime: t.executionTime,
|
|
4072
|
-
query: i,
|
|
4073
|
-
generatedSql: t.generatedSql
|
|
4074
|
-
};
|
|
4075
|
-
} catch (e) {
|
|
4076
|
-
return {
|
|
4077
|
-
success: !1,
|
|
4078
|
-
error: e instanceof Error ? e.message : "Unknown error during query execution",
|
|
4079
|
-
query: i
|
|
4080
|
-
};
|
|
4081
|
-
}
|
|
4082
|
-
}
|
|
4083
|
-
//#endregion
|
|
4084
|
-
//#region llm/editorRefinementToolExecutor.ts
|
|
4085
|
-
function rr() {
|
|
4086
|
-
return {
|
|
4087
|
-
artifactRegistry: /* @__PURE__ */ new Map(),
|
|
4088
|
-
lastQueryResults: { value: null }
|
|
4089
|
-
};
|
|
4090
|
-
}
|
|
4091
|
-
var ir = class {
|
|
4092
|
-
queryExecutionService;
|
|
4093
|
-
connectionStore;
|
|
4094
|
-
editorStore;
|
|
4095
|
-
editorContext;
|
|
4096
|
-
artifactRegistry;
|
|
4097
|
-
lastQueryResults;
|
|
4098
|
-
constructor(e, t, n, r, i) {
|
|
4099
|
-
this.queryExecutionService = e, this.connectionStore = t, this.editorContext = n, this.editorStore = r || null;
|
|
4100
|
-
let a = i ?? rr();
|
|
4101
|
-
this.artifactRegistry = a.artifactRegistry, this.lastQueryResults = a.lastQueryResults;
|
|
4102
|
-
}
|
|
4103
|
-
async executeToolCall(e, t) {
|
|
4104
|
-
switch (e) {
|
|
4105
|
-
case "browse_database_tree": return this.browseDatabaseTree(t);
|
|
4106
|
-
case "validate_query": return this.validateQuery(t.query);
|
|
4107
|
-
case "run_query": return this.runQuery(t.query);
|
|
4108
|
-
case "format_query": return this.formatQuery(t.query);
|
|
4109
|
-
case "edit_chart_config": return this.editChartConfig(t.chartConfig);
|
|
4110
|
-
case "edit_editor": return this.editEditor(t.content, t.replaceSelection === !0);
|
|
4111
|
-
case "run_active_editor_query": return this.runActiveEditorQuery();
|
|
4112
|
-
case "request_close": return this.requestClose(t.message);
|
|
4113
|
-
case "close_session": return this.closeSession();
|
|
4114
|
-
case "finish": return this.closeSession();
|
|
4115
|
-
case "connect_data_connection": return this.connectDataConnection(t.connection);
|
|
4116
|
-
case "get_artifact_rows": return this.getArtifactRows(t.artifact_id, t.start_row, t.end_row);
|
|
4117
|
-
default: return {
|
|
4118
|
-
success: !1,
|
|
4119
|
-
error: `Unknown tool: ${e}.`
|
|
4120
|
-
};
|
|
4121
|
-
}
|
|
4122
|
-
}
|
|
4123
|
-
async browseDatabaseTree(e) {
|
|
4124
|
-
let t = this.editorContext.connectionName, n = this.connectionStore.connectionByName(t);
|
|
4125
|
-
if (!n) return {
|
|
4126
|
-
success: !1,
|
|
4127
|
-
error: `Connection "${t}" not found`
|
|
4128
|
-
};
|
|
4129
|
-
if (!n.connected) return {
|
|
4130
|
-
success: !1,
|
|
4131
|
-
error: `Connection "${t}" is not currently connected`
|
|
4132
|
-
};
|
|
4133
|
-
let r = typeof e.database == "string" ? e.database : void 0, i = typeof e.schema == "string" ? e.schema : void 0, a = typeof e.table == "string" ? e.table : void 0, o = e.refresh !== !1;
|
|
4134
|
-
if (a && (!r || !i)) return {
|
|
4135
|
-
success: !1,
|
|
4136
|
-
error: "table lookup requires both database and schema"
|
|
4137
|
-
};
|
|
4138
|
-
if (i && !r) return {
|
|
4139
|
-
success: !1,
|
|
4140
|
-
error: "schema lookup requires database"
|
|
4141
|
-
};
|
|
4142
|
-
try {
|
|
4143
|
-
if ((o || !n.databases || n.databases.length === 0) && await n.getDatabases(), r && o && (await n.refreshDatabase(r), !n.hasSchema)) {
|
|
4144
|
-
let e = n.databases?.find((e) => e.name === r);
|
|
4145
|
-
e && e.schemas.length > 0 && await n.refreshSchema(r, e.schemas[0].name);
|
|
4146
|
-
}
|
|
4147
|
-
if (r && i && o && await n.refreshSchema(r, i), r && i && a && o) {
|
|
4148
|
-
let e = await n.getColumns(r, i, a), t = n.databases?.find((e) => e.name === r)?.schemas.find((e) => e.name === i)?.tables.find((e) => e.name === a);
|
|
4149
|
-
t && (t.columns = e);
|
|
4150
|
-
}
|
|
4151
|
-
let e = this.serializeDatabaseTree(r, i, a);
|
|
4152
|
-
return {
|
|
4153
|
-
success: !0,
|
|
4154
|
-
message: JSON.stringify(e, null, 2)
|
|
4155
|
-
};
|
|
4156
|
-
} catch (e) {
|
|
4157
|
-
return {
|
|
4158
|
-
success: !1,
|
|
4159
|
-
error: e instanceof Error ? e.message : "Failed to browse database tree"
|
|
4160
|
-
};
|
|
4161
|
-
}
|
|
4162
|
-
}
|
|
4163
|
-
async validateQuery(e) {
|
|
4164
|
-
if (!e || typeof e != "string" || e.trim() === "") return {
|
|
4165
|
-
success: !1,
|
|
4166
|
-
error: "Query is required and must be a non-empty string"
|
|
4167
|
-
};
|
|
4168
|
-
let t = this.editorContext.connectionName, n = this.connectionStore.connectionByName(t);
|
|
4169
|
-
if (!n) return {
|
|
4170
|
-
success: !1,
|
|
4171
|
-
error: `Connection "${t}" not found`
|
|
4172
|
-
};
|
|
4173
|
-
let r = this.buildQueryInput(e);
|
|
4174
|
-
if (r.editorType === "sql") return {
|
|
4175
|
-
success: !0,
|
|
4176
|
-
message: "SQL parser validation is not available. Use run_query to validate by execution.",
|
|
4177
|
-
query: e
|
|
4178
|
-
};
|
|
4179
|
-
try {
|
|
4180
|
-
let t = await this.queryExecutionService.validateQuery(n.id, r);
|
|
4181
|
-
if (t && t.data) {
|
|
4182
|
-
let n = t.data.items.filter((e) => e.severity >= 8), r = (t.data.completion_items || []).filter((e) => e.trilogyType === "concept");
|
|
4183
|
-
if (n.length > 0) {
|
|
4184
|
-
let t = this.buildSymbolsSummary(r);
|
|
4185
|
-
return {
|
|
4186
|
-
success: !1,
|
|
4187
|
-
error: `Validation errors:\n${n.map((e) => `- ${e.message}`).join("\n")}${t}`,
|
|
4188
|
-
query: e,
|
|
4189
|
-
availableSymbols: r
|
|
4190
|
-
};
|
|
4191
|
-
}
|
|
4192
|
-
return {
|
|
4193
|
-
success: !0,
|
|
4194
|
-
message: `Query is valid${this.buildSymbolsSummary(r)}`,
|
|
4195
|
-
query: e,
|
|
4196
|
-
availableSymbols: r
|
|
4197
|
-
};
|
|
4198
|
-
}
|
|
4199
|
-
return {
|
|
4200
|
-
success: !1,
|
|
4201
|
-
error: "Query validation failed - no response from validator",
|
|
4202
|
-
query: e
|
|
4203
|
-
};
|
|
4204
|
-
} catch (t) {
|
|
4205
|
-
return {
|
|
4206
|
-
success: !1,
|
|
4207
|
-
error: t instanceof Error ? t.message : "Validation error",
|
|
4208
|
-
query: e
|
|
4209
|
-
};
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
buildSymbolsSummary(e) {
|
|
4213
|
-
return e.length === 0 ? "" : `\n\nAvailable fields (${e.length} concepts):\n${cn(e)}`;
|
|
4214
|
-
}
|
|
4215
|
-
async runQuery(e) {
|
|
4216
|
-
if (!e || typeof e != "string" || e.trim() === "") return {
|
|
4217
|
-
success: !1,
|
|
4218
|
-
error: "Query is required and must be a non-empty string"
|
|
4219
|
-
};
|
|
4220
|
-
let t = this.editorContext.connectionName, n = this.connectionStore.connectionByName(t);
|
|
4221
|
-
if (!n) return {
|
|
4222
|
-
success: !1,
|
|
4223
|
-
error: `Connection "${t}" not found`,
|
|
4224
|
-
query: e
|
|
4225
|
-
};
|
|
4226
|
-
if (!n.connected) return {
|
|
4227
|
-
success: !1,
|
|
4228
|
-
error: `Connection "${t}" is not currently connected`,
|
|
4229
|
-
query: e
|
|
4230
|
-
};
|
|
4231
|
-
let r = this.buildQueryInput(e);
|
|
4232
|
-
try {
|
|
4233
|
-
let i = await (await this.queryExecutionService.executeQuery(n.id, r, void 0, void 0, void 0, void 0, !1)).resultPromise;
|
|
4234
|
-
if (i.selectCount !== void 0 && i.selectCount > 1) return {
|
|
4235
|
-
success: !1,
|
|
4236
|
-
error: `Query contains ${i.selectCount} SELECT statements. Each run_query call must contain exactly one SELECT statement. Please split your selects across multiple run_query calls.`,
|
|
4237
|
-
query: e
|
|
4238
|
-
};
|
|
4239
|
-
if (!i.success) return {
|
|
4240
|
-
success: !1,
|
|
4241
|
-
error: i.error || "Query execution failed",
|
|
4242
|
-
executionTime: i.executionTime,
|
|
4243
|
-
query: e,
|
|
4244
|
-
generatedSql: i.generatedSql
|
|
4245
|
-
};
|
|
4246
|
-
if (!i.results) return {
|
|
4247
|
-
success: !1,
|
|
4248
|
-
error: "Query returned no results",
|
|
4249
|
-
query: e,
|
|
4250
|
-
generatedSql: i.generatedSql
|
|
4251
|
-
};
|
|
4252
|
-
let a = {
|
|
4253
|
-
id: B(),
|
|
4254
|
-
type: "results",
|
|
4255
|
-
data: i.results,
|
|
4256
|
-
config: {
|
|
4257
|
-
query: e,
|
|
4258
|
-
connectionName: t,
|
|
4259
|
-
generatedSql: i.generatedSql,
|
|
4260
|
-
executionTime: i.executionTime,
|
|
4261
|
-
resultSize: i.resultSize,
|
|
4262
|
-
columnCount: i.columnCount
|
|
4263
|
-
}
|
|
4264
|
-
};
|
|
4265
|
-
this.artifactRegistry.set(a.id, a);
|
|
4266
|
-
let o = i.results;
|
|
4267
|
-
return o && o.headers && (this.lastQueryResults.value = o), {
|
|
4268
|
-
success: !0,
|
|
4269
|
-
artifact: a,
|
|
4270
|
-
executionTime: i.executionTime,
|
|
4271
|
-
query: e,
|
|
4272
|
-
generatedSql: i.generatedSql,
|
|
4273
|
-
message: `Query executed successfully. ${i.resultSize} rows, ${i.columnCount} columns.`
|
|
4274
|
-
};
|
|
4275
|
-
} catch (t) {
|
|
4276
|
-
return {
|
|
4277
|
-
success: !1,
|
|
4278
|
-
error: t instanceof Error ? t.message : "Unknown error during query execution",
|
|
4279
|
-
query: e
|
|
4280
|
-
};
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
async formatQuery(e) {
|
|
4284
|
-
if (!e || typeof e != "string" || e.trim() === "") return {
|
|
4285
|
-
success: !1,
|
|
4286
|
-
error: "Query is required and must be a non-empty string"
|
|
4287
|
-
};
|
|
4288
|
-
let t = this.editorContext.connectionName, n = this.connectionStore.connectionByName(t), r = this.buildEditorExtraContent();
|
|
4289
|
-
try {
|
|
4290
|
-
let i = await this.queryExecutionService.formatQuery(e.trim(), n?.id || t, this.editorContext.editorType, [], r);
|
|
4291
|
-
return i ? {
|
|
4292
|
-
success: !0,
|
|
4293
|
-
formattedQuery: i,
|
|
4294
|
-
message: `Query formatted successfully:\n\`\`\`${this.editorContext.editorType}\n${i}\n\`\`\``
|
|
4295
|
-
} : {
|
|
4296
|
-
success: !1,
|
|
4297
|
-
error: "Could not format query - no result returned",
|
|
4298
|
-
query: e
|
|
4299
|
-
};
|
|
4300
|
-
} catch (t) {
|
|
4301
|
-
return {
|
|
4302
|
-
success: !1,
|
|
4303
|
-
error: t instanceof Error ? t.message : "Format error",
|
|
4304
|
-
query: e
|
|
4305
|
-
};
|
|
4306
|
-
}
|
|
4307
|
-
}
|
|
4308
|
-
editChartConfig(e) {
|
|
4309
|
-
if (this.editorContext.editorType === "sql") return {
|
|
4310
|
-
success: !1,
|
|
4311
|
-
error: "Chart configuration editing is not supported for SQL editors"
|
|
4312
|
-
};
|
|
4313
|
-
if (!e || typeof e != "object") return {
|
|
4314
|
-
success: !1,
|
|
4315
|
-
error: "chartConfig is required and must be an object"
|
|
4316
|
-
};
|
|
4317
|
-
let t = this.editorContext.getCurrentResults?.() ?? this.lastQueryResults.value ?? null;
|
|
4318
|
-
if (t && t.headers) {
|
|
4319
|
-
let n = zn(t.data, t.headers, e);
|
|
4320
|
-
if (!n.valid) {
|
|
4321
|
-
let e = n.suggestedConfig;
|
|
4322
|
-
try {
|
|
4323
|
-
this.editorContext.onChartConfigChange(e);
|
|
4324
|
-
} catch {}
|
|
4325
|
-
return {
|
|
4326
|
-
success: !1,
|
|
4327
|
-
error: "Auto-corrected to default configuration.\n" + Bn(n)
|
|
4328
|
-
};
|
|
4329
|
-
}
|
|
4330
|
-
}
|
|
4331
|
-
try {
|
|
4332
|
-
return this.editorContext.onChartConfigChange(e), {
|
|
4333
|
-
success: !0,
|
|
4334
|
-
message: `Chart configuration updated: ${JSON.stringify(e)}`
|
|
4335
|
-
};
|
|
4336
|
-
} catch (e) {
|
|
4337
|
-
return {
|
|
4338
|
-
success: !1,
|
|
4339
|
-
error: e instanceof Error ? e.message : "Failed to update chart config"
|
|
4340
|
-
};
|
|
4341
|
-
}
|
|
4342
|
-
}
|
|
4343
|
-
async editEditor(e, t) {
|
|
4344
|
-
if (!e || typeof e != "string") return {
|
|
4345
|
-
success: !1,
|
|
4346
|
-
error: "Content is required and must be a string"
|
|
4347
|
-
};
|
|
4348
|
-
try {
|
|
4349
|
-
if (this.editorContext.onEditorContentChange(e, t), this.editorContext.editorType === "sql") return {
|
|
4350
|
-
success: !0,
|
|
4351
|
-
message: t ? "Updated selected text in editor." : "Updated editor contents."
|
|
4352
|
-
};
|
|
4353
|
-
let n = await this.validateQuery(e), r = t ? "Updated selected text in editor" : "Updated editor contents";
|
|
4354
|
-
return n.success ? {
|
|
4355
|
-
success: !0,
|
|
4356
|
-
message: `${r}. ${n.message}`,
|
|
4357
|
-
availableSymbols: n.availableSymbols
|
|
4358
|
-
} : {
|
|
4359
|
-
success: !0,
|
|
4360
|
-
message: `${r}.\n\nValidation errors found:\n${n.error}`,
|
|
4361
|
-
availableSymbols: n.availableSymbols
|
|
4362
|
-
};
|
|
4363
|
-
} catch (e) {
|
|
4364
|
-
return {
|
|
4365
|
-
success: !1,
|
|
4366
|
-
error: e instanceof Error ? e.message : "Failed to update editor"
|
|
4367
|
-
};
|
|
4368
|
-
}
|
|
4369
|
-
}
|
|
4370
|
-
async runActiveEditorQuery() {
|
|
4371
|
-
if (!this.editorContext.onRunActiveEditorQuery) return {
|
|
4372
|
-
success: !1,
|
|
4373
|
-
error: "Run active editor query is not available in this context"
|
|
4374
|
-
};
|
|
4375
|
-
let e = this.editorContext.editorContents;
|
|
4376
|
-
if (!e || e.trim() === "") return {
|
|
4377
|
-
success: !1,
|
|
4378
|
-
error: "Editor is empty - no query to run"
|
|
4379
|
-
};
|
|
4380
|
-
try {
|
|
4381
|
-
let t = await this.editorContext.onRunActiveEditorQuery();
|
|
4382
|
-
if (!t.success) return {
|
|
4383
|
-
success: !1,
|
|
4384
|
-
error: t.error || "Query execution failed",
|
|
4385
|
-
executionTime: t.executionTime,
|
|
4386
|
-
query: e,
|
|
4387
|
-
generatedSql: t.generatedSql
|
|
4388
|
-
};
|
|
4389
|
-
if (!t.results) return {
|
|
4390
|
-
success: !1,
|
|
4391
|
-
error: "Query returned no results",
|
|
4392
|
-
query: e,
|
|
4393
|
-
generatedSql: t.generatedSql
|
|
4394
|
-
};
|
|
4395
|
-
let n = {
|
|
4396
|
-
id: B(),
|
|
4397
|
-
type: "results",
|
|
4398
|
-
data: t.results,
|
|
4399
|
-
config: {
|
|
4400
|
-
query: e,
|
|
4401
|
-
connectionName: this.editorContext.connectionName,
|
|
4402
|
-
generatedSql: t.generatedSql,
|
|
4403
|
-
executionTime: t.executionTime,
|
|
4404
|
-
resultSize: t.resultSize,
|
|
4405
|
-
columnCount: t.columnCount
|
|
4406
|
-
}
|
|
4407
|
-
};
|
|
4408
|
-
return this.artifactRegistry.set(n.id, n), {
|
|
4409
|
-
success: !0,
|
|
4410
|
-
artifact: n,
|
|
4411
|
-
executionTime: t.executionTime,
|
|
4412
|
-
query: e,
|
|
4413
|
-
generatedSql: t.generatedSql,
|
|
4414
|
-
message: `Query executed successfully. ${t.resultSize} rows, ${t.columnCount} columns.`
|
|
4415
|
-
};
|
|
4416
|
-
} catch (t) {
|
|
4417
|
-
return {
|
|
4418
|
-
success: !1,
|
|
4419
|
-
error: t instanceof Error ? t.message : "Failed to execute query",
|
|
4420
|
-
query: e
|
|
4421
|
-
};
|
|
4422
|
-
}
|
|
4423
|
-
}
|
|
4424
|
-
getArtifactRows(e, t, n) {
|
|
4425
|
-
let r = this.artifactRegistry.get(e);
|
|
4426
|
-
return r ? Qn(e, r.data, t, n) : {
|
|
4427
|
-
success: !1,
|
|
4428
|
-
error: `Artifact "${e}" not found. Only artifacts created by run_query or run_active_editor_query in this session are available.`
|
|
4429
|
-
};
|
|
4430
|
-
}
|
|
4431
|
-
requestClose(e) {
|
|
4432
|
-
return {
|
|
4433
|
-
success: !0,
|
|
4434
|
-
message: `${e}\n\nReady to close. Reply with any follow-up requests, or say "done" to close the session.`,
|
|
4435
|
-
awaitsUserInput: !0
|
|
4436
|
-
};
|
|
4437
|
-
}
|
|
4438
|
-
closeSession() {
|
|
4439
|
-
try {
|
|
4440
|
-
return this.editorContext.onFinish(), {
|
|
4441
|
-
success: !0,
|
|
4442
|
-
message: "Session closed. Changes saved.",
|
|
4443
|
-
terminatesLoop: !0
|
|
4444
|
-
};
|
|
4445
|
-
} catch (e) {
|
|
4446
|
-
return {
|
|
4447
|
-
success: !1,
|
|
4448
|
-
error: e instanceof Error ? e.message : "Failed to close session"
|
|
4449
|
-
};
|
|
4450
|
-
}
|
|
4451
|
-
}
|
|
4452
|
-
async connectDataConnection(e) {
|
|
4453
|
-
return Xn(this.connectionStore, e);
|
|
4454
|
-
}
|
|
4455
|
-
serializeDatabaseTree(e, t, n) {
|
|
4456
|
-
let r = this.connectionStore.connectionByName(this.editorContext.connectionName), i = r?.databases || [], a = (e ? i.filter((t) => t.name === e) : i).map((e) => {
|
|
4457
|
-
let r = t ? e.schemas.filter((e) => e.name === t) : e.schemas;
|
|
4458
|
-
return {
|
|
4459
|
-
database: e.name,
|
|
4460
|
-
schemas: r.map((e) => {
|
|
4461
|
-
let t = n ? e.tables.filter((e) => e.name === n) : e.tables;
|
|
4462
|
-
return {
|
|
4463
|
-
schema: e.name,
|
|
4464
|
-
tables: t.map((e) => ({
|
|
4465
|
-
name: e.name,
|
|
4466
|
-
assetType: e.assetType,
|
|
4467
|
-
description: e.description,
|
|
4468
|
-
columns: e.columns.map((e) => ({
|
|
4469
|
-
name: e.name,
|
|
4470
|
-
type: e.type,
|
|
4471
|
-
trilogyType: e.trilogyType,
|
|
4472
|
-
nullable: e.nullable
|
|
4473
|
-
}))
|
|
4474
|
-
}))
|
|
4475
|
-
};
|
|
4476
|
-
})
|
|
4477
|
-
};
|
|
4478
|
-
});
|
|
4479
|
-
return {
|
|
4480
|
-
connection: this.editorContext.connectionName,
|
|
4481
|
-
hasSchema: r?.hasSchema,
|
|
4482
|
-
tree: a
|
|
4483
|
-
};
|
|
4484
|
-
}
|
|
4485
|
-
buildQueryInput(e) {
|
|
4486
|
-
return {
|
|
4487
|
-
text: e.trim(),
|
|
4488
|
-
editorType: this.editorContext.editorType,
|
|
4489
|
-
imports: [],
|
|
4490
|
-
extraContent: this.buildEditorExtraContent()
|
|
4491
|
-
};
|
|
4492
|
-
}
|
|
4493
|
-
buildEditorExtraContent() {
|
|
4494
|
-
return Zn(this.connectionStore, this.editorStore, this.editorContext.connectionName);
|
|
4495
|
-
}
|
|
4496
|
-
};
|
|
4497
|
-
//#endregion
|
|
4498
|
-
export { Ut as $, xe as $t, vn as A, We as At, pn as B, D as Bt, X as C, tt as Ct, Un as D, Ye as Dt, jn as E, O as Et, bn as F, He as Ft, rn as G, oe as Gt, fn as H, De as Ht, mn as I, Ae as It, L as J, re as Jt, sn as K, ne as Kt, V as L, Ie as Lt, gn as M, Re as Mt, hn as N, E as Nt, zn as O, Je as Ot, xn as P, Ve as Pt, R as Q, Ce as Qt, B as R, ze as Rt, Vn as S, Xe as St, Nn as T, et as Tt, qt as U, ae as Ut, z as V, Ue as Vt, on as W, te as Wt, Wt as X, le as Xt, I as Y, b as Yt, Kt as Z, ie as Zt, In as _, ut as _t, nr as a, c as an, Ct as at, W as b, Qe as bt, tr as c, Tt as ct, On as d, j as dt, ye as en, Bt as et, qn as f, N as ft, Fn as g, mt as gt, Jn as h, ht, Xn as i, f as in, wt as it, _n as j, Ge as jt, yn as k, Ke as kt, er as l, Et as lt, Wn as m, gt as mt, rr as n, y as nn, F as nt, Qn as o, d as on, At as ot, Hn as p, A as pt, en as q, se as qt, Zn as r, m as rn, Nt as rt, $n as s, u as sn, St as st, ir as t, Se as tn, zt as tt, Sn as u, M as ut, J as v, ot as vt, Tn as w, $e as wt, Y as x, Ze as xt, Bn as y, k as yt, dn as z, Be as zt };
|