@happyvertical/smrt-reports 0.57.5 → 0.57.7

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 (74) hide show
  1. package/AGENTS.md +10 -0
  2. package/dist/chunks/runtime-time-D7JZ1e4J.js +1052 -0
  3. package/dist/chunks/runtime-time-D7JZ1e4J.js.map +1 -0
  4. package/dist/index.d.ts +7 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +58 -591
  7. package/dist/index.js.map +1 -1
  8. package/dist/manifest.json +28 -4
  9. package/dist/playground.js +1 -1
  10. package/dist/playground.js.map +1 -1
  11. package/dist/recipes.d.ts +21 -0
  12. package/dist/recipes.d.ts.map +1 -1
  13. package/dist/runtime-compiler.d.ts +7 -40
  14. package/dist/runtime-compiler.d.ts.map +1 -1
  15. package/dist/runtime-dimensions.d.ts +43 -0
  16. package/dist/runtime-dimensions.d.ts.map +1 -0
  17. package/dist/runtime-memory.d.ts +81 -0
  18. package/dist/runtime-memory.d.ts.map +1 -0
  19. package/dist/runtime-plan.d.ts +121 -0
  20. package/dist/runtime-plan.d.ts.map +1 -0
  21. package/dist/runtime-report.d.ts.map +1 -1
  22. package/dist/runtime-server.d.ts.map +1 -1
  23. package/dist/runtime-spec-hash.d.ts +11 -0
  24. package/dist/runtime-spec-hash.d.ts.map +1 -0
  25. package/dist/runtime-spec.d.ts +16 -4
  26. package/dist/runtime-spec.d.ts.map +1 -1
  27. package/dist/runtime-time.d.ts +41 -0
  28. package/dist/runtime-time.d.ts.map +1 -0
  29. package/dist/smrt-knowledge.json +37 -12
  30. package/dist/spec.d.ts +25 -0
  31. package/dist/spec.d.ts.map +1 -0
  32. package/dist/spec.js +2 -0
  33. package/dist/state.js +1 -1
  34. package/dist/state.js.map +1 -1
  35. package/dist/svelte/ReportConfirmation.svelte +97 -24
  36. package/dist/svelte/ReportConfirmation.svelte.d.ts +20 -0
  37. package/dist/svelte/ReportConfirmation.svelte.d.ts.map +1 -1
  38. package/dist/svelte/ReportDetail.svelte +263 -12
  39. package/dist/svelte/ReportDetail.svelte.d.ts +10 -1
  40. package/dist/svelte/ReportDetail.svelte.d.ts.map +1 -1
  41. package/dist/svelte/ReportPicker.svelte +47 -14
  42. package/dist/svelte/ReportPicker.svelte.d.ts +3 -0
  43. package/dist/svelte/ReportPicker.svelte.d.ts.map +1 -1
  44. package/dist/svelte/ReportResult.svelte +216 -35
  45. package/dist/svelte/ReportResult.svelte.d.ts +8 -2
  46. package/dist/svelte/ReportResult.svelte.d.ts.map +1 -1
  47. package/dist/svelte/RuntimeReportWidgetOptions.svelte +9 -1
  48. package/dist/svelte/RuntimeReportWidgetOptions.svelte.d.ts.map +1 -1
  49. package/dist/svelte/SavedReportCard.svelte +242 -0
  50. package/dist/svelte/SavedReportCard.svelte.d.ts +30 -0
  51. package/dist/svelte/SavedReportCard.svelte.d.ts.map +1 -0
  52. package/dist/svelte/SavedReports.svelte +206 -33
  53. package/dist/svelte/SavedReports.svelte.d.ts +13 -0
  54. package/dist/svelte/SavedReports.svelte.d.ts.map +1 -1
  55. package/dist/svelte/SavedReportsWidget.svelte +59 -0
  56. package/dist/svelte/SavedReportsWidget.svelte.d.ts +19 -0
  57. package/dist/svelte/SavedReportsWidget.svelte.d.ts.map +1 -0
  58. package/dist/svelte/client.d.ts.map +1 -1
  59. package/dist/svelte/client.js +3 -0
  60. package/dist/svelte/describe.d.ts +94 -0
  61. package/dist/svelte/describe.d.ts.map +1 -0
  62. package/dist/svelte/describe.js +249 -0
  63. package/dist/svelte/index.d.ts +4 -1
  64. package/dist/svelte/index.d.ts.map +1 -1
  65. package/dist/svelte/index.js +4 -1
  66. package/dist/svelte/messages.d.ts +48 -0
  67. package/dist/svelte/messages.d.ts.map +1 -1
  68. package/dist/svelte/messages.js +59 -11
  69. package/dist/svelte/playground.d.ts +2 -2
  70. package/dist/svelte/playground.d.ts.map +1 -1
  71. package/dist/svelte/playground.js +1 -1
  72. package/dist/svelte/types.d.ts +2 -0
  73. package/dist/svelte/types.d.ts.map +1 -1
  74. package/package.json +13 -9
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Words and numbers for a report, shared by every runtime-report screen (the
3
+ * saved-report cards, a report's page, the assistant's proposal card), so they
4
+ * name a report the same way: its source by label, groupings, the period with
5
+ * its dates, measures by their column labels, and headline figures from a run.
6
+ * Pure: it formats with the caller's `t`, locale and currency.
7
+ */
8
+ import { formatWidgetValue } from '@happyvertical/smrt-ui/charts';
9
+ import { reportCell } from './result.js';
10
+ export function humanizeName(name) {
11
+ return name
12
+ .replace(/([a-z\d])([A-Z])/g, '$1 $2')
13
+ .replace(/[_-]+/g, ' ')
14
+ .trim()
15
+ .toLowerCase()
16
+ .replace(/^./, (c) => c.toUpperCase());
17
+ }
18
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}(?:[T ][\d:.]+(?:Z|[+-]\d{2}:?\d{2})?)?$/;
19
+ function asDate(value) {
20
+ if (typeof value !== 'string' || !ISO_DATE.test(value))
21
+ return null;
22
+ const date = new Date(/^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}T00:00:00Z` : value);
23
+ return Number.isNaN(date.getTime()) ? null : date;
24
+ }
25
+ /**
26
+ * The spec's period: a lower (`gte`/`gt`) and/or upper (`lt`/`lte`) bound on
27
+ * one date field. An exclusive upper bound at midnight reads as the day
28
+ * before, so "last month" reads 1–31 December.
29
+ */
30
+ export function reportPeriod(spec, options) {
31
+ const bounds = new Map();
32
+ spec.filters.forEach((filter, index) => {
33
+ const date = asDate(filter.value);
34
+ if (!date)
35
+ return;
36
+ const entry = bounds.get(filter.field) ?? { filters: [] };
37
+ if (filter.op === 'gte' || filter.op === 'gt')
38
+ entry.from = date;
39
+ else if (filter.op === 'lt' || filter.op === 'lte') {
40
+ const to = new Date(date);
41
+ const midnight = to.getUTCHours() === 0 &&
42
+ to.getUTCMinutes() === 0 &&
43
+ to.getUTCSeconds() === 0;
44
+ if (filter.op === 'lt' && midnight)
45
+ to.setUTCDate(to.getUTCDate() - 1);
46
+ entry.to = to;
47
+ }
48
+ else
49
+ return;
50
+ entry.filters.push(index);
51
+ bounds.set(filter.field, entry);
52
+ });
53
+ const [field, found] = [...bounds.entries()][0] ?? [];
54
+ if (!field || !found)
55
+ return null;
56
+ let tag = 'en';
57
+ try {
58
+ tag = Intl.getCanonicalLocales(options.locale)[0] ?? 'en';
59
+ }
60
+ catch {
61
+ // keep `en`
62
+ }
63
+ const format = new Intl.DateTimeFormat(tag, {
64
+ timeZone: 'UTC',
65
+ day: 'numeric',
66
+ month: 'short',
67
+ year: 'numeric',
68
+ });
69
+ const range = found.from && found.to
70
+ ? format.formatRange(found.from, found.to)
71
+ : found.from
72
+ ? options.t('reports.period.since', { date: format.format(found.from) })
73
+ : found.to
74
+ ? options.t('reports.period.until', {
75
+ date: format.format(found.to),
76
+ })
77
+ : '';
78
+ return { field: options.label(field), range, filters: found.filters };
79
+ }
80
+ /** Describe a spec in the source's own words. */
81
+ export function describeReport(spec, options) {
82
+ const { t, locale, currency, source, columns } = options;
83
+ const fieldOf = (name) => source?.fields?.find((f) => f.name === name);
84
+ const label = (name) => fieldOf(name)?.label ?? humanizeName(name);
85
+ const sourceLabel = source?.label ?? humanizeName(spec.source);
86
+ const groupings = spec.dimensions
87
+ .map((d) => d.bucket
88
+ ? t('reports.dimension_bucket', {
89
+ field: label(d.field),
90
+ bucket: t(`reports.bucket_unit.${d.bucket}`),
91
+ })
92
+ : label(d.field))
93
+ .join(', ');
94
+ const period = reportPeriod(spec, { locale, label, t });
95
+ const measures = spec.measures.map((m) => columns?.find((c) => c.id === m.as)?.label ??
96
+ (m.field
97
+ ? t(`reports.aggregate.${m.fn}`, { field: label(m.field) })
98
+ : t('reports.aggregate.rows', { source: sourceLabel })));
99
+ const value = (field, raw) => {
100
+ const show = (v) => fieldOf(field)?.format === 'money' && typeof v === 'number'
101
+ ? formatWidgetValue(v, { format: 'money', currency, locale })
102
+ : String(v ?? '');
103
+ return Array.isArray(raw) ? raw.map(show).join(', ') : show(raw);
104
+ };
105
+ const filters = spec.filters
106
+ .filter((_, index) => !period?.filters.includes(index))
107
+ .map((f) => `${label(f.field)} ${t(`reports.operator.${f.op}`)} ${value(f.field, f.value)}`.trim());
108
+ const measureLabel = (alias) => columns?.find((c) => c.id === alias)?.label ?? humanizeName(alias);
109
+ const having = spec.having.map((h) => `${measureLabel(h.measure)} ${t(`reports.operator.${h.op}`)} ${h.value}`);
110
+ const line = [sourceLabel, groupings, period?.range]
111
+ .filter((part) => Boolean(part))
112
+ .join(' · ');
113
+ return {
114
+ source: sourceLabel,
115
+ groupings,
116
+ period,
117
+ measures,
118
+ filters,
119
+ having,
120
+ line,
121
+ };
122
+ }
123
+ const BUCKETS = new Set([
124
+ 'minute',
125
+ 'hour',
126
+ 'day',
127
+ 'week',
128
+ 'month',
129
+ 'quarter',
130
+ 'year',
131
+ ]);
132
+ /** Does the result's x axis run over time buckets? */
133
+ export function timeAxis(result) {
134
+ const x = result.chart.x
135
+ ? result.columns.find((c) => c.id === result.chart.x)
136
+ : result.columns.find((c) => c.role === 'dimension');
137
+ return x?.bucket && BUCKETS.has(x.bucket) ? x : undefined;
138
+ }
139
+ /** The measure columns a result charts, in order. */
140
+ /** The measure columns, the charted ones (`chart.y`) first. */
141
+ export function measureColumns(result) {
142
+ const measures = result.columns.filter((c) => c.role === 'measure');
143
+ const charted = result.chart.y ?? [];
144
+ return [
145
+ ...measures.filter((c) => charted.includes(c.id)),
146
+ ...measures.filter((c) => !charted.includes(c.id)),
147
+ ];
148
+ }
149
+ /** A measure's chart format. */
150
+ export function measureFormat(column) {
151
+ return column.format === 'money'
152
+ ? 'money'
153
+ : column.type === 'integer'
154
+ ? 'integer'
155
+ : 'decimal';
156
+ }
157
+ /**
158
+ * Headline figures for one measure: the total (only for an additive measure:
159
+ * a sum or a row count), the average per group, and the peak with its group.
160
+ * An ungrouped report has one value, its own figure.
161
+ */
162
+ export function reportFigures(result, measure, options) {
163
+ const { t, locale, currency } = options;
164
+ const values = result.rows
165
+ .map((row) => ({ row, value: row[measure.id] }))
166
+ .filter((entry) => typeof entry.value === 'number' && Number.isFinite(entry.value));
167
+ if (values.length === 0)
168
+ return [];
169
+ const show = (value) => reportCell(measure.type === 'integer' && !Number.isInteger(value)
170
+ ? Math.round(value * 100) / 100
171
+ : value, measure.type === 'integer' && !Number.isInteger(value)
172
+ ? { ...measure, type: 'decimal' }
173
+ : measure, locale, currency);
174
+ const grouped = result.columns.some((c) => c.role === 'dimension');
175
+ if (!grouped || values.length === 1) {
176
+ return [{ label: measure.label, value: show(values[0].value) }];
177
+ }
178
+ const sum = values.reduce((total, entry) => total + entry.value, 0);
179
+ const peak = values.reduce((best, entry) => entry.value > best.value ? entry : best);
180
+ const axis = timeAxis(result);
181
+ const figures = [];
182
+ if (options.fn === 'sum' || options.fn === 'count') {
183
+ figures.push({ label: t('reports.figure.total'), value: show(sum) });
184
+ }
185
+ figures.push({
186
+ label: axis?.bucket
187
+ ? t('reports.figure.average_per', {
188
+ bucket: t(`reports.bucket_unit.${axis.bucket}`),
189
+ })
190
+ : t('reports.figure.average'),
191
+ value: show(sum / values.length),
192
+ });
193
+ figures.push({
194
+ label: t('reports.figure.peak'),
195
+ value: show(peak.value),
196
+ detail: options.groupLabel(peak.row),
197
+ });
198
+ return figures;
199
+ }
200
+ /** "3 days ago", "in 2 hours", "just now": a time relative to `now`. */
201
+ export function relativeTime(iso, locale, now = new Date(),
202
+ /** What under a minute reads as ("just now"); default the locale's "now". */
203
+ justNow) {
204
+ const then = new Date(iso);
205
+ if (Number.isNaN(then.getTime()))
206
+ return iso;
207
+ let tag = 'en';
208
+ try {
209
+ tag = Intl.getCanonicalLocales(locale)[0] ?? 'en';
210
+ }
211
+ catch {
212
+ // keep `en`
213
+ }
214
+ const seconds = Math.round((then.getTime() - now.getTime()) / 1000);
215
+ const steps = [
216
+ ['year', 31_536_000],
217
+ ['month', 2_592_000],
218
+ ['week', 604_800],
219
+ ['day', 86_400],
220
+ ['hour', 3_600],
221
+ ['minute', 60],
222
+ ];
223
+ const format = new Intl.RelativeTimeFormat(tag, { numeric: 'auto' });
224
+ for (const [unit, size] of steps) {
225
+ if (Math.abs(seconds) >= size) {
226
+ return format.format(Math.round(seconds / size), unit);
227
+ }
228
+ }
229
+ return justNow ?? format.format(0, 'second');
230
+ }
231
+ /**
232
+ * A cell as CSV text: quoted when needed, and a text cell is never read as a
233
+ * formula. A number column's cell ("-$5.00", "-3") is left as a number.
234
+ */
235
+ function csvCell(text, numeric = false) {
236
+ const safe = !numeric && /^[=+\-@\t\r]/.test(text) ? `'${text}` : text;
237
+ return /[",\n\r]/.test(safe) ? `"${safe.replaceAll('"', '""')}"` : safe;
238
+ }
239
+ /** The result as CSV with the screen's own formatting (labels, buckets, money). */
240
+ export function reportCsv(result, cell) {
241
+ const lines = [
242
+ result.columns.map((column) => csvCell(column.label)).join(','),
243
+ ...result.rows.map((row) => result.columns
244
+ .map((column) => csvCell(cell(row[column.id], column), (column.type === 'integer' || column.type === 'decimal') &&
245
+ typeof row[column.id] === 'number'))
246
+ .join(',')),
247
+ ];
248
+ return `${lines.join('\r\n')}\r\n`;
249
+ }
@@ -1,8 +1,9 @@
1
1
  export { getRuntimeReportsBrowserClient, type RuntimeReportsBrowserClientOptions, } from './browser-client.js';
2
2
  export { createRuntimeReportsHttpClient, type RuntimeReportsHttpClientOptions, RuntimeReportsHttpError, } from './client.js';
3
+ export { describeReport, humanizeName, type ReportDescription, type ReportFieldInfo, type ReportFigure, type ReportPeriod, type ReportSourceInfo, relativeTime, reportCsv, reportFigures, reportPeriod, } from './describe.js';
3
4
  export { default as MaterializedReportTable } from './MaterializedReportTable.svelte';
4
5
  export type { MaterializedReportCell, MaterializedReportDrilldown, MaterializedReportPage, } from './materialized.js';
5
- export { default as ReportConfirmation } from './ReportConfirmation.svelte';
6
+ export { default as ReportConfirmation, type ReportConfirmationOutcome, } from './ReportConfirmation.svelte';
6
7
  export { default as ReportDetail } from './ReportDetail.svelte';
7
8
  export { default as ReportPicker } from './ReportPicker.svelte';
8
9
  export { default as ReportResult } from './ReportResult.svelte';
@@ -11,7 +12,9 @@ export { default as RuntimeReportDetailRoute } from './RuntimeReportDetailRoute.
11
12
  export { default as RuntimeReportsRoute } from './RuntimeReportsRoute.svelte';
12
13
  export { default as RuntimeReportToolResult } from './RuntimeReportToolResult.svelte';
13
14
  export { default as RuntimeReportWidgetOptions } from './RuntimeReportWidgetOptions.svelte';
15
+ export { default as SavedReportCard } from './SavedReportCard.svelte';
14
16
  export { default as SavedReports } from './SavedReports.svelte';
17
+ export { default as SavedReportsWidget } from './SavedReportsWidget.svelte';
15
18
  export { runtimeReportProposalFromMessage, runtimeReportToolResultComponent, type ToolResultMessage, } from './tool-result.js';
16
19
  export type { RuntimeReportProposal, RuntimeReportResult, RuntimeReportSpec, RuntimeReportsClient, SavedRuntimeReport, } from './types.js';
17
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,KAAK,kCAAkC,GACxC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,8BAA8B,EAC9B,KAAK,+BAA+B,EACpC,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,YAAY,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EACL,gCAAgC,EAChC,gCAAgC,EAChC,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,KAAK,kCAAkC,GACxC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,8BAA8B,EAC9B,KAAK,+BAA+B,EACpC,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,YAAY,EACZ,SAAS,EACT,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,YAAY,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,OAAO,IAAI,kBAAkB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EACL,gCAAgC,EAChC,gCAAgC,EAChC,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
@@ -1,7 +1,8 @@
1
1
  export { getRuntimeReportsBrowserClient, } from './browser-client.js';
2
2
  export { createRuntimeReportsHttpClient, RuntimeReportsHttpError, } from './client.js';
3
+ export { describeReport, humanizeName, relativeTime, reportCsv, reportFigures, reportPeriod, } from './describe.js';
3
4
  export { default as MaterializedReportTable } from './MaterializedReportTable.svelte';
4
- export { default as ReportConfirmation } from './ReportConfirmation.svelte';
5
+ export { default as ReportConfirmation, } from './ReportConfirmation.svelte';
5
6
  export { default as ReportDetail } from './ReportDetail.svelte';
6
7
  export { default as ReportPicker } from './ReportPicker.svelte';
7
8
  export { default as ReportResult } from './ReportResult.svelte';
@@ -10,5 +11,7 @@ export { default as RuntimeReportDetailRoute } from './RuntimeReportDetailRoute.
10
11
  export { default as RuntimeReportsRoute } from './RuntimeReportsRoute.svelte';
11
12
  export { default as RuntimeReportToolResult } from './RuntimeReportToolResult.svelte';
12
13
  export { default as RuntimeReportWidgetOptions } from './RuntimeReportWidgetOptions.svelte';
14
+ export { default as SavedReportCard } from './SavedReportCard.svelte';
13
15
  export { default as SavedReports } from './SavedReports.svelte';
16
+ export { default as SavedReportsWidget } from './SavedReportsWidget.svelte';
14
17
  export { runtimeReportProposalFromMessage, runtimeReportToolResultComponent, } from './tool-result.js';
@@ -1,5 +1,44 @@
1
1
  export declare const M: {
2
2
  readonly 'reports.title': "reports.title";
3
+ readonly 'reports.new': "reports.new";
4
+ readonly 'reports.new_prompt': "reports.new_prompt";
5
+ readonly 'reports.hint': "reports.hint";
6
+ readonly 'reports.ask_where': "reports.ask_where";
7
+ readonly 'reports.empty_title': "reports.empty_title";
8
+ readonly 'reports.filter_label': "reports.filter_label";
9
+ readonly 'reports.filter_all': "reports.filter_all";
10
+ readonly 'reports.filter_mine': "reports.filter_mine";
11
+ readonly 'reports.archived_badge': "reports.archived_badge";
12
+ readonly 'reports.more': "reports.more";
13
+ readonly 'reports.archive_confirm_title': "reports.archive_confirm_title";
14
+ readonly 'reports.archive_confirm': "reports.archive_confirm";
15
+ readonly 'reports.restore': "reports.restore";
16
+ readonly 'reports.saved_at': "reports.saved_at";
17
+ readonly 'reports.saved_by': "reports.saved_by";
18
+ readonly 'reports.saved_by_at': "reports.saved_by_at";
19
+ readonly 'reports.ran_at': "reports.ran_at";
20
+ readonly 'reports.just_now': "reports.just_now";
21
+ readonly 'reports.period': "reports.period";
22
+ readonly 'reports.period.since': "reports.period.since";
23
+ readonly 'reports.period.until': "reports.period.until";
24
+ readonly 'reports.aggregate.rows': "reports.aggregate.rows";
25
+ readonly 'reports.figure.total': "reports.figure.total";
26
+ readonly 'reports.figure.average': "reports.figure.average";
27
+ readonly 'reports.figure.average_per': "reports.figure.average_per";
28
+ readonly 'reports.figure.peak': "reports.figure.peak";
29
+ readonly 'reports.figures': "reports.figures";
30
+ readonly 'reports.edit': "reports.edit";
31
+ readonly 'reports.edit_prompt': "reports.edit_prompt";
32
+ readonly 'reports.export_csv': "reports.export_csv";
33
+ readonly 'reports.view': "reports.view";
34
+ readonly 'reports.view_chart': "reports.view_chart";
35
+ readonly 'reports.view_table': "reports.view_table";
36
+ readonly 'reports.measure_pick': "reports.measure_pick";
37
+ readonly 'reports.view_all': "reports.view_all";
38
+ readonly 'reports.open_report': "reports.open_report";
39
+ readonly 'reports.groups_count': "reports.groups_count";
40
+ readonly 'reports.run_failed': "reports.run_failed";
41
+ readonly 'reports.details': "reports.details";
3
42
  readonly 'reports.only_mine': "reports.only_mine";
4
43
  readonly 'reports.archived': "reports.archived";
5
44
  readonly 'reports.archive': "reports.archive";
@@ -34,7 +73,16 @@ export declare const M: {
34
73
  readonly 'reports.save': "reports.save";
35
74
  readonly 'reports.confirm_title': "reports.confirm_title";
36
75
  readonly 'reports.saved': "reports.saved";
76
+ readonly 'reports.open': "reports.open";
37
77
  readonly 'reports.declined': "reports.declined";
78
+ readonly 'reports.dimension_bucket': "reports.dimension_bucket";
79
+ readonly 'reports.bucket_unit.minute': "reports.bucket_unit.minute";
80
+ readonly 'reports.bucket_unit.hour': "reports.bucket_unit.hour";
81
+ readonly 'reports.bucket_unit.day': "reports.bucket_unit.day";
82
+ readonly 'reports.bucket_unit.week': "reports.bucket_unit.week";
83
+ readonly 'reports.bucket_unit.month': "reports.bucket_unit.month";
84
+ readonly 'reports.bucket_unit.quarter': "reports.bucket_unit.quarter";
85
+ readonly 'reports.bucket_unit.year': "reports.bucket_unit.year";
38
86
  readonly 'reports.groupings': "reports.groupings";
39
87
  readonly 'reports.measures': "reports.measures";
40
88
  readonly 'reports.filters': "reports.filters";
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/svelte/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyEZ,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/svelte/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4HZ,CAAC"}
@@ -1,22 +1,61 @@
1
1
  import { defineMessages } from '@happyvertical/smrt-ui/i18n';
2
2
  export const M = defineMessages({
3
- 'reports.title': 'Reports',
3
+ 'reports.title': 'Saved reports',
4
+ 'reports.new': 'New report',
5
+ 'reports.new_prompt': 'Make a report of ',
6
+ 'reports.hint': 'Ask the assistant for a new one, for example “sales by month”.',
7
+ 'reports.ask_where': 'Open the assistant and ask for a report, for example “sales by month”.',
8
+ 'reports.empty_title': 'No saved reports yet',
9
+ 'reports.filter_label': 'Whose reports',
10
+ 'reports.filter_all': 'Everyone’s',
11
+ 'reports.filter_mine': 'Mine',
12
+ 'reports.archived_badge': 'Archived',
13
+ 'reports.more': 'More actions for {title}',
14
+ 'reports.archive_confirm_title': 'Archive “{title}”?',
15
+ 'reports.archive_confirm': 'It leaves Saved reports for everyone on your team. You can restore it under Show archived.',
16
+ 'reports.restore': 'Restore',
17
+ 'reports.saved_at': 'Saved {time}',
18
+ 'reports.saved_by': 'Saved by {author}',
19
+ 'reports.saved_by_at': 'Saved by {author} {time}',
20
+ 'reports.ran_at': 'Last run {time}',
21
+ 'reports.just_now': 'just now',
22
+ 'reports.period': 'Period',
23
+ 'reports.period.since': 'Since {date}',
24
+ 'reports.period.until': 'Until {date}',
25
+ 'reports.aggregate.rows': 'Number of records',
26
+ 'reports.figure.total': 'Total',
27
+ 'reports.figure.average': 'Average',
28
+ 'reports.figure.average_per': 'Average per {bucket}',
29
+ 'reports.figure.peak': 'Peak',
30
+ 'reports.figures': 'Headline figures',
31
+ 'reports.edit': 'Edit',
32
+ 'reports.edit_prompt': 'Change the report “{title}”: ',
33
+ 'reports.export_csv': 'Export CSV',
34
+ 'reports.view': 'Show as',
35
+ 'reports.view_chart': 'Chart',
36
+ 'reports.view_table': 'Table',
37
+ 'reports.measure_pick': 'Measure',
38
+ 'reports.view_all': 'View all saved reports',
39
+ 'reports.open_report': 'Open report',
40
+ 'reports.groups_count': 'Across {count} groups',
41
+ 'reports.run_failed': 'This report could not run.',
42
+ 'reports.details': 'Report details',
4
43
  'reports.only_mine': 'Only mine',
5
- 'reports.archived': 'Show archived reports',
44
+ 'reports.archived': 'Show archived',
6
45
  'reports.archive': 'Archive',
7
- 'reports.unarchive': 'Unarchive',
46
+ 'reports.unarchive': 'Restore',
8
47
  'reports.loading': 'Loading reports…',
9
48
  'reports.running': 'Running report…',
10
- 'reports.empty': 'No saved reports. Ask the assistant to create a report, then approve its proposal.',
11
- 'reports.no_rows': 'No results match this report.',
49
+ 'reports.empty': 'Ask the assistant for a report, check its preview, and approve it. It is kept here for your team, with its numbers up to date each time you open it.',
50
+ 'reports.no_rows': 'No matching records.',
12
51
  'reports.unavailable': 'Reports are unavailable because this host has no server.',
13
52
  'reports.error': 'The report request failed. Please try again.',
14
53
  'reports.denied': 'You do not have permission to read this report or one of its fields.',
15
54
  'reports.invalid': 'The report returned an invalid result.',
16
55
  'reports.retry': 'Try again',
17
56
  'reports.rerun': 'Re-run',
18
- 'reports.table': 'Table view',
19
- 'reports.chart': 'Chart view',
57
+ 'reports.table': 'Table',
58
+ 'reports.chart': 'Chart',
20
59
  'reports.source': 'Source',
21
60
  'reports.author': 'Author',
22
61
  'reports.last_run': 'Last run: {time}',
@@ -28,14 +67,23 @@ export const M = defineMessages({
28
67
  'reports.select_measure': 'Measure',
29
68
  'reports.choose_report': 'Choose a saved report',
30
69
  'reports.choose_measure': 'Choose a measure',
31
- 'reports.select_dimension': 'Dimension',
32
- 'reports.choose_dimension': 'Choose a dimension',
70
+ 'reports.select_dimension': 'Group by',
71
+ 'reports.choose_dimension': 'The report’s first grouping',
33
72
  'reports.options_invalid': 'Choose a report and measure before saving.',
34
73
  'reports.cancel': 'Cancel',
35
74
  'reports.save': 'Save',
36
75
  'reports.confirm_title': 'Review report proposal',
37
- 'reports.saved': 'Report saved.',
38
- 'reports.declined': 'Report declined. Nothing was saved.',
76
+ 'reports.saved': 'Report saved',
77
+ 'reports.open': 'Open report',
78
+ 'reports.declined': 'Declined — nothing saved',
79
+ 'reports.dimension_bucket': '{field} by {bucket}',
80
+ 'reports.bucket_unit.minute': 'minute',
81
+ 'reports.bucket_unit.hour': 'hour',
82
+ 'reports.bucket_unit.day': 'day',
83
+ 'reports.bucket_unit.week': 'week',
84
+ 'reports.bucket_unit.month': 'month',
85
+ 'reports.bucket_unit.quarter': 'quarter',
86
+ 'reports.bucket_unit.year': 'year',
39
87
  'reports.groupings': 'Group by',
40
88
  'reports.measures': 'Measures',
41
89
  'reports.filters': 'Filters',
@@ -101,7 +101,7 @@ declare const _default: {
101
101
  id: string;
102
102
  title: string;
103
103
  description: string;
104
- loadComponent: () => Promise<import("svelte").Component<import("./ReportResult.svelte").Props, {}, "">>;
104
+ loadComponent: () => Promise<import("svelte").Component<import("./ReportResult.svelte").Props, {}, "view">>;
105
105
  props: {
106
106
  result: {
107
107
  rows: never[];
@@ -109,7 +109,7 @@ declare const _default: {
109
109
  version: 1;
110
110
  specHash: string;
111
111
  title: string;
112
- columns: import("../runtime-compiler.js").RuntimeReportColumn[];
112
+ columns: import("../runtime-plan.js").RuntimeReportColumn[];
113
113
  truncated: boolean;
114
114
  ranAt: string;
115
115
  chart: import("../runtime-spec.js").RuntimeReportChart;
@@ -1 +1 @@
1
- {"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../src/svelte/playground.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,wBAkEE"}
1
+ {"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../src/svelte/playground.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,wBAmEE"}
@@ -7,7 +7,7 @@ export default {
7
7
  {
8
8
  id: 'saved-reports',
9
9
  title: 'Saved reports',
10
- description: 'Shared reports, author filter, and archive controls.',
10
+ description: 'Saved reports as cards, whose and archived filters, and archive in a menu.',
11
11
  loadComponent: () => import('./SavedReports.svelte').then((m) => m.default),
12
12
  props: { client: client() },
13
13
  order: 1,
@@ -9,6 +9,8 @@ export interface SavedRuntimeReport {
9
9
  createdByUserId: string;
10
10
  status: 'active' | 'archived';
11
11
  spec: RuntimeReportSpec;
12
+ /** When the report was saved (approved), when the host knows it. */
13
+ savedAt?: string;
12
14
  /** Browser-session hint only. Runtime result rows and run history are not persisted. */
13
15
  lastRunAt?: string;
14
16
  /** Host permission hint. The archive endpoint authorizes every mutation again. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/svelte/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC9B,IAAI,EAAE,iBAAiB,CAAC;IACxB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,OAAO,EAAE;QACZ,QAAQ,EAAE,OAAO,CAAC;QAClB,eAAe,EAAE,OAAO,CAAC;KAC1B,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACvE;AAED,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAC;AAEvD,wFAAwF;AACxF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,uBAAuB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,mBAAmB,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/svelte/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC9B,IAAI,EAAE,iBAAiB,CAAC;IACxB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,OAAO,EAAE;QACZ,QAAQ,EAAE,OAAO,CAAC;QAClB,eAAe,EAAE,OAAO,CAAC;KAC1B,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACvE;AAED,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAC;AAEvD,wFAAwF;AACxF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,uBAAuB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,mBAAmB,CAAC;CAC9B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-reports",
3
- "version": "0.57.5",
3
+ "version": "0.57.7",
4
4
  "description": "Materialized aggregate report models for SMRT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,6 +39,10 @@
39
39
  "types": "./dist/state.d.ts",
40
40
  "import": "./dist/state.js"
41
41
  },
42
+ "./spec": {
43
+ "types": "./dist/spec.d.ts",
44
+ "import": "./dist/spec.js"
45
+ },
42
46
  "./manifest": "./dist/manifest.json",
43
47
  "./manifest.json": "./dist/manifest.json",
44
48
  "./svelte": {
@@ -52,17 +56,17 @@
52
56
  }
53
57
  },
54
58
  "dependencies": {
55
- "@happyvertical/smrt-core": "0.57.5",
56
- "@happyvertical/smrt-jobs": "0.57.5",
57
- "@happyvertical/smrt-types": "0.57.5",
58
- "@happyvertical/smrt-tenancy": "0.57.5",
59
+ "@happyvertical/smrt-core": "0.57.7",
60
+ "@happyvertical/smrt-jobs": "0.57.7",
61
+ "@happyvertical/smrt-types": "0.57.7",
62
+ "@happyvertical/smrt-tenancy": "0.57.7",
59
63
  "@happyvertical/sql": "^0.105.2",
60
- "@happyvertical/smrt-config": "0.57.5",
61
- "@happyvertical/smrt-ui": "0.57.5"
64
+ "@happyvertical/smrt-config": "0.57.7",
65
+ "@happyvertical/smrt-ui": "0.57.7"
62
66
  },
63
67
  "devDependencies": {
64
- "@happyvertical/smrt-scanner": "0.57.5",
65
- "@happyvertical/smrt-vitest": "0.57.5",
68
+ "@happyvertical/smrt-scanner": "0.57.7",
69
+ "@happyvertical/smrt-vitest": "0.57.7",
66
70
  "@types/node": "24.13.6",
67
71
  "typescript": "6.0.3",
68
72
  "vite": "8.1.4",