@standardbeagle/edit-db 0.3.230 → 0.4.328

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 (55) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +305 -0
  3. package/dist/common/schema.d.ts +1 -1
  4. package/dist/components/confirm-dialog.d.ts +14 -0
  5. package/dist/components/content-editor.d.ts +12 -0
  6. package/dist/components/content-panel.d.ts +18 -0
  7. package/dist/components/content-viewer.d.ts +7 -0
  8. package/dist/components/data-table-column-header.d.ts +8 -0
  9. package/dist/components/data-table-column-header.test.d.ts +0 -0
  10. package/dist/components/data-table.d.ts +71 -2
  11. package/dist/components/data-table.test.d.ts +0 -0
  12. package/dist/components/detail-panel.d.ts +10 -0
  13. package/dist/components/filters/boolean-filter.d.ts +6 -0
  14. package/dist/components/filters/date-filter.d.ts +6 -0
  15. package/dist/components/filters/fk-filter.d.ts +15 -0
  16. package/dist/components/filters/number-filter.d.ts +6 -0
  17. package/dist/components/filters/text-filter.d.ts +6 -0
  18. package/dist/components/fk-cell-popover.d.ts +14 -0
  19. package/dist/components/row-actions.d.ts +14 -0
  20. package/dist/components/table-dimensions.test.d.ts +1 -0
  21. package/dist/components/ui/button.d.ts +1 -1
  22. package/dist/components/ui/dialog.d.ts +12 -12
  23. package/dist/components/ui/hover-card.d.ts +6 -0
  24. package/dist/components/ui/input.d.ts +1 -1
  25. package/dist/components/ui/sheet.d.ts +14 -0
  26. package/dist/components/ui/table.d.ts +9 -2
  27. package/dist/data-data-table.d.ts +6 -1
  28. package/dist/data-edit.d.ts +14 -0
  29. package/dist/data-edit.test.d.ts +0 -0
  30. package/dist/data-panel.d.ts +11 -0
  31. package/dist/edit-db.css +1 -1
  32. package/dist/editor.d.ts +32 -0
  33. package/dist/editor.es.js +9501 -6510
  34. package/dist/editor.umd.cjs +55 -34
  35. package/dist/hooks/useColumnNav.d.ts +28 -0
  36. package/dist/hooks/useDataTable.d.ts +54 -3
  37. package/dist/hooks/useDeleteMutation.d.ts +10 -0
  38. package/dist/hooks/useDeleteMutation.test.d.ts +0 -0
  39. package/dist/hooks/useSchema.d.ts +25 -0
  40. package/dist/hooks/useTableStats.d.ts +76 -0
  41. package/dist/hooks/useTableStats.test.d.ts +1 -0
  42. package/dist/lib/composite-pk-roundtrip.test.d.ts +1 -0
  43. package/dist/lib/content-detect.d.ts +14 -0
  44. package/dist/lib/drill-stack.d.ts +52 -0
  45. package/dist/lib/drill-stack.test.d.ts +1 -0
  46. package/dist/lib/humanize.d.ts +5 -0
  47. package/dist/lib/pk-hygiene.test.d.ts +1 -0
  48. package/dist/lib/query-builder.d.ts +52 -0
  49. package/dist/lib/query-builder.test.d.ts +1 -0
  50. package/dist/lib/row-id.d.ts +14 -0
  51. package/dist/lib/row-id.test.d.ts +1 -0
  52. package/dist/tableList.d.ts +15 -0
  53. package/dist/tableList.test.d.ts +0 -0
  54. package/dist/types/schema.d.ts +88 -0
  55. package/package.json +21 -16
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from 'react';
2
+ import { ColumnPanel } from '../data-panel';
3
+ interface ColumnNavEntry {
4
+ panel: ColumnPanel;
5
+ element: HTMLElement | null;
6
+ }
7
+ interface ColumnNavState {
8
+ mainTable: string | null;
9
+ columns: ColumnNavEntry[];
10
+ focusedIndex: number;
11
+ focusColumn: (index: number) => void;
12
+ closeColumn: (index: number) => void;
13
+ }
14
+ interface ColumnNavRegistration {
15
+ mainTable: string | null;
16
+ columns: ColumnPanel[];
17
+ columnRefs: Map<number, HTMLElement | null>;
18
+ onClose: (index: number) => void;
19
+ }
20
+ export declare function ColumnNavProvider({ children }: {
21
+ children: ReactNode;
22
+ }): import("react/jsx-runtime").JSX.Element;
23
+ export declare function useColumnNav(): ColumnNavState;
24
+ export declare function useColumnNavRegister(): {
25
+ register: (reg: ColumnNavRegistration) => void;
26
+ unregister: () => void;
27
+ };
28
+ export {};
@@ -1,21 +1,72 @@
1
1
  import { Table } from '../types/schema';
