@shotleybuilder/svelte-gridlite-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -0
- package/dist/GridLite.svelte +1361 -0
- package/dist/GridLite.svelte.d.ts +42 -0
- package/dist/components/CellContextMenu.svelte +209 -0
- package/dist/components/CellContextMenu.svelte.d.ts +28 -0
- package/dist/components/ColumnMenu.svelte +234 -0
- package/dist/components/ColumnMenu.svelte.d.ts +29 -0
- package/dist/components/ColumnPicker.svelte +403 -0
- package/dist/components/ColumnPicker.svelte.d.ts +29 -0
- package/dist/components/FilterBar.svelte +390 -0
- package/dist/components/FilterBar.svelte.d.ts +38 -0
- package/dist/components/FilterCondition.svelte +643 -0
- package/dist/components/FilterCondition.svelte.d.ts +35 -0
- package/dist/components/GroupBar.svelte +463 -0
- package/dist/components/GroupBar.svelte.d.ts +33 -0
- package/dist/components/RowDetailModal.svelte +213 -0
- package/dist/components/RowDetailModal.svelte.d.ts +25 -0
- package/dist/components/SortBar.svelte +232 -0
- package/dist/components/SortBar.svelte.d.ts +30 -0
- package/dist/components/SortCondition.svelte +129 -0
- package/dist/components/SortCondition.svelte.d.ts +30 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +29 -0
- package/dist/query/builder.d.ts +160 -0
- package/dist/query/builder.js +432 -0
- package/dist/query/live.d.ts +50 -0
- package/dist/query/live.js +118 -0
- package/dist/query/schema.d.ts +30 -0
- package/dist/query/schema.js +75 -0
- package/dist/state/migrations.d.ts +29 -0
- package/dist/state/migrations.js +113 -0
- package/dist/state/views.d.ts +54 -0
- package/dist/state/views.js +130 -0
- package/dist/styles/gridlite.css +966 -0
- package/dist/types.d.ts +164 -0
- package/dist/types.js +2 -0
- package/dist/utils/filters.d.ts +14 -0
- package/dist/utils/filters.js +49 -0
- package/dist/utils/formatters.d.ts +16 -0
- package/dist/utils/formatters.js +39 -0
- package/dist/utils/fuzzy.d.ts +47 -0
- package/dist/utils/fuzzy.js +142 -0
- package/package.json +76 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Introspection for GridLite
|
|
3
|
+
*
|
|
4
|
+
* Queries information_schema.columns to discover column names, types,
|
|
5
|
+
* and nullability for a given table. Maps Postgres data types to
|
|
6
|
+
* GridLite's ColumnDataType for filter operator selection and UI rendering.
|
|
7
|
+
*/
|
|
8
|
+
// ─── Postgres Type → ColumnDataType Mapping ─────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Map a Postgres data_type string (from information_schema.columns)
|
|
11
|
+
* to a GridLite ColumnDataType.
|
|
12
|
+
*/
|
|
13
|
+
export function mapPostgresType(postgresType) {
|
|
14
|
+
const t = postgresType.toLowerCase();
|
|
15
|
+
// Numeric types
|
|
16
|
+
if (t === 'integer' ||
|
|
17
|
+
t === 'bigint' ||
|
|
18
|
+
t === 'smallint' ||
|
|
19
|
+
t === 'numeric' ||
|
|
20
|
+
t === 'decimal' ||
|
|
21
|
+
t === 'real' ||
|
|
22
|
+
t === 'double precision' ||
|
|
23
|
+
t === 'serial' ||
|
|
24
|
+
t === 'bigserial' ||
|
|
25
|
+
t === 'smallserial' ||
|
|
26
|
+
t === 'money') {
|
|
27
|
+
return 'number';
|
|
28
|
+
}
|
|
29
|
+
// Date/time types
|
|
30
|
+
if (t === 'date' ||
|
|
31
|
+
t === 'timestamp without time zone' ||
|
|
32
|
+
t === 'timestamp with time zone' ||
|
|
33
|
+
t === 'time without time zone' ||
|
|
34
|
+
t === 'time with time zone' ||
|
|
35
|
+
t === 'interval') {
|
|
36
|
+
return 'date';
|
|
37
|
+
}
|
|
38
|
+
// Boolean
|
|
39
|
+
if (t === 'boolean') {
|
|
40
|
+
return 'boolean';
|
|
41
|
+
}
|
|
42
|
+
// Everything else is text (varchar, char, text, json, jsonb, uuid, etc.)
|
|
43
|
+
return 'text';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Introspect a table's schema using information_schema.columns.
|
|
47
|
+
*
|
|
48
|
+
* Returns an array of ColumnMetadata in column ordinal position order.
|
|
49
|
+
* The table name is parameterized to prevent SQL injection.
|
|
50
|
+
*
|
|
51
|
+
* @param db - PGLite instance
|
|
52
|
+
* @param tableName - The table to introspect
|
|
53
|
+
* @param schema - The schema to search (defaults to 'public')
|
|
54
|
+
*/
|
|
55
|
+
export async function introspectTable(db, tableName, schema = 'public') {
|
|
56
|
+
const result = await db.query(`SELECT column_name, data_type, is_nullable, column_default
|
|
57
|
+
FROM information_schema.columns
|
|
58
|
+
WHERE table_name = $1 AND table_schema = $2
|
|
59
|
+
ORDER BY ordinal_position`, [tableName, schema]);
|
|
60
|
+
return result.rows.map((row) => ({
|
|
61
|
+
name: row.column_name,
|
|
62
|
+
dataType: mapPostgresType(row.data_type),
|
|
63
|
+
postgresType: row.data_type,
|
|
64
|
+
nullable: row.is_nullable === 'YES',
|
|
65
|
+
hasDefault: row.column_default !== null
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get the list of column names for a table.
|
|
70
|
+
* Useful for the query builder's allowedColumns parameter.
|
|
71
|
+
*/
|
|
72
|
+
export async function getColumnNames(db, tableName, schema = 'public') {
|
|
73
|
+
const columns = await introspectTable(db, tableName, schema);
|
|
74
|
+
return columns.map((c) => c.name);
|
|
75
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GridLite Config Table Migrations
|
|
3
|
+
*
|
|
4
|
+
* Creates and manages internal tables for persisting grid state:
|
|
5
|
+
* - _gridlite_meta: migration version tracking
|
|
6
|
+
* - _gridlite_views: saved view configurations per grid instance
|
|
7
|
+
* - _gridlite_column_state: column visibility, ordering, sizing per view
|
|
8
|
+
*
|
|
9
|
+
* All tables are prefixed with `_gridlite_` to avoid collision with user tables.
|
|
10
|
+
*/
|
|
11
|
+
import type { PGlite } from "@electric-sql/pglite";
|
|
12
|
+
/**
|
|
13
|
+
* Run all pending migrations.
|
|
14
|
+
*
|
|
15
|
+
* This is idempotent — safe to call on every app startup.
|
|
16
|
+
* Migrations use `IF NOT EXISTS` for table/index creation.
|
|
17
|
+
*
|
|
18
|
+
* @param db - PGLite instance
|
|
19
|
+
* @returns The final migration version
|
|
20
|
+
*/
|
|
21
|
+
export declare function runMigrations(db: PGlite): Promise<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Get the latest migration version available.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getLatestVersion(): number;
|
|
26
|
+
/**
|
|
27
|
+
* Check if migrations are up to date.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isMigrated(db: PGlite): Promise<boolean>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GridLite Config Table Migrations
|
|
3
|
+
*
|
|
4
|
+
* Creates and manages internal tables for persisting grid state:
|
|
5
|
+
* - _gridlite_meta: migration version tracking
|
|
6
|
+
* - _gridlite_views: saved view configurations per grid instance
|
|
7
|
+
* - _gridlite_column_state: column visibility, ordering, sizing per view
|
|
8
|
+
*
|
|
9
|
+
* All tables are prefixed with `_gridlite_` to avoid collision with user tables.
|
|
10
|
+
*/
|
|
11
|
+
const MIGRATIONS = [
|
|
12
|
+
{
|
|
13
|
+
version: 1,
|
|
14
|
+
description: "Create meta, views, and column_state tables",
|
|
15
|
+
sql: `
|
|
16
|
+
CREATE TABLE IF NOT EXISTS _gridlite_meta (
|
|
17
|
+
key TEXT PRIMARY KEY,
|
|
18
|
+
value TEXT NOT NULL
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS _gridlite_views (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
grid_id TEXT NOT NULL,
|
|
24
|
+
name TEXT NOT NULL,
|
|
25
|
+
description TEXT,
|
|
26
|
+
filters JSONB DEFAULT '[]',
|
|
27
|
+
filter_logic TEXT DEFAULT 'and',
|
|
28
|
+
sorting JSONB DEFAULT '[]',
|
|
29
|
+
grouping JSONB DEFAULT '[]',
|
|
30
|
+
column_visibility JSONB DEFAULT '{}',
|
|
31
|
+
column_order JSONB DEFAULT '[]',
|
|
32
|
+
is_default BOOLEAN DEFAULT false,
|
|
33
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
34
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_gridlite_views_grid_id
|
|
38
|
+
ON _gridlite_views (grid_id);
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS _gridlite_column_state (
|
|
41
|
+
grid_id TEXT NOT NULL,
|
|
42
|
+
view_id TEXT NOT NULL DEFAULT '__default__',
|
|
43
|
+
column_name TEXT NOT NULL,
|
|
44
|
+
visible BOOLEAN DEFAULT true,
|
|
45
|
+
width INTEGER,
|
|
46
|
+
position INTEGER,
|
|
47
|
+
PRIMARY KEY (grid_id, view_id, column_name)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_gridlite_column_state_grid
|
|
51
|
+
ON _gridlite_column_state (grid_id);
|
|
52
|
+
`,
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
// ─── Migration Runner ───────────────────────────────────────────────────────
|
|
56
|
+
/**
|
|
57
|
+
* Get the current migration version from the database.
|
|
58
|
+
* Returns 0 if the meta table doesn't exist yet.
|
|
59
|
+
*/
|
|
60
|
+
async function getCurrentVersion(db) {
|
|
61
|
+
try {
|
|
62
|
+
const result = await db.query(`SELECT value FROM _gridlite_meta WHERE key = 'migration_version'`);
|
|
63
|
+
if (result.rows.length > 0) {
|
|
64
|
+
return parseInt(result.rows[0].value, 10);
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Table doesn't exist yet
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Set the migration version in the meta table.
|
|
75
|
+
*/
|
|
76
|
+
async function setVersion(db, version) {
|
|
77
|
+
await db.query(`INSERT INTO _gridlite_meta (key, value) VALUES ('migration_version', $1)
|
|
78
|
+
ON CONFLICT (key) DO UPDATE SET value = $1`, [String(version)]);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Run all pending migrations.
|
|
82
|
+
*
|
|
83
|
+
* This is idempotent — safe to call on every app startup.
|
|
84
|
+
* Migrations use `IF NOT EXISTS` for table/index creation.
|
|
85
|
+
*
|
|
86
|
+
* @param db - PGLite instance
|
|
87
|
+
* @returns The final migration version
|
|
88
|
+
*/
|
|
89
|
+
export async function runMigrations(db) {
|
|
90
|
+
const currentVersion = await getCurrentVersion(db);
|
|
91
|
+
const pending = MIGRATIONS.filter((m) => m.version > currentVersion);
|
|
92
|
+
if (pending.length === 0) {
|
|
93
|
+
return currentVersion;
|
|
94
|
+
}
|
|
95
|
+
for (const migration of pending) {
|
|
96
|
+
await db.exec(migration.sql);
|
|
97
|
+
await setVersion(db, migration.version);
|
|
98
|
+
}
|
|
99
|
+
return pending[pending.length - 1].version;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get the latest migration version available.
|
|
103
|
+
*/
|
|
104
|
+
export function getLatestVersion() {
|
|
105
|
+
return MIGRATIONS.length > 0 ? MIGRATIONS[MIGRATIONS.length - 1].version : 0;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if migrations are up to date.
|
|
109
|
+
*/
|
|
110
|
+
export async function isMigrated(db) {
|
|
111
|
+
const current = await getCurrentVersion(db);
|
|
112
|
+
return current >= getLatestVersion();
|
|
113
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View Configuration Persistence
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for grid view configs stored in PGLite tables.
|
|
5
|
+
* Each grid instance (identified by `gridId`) can have multiple named views.
|
|
6
|
+
* One view per grid can be marked as the default.
|
|
7
|
+
*
|
|
8
|
+
* Requires `runMigrations()` to have been called first.
|
|
9
|
+
*/
|
|
10
|
+
import type { PGlite } from '@electric-sql/pglite';
|
|
11
|
+
import type { ViewPreset } from '../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Save a view configuration. Creates or updates (upserts).
|
|
14
|
+
*/
|
|
15
|
+
export declare function saveView(db: PGlite, gridId: string, view: ViewPreset): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Load a single view by ID.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadView(db: PGlite, viewId: string): Promise<ViewPreset | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Load all views for a grid instance.
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadViews(db: PGlite, gridId: string): Promise<ViewPreset[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Load the default view for a grid instance (if one is set).
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadDefaultView(db: PGlite, gridId: string): Promise<ViewPreset | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Set a view as the default for its grid. Clears any existing default first.
|
|
30
|
+
*/
|
|
31
|
+
export declare function setDefaultView(db: PGlite, gridId: string, viewId: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Delete a view by ID.
|
|
34
|
+
*/
|
|
35
|
+
export declare function deleteView(db: PGlite, viewId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Save column state for a grid (optionally scoped to a view).
|
|
38
|
+
* Replaces all existing column state for the given grid+view.
|
|
39
|
+
*/
|
|
40
|
+
export declare function saveColumnState(db: PGlite, gridId: string, columns: {
|
|
41
|
+
name: string;
|
|
42
|
+
visible?: boolean;
|
|
43
|
+
width?: number;
|
|
44
|
+
position?: number;
|
|
45
|
+
}[], viewId?: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Load column state for a grid (optionally scoped to a view).
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadColumnState(db: PGlite, gridId: string, viewId?: string): Promise<{
|
|
50
|
+
name: string;
|
|
51
|
+
visible: boolean;
|
|
52
|
+
width: number | null;
|
|
53
|
+
position: number | null;
|
|
54
|
+
}[]>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View Configuration Persistence
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for grid view configs stored in PGLite tables.
|
|
5
|
+
* Each grid instance (identified by `gridId`) can have multiple named views.
|
|
6
|
+
* One view per grid can be marked as the default.
|
|
7
|
+
*
|
|
8
|
+
* Requires `runMigrations()` to have been called first.
|
|
9
|
+
*/
|
|
10
|
+
// ─── View CRUD ──────────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Save a view configuration. Creates or updates (upserts).
|
|
13
|
+
*/
|
|
14
|
+
export async function saveView(db, gridId, view) {
|
|
15
|
+
await db.query(`INSERT INTO _gridlite_views
|
|
16
|
+
(id, grid_id, name, description, filters, filter_logic, sorting, grouping, column_visibility, column_order, is_default, updated_at)
|
|
17
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, false, CURRENT_TIMESTAMP)
|
|
18
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
19
|
+
name = $3,
|
|
20
|
+
description = $4,
|
|
21
|
+
filters = $5,
|
|
22
|
+
filter_logic = $6,
|
|
23
|
+
sorting = $7,
|
|
24
|
+
grouping = $8,
|
|
25
|
+
column_visibility = $9,
|
|
26
|
+
column_order = $10,
|
|
27
|
+
updated_at = CURRENT_TIMESTAMP`, [
|
|
28
|
+
view.id,
|
|
29
|
+
gridId,
|
|
30
|
+
view.name,
|
|
31
|
+
view.description ?? null,
|
|
32
|
+
JSON.stringify(view.filters ?? []),
|
|
33
|
+
view.filterLogic ?? 'and',
|
|
34
|
+
JSON.stringify(view.sorting ?? []),
|
|
35
|
+
JSON.stringify(view.grouping ?? []),
|
|
36
|
+
JSON.stringify(view.columnVisibility ?? {}),
|
|
37
|
+
JSON.stringify(view.columnOrder ?? [])
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Load a single view by ID.
|
|
42
|
+
*/
|
|
43
|
+
export async function loadView(db, viewId) {
|
|
44
|
+
const result = await db.query(`SELECT * FROM _gridlite_views WHERE id = $1`, [viewId]);
|
|
45
|
+
if (result.rows.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
return rowToViewPreset(result.rows[0]);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Load all views for a grid instance.
|
|
51
|
+
*/
|
|
52
|
+
export async function loadViews(db, gridId) {
|
|
53
|
+
const result = await db.query(`SELECT * FROM _gridlite_views WHERE grid_id = $1 ORDER BY name`, [gridId]);
|
|
54
|
+
return result.rows.map(rowToViewPreset);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Load the default view for a grid instance (if one is set).
|
|
58
|
+
*/
|
|
59
|
+
export async function loadDefaultView(db, gridId) {
|
|
60
|
+
const result = await db.query(`SELECT * FROM _gridlite_views WHERE grid_id = $1 AND is_default = true LIMIT 1`, [gridId]);
|
|
61
|
+
if (result.rows.length === 0)
|
|
62
|
+
return null;
|
|
63
|
+
return rowToViewPreset(result.rows[0]);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Set a view as the default for its grid. Clears any existing default first.
|
|
67
|
+
*/
|
|
68
|
+
export async function setDefaultView(db, gridId, viewId) {
|
|
69
|
+
// Clear existing default
|
|
70
|
+
await db.query(`UPDATE _gridlite_views SET is_default = false WHERE grid_id = $1`, [gridId]);
|
|
71
|
+
// Set new default
|
|
72
|
+
await db.query(`UPDATE _gridlite_views SET is_default = true WHERE id = $1 AND grid_id = $2`, [viewId, gridId]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Delete a view by ID.
|
|
76
|
+
*/
|
|
77
|
+
export async function deleteView(db, viewId) {
|
|
78
|
+
// Also clean up associated column state
|
|
79
|
+
await db.query(`DELETE FROM _gridlite_column_state WHERE view_id = $1`, [viewId]);
|
|
80
|
+
await db.query(`DELETE FROM _gridlite_views WHERE id = $1`, [viewId]);
|
|
81
|
+
}
|
|
82
|
+
// ─── Column State CRUD ──────────────────────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* Save column state for a grid (optionally scoped to a view).
|
|
85
|
+
* Replaces all existing column state for the given grid+view.
|
|
86
|
+
*/
|
|
87
|
+
export async function saveColumnState(db, gridId, columns, viewId = '__default__') {
|
|
88
|
+
// Clear existing state for this grid+view
|
|
89
|
+
await db.query(`DELETE FROM _gridlite_column_state WHERE grid_id = $1 AND view_id = $2`, [gridId, viewId]);
|
|
90
|
+
// Insert new state
|
|
91
|
+
for (const col of columns) {
|
|
92
|
+
await db.query(`INSERT INTO _gridlite_column_state (grid_id, view_id, column_name, visible, width, position)
|
|
93
|
+
VALUES ($1, $2, $3, $4, $5, $6)`, [
|
|
94
|
+
gridId,
|
|
95
|
+
viewId,
|
|
96
|
+
col.name,
|
|
97
|
+
col.visible ?? true,
|
|
98
|
+
col.width ?? null,
|
|
99
|
+
col.position ?? null
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Load column state for a grid (optionally scoped to a view).
|
|
105
|
+
*/
|
|
106
|
+
export async function loadColumnState(db, gridId, viewId = '__default__') {
|
|
107
|
+
const result = await db.query(`SELECT * FROM _gridlite_column_state
|
|
108
|
+
WHERE grid_id = $1 AND view_id = $2
|
|
109
|
+
ORDER BY position NULLS LAST, column_name`, [gridId, viewId]);
|
|
110
|
+
return result.rows.map((row) => ({
|
|
111
|
+
name: row.column_name,
|
|
112
|
+
visible: row.visible,
|
|
113
|
+
width: row.width,
|
|
114
|
+
position: row.position
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
118
|
+
function rowToViewPreset(row) {
|
|
119
|
+
return {
|
|
120
|
+
id: row.id,
|
|
121
|
+
name: row.name,
|
|
122
|
+
description: row.description ?? undefined,
|
|
123
|
+
filters: row.filters,
|
|
124
|
+
filterLogic: row.filter_logic,
|
|
125
|
+
sorting: row.sorting,
|
|
126
|
+
grouping: row.grouping,
|
|
127
|
+
columnVisibility: row.column_visibility,
|
|
128
|
+
columnOrder: row.column_order
|
|
129
|
+
};
|
|
130
|
+
}
|