sqlite-hub 0.5.0 → 0.7.0

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.
Files changed (50) hide show
  1. package/README.md +109 -2
  2. package/bin/sqlite-hub.js +285 -4
  3. package/changelog.md +15 -0
  4. package/frontend/assets/mockups/connections.png +0 -0
  5. package/frontend/assets/mockups/data.png +0 -0
  6. package/frontend/assets/mockups/data_row_editor.png +0 -0
  7. package/frontend/assets/mockups/home.png +0 -0
  8. package/frontend/assets/mockups/sql_editor.png +0 -0
  9. package/frontend/assets/mockups/sql_editor_croped.png +0 -0
  10. package/frontend/assets/mockups/sql_editor_querydetail.png +0 -0
  11. package/frontend/assets/mockups/structure.png +0 -0
  12. package/frontend/assets/mockups/structure_inspector.png +0 -0
  13. package/frontend/index.html +1 -0
  14. package/frontend/js/api.js +49 -0
  15. package/frontend/js/app.js +377 -9
  16. package/frontend/js/components/modal.js +314 -1
  17. package/frontend/js/components/queryChartRenderer.js +125 -0
  18. package/frontend/js/components/queryEditor.js +37 -8
  19. package/frontend/js/components/queryHistoryPanel.js +16 -5
  20. package/frontend/js/components/sidebar.js +2 -0
  21. package/frontend/js/components/tableDesignerEditor.js +356 -0
  22. package/frontend/js/components/tableDesignerSidebar.js +129 -0
  23. package/frontend/js/components/tableDesignerSqlPreview.js +40 -0
  24. package/frontend/js/lib/queryChartOptions.js +283 -0
  25. package/frontend/js/lib/queryCharts.js +560 -0
  26. package/frontend/js/router.js +18 -0
  27. package/frontend/js/store.js +914 -1
  28. package/frontend/js/utils/tableDesigner.js +1192 -0
  29. package/frontend/js/views/charts.js +471 -0
  30. package/frontend/js/views/data.js +281 -277
  31. package/frontend/js/views/editor.js +19 -13
  32. package/frontend/js/views/structure.js +81 -39
  33. package/frontend/js/views/tableDesigner.js +37 -0
  34. package/frontend/styles/base.css +87 -73
  35. package/frontend/styles/components.css +790 -251
  36. package/frontend/styles/views.css +316 -46
  37. package/package.json +2 -1
  38. package/server/routes/charts.js +153 -0
  39. package/server/routes/tableDesigner.js +60 -0
  40. package/server/server.js +10 -0
  41. package/server/services/sqlite/tableDesigner/changeAnalysis.js +295 -0
  42. package/server/services/sqlite/tableDesigner/schemaMapping.js +233 -0
  43. package/server/services/sqlite/tableDesigner/sql.js +63 -0
  44. package/server/services/sqlite/tableDesigner/validation.js +245 -0
  45. package/server/services/sqlite/tableDesignerService.js +181 -0
  46. package/server/services/storage/appStateStore.js +400 -1
  47. package/server/services/storage/queryHistoryChartUtils.js +145 -0
  48. package/frontend/assets/mockups/data_edit.png +0 -0
  49. package/frontend/assets/mockups/graph_visualize.png +0 -0
  50. package/frontend/assets/mockups/overview.png +0 -0
