@fayz-ai/plugin-reports 0.11.1 → 0.12.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.
- package/dist/chunk-4QIHTUXD.js +179 -0
- package/dist/chunk-4QIHTUXD.js.map +1 -0
- package/dist/components/ExportDropdown.d.ts +7 -1
- package/dist/components/ExportDropdown.d.ts.map +1 -1
- package/dist/components/ReportPagination.d.ts.map +1 -1
- package/dist/{excel-KIJTC7OJ.js → excel-DSORXL4O.js} +6 -5
- package/dist/excel-DSORXL4O.js.map +1 -0
- package/dist/export/csv.d.ts.map +1 -1
- package/dist/export/excel.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +990 -68
- package/dist/index.js.map +1 -1
- package/dist/lib/columns.d.ts +27 -0
- package/dist/lib/columns.d.ts.map +1 -1
- package/dist/lib/preferences.d.ts +90 -0
- package/dist/lib/preferences.d.ts.map +1 -0
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/{pdf-7QQ3U5JQ.js → pdf-DH4CJMV5.js} +3 -3
- package/dist/{pdf-7QQ3U5JQ.js.map → pdf-DH4CJMV5.js.map} +1 -1
- package/dist/types.d.ts +9 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/views/AnalyticsAssistant.d.ts.map +1 -1
- package/dist/views/AnalyticsModule.d.ts +1 -1
- package/dist/views/AnalyticsModule.d.ts.map +1 -1
- package/dist/views/AnalyticsReportViewer.d.ts.map +1 -1
- package/dist/views/AnalyticsSettingsPage.d.ts +16 -0
- package/dist/views/AnalyticsSettingsPage.d.ts.map +1 -0
- package/dist/views/AnalyticsSurface.d.ts +22 -3
- package/dist/views/AnalyticsSurface.d.ts.map +1 -1
- package/package.json +6 -5
- package/dist/chunk-4SPBNVQA.js +0 -101
- package/dist/chunk-4SPBNVQA.js.map +0 -1
- package/dist/excel-KIJTC7OJ.js.map +0 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { PersonLink } from '@fayz-ai/admin';
|
|
3
|
+
import { formatDateTime as formatDateTime$1, formatDate as formatDate$1, formatCurrency as formatCurrency$1 } from '@fayz-ai/core';
|
|
4
|
+
|
|
5
|
+
// src/lib/columns.ts
|
|
6
|
+
function formatCurrency(value, currency) {
|
|
7
|
+
const num = typeof value === "number" ? value : parseFloat(value);
|
|
8
|
+
if (isNaN(num)) return "\u2014";
|
|
9
|
+
return formatCurrency$1(num, currency);
|
|
10
|
+
}
|
|
11
|
+
function formatDate(value) {
|
|
12
|
+
if (!value) return "\u2014";
|
|
13
|
+
return formatDate$1(value);
|
|
14
|
+
}
|
|
15
|
+
function formatDateTime(value) {
|
|
16
|
+
if (!value) return "\u2014";
|
|
17
|
+
return formatDateTime$1(value);
|
|
18
|
+
}
|
|
19
|
+
function formatNumber(value) {
|
|
20
|
+
if (value == null) return "\u2014";
|
|
21
|
+
return typeof value === "number" ? value.toLocaleString() : String(value);
|
|
22
|
+
}
|
|
23
|
+
function formatPercent(value) {
|
|
24
|
+
const num = typeof value === "number" ? value : parseFloat(value);
|
|
25
|
+
return isNaN(num) ? "\u2014" : `${num.toLocaleString(void 0, { maximumFractionDigits: 2 })}%`;
|
|
26
|
+
}
|
|
27
|
+
function formatDuration(value) {
|
|
28
|
+
const hours = typeof value === "number" ? value : parseFloat(value);
|
|
29
|
+
if (isNaN(hours) || hours <= 0) return "\u2014";
|
|
30
|
+
const minutes = Math.round(hours * 60);
|
|
31
|
+
if (minutes < 60) return `${minutes}min`;
|
|
32
|
+
const h = Math.floor(minutes / 60);
|
|
33
|
+
const m = minutes % 60;
|
|
34
|
+
return m ? `${h}h ${m}min` : `${h}h`;
|
|
35
|
+
}
|
|
36
|
+
function plainValue(value) {
|
|
37
|
+
if (value == null || value === "") return "";
|
|
38
|
+
if (Array.isArray(value)) return value.map(plainValue).filter(Boolean).join(", ");
|
|
39
|
+
if (typeof value === "boolean") return value ? "Sim" : "N\xE3o";
|
|
40
|
+
if (typeof value === "object") {
|
|
41
|
+
return Object.entries(value).filter(([, v]) => v !== null && v !== void 0 && v !== "").map(([k, v]) => `${humanizeKey(k)}: ${plainValue(v)}`).join(" \xB7 ");
|
|
42
|
+
}
|
|
43
|
+
return String(value);
|
|
44
|
+
}
|
|
45
|
+
function humanizeKey(key) {
|
|
46
|
+
const spaced = key.replace(/[_-]+/g, " ").replace(/([a-z\d])([A-Z])/g, "$1 $2");
|
|
47
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
48
|
+
}
|
|
49
|
+
function expandBagColumns(columns, data) {
|
|
50
|
+
const bags = columns.filter((c) => c.expand);
|
|
51
|
+
if (!bags.length) return { columns, rows: data };
|
|
52
|
+
const keysByBag = /* @__PURE__ */ new Map();
|
|
53
|
+
for (const bag of bags) {
|
|
54
|
+
const keys = [];
|
|
55
|
+
for (const row of data) {
|
|
56
|
+
const value = row?.[bag.key];
|
|
57
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
58
|
+
for (const key of Object.keys(value)) if (!keys.includes(key)) keys.push(key);
|
|
59
|
+
}
|
|
60
|
+
keysByBag.set(bag.key, keys);
|
|
61
|
+
}
|
|
62
|
+
const expanded = columns.flatMap((col) => {
|
|
63
|
+
if (!col.expand) return [col];
|
|
64
|
+
return (keysByBag.get(col.key) ?? []).map((key) => ({
|
|
65
|
+
key: `${col.key}.${key}`,
|
|
66
|
+
label: humanizeKey(key),
|
|
67
|
+
type: "text",
|
|
68
|
+
// The key exists only on the flattened row, never on the read model, so
|
|
69
|
+
// a server-side ORDER BY on it would 42703. Client sort only.
|
|
70
|
+
sortable: false
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
const rows = data.map((row) => {
|
|
74
|
+
const next = { ...row };
|
|
75
|
+
for (const [bagKey, keys] of keysByBag) {
|
|
76
|
+
const bag = row?.[bagKey];
|
|
77
|
+
for (const key of keys) {
|
|
78
|
+
next[`${bagKey}.${key}`] = bag && typeof bag === "object" ? plainValue(bag[key]) : "";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return next;
|
|
82
|
+
});
|
|
83
|
+
return { columns: expanded, rows };
|
|
84
|
+
}
|
|
85
|
+
function formatValuePlain(value, col, currency) {
|
|
86
|
+
if (value == null || value === "") return "";
|
|
87
|
+
if (col.valueMap) return col.valueMap[String(value)] ?? String(value);
|
|
88
|
+
if (typeof value === "object") return plainValue(value);
|
|
89
|
+
switch (col.type) {
|
|
90
|
+
case "currency":
|
|
91
|
+
return formatCurrency(value, col.currency ?? currency);
|
|
92
|
+
case "date":
|
|
93
|
+
return formatDate(value);
|
|
94
|
+
case "datetime":
|
|
95
|
+
return formatDateTime(value);
|
|
96
|
+
case "number":
|
|
97
|
+
return formatNumber(value);
|
|
98
|
+
case "percent":
|
|
99
|
+
return formatPercent(value);
|
|
100
|
+
case "duration":
|
|
101
|
+
return formatDuration(value);
|
|
102
|
+
case "boolean":
|
|
103
|
+
return value ? "Yes" : "No";
|
|
104
|
+
default:
|
|
105
|
+
return String(value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function reportColumnsToTanstack(columns, currency) {
|
|
109
|
+
return columns.filter((c) => c.visible !== false).map((col) => {
|
|
110
|
+
const sortable = col.sortable ?? ["text", "number", "percent", "duration", "currency", "date", "datetime", "email"].includes(col.type);
|
|
111
|
+
const alignRight = col.align === "right" || !col.align && ["currency", "number", "percent", "duration"].includes(col.type);
|
|
112
|
+
const alignCenter = col.align === "center";
|
|
113
|
+
return {
|
|
114
|
+
accessorKey: col.key,
|
|
115
|
+
header: col.label,
|
|
116
|
+
enableSorting: sortable,
|
|
117
|
+
cell: (ctx) => {
|
|
118
|
+
const value = ctx.getValue();
|
|
119
|
+
const row = ctx.row.original;
|
|
120
|
+
if (col.renderCell) {
|
|
121
|
+
return col.renderCell(value, row);
|
|
122
|
+
}
|
|
123
|
+
if (value == null || value === "" || typeof value === "object" && !plainValue(value)) {
|
|
124
|
+
return React.createElement("span", { className: "text-muted-foreground" }, "\u2014");
|
|
125
|
+
}
|
|
126
|
+
if (col.valueMap) {
|
|
127
|
+
const label = col.valueMap[String(value)] ?? String(value);
|
|
128
|
+
return React.createElement("span", { className: "text-sm" }, label);
|
|
129
|
+
}
|
|
130
|
+
let content;
|
|
131
|
+
switch (col.type) {
|
|
132
|
+
case "person":
|
|
133
|
+
content = React.createElement(PersonLink, {
|
|
134
|
+
personId: col.idKey ? row[col.idKey] : null,
|
|
135
|
+
name: String(value),
|
|
136
|
+
kind: col.personKind,
|
|
137
|
+
size: "sm",
|
|
138
|
+
className: "text-xs"
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
case "currency":
|
|
142
|
+
content = formatCurrency(value, col.currency ?? currency);
|
|
143
|
+
break;
|
|
144
|
+
case "date":
|
|
145
|
+
content = formatDate(value);
|
|
146
|
+
break;
|
|
147
|
+
case "datetime":
|
|
148
|
+
content = formatDateTime(value);
|
|
149
|
+
break;
|
|
150
|
+
case "boolean":
|
|
151
|
+
content = value ? React.createElement(
|
|
152
|
+
"svg",
|
|
153
|
+
{ className: "h-4 w-4 text-success", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
|
|
154
|
+
React.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
155
|
+
) : React.createElement("span", { className: "text-muted-foreground" }, "\u2014");
|
|
156
|
+
break;
|
|
157
|
+
case "number":
|
|
158
|
+
content = formatNumber(value);
|
|
159
|
+
break;
|
|
160
|
+
case "percent":
|
|
161
|
+
content = formatPercent(value);
|
|
162
|
+
break;
|
|
163
|
+
case "duration":
|
|
164
|
+
content = formatDuration(value);
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
content = plainValue(value);
|
|
168
|
+
}
|
|
169
|
+
const cls = alignRight ? "text-right" : alignCenter ? "text-center" : void 0;
|
|
170
|
+
return cls ? React.createElement("div", { className: cls }, content) : React.createElement(React.Fragment, null, content);
|
|
171
|
+
},
|
|
172
|
+
meta: { align: alignRight ? "right" : alignCenter ? "center" : "left" }
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export { expandBagColumns, formatValuePlain, reportColumnsToTanstack };
|
|
178
|
+
//# sourceMappingURL=chunk-4QIHTUXD.js.map
|
|
179
|
+
//# sourceMappingURL=chunk-4QIHTUXD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/columns.ts"],"names":["formatCurrencyLocale","formatDateLocale","formatDateTimeLocale"],"mappings":"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","file":"chunk-4QIHTUXD.js","sourcesContent":["import React from 'react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { ReportColumnDef } from '../types'\nimport { PersonLink } from '@fayz-ai/admin'\nimport {\n formatCurrency as formatCurrencyLocale,\n formatDate as formatDateLocale,\n formatDateTime as formatDateTimeLocale,\n} from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Formatters (mirrors fieldToColumn.tsx logic)\n// ---------------------------------------------------------------------------\n\nfunction formatCurrency(value: any, currency?: string): string {\n const num = typeof value === 'number' ? value : parseFloat(value)\n if (isNaN(num)) return '—'\n return formatCurrencyLocale(num, currency)\n}\n\nfunction formatDate(value: any): string {\n if (!value) return '—'\n return formatDateLocale(value)\n}\n\nfunction formatDateTime(value: any): string {\n if (!value) return '—'\n return formatDateTimeLocale(value)\n}\n\nfunction formatNumber(value: any): string {\n if (value == null) return '—'\n return typeof value === 'number' ? value.toLocaleString() : String(value)\n}\n\nfunction formatPercent(value: any): string {\n const num = typeof value === 'number' ? value : parseFloat(value)\n return isNaN(num) ? '—' : `${num.toLocaleString(undefined, { maximumFractionDigits: 2 })}%`\n}\n\n/** Durations are stored in HOURS, matching the analytics card renderer. */\nfunction formatDuration(value: any): string {\n const hours = typeof value === 'number' ? value : parseFloat(value)\n if (isNaN(hours) || hours <= 0) return '—'\n const minutes = Math.round(hours * 60)\n if (minutes < 60) return `${minutes}min`\n const h = Math.floor(minutes / 60)\n const m = minutes % 60\n return m ? `${h}h ${m}min` : `${h}h`\n}\n\n// ---------------------------------------------------------------------------\n// Plain-text formatter for exports\n// ---------------------------------------------------------------------------\n\n/** A single cell value as text, whatever shape it arrived in. Arrays join, an\n * open bag prints as \"Chave: valor · Chave: valor\" — never \"[object Object]\",\n * which is what a JSON column looked like in a spreadsheet. */\nexport function plainValue(value: any): string {\n if (value == null || value === '') return ''\n if (Array.isArray(value)) return value.map(plainValue).filter(Boolean).join(', ')\n if (typeof value === 'boolean') return value ? 'Sim' : 'Não'\n if (typeof value === 'object') {\n return Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== null && v !== undefined && v !== '')\n .map(([k, v]) => `${humanizeKey(k)}: ${plainValue(v)}`)\n .join(' · ')\n }\n return String(value)\n}\n\n/** `hair_remaining` / `hairRemaining` → \"Hair remaining\". A key that arrives\n * already humanized (\"Estilo\") comes back unchanged. */\nexport function humanizeKey(key: string): string {\n const spaced = key.replace(/[_-]+/g, ' ').replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n\n/**\n * Expand every `expand` column into one column PER KEY found in the rows, and\n * flatten those keys onto the rows so no consumer needs a special case.\n *\n * The keys cannot be declared on the card — each landing page asks something\n * different, and typing them here would make the NEXT form invisible. So they\n * are discovered from the rows themselves, in first-seen order, and the bag\n * column steps aside. \"Estilo\" as a real column can be read down and sorted;\n * \"Estilo: House · Perfil: Outros\" crammed into one cell cannot, and a raw JSON\n * blob is worse still.\n *\n * Used by the report table AND by the writers, so the screen and the file show\n * the same columns.\n *\n * Columns that are not `expand` pass through untouched, order included.\n */\nexport function expandBagColumns(\n columns: ReportColumnDef[],\n data: Record<string, any>[],\n): { columns: ReportColumnDef[]; rows: Record<string, any>[] } {\n const bags = columns.filter((c) => c.expand)\n if (!bags.length) return { columns, rows: data }\n\n // First-seen order, so the spreadsheet's columns follow the form's own order\n // rather than an alphabetical one nobody asked for.\n const keysByBag = new Map<string, string[]>()\n for (const bag of bags) {\n const keys: string[] = []\n for (const row of data) {\n const value = row?.[bag.key]\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n for (const key of Object.keys(value)) if (!keys.includes(key)) keys.push(key)\n }\n keysByBag.set(bag.key, keys)\n }\n\n const expanded = columns.flatMap((col): ReportColumnDef[] => {\n if (!col.expand) return [col]\n return (keysByBag.get(col.key) ?? []).map((key) => ({\n key: `${col.key}.${key}`,\n label: humanizeKey(key),\n type: 'text' as const,\n // The key exists only on the flattened row, never on the read model, so\n // a server-side ORDER BY on it would 42703. Client sort only.\n sortable: false,\n }))\n })\n\n const rows = data.map((row) => {\n const next = { ...row }\n for (const [bagKey, keys] of keysByBag) {\n const bag = row?.[bagKey]\n for (const key of keys) {\n next[`${bagKey}.${key}`] = bag && typeof bag === 'object' ? plainValue(bag[key]) : ''\n }\n }\n return next\n })\n\n return { columns: expanded, rows }\n}\n\nexport function formatValuePlain(value: any, col: ReportColumnDef, currency?: string): string {\n if (value == null || value === '') return ''\n // A stored code is not a word: 'new' in a Situação column is the database\n // talking to itself. Mapped here, so the table and the file agree.\n if (col.valueMap) return col.valueMap[String(value)] ?? String(value)\n if (typeof value === 'object') return plainValue(value)\n switch (col.type) {\n case 'currency':\n return formatCurrency(value, col.currency ?? currency)\n case 'date':\n return formatDate(value)\n case 'datetime':\n return formatDateTime(value)\n case 'number':\n return formatNumber(value)\n case 'percent':\n return formatPercent(value)\n case 'duration':\n return formatDuration(value)\n case 'boolean':\n return value ? 'Yes' : 'No'\n default:\n return String(value)\n }\n}\n\n// ---------------------------------------------------------------------------\n// ReportColumnDef[] → TanStack ColumnDef[]\n// ---------------------------------------------------------------------------\n\nexport function reportColumnsToTanstack(\n columns: ReportColumnDef[],\n currency?: string,\n): ColumnDef<Record<string, any>>[] {\n return columns\n .filter((c) => c.visible !== false)\n .map((col): ColumnDef<Record<string, any>> => {\n const sortable = col.sortable\n ?? ['text', 'number', 'percent', 'duration', 'currency', 'date', 'datetime', 'email'].includes(col.type)\n const alignRight = col.align === 'right'\n || (!col.align && ['currency', 'number', 'percent', 'duration'].includes(col.type))\n const alignCenter = col.align === 'center'\n\n return {\n accessorKey: col.key,\n header: col.label,\n enableSorting: sortable,\n cell: (ctx) => {\n const value = ctx.getValue()\n const row = ctx.row.original\n\n if (col.renderCell) {\n return col.renderCell(value, row)\n }\n\n // An open bag ({} from a lead that answered nothing) is as empty as\n // null — it just does not look like it to a `== null` test.\n if (value == null || value === '' || (typeof value === 'object' && !plainValue(value))) {\n return React.createElement('span', { className: 'text-muted-foreground' }, '—')\n }\n\n if (col.valueMap) {\n const label = col.valueMap[String(value)] ?? String(value)\n return React.createElement('span', { className: 'text-sm' }, label)\n }\n\n let content: React.ReactNode\n switch (col.type) {\n case 'person':\n content = React.createElement(PersonLink, {\n personId: col.idKey ? row[col.idKey] : null,\n name: String(value),\n kind: col.personKind,\n size: 'sm',\n className: 'text-xs',\n })\n break\n case 'currency':\n content = formatCurrency(value, col.currency ?? currency)\n break\n case 'date':\n content = formatDate(value)\n break\n case 'datetime':\n content = formatDateTime(value)\n break\n case 'boolean':\n content = value\n ? React.createElement('svg', { className: 'h-4 w-4 text-success', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2' },\n React.createElement('polyline', { points: '20 6 9 17 4 12' }),\n )\n : React.createElement('span', { className: 'text-muted-foreground' }, '—')\n break\n case 'number':\n content = formatNumber(value)\n break\n case 'percent':\n content = formatPercent(value)\n break\n case 'duration':\n content = formatDuration(value)\n break\n default:\n // plainValue, not String(): a jsonb column (form answers, custom\n // fields) rendered as the literal text \"[object Object]\".\n content = plainValue(value)\n }\n\n const cls = alignRight ? 'text-right' : alignCenter ? 'text-center' : undefined\n return cls\n ? React.createElement('div', { className: cls }, content)\n : React.createElement(React.Fragment, null, content)\n },\n meta: { align: alignRight ? 'right' : alignCenter ? 'center' : 'left' },\n }\n })\n}\n"]}
|
|
@@ -6,7 +6,13 @@ interface ExportDropdownProps {
|
|
|
6
6
|
filename: string;
|
|
7
7
|
currency?: string;
|
|
8
8
|
title?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Fetch the WHOLE result set. The table on screen is one page of 50, and a
|
|
11
|
+
* file holding 50 of 4,000 rows says nothing about being a fragment — so the
|
|
12
|
+
* export asks for everything before it writes. Absent ⇒ the page is exported.
|
|
13
|
+
*/
|
|
14
|
+
fetchAll?: () => Promise<Record<string, any>[]>;
|
|
9
15
|
}
|
|
10
|
-
export declare function ExportDropdown({ columns, data, filename, currency, title }: ExportDropdownProps): React.JSX.Element;
|
|
16
|
+
export declare function ExportDropdown({ columns, data, filename, currency, title, fetchAll }: ExportDropdownProps): React.JSX.Element;
|
|
11
17
|
export {};
|
|
12
18
|
//# sourceMappingURL=ExportDropdown.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportDropdown.d.ts","sourceRoot":"","sources":["../../src/components/ExportDropdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAUlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C,UAAU,mBAAmB;IAC3B,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"ExportDropdown.d.ts","sourceRoot":"","sources":["../../src/components/ExportDropdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAUlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C,UAAU,mBAAmB;IAC3B,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;CAChD;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,mBAAmB,qBAuDzG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportPagination.d.ts","sourceRoot":"","sources":["../../src/components/ReportPagination.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ReportPagination.d.ts","sourceRoot":"","sources":["../../src/components/ReportPagination.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACzC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAAE,qBAAqB,qBAkDhH"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { formatValuePlain } from './chunk-
|
|
1
|
+
import { expandBagColumns, formatValuePlain } from './chunk-4QIHTUXD.js';
|
|
2
2
|
|
|
3
3
|
// src/export/excel.ts
|
|
4
4
|
var load = (m) => new Function("m", "return import(m)")(m);
|
|
5
5
|
async function exportToExcel(columns, data, filename, currency) {
|
|
6
6
|
const XLSX = await load("xlsx");
|
|
7
|
-
const
|
|
7
|
+
const { columns: cols, rows: expanded } = expandBagColumns(columns, data);
|
|
8
|
+
const visibleCols = cols.filter((c) => c.visible !== false);
|
|
8
9
|
const header = visibleCols.map((c) => c.label);
|
|
9
|
-
const rows =
|
|
10
|
+
const rows = expanded.map(
|
|
10
11
|
(row) => visibleCols.map((col) => {
|
|
11
12
|
const value = row[col.key];
|
|
12
13
|
if (col.type === "number" || col.type === "currency") {
|
|
@@ -31,5 +32,5 @@ async function isExcelAvailable() {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export { exportToExcel, isExcelAvailable };
|
|
34
|
-
//# sourceMappingURL=excel-
|
|
35
|
-
//# sourceMappingURL=excel-
|
|
35
|
+
//# sourceMappingURL=excel-DSORXL4O.js.map
|
|
36
|
+
//# sourceMappingURL=excel-DSORXL4O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/export/excel.ts"],"names":[],"mappings":";;;AAKA,IAAM,IAAA,GAAO,CAAC,CAAA,KAAc,IAAI,SAAS,GAAA,EAAK,kBAAkB,EAAE,CAAC,CAAA;AAEnE,eAAsB,aAAA,CACpB,OAAA,EACA,IAAA,EACA,QAAA,EACA,QAAA,EACe;AACf,EAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAM,CAAA;AAE9B,EAAA,MAAM,EAAE,SAAS,IAAA,EAAM,IAAA,EAAM,UAAS,GAAI,gBAAA,CAAiB,SAAS,IAAI,CAAA;AACxE,EAAA,MAAM,cAAc,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,KAAK,CAAA;AAE1D,EAAA,MAAM,SAAS,WAAA,CAAY,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AAC7C,EAAA,MAAM,OAAO,QAAA,CAAS,GAAA;AAAA,IAAI,CAAC,GAAA,KACzB,WAAA,CAAY,GAAA,CAAI,CAAC,GAAA,KAAQ;AACvB,MAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AACzB,MAAA,IAAI,GAAA,CAAI,IAAA,KAAS,QAAA,IAAY,GAAA,CAAI,SAAS,UAAA,EAAY;AACpD,QAAA,MAAM,MAAM,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,WAAW,KAAK,CAAA;AAChE,QAAA,OAAO,KAAA,CAAM,GAAG,CAAA,GAAI,EAAA,GAAK,GAAA;AAAA,MAC3B;AACA,MAAA,OAAO,gBAAA,CAAiB,KAAA,EAAO,GAAA,EAAK,QAAQ,CAAA;AAAA,IAC9C,CAAC;AAAA,GACH;AAEA,EAAA,MAAM,EAAA,GAAK,KAAK,KAAA,CAAM,YAAA,CAAa,CAAC,MAAA,EAAQ,GAAG,IAAI,CAAC,CAAA;AACpD,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,QAAA,EAAS;AAC/B,EAAA,IAAA,CAAK,KAAA,CAAM,iBAAA,CAAkB,EAAA,EAAI,EAAA,EAAI,QAAQ,CAAA;AAC7C,EAAA,IAAA,CAAK,SAAA,CAAU,EAAA,EAAI,CAAA,EAAG,QAAQ,CAAA,KAAA,CAAO,CAAA;AACvC;AAEA,eAAsB,gBAAA,GAAqC;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,KAAK,MAAM,CAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF","file":"excel-DSORXL4O.js","sourcesContent":["import type { ReportColumnDef } from '../types'\nimport { expandBagColumns, formatValuePlain } from '../lib/columns'\n\n// Opaque dynamic import — hidden from Vite's static analysis so it won't\n// fail when xlsx is not installed (it's an optional peer dependency).\nconst load = (m: string) => new Function('m', 'return import(m)')(m) as Promise<any>\n\nexport async function exportToExcel(\n columns: ReportColumnDef[],\n data: Record<string, any>[],\n filename: string,\n currency?: string,\n): Promise<void> {\n const XLSX = await load('xlsx')\n // Mesma expansão do CSV: uma coluna por resposta do formulário.\n const { columns: cols, rows: expanded } = expandBagColumns(columns, data)\n const visibleCols = cols.filter((c) => c.visible !== false)\n\n const header = visibleCols.map((c) => c.label)\n const rows = expanded.map((row) =>\n visibleCols.map((col) => {\n const value = row[col.key]\n if (col.type === 'number' || col.type === 'currency') {\n const num = typeof value === 'number' ? value : parseFloat(value)\n return isNaN(num) ? '' : num\n }\n return formatValuePlain(value, col, currency)\n }),\n )\n\n const ws = XLSX.utils.aoa_to_sheet([header, ...rows])\n const wb = XLSX.utils.book_new()\n XLSX.utils.book_append_sheet(wb, ws, 'Report')\n XLSX.writeFile(wb, `${filename}.xlsx`)\n}\n\nexport async function isExcelAvailable(): Promise<boolean> {\n try {\n await load('xlsx')\n return true\n } catch {\n return false\n }\n}\n"]}
|
package/dist/export/csv.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../src/export/csv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C,wBAAgB,WAAW,CACzB,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,
|
|
1
|
+
{"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../src/export/csv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C,wBAAgB,WAAW,CACzB,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CAaN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"excel.d.ts","sourceRoot":"","sources":["../../src/export/excel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAO/C,wBAAsB,aAAa,CACjC,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"excel.d.ts","sourceRoot":"","sources":["../../src/export/excel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAO/C,wBAAsB,aAAa,CACjC,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,11 +59,12 @@ export declare function createAnalyticsPlugin(options?: AnalyticsPluginOptions):
|
|
|
59
59
|
* `reports` option is still first-class and their catalogues need no rewrite.
|
|
60
60
|
*/
|
|
61
61
|
export declare function createReportsPlugin(options: ReportsPluginOptions): PluginManifest;
|
|
62
|
-
export { AnalyticsSurface, ANALYTICS_BASE, REPORTS_BASE, cardColumns, useAnalyticsConfig, useAnalyticsCards, useOverviewCards, } from './views/AnalyticsSurface';
|
|
62
|
+
export { AnalyticsSurface, ANALYTICS_BASE, REPORTS_BASE, SETTINGS_ROUTE, cardColumns, useAnalyticsConfig, useAnalyticsCards, useAnalyticsCatalogue, useOverviewCards, } from './views/AnalyticsSurface';
|
|
63
63
|
export type { AnalyticsLabels, ResolvedAnalyticsConfig, AnalyticsAssistantConfig, } from './views/AnalyticsSurface';
|
|
64
64
|
export { AnalyticsModule } from './views/AnalyticsModule';
|
|
65
65
|
export type { AnalyticsView, AnalyticsModuleProps } from './views/AnalyticsModule';
|
|
66
66
|
export { AnalyticsOverview } from './views/AnalyticsOverview';
|
|
67
|
+
export { AnalyticsSettingsPage } from './views/AnalyticsSettingsPage';
|
|
67
68
|
export { ReportsListPage } from './views/ReportsListPage';
|
|
68
69
|
export { AnalyticsReportViewer } from './views/AnalyticsReportViewer';
|
|
69
70
|
export { reportDefToCard, reportDefsToCards } from './lib/legacy';
|
|
@@ -72,6 +73,8 @@ export { createSupabaseAnalyticsProvider } from './data/analytics-supabase';
|
|
|
72
73
|
export type { SupabaseAnalyticsProviderConfig } from './data/analytics-supabase';
|
|
73
74
|
export { createMockAnalyticsProvider } from './data/analytics-mock';
|
|
74
75
|
export { markViewed, useLastViewed } from './lib/lastViewed';
|
|
76
|
+
export { useAnalyticsPrefs, resolveCards, resolveCustomReport, fieldPalette, sourceKey, setCardPref, clearCardPref, setOverviewOrder, saveCustomReport, deleteCustomReport, resetAnalyticsPrefs, } from './lib/preferences';
|
|
77
|
+
export type { AnalyticsPrefs, AnalyticsCardPref, CustomReport, FieldPalette } from './lib/preferences';
|
|
75
78
|
export { setReportsTenantId, getReportsTenantId } from './lib/tenant';
|
|
76
79
|
export type { ReportDef, ReportColumnDef, ReportFilterDef, ReportDateRange, ReportQueryState, ReportBadge, ReportDataSource, ReportGrain, ReportAllowedAction, ReportFilterOption, ReportsPluginOptions, ReportsPluginLabels, ResolvedReportsConfig, } from './types';
|
|
77
80
|
export type { ReportDataProvider, ReportResult } from './data/types';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAC/F,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAOvD,OAAO,EAEL,KAAK,eAAe,EAAgC,KAAK,wBAAwB,EAClF,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|