Files
windmill/frontend/src/lib/components/staticDbTableOps.ts
T
Diego ImbertandClaude Opus 5.5 4fd7d62bd0 feat: rework the db manager: native grid, tabs, sql editor, joined columns (#11340)
* feat: replace ag-grid in the db manager table viewer with a native grid

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: add user-managed data, diagram and sql editor tabs to the db manager

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: add schema autocomplete to the db manager sql editor and polish its layout

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: add joined foreign key columns and draggable tabs to the db manager

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: move db manager tabs on drop instead of mid-drag

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: open followed foreign keys in a new db manager tab

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: scroll large tables, drop stale joins and return to the last tab on close

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: tolerate the db manager tabs going away while switching data table

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: keep saved joined columns while metadata loads, test joins in every dialect

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: put the db manager grid on the input surface in dark mode

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: address db manager review nits on joins, boolean keys and sql quoting

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: keep the dark border color on the left pinned column edge

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: tone down the db manager tree menu icons

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: write json and jsonb values from the db manager through a text cast

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: dim unrelated diagram tables less on hover

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: match json columns as text when deleting a db manager row

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: compare postgres json columns as text in exact db manager filters

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: pick the columns the db manager grid shows

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: toggle every db manager column from one checkbox

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: word joined columns as a view in the db manager

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: keep data table roles and access visible when unavailable, with the reason

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: keep data table and instance roles visible in settings when unavailable

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: hide a db manager column from its header menu

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: format db manager columns with a unit, significant digits and color rules

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: drop the before/after hints from the db manager unit picker

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: write the euro after the amount and keep units off non-numeric values

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: color rule presets, bold and italic, layered and reorderable rules in the db manager

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: decimals, thousands separator, compact notation and alignment in db manager column formats

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: compact db manager format controls, a notation toggle group and a reset button

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix: db manager format and filter nits

Keep the value's scale when decimals are auto, read boolean color-rule conditions as
booleans, let a rule's text color reach foreign-key links, close the formatter when the
columns picker opens, and filter BigQuery complex columns through TO_JSON_STRING.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 15:58:25 +02:00

87 lines
2.9 KiB
TypeScript

import { ColumnIdentity, type ColumnDef } from './apps/components/display/dbtable/utils'
import type { IDbTableOps } from './dbOps'
import { matchesColumnFilter } from './dbTableFilters'
import type { DbType } from './dbTypes'
/** A query result has no column types, so they are read off the values: a column is a
* number or a boolean only if every non-null value is. */
function inferDatatype(rows: Record<string, unknown>[], field: string): string {
let kind: 'number' | 'boolean' | undefined
for (const row of rows) {
const v = row[field]
if (v === null || v === undefined) continue
const k = typeof v === 'number' ? 'number' : typeof v === 'boolean' ? 'boolean' : undefined
if (!k || (kind && kind !== k)) return 'text'
kind = k
}
return kind === 'number' ? 'numeric' : kind === 'boolean' ? 'boolean' : 'text'
}
function searchable(value: unknown): string {
if (value === null || value === undefined) return ''
return (typeof value === 'object' ? JSON.stringify(value) : String(value)).toLowerCase()
}
function compare(a: unknown, b: unknown): number {
if (a === b) return 0
if (a === null || a === undefined) return 1
if (b === null || b === undefined) return -1
if (typeof a === 'number' && typeof b === 'number') return a - b
return searchable(a).localeCompare(searchable(b), undefined, { numeric: true })
}
/** Read-only table ops over rows already in memory, e.g. a SQL editor's result: searched,
* filtered and sorted here rather than by a query. */
export function staticDbTableOps(
rows: Record<string, unknown>[],
dbType: DbType,
tableKey: string
): IDbTableOps {
const fields = [...new Set(rows.flatMap((r) => Object.keys(r)))]
const colDefs: ColumnDef[] = fields.map((field) => ({
field,
datatype: inferDatatype(rows, field),
defaultvalue: '',
isprimarykey: false,
isidentity: ColumnIdentity.No,
isnullable: 'YES',
isenum: false
}))
const datatypeOf = Object.fromEntries(colDefs.map((c) => [c.field, c.datatype]))
function filtered(quicksearch: string, columnFilters: Record<string, unknown> = {}) {
const q = quicksearch.toLowerCase()
return rows.filter(
(row) =>
(!q || fields.some((f) => searchable(row[f]).includes(q))) &&
Object.entries(columnFilters).every(([column, filter]) =>
matchesColumnFilter(row[column], datatypeOf[column], filter)
)
)
}
return {
dbType,
tableKey,
colDefs,
getCount: async ({ quicksearch, columnFilters }) => filtered(quicksearch, columnFilters).length,
getRows: async ({
offset,
limit,
quicksearch,
columnFilters,
order_by,
is_desc,
explicitSort
}) => {
let result = filtered(quicksearch, columnFilters)
// Unsorted, a result keeps the order its query gave it.
if (explicitSort) {
result = [...result].sort((a, b) => compare(a[order_by], b[order_by]))
if (is_desc) result.reverse()
}
return result.slice(offset, offset + limit)
}
}
}