@@ -0,0 +1,283 @@
1
+ import {
2
+ coerceDatetimeChartValue,
3
+ coerceNumericChartValue,
4
+ formatTimeOfDayAxisValue,
5
+ formatQueryChartAxisValue,
6
+ getAnalysisColumn,
7
+ sortQueryChartRows,
8
+ } from "./queryCharts.js";
9
+
10
+ const CHART_PALETTE = ["#FCE300", "#2DFAFF", "#FFB4AB", "#CDC7AB", "#7DD3FC", "#86EFAC"];
11
+
12
+ function buildCommonOption() {
13
+ return {
14
+ animationDuration: 220,
15
+ backgroundColor: "transparent",
16
+ color: CHART_PALETTE,
17
+ textStyle: {
18
+ color: "#e5e2e1",
19
+ fontFamily: "Inter, sans-serif",
20
+ },
21
+ tooltip: {
22
+ backgroundColor: "#201f1f",
23
+ borderColor: "rgba(252, 227, 0, 0.14)",
24
+ textStyle: {
25
+ color: "#e5e2e1",
26
+ },
27
+ },
28
+ grid: {
29
+ left: 48,
30
+ right: 24,
31
+ top: 36,
32
+ bottom: 48,
33
+ containLabel: true,
34
+ },
35
+ };
36
+ }
37
+
38
+ function buildAxisLabel(color = "#cdc7ab") {
39
+ return {
40
+ color,
41
+ fontFamily: "Roboto Mono, monospace",
42
+ fontSize: 11,
43
+ };
44
+ }
45
+
46
+ function buildLineLabelConfig(enabled) {
47
+ return enabled
48
+ ? {
49
+ show: true,
50
+ color: "#e5e2e1",
51
+ fontFamily: "Roboto Mono, monospace",
52
+ fontSize: 10,
53
+ }
54
+ : { show: false };
55
+ }
56
+
57
+ export function buildBarChartOption(chart, rows) {
58
+ const sortedRows = sortQueryChartRows(rows, chart.config.x_column, chart.config.sort_direction);
59
+
60
+ return {
61
+ ...buildCommonOption(),
62
+ legend: {
63
+ show: chart.config.show_legend,
64
+ textStyle: { color: "#cdc7ab" },
65
+ },
66
+ xAxis: {
67
+ type: "category",
68
+ data: sortedRows.map((row) => formatQueryChartAxisValue(row[chart.config.x_column])),
69
+ axisLabel: buildAxisLabel(),
70
+ axisLine: { lineStyle: { color: "rgba(205, 199, 171, 0.28)" } },
71
+ },
72
+ yAxis: {
73
+ type: "value",
74
+ axisLabel: buildAxisLabel(),
75
+ splitLine: { lineStyle: { color: "rgba(205, 199, 171, 0.12)" } },
76
+ },
77
+ series: [
78
+ {
79
+ name: chart.name,
80
+ type: "bar",
81
+ label: buildLineLabelConfig(chart.config.show_labels),
82
+ emphasis: { focus: "series" },
83
+ data: sortedRows.map((row) => coerceNumericChartValue(row[chart.config.y_column]) ?? 0),
84
+ },
85
+ ],
86
+ };
87
+ }
88
+
89
+ export function buildLineChartOption(chart, rows) {
90
+ const sortedRows = sortQueryChartRows(rows, chart.config.x_column, chart.config.sort_direction);
91
+
92
+ return {
93
+ ...buildCommonOption(),
94
+ legend: {
95
+ show: chart.config.show_legend,
96
+ textStyle: { color: "#cdc7ab" },
97
+ },
98
+ xAxis: {
99
+ type: "category",
100
+ data: sortedRows.map((row) => formatQueryChartAxisValue(row[chart.config.x_column])),
101
+ axisLabel: buildAxisLabel(),
102
+ axisLine: { lineStyle: { color: "rgba(205, 199, 171, 0.28)" } },
103
+ },
104
+ yAxis: {
105
+ type: "value",
106
+ axisLabel: buildAxisLabel(),
107
+ splitLine: { lineStyle: { color: "rgba(205, 199, 171, 0.12)" } },
108
+ },
109
+ series: [
110
+ {
111
+ name: chart.name,
112
+ type: "line",
113
+ smooth: chart.config.smooth,
114
+ showSymbol: sortedRows.length < 60,
115
+ symbolSize: 8,
116
+ lineStyle: {
117
+ width: 3,
118
+ },
119
+ label: buildLineLabelConfig(chart.config.show_labels),
120
+ data: sortedRows.map((row) => coerceNumericChartValue(row[chart.config.y_column]) ?? 0),
121
+ },
122
+ ],
123
+ };
124
+ }
125
+
126
+ export function buildPieChartOption(chart, rows) {
127
+ return {
128
+ ...buildCommonOption(),
129
+ legend: {
130
+ show: chart.config.show_legend,
131
+ orient: "vertical",
132
+ right: 0,
133
+ top: "middle",
134
+ textStyle: { color: "#cdc7ab" },
135
+ },
136
+ series: [
137
+ {
138
+ name: chart.name,
139
+ type: "pie",
140
+ radius: chart.config.donut ? ["42%", "70%"] : "70%",
141
+ center: chart.config.show_legend ? ["36%", "50%"] : ["50%", "50%"],
142
+ label: {
143
+ show: chart.config.show_labels,
144
+ color: "#e5e2e1",
145
+ formatter: "{b}: {c}",
146
+ fontSize: 11,
147
+ },
148
+ data: rows.map((row) => ({
149
+ name: formatQueryChartAxisValue(row[chart.config.label_column]),
150
+ value: coerceNumericChartValue(row[chart.config.value_column]) ?? 0,
151
+ })),
152
+ },
153
+ ],
154
+ };
155
+ }
156
+
157
+ function resolveScatterAxisType(column) {
158
+ if (column?.type === "datetime") {
159
+ return column.datetimeKind === "time" ? "time-of-day" : "time";
160
+ }
161
+
162
+ return "value";
163
+ }
164
+
165
+ function buildScatterAxisConfig(column, columnName) {
166
+ const axisType = resolveScatterAxisType(column);
167
+ const baseConfig = {
168
+ axisLabel: buildAxisLabel(),
169
+ splitLine: { lineStyle: { color: "rgba(205, 199, 171, 0.12)" } },
170
+ name: columnName,
171
+ nameTextStyle: buildAxisLabel("#FCE300"),
172
+ };
173
+
174
+ if (axisType === "time") {
175
+ return {
176
+ ...baseConfig,
177
+ type: "time",
178
+ };
179
+ }
180
+
181
+ if (axisType === "time-of-day") {
182
+ return {
183
+ ...baseConfig,
184
+ type: "value",
185
+ axisLabel: {
186
+ ...buildAxisLabel(),
187
+ formatter: (value) => formatTimeOfDayAxisValue(value),
188
+ },
189
+ };
190
+ }
191
+
192
+ return {
193
+ ...baseConfig,
194
+ type: "value",
195
+ };
196
+ }
197
+
198
+ function coerceScatterAxisValue(value, axisType) {
199
+ if (axisType === "time" || axisType === "time-of-day") {
200
+ return coerceDatetimeChartValue(value);
201
+ }
202
+
203
+ return coerceNumericChartValue(value);
204
+ }
205
+
206
+ function buildScatterSeries(chart, rows, analysis) {
207
+ const groups = new Map();
208
+ const xColumn = getAnalysisColumn(analysis, chart.config.x_column);
209
+ const yColumn = getAnalysisColumn(analysis, chart.config.y_column);
210
+ const xAxisType = resolveScatterAxisType(xColumn);
211
+ const yAxisType = resolveScatterAxisType(yColumn);
212
+ const sizeValues = rows
213
+ .map((row) => coerceNumericChartValue(row[chart.config.size_column]))
214
+ .filter((value) => value !== null);
215
+ const minSize = sizeValues.length ? Math.min(...sizeValues) : 0;
216
+ const maxSize = sizeValues.length ? Math.max(...sizeValues) : 0;
217
+
218
+ function resolveSymbolSize(sizeValue) {
219
+ if (sizeValue === null || sizeValue === undefined) {
220
+ return 14;
221
+ }
222
+
223
+ if (maxSize <= minSize) {
224
+ return 20;
225
+ }
226
+
227
+ return 10 + ((sizeValue - minSize) / (maxSize - minSize)) * 24;
228
+ }
229
+
230
+ rows.forEach((row) => {
231
+ const seriesName = chart.config.series_column
232
+ ? formatQueryChartAxisValue(row[chart.config.series_column])
233
+ : chart.name;
234
+ const x = coerceScatterAxisValue(row[chart.config.x_column], xAxisType);
235
+ const y = coerceScatterAxisValue(row[chart.config.y_column], yAxisType);
236
+
237
+ if (x === null || y === null) {
238
+ return;
239
+ }
240
+
241
+ const point = {
242
+ value: [
243
+ x,
244
+ y,
245
+ chart.config.size_column ? coerceNumericChartValue(row[chart.config.size_column]) : null,
246
+ ],
247
+ symbolSize: resolveSymbolSize(
248
+ chart.config.size_column ? coerceNumericChartValue(row[chart.config.size_column]) : null
249
+ ),
250
+ };
251
+
252
+ if (!groups.has(seriesName)) {
253
+ groups.set(seriesName, []);
254
+ }
255
+
256
+ groups.get(seriesName).push(point);
257
+ });
258
+
259
+ return Array.from(groups.entries()).map(([seriesName, data]) => ({
260
+ name: seriesName,
261
+ type: "scatter",
262
+ data,
263
+ symbolSize(value, params) {
264
+ return params?.data?.symbolSize ?? resolveSymbolSize(value?.[2] ?? null);
265
+ },
266
+ }));
267
+ }
268
+
269
+ export function buildScatterChartOption(chart, rows, analysis = null) {
270
+ const xColumn = getAnalysisColumn(analysis, chart.config.x_column);
271
+ const yColumn = getAnalysisColumn(analysis, chart.config.y_column);
272
+
273
+ return {
274
+ ...buildCommonOption(),
275
+ legend: {
276
+ show: chart.config.show_legend,
277
+ textStyle: { color: "#cdc7ab" },
278
+ },
279
+ xAxis: buildScatterAxisConfig(xColumn, chart.config.x_column),
280
+ yAxis: buildScatterAxisConfig(yColumn, chart.config.y_column),
281
+ series: buildScatterSeries(chart, rows, analysis),
282
+ };
283
+ }