2
- import { ColumnDef, SortingState } from '@tanstack/react-table';
2
+ import { ColumnDef, ColumnFiltersState, SortingState } from '@tanstack/react-table';
3
+ import { ColumnPanel } from '../data-panel';
4
+ export { getFilterOperators } from '../lib/query-builder';
5
+ export type { ColumnFilterValue } from '../lib/query-builder';
3
6
  interface RowData {
4
7
  id?: number | string;
5
8
  [key: string]: unknown;
6
9
  }
10
+ /**
11
+ * Return type for the useDataTable hook.
12
+ * @interface UseDataTableResult
13
+ */
7
14
  interface UseDataTableResult {
15
+ /** Column definitions for the table */
8
16
  columns: ColumnDef<RowData, unknown>[];
17
+ /** Current sorting state */
9
18
  sorting: SortingState;
19
+ /** Active column filters */
20
+ columnFilters: ColumnFiltersState;
21
+ /** Primary-key column names in declaration order (empty when the table has no PK). */
22
+ primaryKeys: string[];
23
+ /** Current page index (0-based) */
10
24
  pageIndex: number;
25
+ /** Number of rows per page */
11
26
  pageSize: number;
27
+ /** Total number of pages */
12
28
  pageCount: number;
29
+ /** Current page data rows */
13
30
  rows: RowData[];
31
+ /** Whether data is currently loading */
14
32
  loading: boolean;
33
+ /** Error object if the query failed */
15
34
  error: Error | null;
35
+ /** Update sorting state */
16
36
  onSortingChange: (sorting: SortingState) => void;
37
+ /** Update column filters */
38
+ onColumnFiltersChange: (filters: ColumnFiltersState) => void;
39
+ /** Update page index */
17
40
  onPageIndexChange: (pageIndex: number) => void;
41
+ /** Update page size */
18
42
  onPageSizeChange: (pageSize: number) => void;
19
43
  }
20
- export declare function useDataTable(table: Table | null, id?: string, filterTable?: string): UseDataTableResult;
21
- export {};
44
+ /**
45
+ * Hook for managing data table state including sorting, filtering, and pagination.
46
+ *
47
+ * Automatically builds GraphQL queries based on table schema and current state,
48
+ * handles data fetching via React Query, and provides column definitions with
49
+ * proper rendering for foreign keys, dates, and content fields.
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * const {
54
+ * columns,
55
+ * rows,
56
+ * loading,
57
+ * pageIndex,
58
+ * pageCount,
59
+ * onSortingChange,
60
+ * onPageIndexChange,
61
+ * } = useDataTable(table, recordId, parentTable);
62
+ * ```
63
+ *
64
+ * @param table - Table schema definition
65
+ * @param id - Optional record ID for filtering to a specific row
66
+ * @param filterTable - Optional parent table name for relationship filtering
67
+ * @param filterColumn - Optional column name for explicit FK filtering
68
+ * @param onExpandContent - Callback when content expansion is requested
69
+ * @param onOpenColumn - Callback when opening a side panel column
70
+ * @returns Data table state and control functions
71
+ */
72
+ export declare function useDataTable(table: Table | null, id?: string, filterTable?: string, filterColumn?: string, onExpandContent?: (rowIndex: number, columnName: string) => void, onOpenColumn?: (panel: ColumnPanel) => void): UseDataTableResult;
@@ -0,0 +1,10 @@
1
+ import { Table } from '../types/schema';
2
+ import { PkFilter } from '../lib/row-id';
3
+ export type DeleteInput = PkFilter | string | number;
4
+ export interface UseDeleteMutationResult {
5
+ deleteRow: (detail: DeleteInput) => Promise<unknown>;
6
+ deleteRows: (details: DeleteInput[]) => Promise<unknown>;
7
+ isPending: boolean;
8
+ error: Error | null;
9
+ }
10
+ export declare function useDeleteMutation(table: Table): UseDeleteMutationResult;
File without changes
@@ -1,6 +1,31 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { Schema } from '../types/schema';
3
+ /**
4
+ * Provider component for database schema context.
5
+ * Fetches schema via GraphQL and makes it available to child components.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <SchemaProvider>
10
+ * <YourApp />
11
+ * </SchemaProvider>
12
+ * ```
13
+ */
3
14
  export declare const SchemaProvider: ({ children }: {
4
15
  children: ReactNode;
5
16
  }) => import("react/jsx-runtime").JSX.Element;
