@svgrid/enterprise 3.1.22 → 3.1.24
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/SvGridBoard.svelte +39 -0
- package/dist/SvGridGallery.svelte +23 -0
- package/dist/SvGridScheduler.svelte +25 -7
- package/dist/cdn/svgrid-enterprise.svelte-external.js +13739 -13667
- package/dist/designer/assets/{index-ICCQKTGR.js → index-BB1G1RTR.js} +318 -318
- package/dist/designer/assets/index-CHx3F4Ij.css +1 -0
- package/dist/designer/assets/merges-Bg-KqPEl.js +1 -0
- package/dist/designer/index.html +2 -2
- package/dist/export.d.ts +7 -0
- package/dist/export.js +7 -0
- package/dist/fields/RecordView.svelte +5 -2
- package/dist/fields/activity.svelte.d.ts +5 -2
- package/dist/fields/activity.svelte.js +4 -3
- package/dist/fields/grid-access.d.ts +1 -1
- package/dist/fields/grid-access.js +13 -3
- package/dist/fields/index.d.ts +18 -0
- package/dist/fields/index.js +31 -0
- package/dist/node/studio.js +2 -2
- package/dist/review/GhostCell.svelte +60 -0
- package/dist/review/GhostCell.svelte.d.ts +14 -0
- package/dist/review/RichCellMark.svelte +72 -0
- package/dist/review/RichCellMark.svelte.d.ts +8 -0
- package/dist/review/SvReviewPanel.svelte +759 -0
- package/dist/review/SvReviewPanel.svelte.d.ts +16 -0
- package/dist/review/adapters.d.ts +91 -0
- package/dist/review/adapters.js +127 -0
- package/dist/review/agent.d.ts +65 -0
- package/dist/review/agent.js +237 -0
- package/dist/review/card-marks.svelte.d.ts +42 -0
- package/dist/review/card-marks.svelte.js +51 -0
- package/dist/review/cluster.d.ts +40 -0
- package/dist/review/cluster.js +386 -0
- package/dist/review/equal.d.ts +14 -0
- package/dist/review/equal.js +40 -0
- package/dist/review/formats.d.ts +42 -0
- package/dist/review/formats.js +48 -0
- package/dist/review/ghost.d.ts +18 -0
- package/dist/review/ghost.js +105 -0
- package/dist/review/index.d.ts +42 -0
- package/dist/review/index.js +36 -0
- package/dist/review/messages.d.ts +122 -0
- package/dist/review/messages.js +141 -0
- package/dist/review/model.svelte.d.ts +294 -0
- package/dist/review/model.svelte.js +890 -0
- package/dist/review/pending-filter.d.ts +26 -0
- package/dist/review/pending-filter.js +71 -0
- package/dist/review/rich-cells.d.ts +1 -0
- package/dist/review/rich-cells.js +36 -0
- package/dist/review/types.d.ts +96 -0
- package/dist/review/types.js +7 -0
- package/dist/upgrade-prompt.d.ts +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/wc/merges-DQTOlMWM.js +109 -0
- package/dist/wc/sv-sheet-element.js +5688 -5735
- package/package.json +9 -3
- package/dist/designer/assets/index-9APkRkTg.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-Dd_uD5pT.js";var t=e({buildMergeIndex:()=>r,endOf:()=>s,expandRectToMerges:()=>c,isCovered:()=>a,mergeAt:()=>i,mergeDrawAt:()=>u,originOf:()=>o,stepPastMerge:()=>l}),n=(e,t)=>`${e}:${t}`;function r(e){if(!e||e.length===0)return null;let t=new Map,r=[];for(let i of e){let e=Math.max(1,Math.floor(i.rowSpan)),a=Math.max(1,Math.floor(i.colSpan));if(e===1&&a===1)continue;let o={rowIndex:i.rowIndex,colIndex:i.colIndex,rowSpan:e,colSpan:a};r.push(o);for(let r=o.rowIndex;r<o.rowIndex+e;r+=1)for(let e=o.colIndex;e<o.colIndex+a;e+=1)t.set(n(r,e),o)}return r.length?{list:r,byCell:t}:null}function i(e,t,r){return e?.byCell.get(n(t,r))}function a(e,t,n){let r=i(e,t,n);return!!r&&(r.rowIndex!==t||r.colIndex!==n)}function o(e,t,n){let r=i(e,t,n);return r?{rowIndex:r.rowIndex,colIndex:r.colIndex}:{rowIndex:t,colIndex:n}}function s(e,t,n){let r=i(e,t,n);return r?{rowIndex:r.rowIndex+r.rowSpan-1,colIndex:r.colIndex+r.colSpan-1}:{rowIndex:t,colIndex:n}}function c(e,t){if(!e)return t;let{minRow:n,maxRow:r,minCol:i,maxCol:a}=t;for(let t=0;t<64;t+=1){let t=!1;for(let o of e.list){let e=o.rowIndex+o.rowSpan-1,s=o.colIndex+o.colSpan-1;o.rowIndex<=r&&e>=n&&o.colIndex<=a&&s>=i&&(o.rowIndex<n&&(n=o.rowIndex,t=!0),e>r&&(r=e,t=!0),o.colIndex<i&&(i=o.colIndex,t=!0),s>a&&(a=s,t=!0))}if(!t)break}return n===t.minRow&&r===t.maxRow&&i===t.minCol&&a===t.maxCol?t:{minRow:n,maxRow:r,minCol:i,maxCol:a}}function l(e,t,n,r){if(!e)return n;let a=i(e,n.rowIndex,n.colIndex);if(!a)return n;if(i(e,t.rowIndex,t.colIndex)!==a)return{rowIndex:a.rowIndex,colIndex:a.colIndex};let o=Math.sign(n.rowIndex-t.rowIndex),s=Math.sign(n.colIndex-t.colIndex);if(o===0&&s===0)return{rowIndex:a.rowIndex,colIndex:a.colIndex};let c=n.rowIndex,l=n.colIndex;if(o>0?c=a.rowIndex+a.rowSpan:o<0&&(c=a.rowIndex-1),s>0?l=a.colIndex+a.colSpan:s<0&&(l=a.colIndex-1),c<0||c>r.maxRow||l<0||l>r.maxCol)return{rowIndex:a.rowIndex,colIndex:a.colIndex};let u=i(e,c,l);return u?{rowIndex:u.rowIndex,colIndex:u.colIndex}:{rowIndex:c,colIndex:l}}function u(e,t,n,r){let a=i(e,t,n);if(!a)return null;let o=Math.max(a.rowIndex,r.firstRow),s=Math.max(a.colIndex,r.firstCol);if(t!==o||n!==s)return{kind:`skip`};let c=o===a.rowIndex&&s===a.colIndex,l=Math.max(1,Math.min(a.rowIndex+a.rowSpan-t,r.lastRow-t+1)),u=Math.max(1,Math.min(a.colIndex+a.colSpan-n,r.lastCol-n+1));return{kind:c?`origin`:`continuation`,merge:a,rowSpan:l,colSpan:u}}export{t};
|
package/dist/designer/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>SvGrid Studio - Designer</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-BB1G1RTR.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-Dd_uD5pT.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/disclose-version-CIm4S9xS.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/cell-formatting-JoxA0t65.js">
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<link rel="stylesheet" crossorigin href="./assets/SvMenuList-DJ47ba1h.css">
|
|
46
46
|
<link rel="stylesheet" crossorigin href="./assets/SvGridChart-BgLuPO7I.css">
|
|
47
47
|
<link rel="stylesheet" crossorigin href="./assets/SvGridChartPanel-4Pc8y5yO.css">
|
|
48
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
48
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CHx3F4Ij.css">
|
|
49
49
|
</head>
|
|
50
50
|
<body>
|
|
51
51
|
<div id="app"></div>
|
package/dist/export.d.ts
CHANGED
|
@@ -304,6 +304,13 @@ export declare function buildLinkResolver<TData extends RowData>(cols: ReadonlyA
|
|
|
304
304
|
* the numeric / currency columns. Values use the same formatting as the grid.
|
|
305
305
|
*/
|
|
306
306
|
export declare function buildGroupedPdfBody<TData extends RowData>(cols: ReadonlyArray<ExportColumn<TData>>, rows: ReadonlyArray<TData>, groupBy: ReadonlyArray<string>): PdfBodyRow[];
|
|
307
|
+
/**
|
|
308
|
+
* Export a grid's rows to a file: xlsx, xls, pdf, csv, tsv, html, json, xml
|
|
309
|
+
* or md, picked by `opts.format`. It reads the columns and rows through the
|
|
310
|
+
* grid api, so sorting, filtering and grouping carry over, and downloads the
|
|
311
|
+
* file unless `opts.download` is false. Resolves with the file (`ExportResult`)
|
|
312
|
+
* on the paths that build it in memory, undefined on the others.
|
|
313
|
+
*/
|
|
307
314
|
export declare function exportGrid<TFeatures extends TableFeatures, TData extends RowData>(api: SvGridApi<TFeatures, TData>, opts: ExportOptions<TData>): Promise<ExportResult | undefined>;
|
|
308
315
|
/** Native formats that can be placed on the clipboard. */
|
|
309
316
|
export type ClipboardFormat = 'csv' | 'tsv' | 'html' | 'json' | 'xml' | 'md';
|
package/dist/export.js
CHANGED
|
@@ -833,6 +833,13 @@ async function exportXlsxNative(api, opts) {
|
|
|
833
833
|
opts.onProgress?.({ phase: 'write', ratio: 1, total: src.length });
|
|
834
834
|
return deliver(blob, ensureExt(filename, 'xlsx'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', src.length, opts.download);
|
|
835
835
|
}
|
|
836
|
+
/**
|
|
837
|
+
* Export a grid's rows to a file: xlsx, xls, pdf, csv, tsv, html, json, xml
|
|
838
|
+
* or md, picked by `opts.format`. It reads the columns and rows through the
|
|
839
|
+
* grid api, so sorting, filtering and grouping carry over, and downloads the
|
|
840
|
+
* file unless `opts.download` is false. Resolves with the file (`ExportResult`)
|
|
841
|
+
* on the paths that build it in memory, undefined on the others.
|
|
842
|
+
*/
|
|
836
843
|
export async function exportGrid(api, opts) {
|
|
837
844
|
assertEnterpriseLicensed('Export');
|
|
838
845
|
// Native text formats have their own dependency-free, streaming path.
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
|
|
144
144
|
// ---- Activity ---------------------------------------------------------------
|
|
145
145
|
const allCols = $derived([...columns, ...hidden])
|
|
146
|
-
type FeedItem = { key: string; at: number; by?: string; automation?: string; remote?: boolean; kind: 'edit' | 'added' | 'comment'; field: string; text: string; from?: string }
|
|
146
|
+
type FeedItem = { key: string; at: number; by?: string; automation?: string; via?: string; remote?: boolean; kind: 'edit' | 'added' | 'comment'; field: string; text: string; from?: string }
|
|
147
147
|
const feed = $derived.by(() => {
|
|
148
148
|
if (!row) return []
|
|
149
149
|
const edits = changesOf(ctrl, row.id).map((ch): FeedItem => {
|
|
@@ -155,6 +155,7 @@
|
|
|
155
155
|
at: ch.at,
|
|
156
156
|
by: ch.by,
|
|
157
157
|
automation: ch.automation,
|
|
158
|
+
via: ch.via,
|
|
158
159
|
remote: ch.remote,
|
|
159
160
|
kind: 'edit',
|
|
160
161
|
field: c ? label(c) : ch.columnId,
|
|
@@ -166,8 +167,10 @@
|
|
|
166
167
|
const notes = commentsOf(ctrl, row.id).map((n): FeedItem => ({ key: n.id, at: n.at, by: n.by, kind: 'comment', field: '', text: n.text }))
|
|
167
168
|
return [...edits, ...notes].sort((a, b) => a.at - b.at)
|
|
168
169
|
})
|
|
170
|
+
const person = (item: FeedItem) => (item.by ? (findFieldUser(item.by)?.name ?? 'Someone') : item.remote ? 'Someone else' : 'You')
|
|
171
|
+
// A proposal someone accepted (change review) is credited to what proposed it, and to them.
|
|
169
172
|
const who = (item: FeedItem) =>
|
|
170
|
-
item.automation ? `Automation: ${item.automation}` : item.
|
|
173
|
+
item.automation ? `Automation: ${item.automation}` : item.via ? `${item.via} (accepted by ${person(item)})` : person(item)
|
|
171
174
|
// Shown here: a change made elsewhere is seen, so the grid stops marking it.
|
|
172
175
|
$effect(() => {
|
|
173
176
|
const id = row?.id
|
|
@@ -25,6 +25,8 @@ export type RecordChange = {
|
|
|
25
25
|
by?: string;
|
|
26
26
|
/** The automation that made it, by name. */
|
|
27
27
|
automation?: string;
|
|
28
|
+
/** What proposed it, when `by` accepted a proposal (change review): "CRM agent". */
|
|
29
|
+
via?: string;
|
|
28
30
|
/** Made elsewhere (another user, a script, an agent) and read from the database. */
|
|
29
31
|
remote?: boolean;
|
|
30
32
|
/** The record was added elsewhere: one entry, with no field. */
|
|
@@ -60,9 +62,10 @@ export declare function setRecordComments(next: RecordCommentStore | null): void
|
|
|
60
62
|
/**
|
|
61
63
|
* Note a change to a cell (called after every edit, paste, fill and clear).
|
|
62
64
|
* `scope` is the grid, or the table (its base and id) for a change made
|
|
63
|
-
* outside it (an automation). `automation` names the automation that made it
|
|
65
|
+
* outside it (an automation). `automation` names the automation that made it;
|
|
66
|
+
* `via` names what proposed a change the signed-in user accepted.
|
|
64
67
|
*/
|
|
65
|
-
export declare function noteChange(scope: ActivityScope, rowId: string, columnId: string, value: unknown, automation?: string): void;
|
|
68
|
+
export declare function noteChange(scope: ActivityScope, rowId: string, columnId: string, value: unknown, automation?: string, via?: string): void;
|
|
66
69
|
export declare function changesOf(scope: ActivityScope, rowId: string): ReadonlyArray<RecordChange>;
|
|
67
70
|
/**
|
|
68
71
|
* Note a change made elsewhere and read from the database: an activity entry
|
|
@@ -50,13 +50,14 @@ export function setRecordComments(next) {
|
|
|
50
50
|
/**
|
|
51
51
|
* Note a change to a cell (called after every edit, paste, fill and clear).
|
|
52
52
|
* `scope` is the grid, or the table (its base and id) for a change made
|
|
53
|
-
* outside it (an automation). `automation` names the automation that made it
|
|
53
|
+
* outside it (an automation). `automation` names the automation that made it;
|
|
54
|
+
* `via` names what proposed a change the signed-in user accepted.
|
|
54
55
|
*/
|
|
55
|
-
export function noteChange(scope, rowId, columnId, value, automation) {
|
|
56
|
+
export function noteChange(scope, rowId, columnId, value, automation, via) {
|
|
56
57
|
const byRow = rowsOf(changes, scope, true);
|
|
57
58
|
const list = byRow.get(rowId) ?? [];
|
|
58
59
|
// Kept short: the panel shows the latest.
|
|
59
|
-
list.push({ at: Date.now(), ...(automation ? { automation } : { by: getCurrentUser()?.id }), columnId, value: Array.isArray(value) ? [...value] : value });
|
|
60
|
+
list.push({ at: Date.now(), ...(automation ? { automation } : { by: getCurrentUser()?.id }), ...(via ? { via } : {}), columnId, value: Array.isArray(value) ? [...value] : value });
|
|
60
61
|
if (list.length > 50)
|
|
61
62
|
list.splice(0, list.length - 50);
|
|
62
63
|
byRow.set(rowId, list);
|
|
@@ -16,7 +16,7 @@ export type FieldColumn = {
|
|
|
16
16
|
};
|
|
17
17
|
/** Called on every draw of a grid with fields turned on. */
|
|
18
18
|
export declare function rememberGrid(ctrl: any): void;
|
|
19
|
-
/** The grid an api belongs to; undefined until that grid has drawn once. */
|
|
19
|
+
/** The grid an api belongs to (or a `$state` proxy of it); undefined until that grid has drawn once. */
|
|
20
20
|
export declare function gridOf(api: unknown): any;
|
|
21
21
|
export declare const columnIdOf: (def: Record<string, any>) => string;
|
|
22
22
|
/** Every data column (declared ones with a field), in screen order, hidden ones last. */
|
|
@@ -7,15 +7,25 @@
|
|
|
7
7
|
import { getAdvancedFilterEngine } from '@svgrid/grid';
|
|
8
8
|
// The grid behind each api object (the grid keeps one api per grid).
|
|
9
9
|
const grids = new WeakMap();
|
|
10
|
+
// The same, by one of the api's methods. An app that keeps the api in
|
|
11
|
+
// `$state` hands over a proxy of it, which is not the object above; Svelte
|
|
12
|
+
// does not proxy functions, so the proxy's methods are the api's own.
|
|
13
|
+
const byMethod = new WeakMap();
|
|
10
14
|
/** Called on every draw of a grid with fields turned on. */
|
|
11
15
|
export function rememberGrid(ctrl) {
|
|
12
16
|
const api = ctrl?.buildApi?.();
|
|
13
|
-
if (api && !grids.has(api))
|
|
17
|
+
if (api && !grids.has(api)) {
|
|
14
18
|
grids.set(api, ctrl);
|
|
19
|
+
if (typeof api.getData === 'function')
|
|
20
|
+
byMethod.set(api.getData, ctrl);
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
|
-
/** The grid an api belongs to; undefined until that grid has drawn once. */
|
|
23
|
+
/** The grid an api belongs to (or a `$state` proxy of it); undefined until that grid has drawn once. */
|
|
17
24
|
export function gridOf(api) {
|
|
18
|
-
|
|
25
|
+
if (!api || typeof api !== 'object')
|
|
26
|
+
return undefined;
|
|
27
|
+
const getData = api.getData;
|
|
28
|
+
return grids.get(api) ?? (typeof getData === 'function' ? byMethod.get(getData) : undefined);
|
|
19
29
|
}
|
|
20
30
|
export const columnIdOf = (def) => String(def.id ?? def.field ?? '');
|
|
21
31
|
/** Every data column (declared ones with a field), in screen order, hidden ones last. */
|
package/dist/fields/index.d.ts
CHANGED
|
@@ -25,6 +25,24 @@ export type { FieldView, FieldViewType, ColorSetting } from './view-model.js';
|
|
|
25
25
|
export type { FieldPropertyDef, FieldEditorContext, FieldFillContext, FieldRowContext } from './registry.svelte.js';
|
|
26
26
|
export { BUILTIN_FIELD_TYPES } from './builtin-types.js';
|
|
27
27
|
export { setAttachmentUploader, attachmentsFromText, attachmentsText, toAttachments, type Attachment, type AttachmentFieldProps, type AttachmentUploader, type AttachmentUploadContext, } from './attachments.js';
|
|
28
|
+
/**
|
|
29
|
+
* Change review (`@svgrid/enterprise/review`) in SvGrid Base: what an edit
|
|
30
|
+
* does, done for each accepted proposal. Last modified time / by fields are
|
|
31
|
+
* stamped, and the record's activity notes the change, credited to the
|
|
32
|
+
* signed-in user who accepted it and to what proposed it ("CRM agent
|
|
33
|
+
* (accepted by Dana)"). An undo is noted as the user's own change.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* const review = createReview({ api: () => api, setRows, onApply: baseReviewApplied(() => api) })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function baseReviewApplied(api: unknown): (applied: ReadonlyArray<{
|
|
40
|
+
rowId: string;
|
|
41
|
+
field: string;
|
|
42
|
+
source: {
|
|
43
|
+
label: string;
|
|
44
|
+
};
|
|
45
|
+
}>, how: 'accept' | 'undo' | 'redo', rows?: ReadonlyArray<unknown>) => void;
|
|
28
46
|
/**
|
|
29
47
|
* Turn field types on for every `<SvGrid>` on the page: registers the
|
|
30
48
|
* built-in types and plugs the cell drawing into the grid. Safe to call more
|
package/dist/fields/index.js
CHANGED
|
@@ -184,6 +184,37 @@ function stampModified(ctrl, row, columnId) {
|
|
|
184
184
|
overlay(id, (row[c.field] = author));
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Change review (`@svgrid/enterprise/review`) in SvGrid Base: what an edit
|
|
189
|
+
* does, done for each accepted proposal. Last modified time / by fields are
|
|
190
|
+
* stamped, and the record's activity notes the change, credited to the
|
|
191
|
+
* signed-in user who accepted it and to what proposed it ("CRM agent
|
|
192
|
+
* (accepted by Dana)"). An undo is noted as the user's own change.
|
|
193
|
+
*
|
|
194
|
+
* ```ts
|
|
195
|
+
* const review = createReview({ api: () => api, setRows, onApply: baseReviewApplied(() => api) })
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export function baseReviewApplied(api) {
|
|
199
|
+
return (applied, how, next) => {
|
|
200
|
+
const ctrl = gridOf(typeof api === 'function' ? api() : api);
|
|
201
|
+
if (!ctrl)
|
|
202
|
+
return;
|
|
203
|
+
const gridApi = ctrl.buildApi?.();
|
|
204
|
+
const idOf = gridApi?.getOption?.('getRowId');
|
|
205
|
+
const rows = new Map();
|
|
206
|
+
(next ?? gridApi?.getData?.() ?? []).forEach((r, i) => rows.set(String(idOf ? idOf(r, i) : i), r));
|
|
207
|
+
const columnOf = new Map((ctrl.allColumns ?? []).map((c) => [c.columnDef?.field, c.id]));
|
|
208
|
+
for (const p of applied) {
|
|
209
|
+
const row = rows.get(p.rowId);
|
|
210
|
+
const columnId = columnOf.get(p.field);
|
|
211
|
+
if (!row || !columnId)
|
|
212
|
+
continue;
|
|
213
|
+
stampModified(ctrl, row, columnId);
|
|
214
|
+
noteChange(ctrl, p.rowId, columnId, row[p.field], undefined, how === 'undo' ? undefined : p.source.label);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
187
218
|
/** The record's activity: what a cell now holds after an edit. */
|
|
188
219
|
function noteEdit(ctrl, row, columnId) {
|
|
189
220
|
if (!row)
|
package/dist/node/studio.js
CHANGED
|
@@ -16506,7 +16506,7 @@ function hasFieldConditions(schema) {
|
|
|
16506
16506
|
*
|
|
16507
16507
|
* `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
|
|
16508
16508
|
*/
|
|
16509
|
-
var SVGRID_VERSION = "3.1.
|
|
16509
|
+
var SVGRID_VERSION = "3.1.24";
|
|
16510
16510
|
/**
|
|
16511
16511
|
* The version of `@svgrid/grid`, which releases on its own line: enterprise is
|
|
16512
16512
|
* on 3.1.x while the grid is on 3.0.x.
|
|
@@ -16519,7 +16519,7 @@ var SVGRID_VERSION = "3.1.22";
|
|
|
16519
16519
|
*
|
|
16520
16520
|
* `version.test.ts` asserts this matches packages/grid/package.json.
|
|
16521
16521
|
*/
|
|
16522
|
-
var GRID_VERSION = "3.0.
|
|
16522
|
+
var GRID_VERSION = "3.0.22";
|
|
16523
16523
|
//#endregion
|
|
16524
16524
|
//#region src/studio/emit-project.ts
|
|
16525
16525
|
var has = (blocks, kind) => blocks.some((b) => b.config.kind === kind);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
A cell with a pending proposal: the proposed value, then what the cell
|
|
3
|
+
holds now, struck through. `own` is what the column's own `cell` returned (a
|
|
4
|
+
component, a snippet, text, or nothing for a plain column).
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import type { Component, Snippet } from 'svelte'
|
|
8
|
+
|
|
9
|
+
let { own, before, beforeText, after, empty, title }: {
|
|
10
|
+
own: unknown
|
|
11
|
+
before: unknown
|
|
12
|
+
beforeText: string
|
|
13
|
+
after: string
|
|
14
|
+
/** The text for a blank proposed value, in the review's wording. */
|
|
15
|
+
empty: string
|
|
16
|
+
/** "{source} proposes {value} - reason", built by the wrapper. */
|
|
17
|
+
title: string
|
|
18
|
+
} = $props()
|
|
19
|
+
|
|
20
|
+
// The grid's render configs (`renderComponent` / `renderSnippet`) are read by
|
|
21
|
+
// shape: the classes are not part of the public surface.
|
|
22
|
+
type ComponentConfig = { component: Component<any>; props?: Record<string, unknown> }
|
|
23
|
+
type SnippetConfig = { snippet: Snippet<[unknown]>; params?: unknown }
|
|
24
|
+
const isObj = (v: unknown): v is Record<string, unknown> => v !== null && typeof v === 'object'
|
|
25
|
+
const ownComponent = $derived(isObj(own) && typeof own.component === 'function' ? (own as ComponentConfig) : null)
|
|
26
|
+
const ownSnippet = $derived(isObj(own) && typeof own.snippet === 'function' ? (own as SnippetConfig) : null)
|
|
27
|
+
const ownText = $derived(typeof own === 'string' || typeof own === 'number' ? String(own) : beforeText)
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<span class="sv-review-ghost" {title}>
|
|
31
|
+
<span class="sv-review-ghost-after">{after || empty}</span>
|
|
32
|
+
{#if before != null && before !== ''}
|
|
33
|
+
<s class="sv-review-ghost-before">
|
|
34
|
+
{#if ownComponent}<ownComponent.component {...ownComponent.props ?? {}} />{:else if ownSnippet}{@render ownSnippet.snippet(ownSnippet.params)}{:else}{ownText}{/if}
|
|
35
|
+
</s>
|
|
36
|
+
{/if}
|
|
37
|
+
</span>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
/* Inline text beside the grid's own icon: a block or flex box here would drop
|
|
41
|
+
to a line of its own. The proposed value comes first and is plain text, so
|
|
42
|
+
the cell's ellipsis cuts its end. The struck value is one box, at most half
|
|
43
|
+
the cell: when it does not fit, the ellipsis takes it whole instead of
|
|
44
|
+
leaving a cut-off fragment, and the cell's title still names it. */
|
|
45
|
+
.sv-review-ghost-before {
|
|
46
|
+
display: inline-block;
|
|
47
|
+
max-width: 50%;
|
|
48
|
+
margin-left: 6px;
|
|
49
|
+
overflow: hidden;
|
|
50
|
+
text-overflow: ellipsis;
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
vertical-align: bottom;
|
|
53
|
+
color: var(--sg-muted, #6b7280);
|
|
54
|
+
text-decoration-thickness: 1px;
|
|
55
|
+
}
|
|
56
|
+
.sv-review-ghost-after {
|
|
57
|
+
color: var(--sg-fg, inherit);
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
own: unknown;
|
|
4
|
+
before: unknown;
|
|
5
|
+
beforeText: string;
|
|
6
|
+
after: string;
|
|
7
|
+
/** The text for a blank proposed value, in the review's wording. */
|
|
8
|
+
empty: string;
|
|
9
|
+
/** "{source} proposes {value} - reason", built by the wrapper. */
|
|
10
|
+
title: string;
|
|
11
|
+
};
|
|
12
|
+
declare const GhostCell: Component<$$ComponentProps, {}, "">;
|
|
13
|
+
type GhostCell = ReturnType<typeof GhostCell>;
|
|
14
|
+
export default GhostCell;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The proposed value after a rich cell (a select, a rating, a person): the
|
|
3
|
+
cell draws as it always does, and "-> Closed" follows it. The text is the
|
|
4
|
+
column's own formatter's (a person's name, not their id), else the plain
|
|
5
|
+
formatted value.
|
|
6
|
+
-->
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { formatValueForExport } from '@svgrid/grid'
|
|
9
|
+
import { cellProposalFor } from './card-marks.svelte'
|
|
10
|
+
import { showValue } from './cluster'
|
|
11
|
+
import { fill } from './messages'
|
|
12
|
+
|
|
13
|
+
let { ctrl, row, column }: { ctrl: any; row: any; column: any } = $props()
|
|
14
|
+
|
|
15
|
+
/** A value's label from a static options list ({ value, label } or plain values); null when there is none. */
|
|
16
|
+
function optionLabels(options: unknown): ((v: unknown) => string | null) | null {
|
|
17
|
+
if (!Array.isArray(options)) return null
|
|
18
|
+
const byValue = new Map<string, string>()
|
|
19
|
+
for (const o of options) {
|
|
20
|
+
if (o && typeof o === 'object' && 'value' in o) byValue.set(String((o as { value: unknown }).value), String((o as { label?: unknown }).label ?? (o as { value: unknown }).value))
|
|
21
|
+
else byValue.set(String(o), String(o))
|
|
22
|
+
}
|
|
23
|
+
return (v) => byValue.get(String(v)) ?? null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const proposal = $derived(cellProposalFor(ctrl?.props?.getRowId, row?.original, String(row?.id), column?.columnDef?.field))
|
|
27
|
+
const text = $derived.by(() => {
|
|
28
|
+
if (!proposal) return ''
|
|
29
|
+
const def = column?.columnDef ?? {}
|
|
30
|
+
const value = proposal.after
|
|
31
|
+
if (value == null || value === '') return proposal.empty
|
|
32
|
+
if (typeof def.formatter === 'function') {
|
|
33
|
+
try {
|
|
34
|
+
return String(def.formatter({ value, row, column, table: ctrl?.grid }) ?? '')
|
|
35
|
+
} catch {
|
|
36
|
+
// A formatter that needs more than a value: fall back to the value.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// A list or chips column shows option labels, not stored values.
|
|
40
|
+
const labelOf = optionLabels(def.editorOptions)
|
|
41
|
+
const one = (v: unknown) => labelOf?.(v) ?? (Array.isArray(value) ? showValue(v).replace(/^"|"$/g, '') : formatValueForExport(v, def.format))
|
|
42
|
+
return Array.isArray(value) ? value.map(one).join(', ') : one(value)
|
|
43
|
+
})
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
{#if proposal}
|
|
47
|
+
<span
|
|
48
|
+
class="sv-review-cellmark"
|
|
49
|
+
title="{fill(proposal.proposes, { source: proposal.source, value: text })}{proposal.reason ? ` - ${proposal.reason}` : ''}"
|
|
50
|
+
><span aria-hidden="true">→</span> {text}</span>
|
|
51
|
+
{/if}
|
|
52
|
+
|
|
53
|
+
<style>
|
|
54
|
+
.sv-review-cellmark {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: 3px;
|
|
58
|
+
margin-left: 6px;
|
|
59
|
+
flex: none;
|
|
60
|
+
max-width: 60%;
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
text-overflow: ellipsis;
|
|
64
|
+
font-size: 0.92em;
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
color: var(--sg-fg, #111827);
|
|
67
|
+
}
|
|
68
|
+
.sv-review-cellmark > span {
|
|
69
|
+
color: var(--sg-muted, #6b7280);
|
|
70
|
+
font-weight: 400;
|
|
71
|
+
}
|
|
72
|
+
</style>
|