@eclipse-lyra/extension-dataviewer 0.7.19 → 0.7.20
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/api.d.ts +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -1
- package/dist/dataview-part.d.ts +2 -0
- package/dist/dataview-part.d.ts.map +1 -1
- package/dist/{dataviewer-extension-d9jiyV7k.js → dataviewer-extension-4EAxXuUk.js} +43 -8
- package/dist/dataviewer-extension-4EAxXuUk.js.map +1 -0
- package/dist/dataviewer-service.d.ts +1 -0
- package/dist/dataviewer-service.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/dataviewer-extension-d9jiyV7k.js.map +0 -1
package/dist/api.d.ts
CHANGED
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC"}
|
package/dist/api.js
CHANGED
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sources":["../src/api.ts"],"sourcesContent":["export interface TabularData {\n columns: string[];\n rows: unknown[][];\n}\n\nexport interface DataView {\n id?: string;\n title: string;\n data: TabularData;\n source?: string;\n createdAt?: number;\n}\n\nexport const TOPIC_DATAVIEW_PUBLISH = 'dataview/publish';\n"],"names":[],"mappings":"AAaO,MAAM,yBAAyB;"}
|
|
1
|
+
{"version":3,"file":"api.js","sources":["../src/api.ts"],"sourcesContent":["export interface TabularData {\n columns: string[];\n rows: unknown[][];\n}\n\nexport interface DataView {\n id?: string;\n title: string;\n data: TabularData;\n source?: string;\n createdAt?: number;\n}\n\nexport const TOPIC_DATAVIEW_PUBLISH = 'dataview/publish';\nexport const TOPIC_DATAVIEW_ADDED = 'dataview/added';\n"],"names":[],"mappings":"AAaO,MAAM,yBAAyB;AAC/B,MAAM,uBAAuB;"}
|
package/dist/dataview-part.d.ts
CHANGED
|
@@ -6,10 +6,12 @@ export declare class DataViewPart extends LyraPart {
|
|
|
6
6
|
private selectedStorageKey;
|
|
7
7
|
private selectedView;
|
|
8
8
|
private loadingList;
|
|
9
|
+
private autoActivateTab;
|
|
9
10
|
private get displayed();
|
|
10
11
|
protected doInitUI(): Promise<void>;
|
|
11
12
|
private refreshPersistedList;
|
|
12
13
|
private selectStorageKey;
|
|
14
|
+
private onAutoActivateChange;
|
|
13
15
|
private onHistorySelect;
|
|
14
16
|
private onDeleteView;
|
|
15
17
|
protected renderToolbar(): import('lit-html').TemplateResult<1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataview-part.d.ts","sourceRoot":"","sources":["../src/dataview-part.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"dataview-part.d.ts","sourceRoot":"","sources":["../src/dataview-part.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAc,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAItC,qBACa,YAAa,SAAQ,QAAQ;IAExC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IAGjC,OAAO,CAAC,aAAa,CAA2B;IAGhD,OAAO,CAAC,kBAAkB,CAAM;IAGhC,OAAO,CAAC,YAAY,CAAyB;IAG7C,OAAO,CAAC,WAAW,CAAQ;IAG3B,OAAO,CAAC,eAAe,CAAQ;IAE/B,OAAO,KAAK,SAAS,GAEpB;cAEe,QAAQ;YAUV,oBAAoB;YAyBpB,gBAAgB;YAkBhB,oBAAoB;YAQpB,eAAe;YASf,YAAY;IAgB1B,SAAS,CAAC,aAAa;IAwEvB,OAAO,CAAC,WAAW;IA2BnB,MAAM;IAMN,MAAM,CAAC,MAAM,0BAaX;CAEH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { css, html } from "lit";
|
|
2
|
-
import { subscribe, persistenceService, LyraPart, toastError, rootContext, contributionRegistry, PANEL_BOTTOM, editorRegistry, File } from "@eclipse-lyra/core";
|
|
2
|
+
import { subscribe, persistenceService, publish, LyraPart, toastError, rootContext, contributionRegistry, PANEL_BOTTOM, editorRegistry, File } from "@eclipse-lyra/core";
|
|
3
3
|
import { v4 } from "@eclipse-lyra/core/externals/third-party";
|
|
4
|
-
import { TOPIC_DATAVIEW_PUBLISH } from "./api.js";
|
|
4
|
+
import { TOPIC_DATAVIEW_PUBLISH, TOPIC_DATAVIEW_ADDED } from "./api.js";
|
|
5
5
|
import { property, state, customElement } from "lit/decorators.js";
|
|
6
|
+
import { when } from "@eclipse-lyra/core/externals/lit";
|
|
6
7
|
import Papa from "papaparse";
|
|
7
8
|
const KEY_PREFIX = "dataview/";
|
|
8
9
|
const KEY_INDEX = KEY_PREFIX + "index";
|
|
@@ -26,8 +27,9 @@ class DataviewerService {
|
|
|
26
27
|
await persistenceService.persistObject(KEY_PREFIX + storageKey, entry);
|
|
27
28
|
const index = await persistenceService.getObject(KEY_INDEX);
|
|
28
29
|
const list = Array.isArray(index) ? index : [];
|
|
29
|
-
list.push({ storageKey, title: payload.title, createdAt });
|
|
30
|
+
list.push({ storageKey, title: payload.title, source: payload.source, createdAt });
|
|
30
31
|
await persistenceService.persistObject(KEY_INDEX, list);
|
|
32
|
+
publish(TOPIC_DATAVIEW_ADDED, { storageKey, title: payload.title, createdAt });
|
|
31
33
|
}
|
|
32
34
|
async listViews() {
|
|
33
35
|
const raw = await persistenceService.getObject(KEY_INDEX);
|
|
@@ -72,12 +74,18 @@ let DataViewPart = class extends LyraPart {
|
|
|
72
74
|
this.selectedStorageKey = "";
|
|
73
75
|
this.selectedView = null;
|
|
74
76
|
this.loadingList = true;
|
|
77
|
+
this.autoActivateTab = true;
|
|
75
78
|
}
|
|
76
79
|
get displayed() {
|
|
77
80
|
return this.selectedView ?? this.dataview;
|
|
78
81
|
}
|
|
79
82
|
async doInitUI() {
|
|
80
|
-
|
|
83
|
+
const persisted = await this.getDialogSetting();
|
|
84
|
+
if (persisted && typeof persisted.autoActivateTab === "boolean") this.autoActivateTab = persisted.autoActivateTab;
|
|
85
|
+
this.subscribe(TOPIC_DATAVIEW_ADDED, async () => {
|
|
86
|
+
await this.refreshPersistedList(true);
|
|
87
|
+
if (this.autoActivateTab) this.activateContainingTab();
|
|
88
|
+
});
|
|
81
89
|
await this.refreshPersistedList(false);
|
|
82
90
|
}
|
|
83
91
|
async refreshPersistedList(selectLatest) {
|
|
@@ -109,6 +117,7 @@ let DataViewPart = class extends LyraPart {
|
|
|
109
117
|
if (!key) {
|
|
110
118
|
this.selectedView = null;
|
|
111
119
|
this.requestUpdate();
|
|
120
|
+
this.updateToolbar();
|
|
112
121
|
return;
|
|
113
122
|
}
|
|
114
123
|
try {
|
|
@@ -118,6 +127,14 @@ let DataViewPart = class extends LyraPart {
|
|
|
118
127
|
this.selectedView = null;
|
|
119
128
|
}
|
|
120
129
|
this.requestUpdate();
|
|
130
|
+
this.updateToolbar();
|
|
131
|
+
}
|
|
132
|
+
async onAutoActivateChange(e) {
|
|
133
|
+
const checked = e.target.checked;
|
|
134
|
+
this.autoActivateTab = checked;
|
|
135
|
+
const current = await this.getDialogSetting() ?? {};
|
|
136
|
+
await this.setDialogSetting({ ...current, autoActivateTab: checked });
|
|
137
|
+
this.updateToolbar();
|
|
121
138
|
}
|
|
122
139
|
async onHistorySelect(e) {
|
|
123
140
|
const value = e.detail?.item?.value ?? "";
|
|
@@ -146,9 +163,10 @@ let DataViewPart = class extends LyraPart {
|
|
|
146
163
|
const selectedMeta = this.persistedList.find((e) => e.storageKey === this.selectedStorageKey);
|
|
147
164
|
const baseTitle = selectedMeta?.title ?? current?.title ?? (this.persistedList.length > 0 ? "Latest data view" : "No data");
|
|
148
165
|
const formattedCreatedAt = selectedMeta?.createdAt ?? current?.createdAt ? new Date(selectedMeta?.createdAt ?? current?.createdAt).toLocaleString() : null;
|
|
149
|
-
const
|
|
166
|
+
const engineLabel = current?.source ?? null;
|
|
167
|
+
const titleWithEngine = engineLabel ? `${baseTitle} · ${engineLabel}` : baseTitle;
|
|
168
|
+
const currentLabel = formattedCreatedAt ? `${titleWithEngine} (${formattedCreatedAt})` : titleWithEngine;
|
|
150
169
|
return html`
|
|
151
|
-
<span>${currentLabel}</span>
|
|
152
170
|
<wa-dropdown
|
|
153
171
|
placement="bottom-start"
|
|
154
172
|
distance="4"
|
|
@@ -173,7 +191,7 @@ let DataViewPart = class extends LyraPart {
|
|
|
173
191
|
${this.persistedList.map(
|
|
174
192
|
(entry) => html`
|
|
175
193
|
<wa-dropdown-item value=${entry.storageKey}>
|
|
176
|
-
${entry.title}
|
|
194
|
+
${entry.source ? `${entry.title} · ${entry.source}` : entry.title}
|
|
177
195
|
${entry.createdAt ? html`<span style="opacity: 0.7; margin-left: 0.5rem; font-size: 0.75em;">
|
|
178
196
|
(${new Date(entry.createdAt).toLocaleString()})
|
|
179
197
|
</span>` : null}
|
|
@@ -190,6 +208,20 @@ let DataViewPart = class extends LyraPart {
|
|
|
190
208
|
`
|
|
191
209
|
)}
|
|
192
210
|
</wa-dropdown>
|
|
211
|
+
|
|
212
|
+
<wa-divider orientation="vertical"></wa-divider>
|
|
213
|
+
|
|
214
|
+
<wa-switch
|
|
215
|
+
?checked=${this.autoActivateTab}
|
|
216
|
+
size="small"
|
|
217
|
+
title="Switch to this tab when new results arrive"
|
|
218
|
+
@change=${(e) => this.onAutoActivateChange(e)}
|
|
219
|
+
style="margin-top: 0.5rem;"
|
|
220
|
+
>
|
|
221
|
+
Auto-show
|
|
222
|
+
</wa-switch>
|
|
223
|
+
|
|
224
|
+
${when(current, () => html`<wa-divider orientation="vertical"></wa-divider><span>${currentLabel}</span>`)}
|
|
193
225
|
`;
|
|
194
226
|
}
|
|
195
227
|
renderTable(dv) {
|
|
@@ -253,6 +285,9 @@ __decorateClass([
|
|
|
253
285
|
__decorateClass([
|
|
254
286
|
state()
|
|
255
287
|
], DataViewPart.prototype, "loadingList", 2);
|
|
288
|
+
__decorateClass([
|
|
289
|
+
state()
|
|
290
|
+
], DataViewPart.prototype, "autoActivateTab", 2);
|
|
256
291
|
DataViewPart = __decorateClass([
|
|
257
292
|
customElement("lyra-dataview")
|
|
258
293
|
], DataViewPart);
|
|
@@ -332,4 +367,4 @@ function dataviewerExtension() {
|
|
|
332
367
|
export {
|
|
333
368
|
dataviewerExtension as default
|
|
334
369
|
};
|
|
335
|
-
//# sourceMappingURL=dataviewer-extension-
|
|
370
|
+
//# sourceMappingURL=dataviewer-extension-4EAxXuUk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataviewer-extension-4EAxXuUk.js","sources":["../src/dataviewer-service.ts","../src/dataview-part.ts","../src/parse-csv.ts","../src/dataviewer-extension.ts"],"sourcesContent":["import { persistenceService, subscribe, publish } from '@eclipse-lyra/core';\nimport { v4 } from '@eclipse-lyra/core/externals/third-party';\nimport type { DataView } from './api';\nimport { TOPIC_DATAVIEW_PUBLISH, TOPIC_DATAVIEW_ADDED } from './api';\n\nconst KEY_PREFIX = 'dataview/';\nconst KEY_INDEX = KEY_PREFIX + 'index';\n\nexport interface DataviewListEntry {\n storageKey: string;\n title: string;\n source?: string;\n createdAt: number;\n}\n\ntype IndexEntry = DataviewListEntry;\n\nexport class DataviewerService {\n private subscriptionToken?: string;\n\n init(): void {\n if (this.subscriptionToken !== undefined) return;\n this.subscriptionToken = subscribe(TOPIC_DATAVIEW_PUBLISH, (payload: DataView) => {\n void this.handlePublish(payload);\n });\n }\n\n private async handlePublish(payload: DataView): Promise<void> {\n const storageKey = v4();\n const createdAt = Date.now();\n const entry: DataView = {\n id: payload.id ?? storageKey,\n title: payload.title,\n data: payload.data,\n source: payload.source,\n createdAt,\n };\n await persistenceService.persistObject(KEY_PREFIX + storageKey, entry);\n const index = (await persistenceService.getObject(KEY_INDEX)) as IndexEntry[] | undefined;\n const list = Array.isArray(index) ? index : [];\n list.push({ storageKey, title: payload.title, source: payload.source, createdAt });\n await persistenceService.persistObject(KEY_INDEX, list);\n publish(TOPIC_DATAVIEW_ADDED, { storageKey, title: payload.title, createdAt });\n }\n\n async listViews(): Promise<DataviewListEntry[]> {\n const raw = await persistenceService.getObject(KEY_INDEX);\n if (!Array.isArray(raw) || raw.length === 0) return [];\n if (typeof raw[0] === 'string') {\n return (raw as string[]).map((storageKey) => ({\n storageKey,\n title: storageKey,\n createdAt: 0,\n }));\n }\n const list = raw as IndexEntry[];\n return [...list].sort((a, b) => a.createdAt - b.createdAt);\n }\n\n async getView(storageKey: string): Promise<DataView | null> {\n const entry = await persistenceService.getObject(KEY_PREFIX + storageKey);\n return entry ?? null;\n }\n\n async deleteView(storageKey: string): Promise<void> {\n const index = (await persistenceService.getObject(KEY_INDEX)) as IndexEntry[] | undefined;\n const list = Array.isArray(index) ? index.filter((e) => e.storageKey !== storageKey) : [];\n await persistenceService.persistObject(KEY_INDEX, list);\n await persistenceService.persistObject(KEY_PREFIX + storageKey, null);\n }\n}\n\nexport const dataviewerService = new DataviewerService();\n","import { customElement, property, state } from 'lit/decorators.js';\nimport { css, html } from 'lit';\nimport { LyraPart, toastError } from '@eclipse-lyra/core';\nimport { dataviewerService, type DataviewListEntry } from './dataviewer-service';\nimport type { DataView } from './api';\nimport { TOPIC_DATAVIEW_ADDED } from './api';\nimport { when } from '@eclipse-lyra/core/externals/lit';\n\n@customElement('lyra-dataview')\nexport class DataViewPart extends LyraPart {\n @property({ attribute: false })\n dataview: DataView | null = null;\n\n @state()\n private persistedList: DataviewListEntry[] = [];\n\n @state()\n private selectedStorageKey = '';\n\n @state()\n private selectedView: DataView | null = null;\n\n @state()\n private loadingList = true;\n\n @state()\n private autoActivateTab = true;\n\n private get displayed(): DataView | null {\n return this.selectedView ?? this.dataview;\n }\n\n protected async doInitUI() {\n const persisted = await this.getDialogSetting();\n if (persisted && typeof persisted.autoActivateTab === 'boolean') this.autoActivateTab = persisted.autoActivateTab;\n this.subscribe(TOPIC_DATAVIEW_ADDED, async () => {\n await this.refreshPersistedList(true);\n if (this.autoActivateTab) this.activateContainingTab();\n });\n await this.refreshPersistedList(false);\n }\n\n private async refreshPersistedList(selectLatest: boolean): Promise<void> {\n this.loadingList = true;\n this.requestUpdate();\n try {\n this.persistedList = await dataviewerService.listViews();\n if (selectLatest && this.persistedList.length > 0) {\n const latest = this.persistedList[this.persistedList.length - 1];\n this.selectedStorageKey = latest.storageKey;\n this.selectedView = await dataviewerService.getView(latest.storageKey);\n } else if (this.selectedStorageKey) {\n this.selectedView = await dataviewerService.getView(this.selectedStorageKey);\n } else {\n this.selectedView = null;\n }\n } catch (e) {\n toastError(e instanceof Error ? e.message : String(e));\n this.persistedList = [];\n this.selectedView = null;\n } finally {\n this.loadingList = false;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private async selectStorageKey(key: string): Promise<void> {\n this.selectedStorageKey = key;\n if (!key) {\n this.selectedView = null;\n this.requestUpdate();\n this.updateToolbar();\n return;\n }\n try {\n this.selectedView = await dataviewerService.getView(key);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n this.selectedView = null;\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private async onAutoActivateChange(e: Event): Promise<void> {\n const checked = (e.target as HTMLInputElement).checked;\n this.autoActivateTab = checked;\n const current = (await this.getDialogSetting()) ?? {};\n await this.setDialogSetting({ ...current, autoActivateTab: checked });\n this.updateToolbar();\n }\n\n private async onHistorySelect(e: CustomEvent<{ item?: { value?: string } }>): Promise<void> {\n const value = e.detail?.item?.value ?? '';\n if (!value || value === '__stats__') {\n // Ignore the stats item and empty\n return;\n }\n await this.selectStorageKey(value);\n }\n\n private async onDeleteView(e: Event, storageKey: string): Promise<void> {\n e.stopPropagation();\n e.preventDefault();\n try {\n await dataviewerService.deleteView(storageKey);\n const deletedWasSelected = this.selectedStorageKey === storageKey;\n if (deletedWasSelected) {\n this.selectedStorageKey = '';\n this.selectedView = null;\n }\n await this.refreshPersistedList(true);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n protected renderToolbar() {\n const current = this.selectedView ?? this.dataview;\n const selectedMeta = this.persistedList.find((e) => e.storageKey === this.selectedStorageKey);\n const baseTitle = selectedMeta?.title ?? current?.title ?? (this.persistedList.length > 0 ? 'Latest data view' : 'No data');\n const formattedCreatedAt =\n (selectedMeta?.createdAt ?? (current as any)?.createdAt)\n ? new Date(selectedMeta?.createdAt ?? (current as any)?.createdAt).toLocaleString()\n : null;\n const engineLabel = current?.source ?? null;\n const titleWithEngine = engineLabel ? `${baseTitle} · ${engineLabel}` : baseTitle;\n const currentLabel = formattedCreatedAt ? `${titleWithEngine} (${formattedCreatedAt})` : titleWithEngine;\n return html`\n <wa-dropdown\n placement=\"bottom-start\"\n distance=\"4\"\n size=\"small\"\n hoist\n @wa-select=${(e: CustomEvent) => this.onHistorySelect(e as any)}\n >\n <wa-button\n slot=\"trigger\"\n appearance=\"plain\"\n size=\"small\"\n with-caret\n title=\"Data view history\"\n >\n <wa-icon name=\"clock-rotate-left\" label=\"History\"></wa-icon>\n </wa-button>\n\n <wa-dropdown-item value=\"__stats__\" disabled>\n ${this.persistedList.length} data view${this.persistedList.length === 1 ? '' : 's'}\n </wa-dropdown-item>\n\n ${this.persistedList.map(\n (entry) => html`\n <wa-dropdown-item value=${entry.storageKey}>\n ${entry.source ? `${entry.title} · ${entry.source}` : entry.title}\n ${entry.createdAt\n ? html`<span style=\"opacity: 0.7; margin-left: 0.5rem; font-size: 0.75em;\">\n (${new Date(entry.createdAt).toLocaleString()})\n </span>`\n : null}\n <wa-button\n slot=\"details\"\n appearance=\"plain\"\n size=\"small\"\n title=\"Delete data view\"\n @click=${(e: Event) => this.onDeleteView(e, entry.storageKey)}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n </wa-dropdown-item>\n `\n )}\n </wa-dropdown>\n\n <wa-divider orientation=\"vertical\"></wa-divider>\n\n <wa-switch\n ?checked=${this.autoActivateTab}\n size=\"small\"\n title=\"Switch to this tab when new results arrive\"\n @change=${(e: Event) => this.onAutoActivateChange(e)}\n style=\"margin-top: 0.5rem;\"\n >\n Auto-show\n </wa-switch>\n\n ${when(current, () => html`<wa-divider orientation=\"vertical\"></wa-divider><span>${currentLabel}</span>`)}\n `;\n }\n\n private renderTable(dv: DataView) {\n const { columns, rows } = dv.data;\n if (columns.length === 0 && rows.length === 0) {\n return html`<div class=\"result-empty\">No data.</div>`;\n }\n return html`\n <div class=\"result-table-wrap\">\n <table class=\"result-table\">\n <thead>\n <tr>\n ${columns.map((col) => html`<th>${col}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${rows.map(\n (row) => html`\n <tr>\n ${row.map((cell) => html`<td>${String(cell ?? '')}</td>`)}\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n `;\n }\n\n render() {\n const dv = this.displayed;\n if (dv != null) return this.renderTable(dv);\n return html`<div class=\"result-empty\">No data.</div>`;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .result-empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n }\n `;\n\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'lyra-dataview': DataViewPart;\n }\n}\n","import Papa from 'papaparse';\n\n/** Parses CSV-like (comma-, tab-, or other delimited) text; delimiter is auto-detected. */\nexport function parseCsv(text: string): { columns: string[]; rows: unknown[][] } {\n const result = Papa.parse<Record<string, unknown>>(text, {\n header: true,\n skipEmptyLines: true,\n });\n const columns = result.meta.fields ?? [];\n const rows = result.data.map((row: Record<string, unknown>) =>\n columns.map((col: string) => row[col])\n );\n return { columns, rows };\n}\n","import { html } from 'lit';\nimport {\n rootContext,\n editorRegistry,\n contributionRegistry,\n File,\n type EditorInput,\n} from '@eclipse-lyra/core';\nimport { PANEL_BOTTOM } from '@eclipse-lyra/core';\nimport { dataviewerService } from './dataviewer-service';\nimport './dataview-part';\nimport type { DataView } from './api';\nimport { parseCsv } from './parse-csv';\n\nconst DATAVIEW_KEY_PREFIX = '.dataview/';\n\ndataviewerService.init();\nrootContext.put('dataviewerService', dataviewerService);\n\ncontributionRegistry.registerContribution(PANEL_BOTTOM, {\n name: 'view.dataviewer',\n label: 'Data Views',\n icon: 'table',\n component: (id: string) => html`<lyra-dataview id=\"${id}\"></lyra-dataview>`,\n});\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.dataviewer',\n label: 'Data View',\n icon: 'table',\n ranking: 900,\n canHandle: (input: unknown) =>\n typeof (input as EditorInput)?.key === 'string' &&\n (input as EditorInput).key.startsWith(DATAVIEW_KEY_PREFIX),\n handle: async (input: EditorInput) => {\n const storageKey = (input.data?.storageKey as string) ?? (input.key?.replace(DATAVIEW_KEY_PREFIX, '') as string);\n const entry = await dataviewerService.getView(storageKey);\n if (!entry) {\n return Promise.reject(new Error('Data view not found'));\n }\n const title = entry.title || `Data: ${entry.id}`;\n return {\n key: input.key,\n title,\n data: entry,\n icon: 'table',\n noOverflow: false,\n state: {},\n component: () =>\n html`<lyra-dataview .dataview=${entry}></lyra-dataview>`,\n } as EditorInput;\n },\n});\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.dataviewer-table',\n label: 'Table',\n icon: 'table',\n ranking: 800,\n canHandle: (input: unknown) => {\n if (!(input instanceof File)) return false;\n const lower = input.getName().toLowerCase();\n return lower.endsWith('.csv') || lower.endsWith('.tsv');\n },\n handle: async (input: File) => {\n const name = input.getName();\n const text = (await input.getContents()) as string;\n const { columns, rows } = parseCsv(text ?? '');\n const dataView: DataView = { title: name, data: { columns, rows } };\n const editorInput: EditorInput = {\n title: name,\n data: dataView,\n key: name,\n icon: 'table',\n noOverflow: false,\n state: {},\n component: () => html`<lyra-dataview .dataview=${dataView}></lyra-dataview>`,\n };\n return editorInput;\n },\n});\n\nexport default function () {}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataviewer-service.d.ts","sourceRoot":"","sources":["../src/dataviewer-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAMtC,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAS;IAEnC,IAAI,IAAI,IAAI;YAOE,aAAa;
|
|
1
|
+
{"version":3,"file":"dataviewer-service.d.ts","sourceRoot":"","sources":["../src/dataviewer-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAMtC,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAS;IAEnC,IAAI,IAAI,IAAI;YAOE,aAAa;IAkBrB,SAAS,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAczC,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAKrD,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMpD;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ extensionRegistry.registerExtension({
|
|
|
4
4
|
id: pkg.name,
|
|
5
5
|
name: "Data Viewer",
|
|
6
6
|
description: "Tabular data views, persistence, and CSV/TSV/DuckDB integration",
|
|
7
|
-
loader: () => import("./dataviewer-extension-
|
|
7
|
+
loader: () => import("./dataviewer-extension-4EAxXuUk.js"),
|
|
8
8
|
icon: "table"
|
|
9
9
|
});
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dataviewer-extension-d9jiyV7k.js","sources":["../src/dataviewer-service.ts","../src/dataview-part.ts","../src/parse-csv.ts","../src/dataviewer-extension.ts"],"sourcesContent":["import { persistenceService, subscribe } from '@eclipse-lyra/core';\nimport { v4 } from '@eclipse-lyra/core/externals/third-party';\nimport type { DataView } from './api';\nimport { TOPIC_DATAVIEW_PUBLISH } from './api';\n\nconst KEY_PREFIX = 'dataview/';\nconst KEY_INDEX = KEY_PREFIX + 'index';\n\nexport interface DataviewListEntry {\n storageKey: string;\n title: string;\n createdAt: number;\n}\n\ntype IndexEntry = DataviewListEntry;\n\nexport class DataviewerService {\n private subscriptionToken?: string;\n\n init(): void {\n if (this.subscriptionToken !== undefined) return;\n this.subscriptionToken = subscribe(TOPIC_DATAVIEW_PUBLISH, (payload: DataView) => {\n void this.handlePublish(payload);\n });\n }\n\n private async handlePublish(payload: DataView): Promise<void> {\n const storageKey = v4();\n const createdAt = Date.now();\n const entry: DataView = {\n id: payload.id ?? storageKey,\n title: payload.title,\n data: payload.data,\n source: payload.source,\n createdAt,\n };\n await persistenceService.persistObject(KEY_PREFIX + storageKey, entry);\n const index = (await persistenceService.getObject(KEY_INDEX)) as IndexEntry[] | undefined;\n const list = Array.isArray(index) ? index : [];\n list.push({ storageKey, title: payload.title, createdAt });\n await persistenceService.persistObject(KEY_INDEX, list);\n }\n\n async listViews(): Promise<DataviewListEntry[]> {\n const raw = await persistenceService.getObject(KEY_INDEX);\n if (!Array.isArray(raw) || raw.length === 0) return [];\n if (typeof raw[0] === 'string') {\n return (raw as string[]).map((storageKey) => ({\n storageKey,\n title: storageKey,\n createdAt: 0,\n }));\n }\n const list = raw as IndexEntry[];\n return [...list].sort((a, b) => a.createdAt - b.createdAt);\n }\n\n async getView(storageKey: string): Promise<DataView | null> {\n const entry = await persistenceService.getObject(KEY_PREFIX + storageKey);\n return entry ?? null;\n }\n\n async deleteView(storageKey: string): Promise<void> {\n const index = (await persistenceService.getObject(KEY_INDEX)) as IndexEntry[] | undefined;\n const list = Array.isArray(index) ? index.filter((e) => e.storageKey !== storageKey) : [];\n await persistenceService.persistObject(KEY_INDEX, list);\n await persistenceService.persistObject(KEY_PREFIX + storageKey, null);\n }\n}\n\nexport const dataviewerService = new DataviewerService();\n","import { customElement, property, state } from 'lit/decorators.js';\nimport { css, html } from 'lit';\nimport { LyraPart } from '@eclipse-lyra/core';\nimport { toastError } from '@eclipse-lyra/core';\nimport { dataviewerService, type DataviewListEntry } from './dataviewer-service';\nimport type { DataView } from './api';\nimport { TOPIC_DATAVIEW_PUBLISH } from './api';\n\n@customElement('lyra-dataview')\nexport class DataViewPart extends LyraPart {\n @property({ attribute: false })\n dataview: DataView | null = null;\n\n @state()\n private persistedList: DataviewListEntry[] = [];\n\n @state()\n private selectedStorageKey = '';\n\n @state()\n private selectedView: DataView | null = null;\n\n @state()\n private loadingList = true;\n\n private get displayed(): DataView | null {\n return this.selectedView ?? this.dataview;\n }\n\n protected async doInitUI() {\n this.subscribe(TOPIC_DATAVIEW_PUBLISH, () => this.refreshPersistedList(true));\n await this.refreshPersistedList(false);\n }\n\n private async refreshPersistedList(selectLatest: boolean): Promise<void> {\n this.loadingList = true;\n this.requestUpdate();\n try {\n this.persistedList = await dataviewerService.listViews();\n if (selectLatest && this.persistedList.length > 0) {\n const latest = this.persistedList[this.persistedList.length - 1];\n this.selectedStorageKey = latest.storageKey;\n this.selectedView = await dataviewerService.getView(latest.storageKey);\n } else if (this.selectedStorageKey) {\n this.selectedView = await dataviewerService.getView(this.selectedStorageKey);\n } else {\n this.selectedView = null;\n }\n } catch (e) {\n toastError(e instanceof Error ? e.message : String(e));\n this.persistedList = [];\n this.selectedView = null;\n } finally {\n this.loadingList = false;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private async selectStorageKey(key: string): Promise<void> {\n this.selectedStorageKey = key;\n if (!key) {\n this.selectedView = null;\n this.requestUpdate();\n return;\n }\n try {\n this.selectedView = await dataviewerService.getView(key);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n this.selectedView = null;\n }\n this.requestUpdate();\n }\n\n private async onHistorySelect(e: CustomEvent<{ item?: { value?: string } }>): Promise<void> {\n const value = e.detail?.item?.value ?? '';\n if (!value || value === '__stats__') {\n // Ignore the stats item and empty\n return;\n }\n await this.selectStorageKey(value);\n }\n\n private async onDeleteView(e: Event, storageKey: string): Promise<void> {\n e.stopPropagation();\n e.preventDefault();\n try {\n await dataviewerService.deleteView(storageKey);\n const deletedWasSelected = this.selectedStorageKey === storageKey;\n if (deletedWasSelected) {\n this.selectedStorageKey = '';\n this.selectedView = null;\n }\n await this.refreshPersistedList(true);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n protected renderToolbar() {\n const current = this.selectedView ?? this.dataview;\n const selectedMeta = this.persistedList.find((e) => e.storageKey === this.selectedStorageKey);\n const baseTitle = selectedMeta?.title ?? current?.title ?? (this.persistedList.length > 0 ? 'Latest data view' : 'No data');\n const formattedCreatedAt =\n (selectedMeta?.createdAt ?? (current as any)?.createdAt)\n ? new Date(selectedMeta?.createdAt ?? (current as any)?.createdAt).toLocaleString()\n : null;\n const currentLabel = formattedCreatedAt ? `${baseTitle} (${formattedCreatedAt})` : baseTitle;\n return html`\n <span>${currentLabel}</span>\n <wa-dropdown\n placement=\"bottom-start\"\n distance=\"4\"\n size=\"small\"\n hoist\n @wa-select=${(e: CustomEvent) => this.onHistorySelect(e as any)}\n >\n <wa-button\n slot=\"trigger\"\n appearance=\"plain\"\n size=\"small\"\n with-caret\n title=\"Data view history\"\n >\n <wa-icon name=\"clock-rotate-left\" label=\"History\"></wa-icon>\n </wa-button>\n\n <wa-dropdown-item value=\"__stats__\" disabled>\n ${this.persistedList.length} data view${this.persistedList.length === 1 ? '' : 's'}\n </wa-dropdown-item>\n\n ${this.persistedList.map(\n (entry) => html`\n <wa-dropdown-item value=${entry.storageKey}>\n ${entry.title}\n ${entry.createdAt\n ? html`<span style=\"opacity: 0.7; margin-left: 0.5rem; font-size: 0.75em;\">\n (${new Date(entry.createdAt).toLocaleString()})\n </span>`\n : null}\n <wa-button\n slot=\"details\"\n appearance=\"plain\"\n size=\"small\"\n title=\"Delete data view\"\n @click=${(e: Event) => this.onDeleteView(e, entry.storageKey)}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n </wa-dropdown-item>\n `\n )}\n </wa-dropdown>\n `;\n }\n\n private renderTable(dv: DataView) {\n const { columns, rows } = dv.data;\n if (columns.length === 0 && rows.length === 0) {\n return html`<div class=\"result-empty\">No data.</div>`;\n }\n return html`\n <div class=\"result-table-wrap\">\n <table class=\"result-table\">\n <thead>\n <tr>\n ${columns.map((col) => html`<th>${col}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${rows.map(\n (row) => html`\n <tr>\n ${row.map((cell) => html`<td>${String(cell ?? '')}</td>`)}\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n `;\n }\n\n render() {\n const dv = this.displayed;\n if (dv != null) return this.renderTable(dv);\n return html`<div class=\"result-empty\">No data.</div>`;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .result-empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n }\n `;\n\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'lyra-dataview': DataViewPart;\n }\n}\n","import Papa from 'papaparse';\n\n/** Parses CSV-like (comma-, tab-, or other delimited) text; delimiter is auto-detected. */\nexport function parseCsv(text: string): { columns: string[]; rows: unknown[][] } {\n const result = Papa.parse<Record<string, unknown>>(text, {\n header: true,\n skipEmptyLines: true,\n });\n const columns = result.meta.fields ?? [];\n const rows = result.data.map((row: Record<string, unknown>) =>\n columns.map((col: string) => row[col])\n );\n return { columns, rows };\n}\n","import { html } from 'lit';\nimport {\n rootContext,\n editorRegistry,\n contributionRegistry,\n File,\n type EditorInput,\n} from '@eclipse-lyra/core';\nimport { PANEL_BOTTOM } from '@eclipse-lyra/core';\nimport { dataviewerService } from './dataviewer-service';\nimport './dataview-part';\nimport type { DataView } from './api';\nimport { parseCsv } from './parse-csv';\n\nconst DATAVIEW_KEY_PREFIX = '.dataview/';\n\ndataviewerService.init();\nrootContext.put('dataviewerService', dataviewerService);\n\ncontributionRegistry.registerContribution(PANEL_BOTTOM, {\n name: 'view.dataviewer',\n label: 'Data Views',\n icon: 'table',\n component: (id: string) => html`<lyra-dataview id=\"${id}\"></lyra-dataview>`,\n});\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.dataviewer',\n label: 'Data View',\n icon: 'table',\n ranking: 900,\n canHandle: (input: unknown) =>\n typeof (input as EditorInput)?.key === 'string' &&\n (input as EditorInput).key.startsWith(DATAVIEW_KEY_PREFIX),\n handle: async (input: EditorInput) => {\n const storageKey = (input.data?.storageKey as string) ?? (input.key?.replace(DATAVIEW_KEY_PREFIX, '') as string);\n const entry = await dataviewerService.getView(storageKey);\n if (!entry) {\n return Promise.reject(new Error('Data view not found'));\n }\n const title = entry.title || `Data: ${entry.id}`;\n return {\n key: input.key,\n title,\n data: entry,\n icon: 'table',\n noOverflow: false,\n state: {},\n component: () =>\n html`<lyra-dataview .dataview=${entry}></lyra-dataview>`,\n } as EditorInput;\n },\n});\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.dataviewer-table',\n label: 'Table',\n icon: 'table',\n ranking: 800,\n canHandle: (input: unknown) => {\n if (!(input instanceof File)) return false;\n const lower = input.getName().toLowerCase();\n return lower.endsWith('.csv') || lower.endsWith('.tsv');\n },\n handle: async (input: File) => {\n const name = input.getName();\n const text = (await input.getContents()) as string;\n const { columns, rows } = parseCsv(text ?? '');\n const dataView: DataView = { title: name, data: { columns, rows } };\n const editorInput: EditorInput = {\n title: name,\n data: dataView,\n key: name,\n icon: 'table',\n noOverflow: false,\n state: {},\n component: () => html`<lyra-dataview .dataview=${dataView}></lyra-dataview>`,\n };\n return editorInput;\n },\n});\n\nexport default function () {}\n"],"names":[],"mappings":"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"}
|