17
+ /**
18
+ * Hook to access the database schema context.
19
+ *
20
+ * Returns schema loading state, error information, table definitions,
21
+ * and a utility function to find tables by name.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * const { loading, error, data, findTable } = useSchema();
26
+ * const userTable = findTable('users');
27
+ * ```
28
+ *
29
+ * @returns Schema context value with tables and metadata
30
+ */
6
31
  export declare function useSchema(): Schema;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Interface representing statistics for a single table.
3
+ * @interface TableStats
4
+ */
5
+ export interface TableStats {
6
+ /** Number of columns in the table */
7
+ columnCount: number;
8
+ /** Number of rows in the table (null if loading/error) */
9
+ rowCount: number | null;
10
+ /** Number of foreign key relationships (singleJoins) */
11
+ fkCount: number;
12
+ /** Whether row count is currently loading */
13
+ isLoading: boolean;
14
+ /** Error message if row count fetch failed */
15
+ error: string | null;
16
+ }
17
+ /**
18
+ * Type for table stats record keyed by table name.
19
+ * @type TableStatsMap
20
+ */
21
+ export type TableStatsMap = Record<string, TableStats>;
22
+ /**
23
+ * Result type for the useTableStats hook.
24
+ * @interface UseTableStatsResult
25
+ */
26
+ export interface UseTableStatsResult {
27
+ /** Map of table names to their stats */
28
+ stats: TableStatsMap;
29
+ /** Whether any stats are loading */
30
+ isLoading: boolean;
31
+ /** Error if schema loading failed */
32
+ error: {
33
+ message: string;
34
+ } | null;
35
+ }
36
+ /**
37
+ * Hook to fetch table statistics including row counts.
38
+ *
39
+ * Automatically fetches row counts for all tables in the schema.
40
+ * Column counts and FK counts are derived from schema metadata (synchronous).
41
+ * Row counts are fetched via GraphQL (asynchronous).
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * const { stats, isLoading } = useTableStats();
46
+ * const customerStats = stats['customers'];
47
+ * // customerStats = { columnCount: 12, rowCount: 1250, fkCount: 3, isLoading: false, error: null }
48
+ * ```
49
+ *
50
+ * @returns Table statistics map and loading state
51
+ */
52
+ export declare function useTableStats(): UseTableStatsResult;
53
+ /**
54
+ * Formats a number into an abbreviated string representation.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * abbreviateNumber(12) // "12"
59
+ * abbreviateNumber(1200) // "1.2k"
60
+ * abbreviateNumber(45000) // "45k"
61
+ * abbreviateNumber(1200000) // "1.2M"
62
+ * ```
63
+ *
64
+ * @param num - Number to abbreviate
65
+ * @returns Abbreviated string representation
66
+ */
67
+ export declare function abbreviateNumber(num: number | null): string;
68
+ /**
69
+ * Calculates a visual bar width (1-10) based on row count.
70
+ * Used for sparkline visualization.
71
+ *
72
+ * @param count - Row count
73
+ * @param maxCount - Maximum row count across all tables for scaling
74
+ * @returns Width value from 1-10
75
+ */
76
+ export declare function calculateBarWidth(count: number | null, maxCount: number): number;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ /** Detected content type for smart rendering */
2
+ export type ContentKind = 'json' | 'xml' | 'php-serialized' | 'binary' | 'longtext' | 'text';
3
+ /** Check if a dbType is a binary/blob type */
4
+ export declare function isBinaryDbType(dbType: string): boolean;
5
+ /** Check if a dbType is a long text type (text, ntext, varchar(max), xml) */
6
+ export declare function isLongTextDbType(dbType: string): boolean;
7
+ /** Detect content kind from a string value and optional dbType hint */
8
+ export declare function detectContentKind(value: string, dbType?: string): ContentKind;
9
+ /** Max characters to show in a table cell before truncating */
10
+ export declare const CELL_TRUNCATE = 80;
11
+ /** Truncate text for table cell display */
12
+ export declare function truncateForCell(value: string): string;
13
+ /** Format binary data (base64 string) for display */
14
+ export declare function formatBinaryPreview(value: string): string;
@@ -0,0 +1,52 @@
1
+ import { ColumnPanel } from '../data-panel';
2
+ /**
3
+ * A single frame in the drill navigation chain, visible as one side column.
4
+ */
5
+ export type DrillFrame = ColumnPanel;
6
+ /**
7
+ * Is `frame` the same drill target as `other` (same table + same filter)?
8
+ *
9
+ * Used for cycle detection — drilling the same (table, filterId, filterColumn)
10
+ * we already have on the stack is a no-op. Using strict equality on all four
11
+ * fields is safe because they are primitives.
12
+ */
13
+ export declare function framesEqual(a: DrillFrame, b: DrillFrame): boolean;
14
+ /**
15
+ * Push `frame` onto `stack`, guarding against:
16
+ * 1. Exact duplicates of the top frame (no-op, returns `stack`).
17
+ * 2. Cycles — if `frame` already appears anywhere in the stack, truncate
18
+ * back to that frame instead of re-pushing. This produces the natural
19
+ * "breadcrumb jump" behaviour when a user drills back into an ancestor.
20
+ *
21
+ * Returns a new array; never mutates the input.
22
+ */
23
+ export declare function pushDrillFrame(stack: DrillFrame[], frame: DrillFrame): DrillFrame[];
24
+ /**
25
+ * Pop entries from `stack` down to (and including) `index`.
26
+ * Popping index 0 yields an empty stack (all side columns closed); popping
27
+ * an out-of-range index is a no-op.
28
+ */
29
+ export declare function popDrillFramesTo(stack: DrillFrame[], index: number): DrillFrame[];
30
+ /**
31
+ * A crumb displayed in the breadcrumb bar above the drill panels.
32
+ * `index = -1` represents the main (non-stack) view.
33
+ */
34
+ export interface DrillCrumb {
35
+ /** -1 for the main view, 0+ for each side-column stack entry. */
36
+ index: number;
37
+ /** Display label — usually the table's human label. */
38
+ label: string;
39
+ /** Optional secondary label showing filter context (e.g. "from Customers #42"). */
40
+ detail?: string;
41
+ /** The underlying frame for index >= 0 (undefined for main view). */
42
+ frame?: DrillFrame;
43
+ }
44
+ /**
45
+ * Resolve table labels for a drill stack and produce breadcrumb entries.
46
+ *
47
+ * @param mainTable - GraphQL name of the root/main table
48
+ * @param stack - Current drill stack
49
+ * @param lookup - Function returning a human label for a given GraphQL table name,
50
+ * or `undefined` if not found (caller falls back to the raw name).
51
+ */
52
+ export declare function buildDrillCrumbs(mainTable: string, stack: DrillFrame[], lookup: (tableName: string) => string | undefined): DrillCrumb[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Converts raw database names into human-readable Title Case labels.
3
+ * Handles snake_case, camelCase, and schema-prefixed names (e.g. dbo.order_details).
4
+ */
5
+ export declare function humanizeName(name: string): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { Table, Schema } from '../types/schema';
2
+ import { ColumnFiltersState } from '@tanstack/react-table';
3
+ export interface FilterResult {
4
+ variables: Record<string, unknown>;
5
+ param: string;
6
+ filterText: string;
7
+ }
8
+ export interface ColumnFilterValue {
9
+ operator: string;
10
+ value: unknown;
11
+ }
12
+ export interface ColumnFilterResult {
13
+ variables: Record<string, unknown>;
14
+ params: string[];
15
+ filterTexts: string[];
16
+ }
17
+ export interface PkTypeInfo {
18
+ name: string;
19
+ gqlType: string;
20
+ }
21
+ interface RowData {
22
+ id?: number | string | null;
23
+ [key: string]: unknown;
24
+ }
25
+ export declare function getFilterOperators(paramType: string): string[];
26
+ export declare function getFilterObj(filterString: string): FilterResult;
27
+ export declare function toLocaleDate(d: string): string;
28
+ export declare function getRowPkValue(row: RowData, table: Table): string;
29
+ export declare function getGraphQlType(paramType: string): string;
30
+ export declare function buildColumnFilters(columnFilters: ColumnFiltersState, table: Table): ColumnFilterResult;
31
+ export declare function serializeColumnFilters(columnFilters: ColumnFiltersState): string;
32
+ export declare function deserializeColumnFilters(raw: string): ColumnFiltersState;
33
+ /**
34
+ * Returns the GraphQL type of the first PK column. For composite PKs use {@link getPkTypes}.
35
+ */
36
+ export declare function getPkType(table: Table): string;
37
+ /**
38
+ * Returns one {name, gqlType} per primary-key column in declaration order.
39
+ * Empty array if the table has no primary keys.
40
+ */
41
+ export declare function getPkTypes(table: Table): PkTypeInfo[];
42
+ /**
43
+ * Builds the variables dict that accompanies a buildQuery result for a single-record lookup.
44
+ * - Single PK: returns `{ id: <coerced value> }` matching the `$id` variable in the query.
45
+ * - Composite PK: returns `{ pk_${col1}: ..., pk_${col2}: ... }` matching the composite form.
46
+ *
47
+ * `idRoute` is the same string passed to buildQuery's `id` parameter — for composite PKs
48
+ * it is a route-encoded string produced by {@link encodePkRoute}.
49
+ */
50
+ export declare function buildPkEqVariables(idRoute: string, table: Table): Record<string, unknown>;
51
+ export declare function buildQuery(table: Table, schema: Schema, filterString: string, columnFilters: ColumnFiltersState, id?: string, tableFilter?: string, filterColumn?: string): string | null;
52
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { Table } from '../types/schema';
2
+ export type PkFilter = Record<string, unknown>;
3
+ export interface PkEqFilterResult {
4
+ filterText: string;
5
+ variables: Record<string, unknown>;
6
+ params: string[];
7
+ }
8
+ type TableLike = Pick<Table, 'primaryKeys'> & Partial<Pick<Table, 'columns'>>;
9
+ export declare function rowIdOf(row: Record<string, unknown> | null | undefined, table: TableLike, index: number): string;
10
+ export declare function pkFilterFor(row: Record<string, unknown> | null | undefined, table: TableLike): PkFilter | null;
11
+ export declare function buildPkEqFilter(row: Record<string, unknown> | null | undefined, table: Pick<Table, 'primaryKeys' | 'columns'>): PkEqFilterResult | null;
12
+ export declare function encodePkRoute(filter: PkFilter, table: TableLike): string;
13
+ export declare function parsePkRoute(raw: string, table: TableLike): PkFilter | null;
14
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1,16 @@
1
+ /**
2
+ * TableList component that displays database tables in a sidebar.
3
+ *
4
+ * Features:
5
+ * - Lists all tables from the schema
6
+ * - Shows loading and error states
7
+ * - Displays table statistics (columns, rows, FKs) as sparklines
8
+ * - Responsive layout with visual hierarchy
9
+ *
10
+ * @component
11
+ * @example
12
+ * ```tsx
13
+ * <TableList />
14
+ * ```
15
+ */
1
16
  export declare function TableList(): import("react/jsx-runtime").JSX.Element;
File without changes
@@ -1,4 +1,15 @@
1
+ /**
2
+ * @module types/schema
3
+ *
4
+ * TypeScript type definitions for database schema metadata.
5
+ * These types represent the structure returned by the _dbSchema GraphQL query.
6
+ */
7
+ /**
8
+ * Metadata attached to tables for custom behavior configuration.
9
+ * @interface TableMetadata
10
+ */
1
11
  export interface TableMetadata {
12
+ /** Lookup configuration for reference tables */
2
13
  type?: {
3
14
  type: 'lookup';
4
15
  id: string;
@@ -6,50 +17,127 @@ export interface TableMetadata {
6
17
  };
7
18
  [key: string]: any;
8
19
  }
20
+ /**
21
+ * Lookup table metadata defining ID and label columns.
22
+ * @interface LookupMetadata
23
+ */
9
24
  export interface LookupMetadata {
10
25
  type: 'lookup';
11
26
  id: string;
12
27
  label: string;
13
28
  }
29
+ /**
30
+ * Column-level metadata for custom configuration.
31
+ * @interface ColumnMetadata
32
+ */
14
33
  export interface ColumnMetadata {
15
34
  [key: string]: string | LookupMetadata | undefined;
16
35
  }
36
+ /**
37
+ * Column definition from database schema introspection.
38
+ * @interface Column
39
+ */
17
40
  export interface Column {
41
+ /** Original database column name */
18
42
  dbName: string;
43
+ /** GraphQL field name for the column */
19
44
  graphQlName: string;
45
+ /** Alias for graphQlName */
20
46
  name: string;
47
+ /** Human-readable label for the column */
21
48
  label: string;
49
+ /** GraphQL parameter type (e.g., "String", "Int!") */
22
50
  paramType: string;
51
+ /** Database-specific type (e.g., "nvarchar", "int") */
52
+ dbType: string;
53
+ /** Whether this column is part of the primary key */
23
54
  isPrimaryKey: boolean;
55
+ /** Whether this column is auto-generated by the database */
24
56
  isIdentity: boolean;
57
+ /** Whether this column allows NULL values */
25
58
  isNullable: boolean;
59
+ /** Whether this column is read-only (e.g., computed columns) */
26
60
  isReadOnly: boolean;
61
+ /** Custom metadata for the column */
27
62
  metadata: ColumnMetadata;
63
+ /** Maximum string length (for validation) */
64
+ maxLength?: number;
65
+ /** Minimum string length (for validation) */
66
+ minLength?: number;
67
+ /** Minimum numeric value (for validation) */
68
+ min?: number;
69
+ /** Maximum numeric value (for validation) */
70
+ max?: number;
71
+ /** Step increment for numeric inputs */
72
+ step?: number;
73
+ /** Regex pattern for validation */
74
+ pattern?: string;
75
+ /** Error message for pattern validation failures */
76
+ patternMessage?: string;
77
+ /** HTML input type override */
78
+ inputType?: 'text' | 'email' | 'url' | 'tel' | 'date' | 'datetime-local' | 'number' | 'password' | 'search';
79
+ /** Default value for new records */
80
+ defaultValue?: string;
81
+ /** Allowed enum values */
82
+ enumValues?: string[];
83
+ /** Display labels for enum values */
84
+ enumLabels?: string[];
28
85
  }
86
+ /**
87
+ * Relationship join definition between tables.
88
+ * @interface Join
89
+ */
29
90
  export interface Join {
91
+ /** Name of the join relationship */
30
92
  name: string;
93
+ /** Column names in the source table */
31
94
  sourceColumnNames: string[];
95
+ /** Target table name */
32
96
  destinationTable: string;
97
+ /** Column names in the target table */
33
98
  destinationColumnNames: string[];
34
99
  }
100
+ /**
101
+ * Table definition from database schema introspection.
102
+ * @interface Table
103
+ */
35
104
  export interface Table {
105
+ /** Original database table name */
36
106
  dbName: string;
107
+ /** GraphQL type name for the table */
37
108
  graphQlName: string;
109
+ /** Alias for graphQlName */
38
110
  name: string;
111
+ /** Human-readable label for the table */
39
112
  label: string;
113
+ /** Column used as the display label for foreign key references */
40
114
  labelColumn: string;
115
+ /** Primary key column names */
41
116
  primaryKeys: string[];
117
+ /** Whether this table supports mutations */
42
118
  isEditable: boolean;
119
+ /** Custom metadata for the table */
43
120
  metadata: TableMetadata;
121
+ /** Column definitions */
44
122
  columns: Column[];
123
+ /** One-to-many relationship joins */
45
124
  multiJoins: Join[];
125
+ /** Many-to-one relationship joins */
46
126
  singleJoins: Join[];
47
127
  }
128
+ /**
129
+ * Schema context value containing database metadata and loading state.
130
+ * @interface Schema
131
+ */
48
132
  export interface Schema {
133
+ /** Whether schema data is currently loading */
49
134
  loading: boolean;
135
+ /** Error object if schema loading failed, null otherwise */
50
136
  error: {
51
137
  message: string;
52
138
  } | null;
139
+ /** Array of table definitions */
53
140
  data: Table[];
141
+ /** Find a table by its GraphQL name */
54
142
  findTable: (tableName: string) => Table | undefined;
55
143
  }
package/package.json CHANGED
@@ -1,17 +1,8 @@
1
1
  {
2
2
  "name": "@standardbeagle/edit-db",
3
3
  "private": false,
4
- "version": "0.3.230",
4
+ "version": "0.4.328",
5
5
  "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc && vite build --mode production",
9
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
- "preview": "vite preview",
11
- "storybook": "storybook dev -p 6006",
12
- "storybook-build": "storybook build",
13
- "ts": "tsc"
14
- },
15
6
  "dependencies": {
16
7
  "@radix-ui/react-slot": "^1.2.4",
17
8
  "@tanstack/react-form": "^1.28.5",
@@ -35,6 +26,8 @@
35
26
  "@storybook/react": "^10.2.7",
36
27
  "@storybook/react-vite": "^10.2.7",
37
28
  "@tailwindcss/vite": "^4.2.1",
29
+ "@testing-library/jest-dom": "^6.9.1",
30
+ "@testing-library/react": "^16.3.2",
38
31
  "@types/react": "^18.3.28",
39
32
  "@types/react-dom": "^18.3.7",
40
33
  "@types/redux-actions": "^2.6.5",
@@ -47,14 +40,13 @@
47
40
  "eslint": "^8.55.0",
48
41
  "eslint-plugin-react-hooks": "^4.6.2",
49
42
  "eslint-plugin-react-refresh": "^0.4.7",
50
- "sass": "^1.97.3",
43
+ "jsdom": "^25.0.1",
51
44
  "storybook": "^10.2.7",
52
- "stylelint": "^17.1.1",
53
45
  "tailwindcss": "^4.2.1",
54
46
  "typescript": "^5.9.3",
55
47
  "vite": "^7.3.1",
56
- "vite-plugin-browser-sync": "^3.0.2",
57
- "vite-plugin-dts": "^4.5.4"
48
+ "vite-plugin-dts": "^4.5.4",
49
+ "vitest": "^3.2.4"
58
50
  },
59
51
  "peerDependencies": {
60
52
  "@tanstack/react-query": "^5.0.0"
@@ -65,6 +57,7 @@
65
57
  "main": "./dist/editor.umd.cjs",
66
58
  "module": "./dist/editor.es.js",
67
59
  "types": "./dist/index.d.ts",
60
+ "style": "./dist/edit-db.css",
68
61
  "exports": {
69
62
  ".": {
70
63
  "import": {
@@ -75,6 +68,18 @@
75
68
  "types": "./dist/index.d.ts",
76
69
  "default": "./dist/editor.umd.cjs"
77
70
  }
78
- }
71
+ },
72
+ "./style.css": "./dist/edit-db.css"
73
+ },
74
+ "scripts": {
75
+ "dev": "vite",
76
+ "build": "tsc && vite build --mode production",
77
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
78
+ "preview": "vite preview",
79
+ "storybook": "storybook dev -p 6006",
80
+ "storybook-build": "storybook build",
81
+ "ts": "tsc",
82
+ "test": "vitest run",
83
+ "test:watch": "vitest"
79
84
  }
80
- }
85
+ }