@antelopejs/dms-database 0.0.14 → 0.1.1

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 (173) hide show
  1. package/README.md +30 -5
  2. package/dist/db/models/query_history.model.d.ts +1 -0
  3. package/dist/db/models/query_history.model.js +6 -0
  4. package/dist/db/models/query_history.model.js.map +1 -1
  5. package/dist/db/tables/query_history.table.d.ts +3 -0
  6. package/dist/db/tables/query_history.table.js +12 -0
  7. package/dist/db/tables/query_history.table.js.map +1 -1
  8. package/dist/db/tables/saved_queries.table.d.ts +1 -0
  9. package/dist/db/tables/saved_queries.table.js +4 -0
  10. package/dist/db/tables/saved_queries.table.js.map +1 -1
  11. package/dist/i18n/messages.d.ts +39 -0
  12. package/dist/i18n/messages.js +64 -0
  13. package/dist/i18n/messages.js.map +1 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/module.d.ts +11 -0
  18. package/dist/module.js +55 -0
  19. package/dist/module.js.map +1 -0
  20. package/dist/pages/data.d.ts +1 -1
  21. package/dist/pages/data.js +9 -6
  22. package/dist/pages/data.js.map +1 -1
  23. package/dist/pages/diagram.d.ts +9 -0
  24. package/dist/pages/diagram.js +45 -0
  25. package/dist/pages/diagram.js.map +1 -0
  26. package/dist/pages/index.d.ts +1 -0
  27. package/dist/pages/index.js +1 -0
  28. package/dist/pages/index.js.map +1 -1
  29. package/dist/pages/overview.d.ts +4 -1
  30. package/dist/pages/overview.js +113 -6
  31. package/dist/pages/overview.js.map +1 -1
  32. package/dist/pages/query.d.ts +1 -1
  33. package/dist/pages/query.js +22 -6
  34. package/dist/pages/query.js.map +1 -1
  35. package/dist/pages/schemas.d.ts +2 -1
  36. package/dist/pages/schemas.js +143 -6
  37. package/dist/pages/schemas.js.map +1 -1
  38. package/dist/routes/data.d.ts +8 -0
  39. package/dist/routes/data.js +84 -21
  40. package/dist/routes/data.js.map +1 -1
  41. package/dist/routes/index.d.ts +1 -0
  42. package/dist/routes/index.js +1 -0
  43. package/dist/routes/index.js.map +1 -1
  44. package/dist/routes/overview.d.ts +12 -0
  45. package/dist/routes/overview.js +55 -0
  46. package/dist/routes/overview.js.map +1 -0
  47. package/dist/routes/query.d.ts +5 -1
  48. package/dist/routes/query.js +162 -27
  49. package/dist/routes/query.js.map +1 -1
  50. package/dist/routes/tables.d.ts +15 -12
  51. package/dist/routes/tables.js +95 -55
  52. package/dist/routes/tables.js.map +1 -1
  53. package/dist/service/catalog.d.ts +3 -0
  54. package/dist/service/catalog.js +26 -0
  55. package/dist/service/catalog.js.map +1 -0
  56. package/dist/service/health.d.ts +3 -3
  57. package/dist/service/health.js +17 -14
  58. package/dist/service/health.js.map +1 -1
  59. package/dist/service/introspect.d.ts +3 -1
  60. package/dist/service/introspect.js +131 -43
  61. package/dist/service/introspect.js.map +1 -1
  62. package/dist/service/overview.d.ts +9 -0
  63. package/dist/service/overview.js +113 -0
  64. package/dist/service/overview.js.map +1 -0
  65. package/dist/service/queryInspection.d.ts +15 -0
  66. package/dist/service/queryInspection.js +107 -0
  67. package/dist/service/queryInspection.js.map +1 -0
  68. package/dist/service/references.d.ts +9 -0
  69. package/dist/service/references.js +52 -0
  70. package/dist/service/references.js.map +1 -0
  71. package/dist/service/schemaFilters.d.ts +26 -0
  72. package/dist/service/schemaFilters.js +42 -0
  73. package/dist/service/schemaFilters.js.map +1 -0
  74. package/dist/service/stagedSerialization.d.ts +2 -0
  75. package/dist/service/stagedSerialization.js +38 -10
  76. package/dist/service/stagedSerialization.js.map +1 -1
  77. package/dist/service/types.d.ts +11 -1
  78. package/dist/types/constants.d.ts +2 -0
  79. package/dist/types/constants.js +3 -1
  80. package/dist/types/constants.js.map +1 -1
  81. package/dist/utils/query.d.ts +0 -2
  82. package/dist/utils/query.js +0 -20
  83. package/dist/utils/query.js.map +1 -1
  84. package/frontend-vue/app/{composables → build/composables}/useDataBrowserGrid.ts +65 -50
  85. package/frontend-vue/app/build/composables/useDataBrowserTabs.ts +366 -0
  86. package/frontend-vue/app/build/composables/useDatabaseHealth.ts +50 -0
  87. package/frontend-vue/app/build/composables/useDatabaseSchemas.ts +140 -0
  88. package/frontend-vue/app/{composables → build/composables}/useDiagramPersistence.ts +47 -39
  89. package/frontend-vue/app/build/composables/useQueryRuntime.ts +217 -0
  90. package/frontend-vue/app/build/composables/useQueryStore.ts +162 -0
  91. package/frontend-vue/app/build/data/cellValues.ts +132 -0
  92. package/frontend-vue/app/build/data/instanceOptions.ts +36 -0
  93. package/frontend-vue/app/build/data/pickerMenus.ts +175 -0
  94. package/frontend-vue/app/build/data/recentTables.ts +48 -0
  95. package/frontend-vue/app/build/data/stagedEdits.ts +117 -0
  96. package/frontend-vue/app/build/data/stagedWrites.ts +64 -0
  97. package/frontend-vue/app/build/data/useStagedSave.ts +298 -0
  98. package/frontend-vue/app/build/diagram/autosave.ts +72 -0
  99. package/frontend-vue/app/build/diagram/graph.ts +585 -0
  100. package/frontend-vue/app/build/diagram/history.ts +178 -0
  101. package/frontend-vue/app/build/diagram/shortcuts.ts +62 -0
  102. package/frontend-vue/app/build/diagram/sync.ts +137 -0
  103. package/frontend-vue/app/build/query/completion.ts +100 -0
  104. package/frontend-vue/app/build/query/csv.ts +32 -0
  105. package/frontend-vue/app/build/query/examples.ts +38 -0
  106. package/frontend-vue/app/build/query/runs.ts +168 -0
  107. package/frontend-vue/app/build/query/tableColumns.ts +35 -0
  108. package/frontend-vue/app/build/query/target.ts +143 -0
  109. package/frontend-vue/app/build/schemas/filterState.ts +128 -0
  110. package/frontend-vue/app/build/schemas/useSchemasListing.ts +62 -0
  111. package/frontend-vue/app/build/utils/databaseLinks.ts +98 -0
  112. package/frontend-vue/app/build/utils/fieldTypes.ts +198 -0
  113. package/frontend-vue/app/build/utils/relativeTime.ts +19 -0
  114. package/frontend-vue/app/{utils → build/utils}/stagedSerialization.ts +7 -1
  115. package/frontend-vue/app/components/ConnectionStatus.vue +122 -0
  116. package/frontend-vue/app/components/DataBrowser.vue +126 -0
  117. package/frontend-vue/app/components/DataBrowserSidebar.vue +293 -210
  118. package/frontend-vue/app/components/DataBrowserTabBar.vue +185 -93
  119. package/frontend-vue/app/components/DataFilterBar.vue +163 -0
  120. package/frontend-vue/app/components/DataGrid.vue +737 -499
  121. package/frontend-vue/app/components/DataGridCell.vue +125 -77
  122. package/frontend-vue/app/components/DataGridHeaderCell.vue +119 -81
  123. package/frontend-vue/app/components/DiagramNoteNode.vue +81 -63
  124. package/frontend-vue/app/components/DiagramRelationEdge.vue +57 -27
  125. package/frontend-vue/app/components/DiagramStubNode.vue +16 -17
  126. package/frontend-vue/app/components/DiagramTableNode.vue +106 -68
  127. package/frontend-vue/app/components/InstancePicker.vue +195 -0
  128. package/frontend-vue/app/components/JsonCellPanel.vue +55 -41
  129. package/frontend-vue/app/components/QueryBuilderPanel.vue +290 -238
  130. package/frontend-vue/app/components/QueryConsole.vue +726 -0
  131. package/frontend-vue/app/components/QueryLibrary.vue +314 -0
  132. package/frontend-vue/app/components/QueryResultPanel.vue +556 -126
  133. package/frontend-vue/app/components/RowDrawer.vue +520 -0
  134. package/frontend-vue/app/components/SchemaDiagram.vue +1016 -1051
  135. package/frontend-vue/app/components/SchemaPicker.vue +86 -0
  136. package/frontend-vue/app/components/SchemasFilterBar.vue +201 -0
  137. package/frontend-vue/app/components/TableInspector.vue +741 -0
  138. package/frontend-vue/app/config/shortcuts-registry.ts +65 -0
  139. package/frontend-vue/dms.frontend.ts +5 -14
  140. package/frontend-vue/i18n/locales/database-en-GB.json +527 -193
  141. package/frontend-vue/i18n/locales/database-fr-FR.json +529 -195
  142. package/frontend-vue/package.json +2 -1
  143. package/frontend-vue/pnpm-lock.yaml +2601 -858
  144. package/frontend-vue/pnpm-workspace.yaml +1 -1
  145. package/frontend-vue/tests/dataBrowser.test.ts +206 -0
  146. package/frontend-vue/tests/diagram.test.ts +516 -0
  147. package/frontend-vue/tests/helpers.test.ts +205 -0
  148. package/frontend-vue/tests/instanceOptions.test.ts +53 -0
  149. package/frontend-vue/tests/locales.test.ts +56 -0
  150. package/frontend-vue/tests/persistence.test.ts +106 -5
  151. package/frontend-vue/tests/pickerMenus.test.ts +254 -0
  152. package/frontend-vue/tests/queryConsole.test.ts +282 -0
  153. package/frontend-vue/tests/queryRuntime.test.ts +2 -2
  154. package/frontend-vue/tests/registration.test.ts +36 -25
  155. package/frontend-vue/tests/schemasFilters.test.ts +115 -0
  156. package/package.json +7 -7
  157. package/frontend-vue/app/components/QueryFavoritesPanel.vue +0 -127
  158. package/frontend-vue/app/components/QueryHistoryPanel.vue +0 -134
  159. package/frontend-vue/app/components/SchemaTableInspector.vue +0 -278
  160. package/frontend-vue/app/composables/useDataBrowserTabs.ts +0 -255
  161. package/frontend-vue/app/composables/useDatabaseHealth.ts +0 -50
  162. package/frontend-vue/app/composables/useDatabaseSchemas.ts +0 -92
  163. package/frontend-vue/app/composables/useQueryRuntime.ts +0 -118
  164. package/frontend-vue/app/composables/useQueryStore.ts +0 -117
  165. package/frontend-vue/app/composables/useTableViewRowClick.ts +0 -22
  166. package/frontend-vue/app/custom-pages/database/data.vue +0 -41
  167. package/frontend-vue/app/custom-pages/database/overview.vue +0 -367
  168. package/frontend-vue/app/custom-pages/database/query.vue +0 -436
  169. package/frontend-vue/app/custom-pages/database/schemas.vue +0 -218
  170. package/frontend-vue/app/utils/databaseFieldModifiers.ts +0 -33
  171. package/frontend-vue/app/utils/databaseFieldTypeIcons.ts +0 -224
  172. package/frontend-vue/app/utils/dmsTableView.ts +0 -83
  173. package/frontend-vue/app/utils/relativeTime.ts +0 -18
@@ -0,0 +1,314 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ dayLabel,
4
+ groupByDay,
5
+ HISTORY_KEPT,
6
+ RUN_DOT_CLASSES,
7
+ runKind,
8
+ } from '../build/query/runs'
9
+ import { describeTarget, runTarget } from '../build/query/target'
10
+ import type {
11
+ HistoryEntry,
12
+ SavedQuery,
13
+ } from '../build/composables/useQueryStore'
14
+
15
+ // The query library (D-11): one rail for the runs of the caller (History),
16
+ // the queries they saved (Saved) and the ones teammates shared (Team), with
17
+ // one search over all three. Runs are grouped by day and carry a dot telling
18
+ // a fast, slow, failed or writing run apart.
19
+
20
+ type LibraryTab = 'history' | 'saved' | 'team'
21
+
22
+ const props = defineProps<{
23
+ history: HistoryEntry[]
24
+ saved: SavedQuery[]
25
+ team: SavedQuery[]
26
+ /** The saved query open in the editor. */
27
+ activeSavedId: string | null
28
+ activeHistoryId: string | null
29
+ loading: boolean
30
+ }>()
31
+
32
+ const emit = defineEmits<{
33
+ 'open-history': [entry: HistoryEntry]
34
+ 'save-history': [entry: HistoryEntry]
35
+ 'open-saved': [query: SavedQuery]
36
+ 'edit-saved': [query: SavedQuery]
37
+ 'delete-saved': [query: SavedQuery]
38
+ 'clear-history': []
39
+ }>()
40
+
41
+ const { t, n, locale } = useI18n()
42
+
43
+ const tab = ref<LibraryTab>('history')
44
+ const search = ref('')
45
+
46
+ const tabs = computed(() => [
47
+ { value: 'history', label: t('dms_database.query.library.history') },
48
+ {
49
+ value: 'saved',
50
+ label: t('dms_database.query.library.saved'),
51
+ badge: props.saved.length,
52
+ },
53
+ {
54
+ value: 'team',
55
+ label: t('dms_database.query.library.team'),
56
+ badge: props.team.length,
57
+ },
58
+ ])
59
+
60
+ function matches(...texts: (string | undefined)[]): boolean {
61
+ const needle = search.value.trim().toLowerCase()
62
+ return !needle || texts.some((text) => text?.toLowerCase().includes(needle))
63
+ }
64
+
65
+ // Each run leads with where it pointed: runs on one schema all start alike.
66
+ const runs = computed(() =>
67
+ props.history.map((entry) => ({
68
+ entry,
69
+ target: describeTarget(runTarget(entry)),
70
+ })),
71
+ )
72
+
73
+ const historyGroups = computed(() =>
74
+ groupByDay(
75
+ runs.value.filter(({ entry, target }) =>
76
+ matches(entry.source, entry.error, target),
77
+ ),
78
+ ({ entry }) => entry.executedAt,
79
+ ).map((group) => ({
80
+ ...group,
81
+ label: dayLabel(group.date, locale.value, {
82
+ today: t('dms_database.query.library.today'),
83
+ yesterday: t('dms_database.query.library.yesterday'),
84
+ }),
85
+ })),
86
+ )
87
+
88
+ const savedItems = computed(() =>
89
+ (tab.value === 'team' ? props.team : props.saved).filter((query) =>
90
+ matches(query.name, query.description, query.source, query.ownerName),
91
+ ),
92
+ )
93
+
94
+ function time(iso: string): string {
95
+ return new Intl.DateTimeFormat(locale.value, {
96
+ hour: '2-digit',
97
+ minute: '2-digit',
98
+ }).format(new Date(iso))
99
+ }
100
+
101
+ function runMeta(entry: HistoryEntry): string {
102
+ if (entry.status === 'error')
103
+ return entry.error ?? t('dms_database.query.library.failed')
104
+ const outcome = entry.mutation
105
+ ? t(
106
+ 'dms_database.query.library.changed',
107
+ { count: n(entry.rowCount) },
108
+ entry.rowCount,
109
+ )
110
+ : t(
111
+ 'dms_database.query.library.rows',
112
+ { count: n(entry.rowCount) },
113
+ entry.rowCount,
114
+ )
115
+ return `${time(entry.executedAt)} · ${n(entry.durationMs)} ms · ${outcome}`
116
+ }
117
+
118
+ function savedMeta(query: SavedQuery): string {
119
+ const date = new Intl.DateTimeFormat(locale.value, {
120
+ day: 'numeric',
121
+ month: 'short',
122
+ }).format(new Date(query.updatedAt ?? query.createdAt))
123
+ return query.ownerName ? `${query.ownerName} · ${date}` : date
124
+ }
125
+
126
+ function initials(name?: string): string {
127
+ return (name ?? '?')
128
+ .split(/\s+/)
129
+ .map((part) => part[0] ?? '')
130
+ .join('')
131
+ .slice(0, 2)
132
+ .toUpperCase()
133
+ }
134
+ </script>
135
+
136
+ <template>
137
+ <DmsCard :padded="false" class="flex min-h-0 flex-col overflow-hidden">
138
+ <div class="border-default border-b px-3 pt-2">
139
+ <UTabs
140
+ v-model="tab"
141
+ :items="tabs"
142
+ variant="link"
143
+ size="sm"
144
+ :content="false"
145
+ />
146
+ </div>
147
+ <div class="p-3 pb-2">
148
+ <UInput
149
+ v-model="search"
150
+ icon="i-ph-magnifying-glass"
151
+ size="sm"
152
+ class="w-full"
153
+ :placeholder="t('dms_database.query.library.search')"
154
+ />
155
+ </div>
156
+
157
+ <div class="min-h-0 flex-1 overflow-y-auto px-2 pb-2">
158
+ <template v-if="tab === 'history'">
159
+ <section v-for="group in historyGroups" :key="group.key" class="mb-2">
160
+ <DmsEyebrow :label="group.label" class="px-2 pb-1 pt-2" />
161
+ <div
162
+ v-for="{ entry, target } in group.items"
163
+ :key="entry.id"
164
+ class="group/run focus-within:bg-elevated hover:bg-elevated relative grid cursor-pointer grid-cols-[auto_1fr_auto] items-start gap-x-2 rounded-md px-2 py-1.5"
165
+ :class="entry.id === activeHistoryId ? 'bg-primary/10' : ''"
166
+ role="button"
167
+ tabindex="0"
168
+ @click="emit('open-history', entry)"
169
+ @keydown.enter="emit('open-history', entry)"
170
+ >
171
+ <span
172
+ class="mt-1.5 size-2 rounded-full"
173
+ :class="RUN_DOT_CLASSES[runKind(entry)]"
174
+ />
175
+ <span class="min-w-0" :title="entry.source">
176
+ <span
177
+ v-if="target"
178
+ class="text-highlighted block truncate font-mono text-[12px] font-medium"
179
+ >
180
+ {{ target }}
181
+ </span>
182
+ <span
183
+ class="text-muted line-clamp-2 break-all font-mono text-[11px]"
184
+ >
185
+ {{ entry.source }}
186
+ </span>
187
+ </span>
188
+ <UButton
189
+ icon="i-ph-star"
190
+ color="neutral"
191
+ variant="ghost"
192
+ size="xs"
193
+ class="opacity-0 group-focus-within/run:opacity-100 group-hover/run:opacity-100"
194
+ :aria-label="t('dms_database.query.library.save')"
195
+ :title="t('dms_database.query.library.save')"
196
+ @click.stop="emit('save-history', entry)"
197
+ />
198
+ <span
199
+ class="col-start-2 truncate text-[11px]"
200
+ :class="entry.status === 'error' ? 'text-error' : 'text-dimmed'"
201
+ >
202
+ {{ runMeta(entry) }}
203
+ </span>
204
+ </div>
205
+ </section>
206
+ <DmsEmptyState
207
+ v-if="historyGroups.length === 0 && !loading"
208
+ size="sm"
209
+ icon="i-ph-clock-counter-clockwise"
210
+ :title="
211
+ search
212
+ ? t('dms_database.query.library.no_match')
213
+ : t('dms_database.query.library.history_empty')
214
+ "
215
+ />
216
+ </template>
217
+
218
+ <template v-else>
219
+ <div
220
+ v-for="query in savedItems"
221
+ :key="query.id"
222
+ class="group/saved hover:bg-elevated focus-within:bg-elevated grid cursor-pointer gap-0.5 rounded-md px-2 py-2"
223
+ :class="query.id === activeSavedId ? 'bg-primary/10' : ''"
224
+ role="button"
225
+ tabindex="0"
226
+ @click="emit('open-saved', query)"
227
+ @keydown.enter="emit('open-saved', query)"
228
+ >
229
+ <div class="flex items-center gap-2">
230
+ <span class="text-highlighted truncate text-[13px] font-medium">
231
+ {{ query.name }}
232
+ </span>
233
+ <UBadge
234
+ v-if="query.shared && tab === 'saved'"
235
+ color="neutral"
236
+ variant="outline"
237
+ size="sm"
238
+ >
239
+ {{ t('dms_database.query.library.shared') }}
240
+ </UBadge>
241
+ <span
242
+ v-if="tab === 'saved'"
243
+ class="ml-auto flex opacity-0 group-focus-within/saved:opacity-100 group-hover/saved:opacity-100"
244
+ >
245
+ <UButton
246
+ icon="i-ph-pencil-simple"
247
+ color="neutral"
248
+ variant="ghost"
249
+ size="xs"
250
+ :aria-label="t('dms_database.query.library.edit')"
251
+ :title="t('dms_database.query.library.edit')"
252
+ @click.stop="emit('edit-saved', query)"
253
+ />
254
+ <UButton
255
+ icon="i-ph-trash"
256
+ color="error"
257
+ variant="ghost"
258
+ size="xs"
259
+ :aria-label="t('dms_database.query.library.delete')"
260
+ :title="t('dms_database.query.library.delete')"
261
+ @click.stop="emit('delete-saved', query)"
262
+ />
263
+ </span>
264
+ </div>
265
+ <p v-if="query.description" class="text-muted line-clamp-2 text-xs">
266
+ {{ query.description }}
267
+ </p>
268
+ <span class="text-dimmed flex items-center gap-1.5 text-[11px]">
269
+ <UAvatar
270
+ v-if="tab === 'team'"
271
+ :text="initials(query.ownerName)"
272
+ size="3xs"
273
+ />
274
+ {{ savedMeta(query) }}
275
+ </span>
276
+ </div>
277
+ <DmsEmptyState
278
+ v-if="savedItems.length === 0 && !loading"
279
+ size="sm"
280
+ icon="i-ph-star"
281
+ :title="
282
+ search
283
+ ? t('dms_database.query.library.no_match')
284
+ : tab === 'team'
285
+ ? t('dms_database.query.library.team_empty')
286
+ : t('dms_database.query.library.saved_empty')
287
+ "
288
+ />
289
+ </template>
290
+ </div>
291
+
292
+ <footer
293
+ v-if="tab === 'history'"
294
+ class="border-default text-dimmed flex items-center gap-2 border-t px-3 py-2 text-[11.5px]"
295
+ >
296
+ {{
297
+ t(
298
+ 'dms_database.query.library.history_kept',
299
+ { count: n(HISTORY_KEPT) },
300
+ HISTORY_KEPT,
301
+ )
302
+ }}
303
+ <UButton
304
+ class="ml-auto"
305
+ size="xs"
306
+ color="neutral"
307
+ variant="ghost"
308
+ :disabled="history.length === 0"
309
+ :label="t('dms_database.query.library.clear')"
310
+ @click="emit('clear-history')"
311
+ />
312
+ </footer>
313
+ </DmsCard>
314
+ </template>