@rozenite/sqlite-plugin 2.0.0 → 2.2.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/devtools/assets/{panel-CsA6Ejak.js → panel-B2O8mY15.js} +4 -4
  3. package/dist/devtools/panel.html +1 -1
  4. package/dist/react-native/chunks/index.require.js +4 -16
  5. package/dist/react-native/chunks/sql.require.js +1 -3
  6. package/dist/react-native/chunks/useRozeniteSqlitePlugin.require.js +92 -110
  7. package/dist/react-native/index.d.ts +1 -1
  8. package/dist/rozenite.json +1 -1
  9. package/package.json +23 -23
  10. package/react-native.ts +7 -14
  11. package/src/react-native/adapters/__tests__/expo-sqlite.test.ts +4 -14
  12. package/src/react-native/adapters/expo-sqlite.ts +11 -40
  13. package/src/react-native/adapters/generic.ts +5 -13
  14. package/src/react-native/adapters/index.ts +1 -4
  15. package/src/react-native/sqlite-view.ts +2 -8
  16. package/src/react-native/useRozeniteSqlitePlugin.ts +110 -130
  17. package/src/react-native/useSqliteAgentTools.ts +6 -18
  18. package/src/shared/__tests__/bridge-values.test.ts +6 -11
  19. package/src/shared/__tests__/sql.test.ts +4 -8
  20. package/src/shared/bridge-values.ts +2 -5
  21. package/src/shared/sql.ts +3 -7
  22. package/src/ui/__tests__/sql-editor-utils.test.ts +1 -5
  23. package/src/ui/__tests__/sqlite-drop-mutations.test.ts +6 -3
  24. package/src/ui/__tests__/sqlite-row-mutations.test.ts +1 -3
  25. package/src/ui/__tests__/sqlite-table-column-order.test.ts +4 -19
  26. package/src/ui/cell-detail-drawer.tsx +1 -6
  27. package/src/ui/globals.css +14 -65
  28. package/src/ui/panel.tsx +256 -596
  29. package/src/ui/query-result-table.tsx +8 -26
  30. package/src/ui/sql-editor-utils.ts +24 -55
  31. package/src/ui/sql-editor.tsx +13 -46
  32. package/src/ui/sqlite-data-table.tsx +11 -28
  33. package/src/ui/sqlite-drop-modal.tsx +17 -43
  34. package/src/ui/sqlite-drop-mutations.ts +3 -10
  35. package/src/ui/sqlite-introspection.ts +9 -25
  36. package/src/ui/sqlite-row-delete-modal.tsx +5 -12
  37. package/src/ui/sqlite-row-edit-modal.tsx +22 -64
  38. package/src/ui/sqlite-row-edit-value.ts +2 -11
  39. package/src/ui/sqlite-row-mutations.ts +10 -32
  40. package/src/ui/sqlite-table-column-order.ts +8 -23
  41. package/src/ui/use-sqlite-requests.ts +46 -86
  42. package/src/ui/utils.ts +1 -5
  43. package/src/ui/value-utils.tsx +3 -11
  44. package/tsconfig.json +4 -4
package/src/ui/panel.tsx CHANGED
@@ -65,10 +65,7 @@ import {
65
65
  } from './sqlite-introspection';
66
66
  import { QueryResultTable } from './query-result-table';
67
67
  import { SqliteRowDeleteModal } from './sqlite-row-delete-modal';
68
- import {
69
- SqliteDropModal,
70
- type SqliteDropModalTarget,
71
- } from './sqlite-drop-modal';
68
+ import { SqliteDropModal, type SqliteDropModalTarget } from './sqlite-drop-modal';
72
69
  import {
73
70
  buildDropAllEntitiesSql,
74
71
  buildDropEntitySql,
@@ -111,12 +108,7 @@ import {
111
108
  getDefaultTableColumnOrder,
112
109
  resolveTableColumnOrderUpdate,
113
110
  } from './sqlite-table-column-order';
114
- import {
115
- copyToClipboard,
116
- downloadTextFile,
117
- formatNumber,
118
- slugifyFileName,
119
- } from './utils';
111
+ import { copyToClipboard, downloadTextFile, formatNumber, slugifyFileName } from './utils';
120
112
  import { getResultSummary, getScriptResultSummary } from './value-utils';
121
113
  import './globals.css';
122
114
 
@@ -168,8 +160,7 @@ type ActiveDropState = {
168
160
  target: SqliteDropModalTarget;
169
161
  } | null;
170
162
 
171
- const DEFAULT_QUERY =
172
- 'SELECT name, type FROM sqlite_schema ORDER BY type, name';
163
+ const DEFAULT_QUERY = 'SELECT name, type FROM sqlite_schema ORDER BY type, name';
173
164
  const DEFAULT_QUERY_LIMIT = 100;
174
165
  const DEFAULT_PAGE_SIZE = 50;
175
166
  const MIN_EDITOR_HEIGHT = 180;
@@ -192,18 +183,13 @@ const DEFAULT_DROP_TARGET: SqliteDropModalTarget = {
192
183
  sql: '',
193
184
  };
194
185
 
195
- const joinClassNames = (
196
- ...classNames: Array<string | false | null | undefined>
197
- ) => classNames.filter(Boolean).join(' ');
186
+ const joinClassNames = (...classNames: Array<string | false | null | undefined>) =>
187
+ classNames.filter(Boolean).join(' ');
198
188
 
199
- const safeError = (error: unknown) =>
200
- error instanceof Error ? error.message : String(error);
189
+ const safeError = (error: unknown) => (error instanceof Error ? error.message : String(error));
201
190
 
202
- const getEntityKey = (
203
- databaseId: string,
204
- schemaName: string,
205
- entityName: string,
206
- ) => JSON.stringify([databaseId, schemaName, entityName]);
191
+ const getEntityKey = (databaseId: string, schemaName: string, entityName: string) =>
192
+ JSON.stringify([databaseId, schemaName, entityName]);
207
193
 
208
194
  const getSchemaKey = (databaseId: string, schemaName: string) =>
209
195
  JSON.stringify([databaseId, schemaName]);
@@ -211,20 +197,12 @@ const getSchemaKey = (databaseId: string, schemaName: string) =>
211
197
  const getLineNumberAtPosition = (value: string, position: number) =>
212
198
  value.slice(0, Math.max(0, position)).split('\n').length;
213
199
 
214
- const buildGeneratedSelect = (
215
- entity: SqliteEntity | null,
216
- rowLimit: number,
217
- ) => {
200
+ const buildGeneratedSelect = (entity: SqliteEntity | null, rowLimit: number) => {
218
201
  if (!entity) {
219
202
  return DEFAULT_QUERY;
220
203
  }
221
204
 
222
- return buildBrowseEntitySql(
223
- entity.schemaName,
224
- entity.name,
225
- Math.max(1, Math.floor(rowLimit)),
226
- 0,
227
- );
205
+ return buildBrowseEntitySql(entity.schemaName, entity.name, Math.max(1, Math.floor(rowLimit)), 0);
228
206
  };
229
207
 
230
208
  const buildCsv = (result: SqliteQueryResult | null) => {
@@ -240,15 +218,11 @@ const buildCsv = (result: SqliteQueryResult | null) => {
240
218
 
241
219
  return [
242
220
  result.columns.join(','),
243
- ...result.rows.map((row) =>
244
- result.columns.map((column) => escapeCell(row[column])).join(','),
245
- ),
221
+ ...result.rows.map((row) => result.columns.map((column) => escapeCell(row[column])).join(',')),
246
222
  ].join('\n');
247
223
  };
248
224
 
249
- const getDefaultSelectedQueryStatementIndex = (
250
- execution: SqliteScriptResult | null,
251
- ) => {
225
+ const getDefaultSelectedQueryStatementIndex = (execution: SqliteScriptResult | null) => {
252
226
  if (!execution || execution.statements.length === 0) {
253
227
  return null;
254
228
  }
@@ -260,18 +234,11 @@ const getDefaultSelectedQueryStatementIndex = (
260
234
  );
261
235
  };
262
236
 
263
- const getStatementQueryResult = (
264
- statement: SqliteScriptStatementResult | null,
265
- ) => statement?.execution?.result ?? null;
237
+ const getStatementQueryResult = (statement: SqliteScriptStatementResult | null) =>
238
+ statement?.execution?.result ?? null;
266
239
 
267
- const getStatementSelectorLabel = (
268
- statement: SqliteScriptStatementResult,
269
- maxLength = 72,
270
- ) => {
271
- const normalizedSql = statement.input.sql
272
- .replace(/\s+/g, ' ')
273
- .replace(/;\s*$/, '')
274
- .trim();
240
+ const getStatementSelectorLabel = (statement: SqliteScriptStatementResult, maxLength = 72) => {
241
+ const normalizedSql = statement.input.sql.replace(/\s+/g, ' ').replace(/;\s*$/, '').trim();
275
242
 
276
243
  if (normalizedSql.length <= maxLength) {
277
244
  return `${formatNumber(statement.index + 1)}. ${normalizedSql}`;
@@ -305,19 +272,13 @@ const buildExplorerGroups = (
305
272
 
306
273
  return schemas
307
274
  .map((schema) => {
308
- const schemaEntities = entities.filter(
309
- (entity) => entity.schemaName === schema.name,
310
- );
275
+ const schemaEntities = entities.filter((entity) => entity.schemaName === schema.name);
311
276
  const filteredEntities = term
312
277
  ? schemaEntities.filter((entity) =>
313
- `${entity.name} ${entity.type} ${schema.name}`
314
- .toLowerCase()
315
- .includes(term),
278
+ `${entity.name} ${entity.type} ${schema.name}`.toLowerCase().includes(term),
316
279
  )
317
280
  : schemaEntities;
318
- const tables = filteredEntities.filter(
319
- (entity) => entity.type === 'table',
320
- );
281
+ const tables = filteredEntities.filter((entity) => entity.type === 'table');
321
282
  const views = filteredEntities.filter((entity) => entity.type === 'view');
322
283
  const visible =
323
284
  term.length === 0 ||
@@ -377,8 +338,7 @@ export default function SqlitePanel() {
377
338
  const client = useRozeniteDevToolsClient<SqliteEventMap>({
378
339
  pluginId: PLUGIN_ID,
379
340
  });
380
- const { requestDatabases, requestQuery, requestScriptExecution } =
381
- useSqliteRequests(client);
341
+ const { requestDatabases, requestQuery, requestScriptExecution } = useSqliteRequests(client);
382
342
 
383
343
  const querySplitRef = useRef<HTMLDivElement | null>(null);
384
344
  const sidebarRef = useRef<HTMLDivElement | null>(null);
@@ -394,19 +354,14 @@ export default function SqlitePanel() {
394
354
  const [editorSplit, setEditorSplit] = useState(50);
395
355
  const [expandedDatabaseIds, setExpandedDatabaseIds] = useState<string[]>([]);
396
356
  const [expandedSchemaKeys, setExpandedSchemaKeys] = useState<string[]>([]);
397
- const [structureSection, setStructureSection] =
398
- useState<StructureSection>('columns');
357
+ const [structureSection, setStructureSection] = useState<StructureSection>('columns');
399
358
 
400
359
  const [databases, setDatabases] = useState<SqliteDatabaseInfo[]>([]);
401
- const [selectedDatabaseId, setSelectedDatabaseId] = useState<string | null>(
402
- null,
403
- );
360
+ const [selectedDatabaseId, setSelectedDatabaseId] = useState<string | null>(null);
404
361
  const [explorerStateByDatabase, setExplorerStateByDatabase] = useState<
405
362
  Record<string, ExplorerState>
406
363
  >({});
407
- const [selectedEntityKey, setSelectedEntityKey] = useState<string | null>(
408
- null,
409
- );
364
+ const [selectedEntityKey, setSelectedEntityKey] = useState<string | null>(null);
410
365
 
411
366
  const [databaseLoading, setDatabaseLoading] = useState(false);
412
367
  const [browseLoading, setBrowseLoading] = useState(false);
@@ -420,9 +375,7 @@ export default function SqlitePanel() {
420
375
 
421
376
  const [browseOffset, setBrowseOffset] = useState(0);
422
377
  const [browsePageSize, setBrowsePageSize] = useState(DEFAULT_PAGE_SIZE);
423
- const [browseResult, setBrowseResult] = useState<SqliteQueryResult | null>(
424
- null,
425
- );
378
+ const [browseResult, setBrowseResult] = useState<SqliteQueryResult | null>(null);
426
379
  const [entityRowCount, setEntityRowCount] = useState<number | null>(null);
427
380
  const [structureState, setStructureState] = useState<StructureState>({
428
381
  columns: [],
@@ -431,20 +384,16 @@ export default function SqlitePanel() {
431
384
  });
432
385
 
433
386
  const [queryInput, setQueryInput] = useState(DEFAULT_QUERY);
434
- const [queryExecution, setQueryExecution] =
435
- useState<SqliteScriptResult | null>(null);
436
- const [selectedQueryStatementIndex, setSelectedQueryStatementIndex] =
437
- useState<number | null>(null);
387
+ const [queryExecution, setQueryExecution] = useState<SqliteScriptResult | null>(null);
388
+ const [selectedQueryStatementIndex, setSelectedQueryStatementIndex] = useState<number | null>(
389
+ null,
390
+ );
438
391
  const [queryRowLimit, setQueryRowLimit] = useState(DEFAULT_QUERY_LIMIT);
439
392
  const [querySelection, setQuerySelection] = useState({ start: 0, end: 0 });
440
393
  const [, setQueryMessage] = useState('Ready.');
441
394
  const [queryErrorLine, setQueryErrorLine] = useState<number | null>(null);
442
- const [queryColumnCache, setQueryColumnCache] = useState(() =>
443
- createSqlEditorColumnCache(),
444
- );
445
- const [tableColumnOrderById, setTableColumnOrderById] = useState<
446
- Record<string, string[]>
447
- >({});
395
+ const [queryColumnCache, setQueryColumnCache] = useState(() => createSqlEditorColumnCache());
396
+ const [tableColumnOrderById, setTableColumnOrderById] = useState<Record<string, string[]>>({});
448
397
  const [editingRow, setEditingRow] = useState<ActiveRowMutationState>(null);
449
398
  const [deletingRow, setDeletingRow] = useState<ActiveRowMutationState>(null);
450
399
  const [activeDrop, setActiveDrop] = useState<ActiveDropState>(null);
@@ -453,16 +402,14 @@ export default function SqlitePanel() {
453
402
  const [dataSearch, setDataSearch] = useState('');
454
403
 
455
404
  const selectedDatabase = useMemo(
456
- () =>
457
- databases.find((database) => database.id === selectedDatabaseId) ?? null,
405
+ () => databases.find((database) => database.id === selectedDatabaseId) ?? null,
458
406
  [databases, selectedDatabaseId],
459
407
  );
460
408
 
461
409
  const selectedExplorerState = useMemo(
462
410
  () =>
463
- (selectedDatabaseId
464
- ? explorerStateByDatabase[selectedDatabaseId]
465
- : null) ?? DEFAULT_EXPLORER_STATE,
411
+ (selectedDatabaseId ? explorerStateByDatabase[selectedDatabaseId] : null) ??
412
+ DEFAULT_EXPLORER_STATE,
466
413
  [explorerStateByDatabase, selectedDatabaseId],
467
414
  );
468
415
 
@@ -475,8 +422,7 @@ export default function SqlitePanel() {
475
422
  entities.find(
476
423
  (entity) =>
477
424
  selectedDatabaseId != null &&
478
- getEntityKey(selectedDatabaseId, entity.schemaName, entity.name) ===
479
- selectedEntityKey,
425
+ getEntityKey(selectedDatabaseId, entity.schemaName, entity.name) === selectedEntityKey,
480
426
  ) ?? null,
481
427
  [entities, selectedDatabaseId, selectedEntityKey],
482
428
  );
@@ -576,20 +522,12 @@ export default function SqlitePanel() {
576
522
  }, [browseResult, filteredBrowseRows]);
577
523
 
578
524
  const dataPageStart = filteredBrowseRows.length > 0 ? browseOffset + 1 : 0;
579
- const dataPageEnd =
580
- filteredBrowseRows.length > 0
581
- ? browseOffset + filteredBrowseRows.length
582
- : 0;
525
+ const dataPageEnd = filteredBrowseRows.length > 0 ? browseOffset + filteredBrowseRows.length : 0;
583
526
  const canBrowseBackward = browseOffset > 0;
584
- const canBrowseForward =
585
- entityRowCount != null && browseOffset + browsePageSize < entityRowCount;
586
- const currentDataPage = selectedEntity
587
- ? Math.floor(browseOffset / browsePageSize) + 1
588
- : 0;
527
+ const canBrowseForward = entityRowCount != null && browseOffset + browsePageSize < entityRowCount;
528
+ const currentDataPage = selectedEntity ? Math.floor(browseOffset / browsePageSize) + 1 : 0;
589
529
  const totalDataPages =
590
- entityRowCount == null || entityRowCount === 0
591
- ? 0
592
- : Math.ceil(entityRowCount / browsePageSize);
530
+ entityRowCount == null || entityRowCount === 0 ? 0 : Math.ceil(entityRowCount / browsePageSize);
593
531
  const primaryKeyColumns = useMemo(
594
532
  () => getPrimaryKeyColumns(structureState.columns),
595
533
  [structureState.columns],
@@ -618,11 +556,8 @@ export default function SqlitePanel() {
618
556
  type: column.type || '—',
619
557
  nullable: column.notNull ? 'No' : 'Yes',
620
558
  defaultValue: column.defaultValue ?? '—',
621
- primaryKey:
622
- column.primaryKeyOrder > 0 ? `PK ${column.primaryKeyOrder}` : '—',
623
- foreignKey: structureState.foreignKeys.some(
624
- (foreignKey) => foreignKey.from === column.name,
625
- )
559
+ primaryKey: column.primaryKeyOrder > 0 ? `PK ${column.primaryKeyOrder}` : '—',
560
+ foreignKey: structureState.foreignKeys.some((foreignKey) => foreignKey.from === column.name)
626
561
  ? 'Yes'
627
562
  : '—',
628
563
  extra: column.hidden > 0 ? `Hidden ${column.hidden}` : '—',
@@ -641,9 +576,7 @@ export default function SqlitePanel() {
641
576
  [structureState.indexes],
642
577
  );
643
578
 
644
- const structureColumnsTableColumns = useMemo<
645
- ColumnDef<StructureColumnRow, unknown>[]
646
- >(
579
+ const structureColumnsTableColumns = useMemo<ColumnDef<StructureColumnRow, unknown>[]>(
647
580
  () => [
648
581
  { id: 'name', header: 'Name', accessorKey: 'name' },
649
582
  { id: 'type', header: 'Type', accessorKey: 'type' },
@@ -656,9 +589,7 @@ export default function SqlitePanel() {
656
589
  [],
657
590
  );
658
591
 
659
- const structureIndexesTableColumns = useMemo<
660
- ColumnDef<StructureIndexRow, unknown>[]
661
- >(
592
+ const structureIndexesTableColumns = useMemo<ColumnDef<StructureIndexRow, unknown>[]>(
662
593
  () => [
663
594
  { id: 'indexName', header: 'Index Name', accessorKey: 'indexName' },
664
595
  { id: 'columns', header: 'Columns', accessorKey: 'columns' },
@@ -668,10 +599,7 @@ export default function SqlitePanel() {
668
599
  [],
669
600
  );
670
601
 
671
- const queryStatements = useMemo(
672
- () => splitSqlStatements(queryInput),
673
- [queryInput],
674
- );
602
+ const queryStatements = useMemo(() => splitSqlStatements(queryInput), [queryInput]);
675
603
 
676
604
  const selectedQueryStatement = useMemo(() => {
677
605
  if (!queryExecution) {
@@ -679,18 +607,13 @@ export default function SqlitePanel() {
679
607
  }
680
608
 
681
609
  const nextIndex =
682
- selectedQueryStatementIndex ??
683
- getDefaultSelectedQueryStatementIndex(queryExecution);
610
+ selectedQueryStatementIndex ?? getDefaultSelectedQueryStatementIndex(queryExecution);
684
611
 
685
612
  if (nextIndex == null) {
686
613
  return null;
687
614
  }
688
615
 
689
- return (
690
- queryExecution.statements.find(
691
- (statement) => statement.index === nextIndex,
692
- ) ?? null
693
- );
616
+ return queryExecution.statements.find((statement) => statement.index === nextIndex) ?? null;
694
617
  }, [queryExecution, selectedQueryStatementIndex]);
695
618
 
696
619
  const activeQueryResult = useMemo(
@@ -701,8 +624,7 @@ export default function SqlitePanel() {
701
624
  const selectedQueryStatementValue = selectedQueryStatement?.index ?? '';
702
625
 
703
626
  const queryTableId = useMemo(
704
- () =>
705
- buildQueryTableId(selectedDatabaseId, activeQueryResult?.columns ?? []),
627
+ () => buildQueryTableId(selectedDatabaseId, activeQueryResult?.columns ?? []),
706
628
  [activeQueryResult?.columns, selectedDatabaseId],
707
629
  );
708
630
 
@@ -740,19 +662,12 @@ export default function SqlitePanel() {
740
662
  );
741
663
 
742
664
  const getTableColumnOrder = useCallback(
743
- (
744
- tableId: string,
745
- columnIds: string[],
746
- fixedLeadingColumnIds: string[] = [],
747
- ) =>
665
+ (tableId: string, columnIds: string[], fixedLeadingColumnIds: string[] = []) =>
748
666
  resolveTableColumnOrderUpdate({
749
667
  columnIds,
750
668
  fixedLeadingColumnIds,
751
669
  storedColumnOrder: tableColumnOrderById[tableId],
752
- nextColumnOrder: getDefaultTableColumnOrder(
753
- columnIds,
754
- fixedLeadingColumnIds,
755
- ),
670
+ nextColumnOrder: getDefaultTableColumnOrder(columnIds, fixedLeadingColumnIds),
756
671
  }),
757
672
  [tableColumnOrderById],
758
673
  );
@@ -807,39 +722,26 @@ export default function SqlitePanel() {
807
722
  );
808
723
 
809
724
  const queryColumnOrder = useMemo(
810
- () =>
811
- getTableColumnOrder(queryTableId, queryColumnIds, [
812
- SQLITE_ROW_NUMBER_COLUMN_ID,
813
- ]),
725
+ () => getTableColumnOrder(queryTableId, queryColumnIds, [SQLITE_ROW_NUMBER_COLUMN_ID]),
814
726
  [getTableColumnOrder, queryColumnIds, queryTableId],
815
727
  );
816
728
  const dataColumnOrder = useMemo(
817
- () =>
818
- getTableColumnOrder(dataTableId, dataColumnIds, [
819
- SQLITE_ROW_NUMBER_COLUMN_ID,
820
- ]),
729
+ () => getTableColumnOrder(dataTableId, dataColumnIds, [SQLITE_ROW_NUMBER_COLUMN_ID]),
821
730
  [dataColumnIds, dataTableId, getTableColumnOrder],
822
731
  );
823
732
  const structureColumnsColumnOrder = useMemo(
824
- () =>
825
- getTableColumnOrder(structureColumnsTableId, structureColumnsColumnIds),
733
+ () => getTableColumnOrder(structureColumnsTableId, structureColumnsColumnIds),
826
734
  [getTableColumnOrder, structureColumnsColumnIds, structureColumnsTableId],
827
735
  );
828
736
  const structureIndexesColumnOrder = useMemo(
829
- () =>
830
- getTableColumnOrder(structureIndexesTableId, structureIndexesColumnIds),
737
+ () => getTableColumnOrder(structureIndexesTableId, structureIndexesColumnIds),
831
738
  [getTableColumnOrder, structureIndexesColumnIds, structureIndexesTableId],
832
739
  );
833
740
 
834
- const setEntitySelection = useCallback(
835
- (databaseId: string, entity: SqliteEntity) => {
836
- setSelectedDatabaseId(databaseId);
837
- setSelectedEntityKey(
838
- getEntityKey(databaseId, entity.schemaName, entity.name),
839
- );
840
- },
841
- [],
842
- );
741
+ const setEntitySelection = useCallback((databaseId: string, entity: SqliteEntity) => {
742
+ setSelectedDatabaseId(databaseId);
743
+ setSelectedEntityKey(getEntityKey(databaseId, entity.schemaName, entity.name));
744
+ }, []);
843
745
 
844
746
  const loadDatabases = useCallback(async () => {
845
747
  setDatabaseLoading(true);
@@ -867,10 +769,7 @@ export default function SqlitePanel() {
867
769
  return [...currentIds, ...missingIds];
868
770
  });
869
771
  setSelectedDatabaseId((current) => {
870
- if (
871
- current &&
872
- nextDatabases.some((database) => database.id === current)
873
- ) {
772
+ if (current && nextDatabases.some((database) => database.id === current)) {
874
773
  return current;
875
774
  }
876
775
 
@@ -929,9 +828,7 @@ export default function SqlitePanel() {
929
828
  },
930
829
  }));
931
830
  setExpandedSchemaKeys((current) => {
932
- const nextKeys = nextSchemas.map((schema) =>
933
- getSchemaKey(databaseId, schema.name),
934
- );
831
+ const nextKeys = nextSchemas.map((schema) => getSchemaKey(databaseId, schema.name));
935
832
  return Array.from(new Set([...current, ...nextKeys]));
936
833
  });
937
834
  } catch (error) {
@@ -978,17 +875,12 @@ export default function SqlitePanel() {
978
875
  selectedEntity.name,
979
876
  browsePageSize,
980
877
  browseOffset,
981
- rowMutationDescriptor?.mode === 'rowid'
982
- ? rowMutationDescriptor.rowIdIdentifier
983
- : null,
878
+ rowMutationDescriptor?.mode === 'rowid' ? rowMutationDescriptor.rowIdIdentifier : null,
984
879
  ),
985
880
  }),
986
881
  requestQuery({
987
882
  databaseId: selectedDatabaseId,
988
- sql: buildEntityCountSql(
989
- selectedEntity.schemaName,
990
- selectedEntity.name,
991
- ),
883
+ sql: buildEntityCountSql(selectedEntity.schemaName, selectedEntity.name),
992
884
  }),
993
885
  ]);
994
886
 
@@ -1051,43 +943,27 @@ export default function SqlitePanel() {
1051
943
  setStructureError(null);
1052
944
 
1053
945
  try {
1054
- const [columnsOutcome, foreignKeysOutcome, indexesOutcome] =
1055
- await Promise.allSettled([
1056
- requestQuery({
1057
- databaseId: selectedDatabaseId,
1058
- sql: buildTableXInfoSql(
1059
- selectedEntity.schemaName,
1060
- selectedEntity.name,
1061
- ),
1062
- }),
1063
- requestQuery({
1064
- databaseId: selectedDatabaseId,
1065
- sql: buildForeignKeySql(
1066
- selectedEntity.schemaName,
1067
- selectedEntity.name,
1068
- ),
1069
- }),
1070
- requestQuery({
1071
- databaseId: selectedDatabaseId,
1072
- sql: buildIndexListSql(
1073
- selectedEntity.schemaName,
1074
- selectedEntity.name,
1075
- ),
1076
- }),
1077
- ]);
946
+ const [columnsOutcome, foreignKeysOutcome, indexesOutcome] = await Promise.allSettled([
947
+ requestQuery({
948
+ databaseId: selectedDatabaseId,
949
+ sql: buildTableXInfoSql(selectedEntity.schemaName, selectedEntity.name),
950
+ }),
951
+ requestQuery({
952
+ databaseId: selectedDatabaseId,
953
+ sql: buildForeignKeySql(selectedEntity.schemaName, selectedEntity.name),
954
+ }),
955
+ requestQuery({
956
+ databaseId: selectedDatabaseId,
957
+ sql: buildIndexListSql(selectedEntity.schemaName, selectedEntity.name),
958
+ }),
959
+ ]);
1078
960
 
1079
961
  const columns =
1080
- columnsOutcome.status === 'fulfilled'
1081
- ? parseColumns(columnsOutcome.value)
1082
- : [];
962
+ columnsOutcome.status === 'fulfilled' ? parseColumns(columnsOutcome.value) : [];
1083
963
  const foreignKeys =
1084
- foreignKeysOutcome.status === 'fulfilled'
1085
- ? parseForeignKeys(foreignKeysOutcome.value)
1086
- : [];
964
+ foreignKeysOutcome.status === 'fulfilled' ? parseForeignKeys(foreignKeysOutcome.value) : [];
1087
965
  const indexes =
1088
- indexesOutcome.status === 'fulfilled'
1089
- ? parseIndexes(indexesOutcome.value)
1090
- : [];
966
+ indexesOutcome.status === 'fulfilled' ? parseIndexes(indexesOutcome.value) : [];
1091
967
 
1092
968
  const enrichedIndexes = await Promise.all(
1093
969
  indexes.map(async (index) => {
@@ -1149,9 +1025,7 @@ export default function SqlitePanel() {
1149
1025
 
1150
1026
  const refreshExplorerData = useCallback(async () => {
1151
1027
  const nextDatabases = await loadDatabases();
1152
- await Promise.all(
1153
- nextDatabases.map((database) => loadExplorer(database.id)),
1154
- );
1028
+ await Promise.all(nextDatabases.map((database) => loadExplorer(database.id)));
1155
1029
  }, [loadDatabases, loadExplorer]);
1156
1030
 
1157
1031
  const refreshWorkspace = useCallback(async () => {
@@ -1164,12 +1038,7 @@ export default function SqlitePanel() {
1164
1038
 
1165
1039
  const handleSaveRow = useCallback(
1166
1040
  async (nextValues: Record<string, unknown>) => {
1167
- if (
1168
- !selectedDatabaseId ||
1169
- !selectedEntity ||
1170
- !editingRow ||
1171
- !rowMutationDescriptor
1172
- ) {
1041
+ if (!selectedDatabaseId || !selectedEntity || !editingRow || !rowMutationDescriptor) {
1173
1042
  throw new Error('The selected row is no longer available.');
1174
1043
  }
1175
1044
 
@@ -1201,12 +1070,7 @@ export default function SqlitePanel() {
1201
1070
  );
1202
1071
 
1203
1072
  const handleDeleteRow = useCallback(async () => {
1204
- if (
1205
- !selectedDatabaseId ||
1206
- !selectedEntity ||
1207
- !deletingRow ||
1208
- !rowMutationDescriptor
1209
- ) {
1073
+ if (!selectedDatabaseId || !selectedEntity || !deletingRow || !rowMutationDescriptor) {
1210
1074
  throw new Error('The selected row is no longer available.');
1211
1075
  }
1212
1076
 
@@ -1254,12 +1118,8 @@ export default function SqlitePanel() {
1254
1118
  return;
1255
1119
  }
1256
1120
 
1257
- const tableCount = entities.filter(
1258
- (entity) => entity.type === 'table',
1259
- ).length;
1260
- const viewCount = entities.filter(
1261
- (entity) => entity.type === 'view',
1262
- ).length;
1121
+ const tableCount = entities.filter((entity) => entity.type === 'table').length;
1122
+ const viewCount = entities.filter((entity) => entity.type === 'view').length;
1263
1123
 
1264
1124
  setActiveDrop({
1265
1125
  databaseId: selectedDatabaseId,
@@ -1291,9 +1151,7 @@ export default function SqlitePanel() {
1291
1151
  databaseId,
1292
1152
  sql: SQLITE_READ_FOREIGN_KEYS_SQL,
1293
1153
  });
1294
- const foreignKeysWereEnabled = isForeignKeysEnabled(
1295
- foreignKeysResult.rows,
1296
- );
1154
+ const foreignKeysWereEnabled = isForeignKeysEnabled(foreignKeysResult.rows);
1297
1155
 
1298
1156
  if (foreignKeysWereEnabled) {
1299
1157
  await requestQuery({
@@ -1312,8 +1170,7 @@ export default function SqlitePanel() {
1312
1170
 
1313
1171
  if (scriptResult.failedStatementIndex != null) {
1314
1172
  const failedStatement = scriptResult.statements.find(
1315
- (statement) =>
1316
- statement.index === scriptResult.failedStatementIndex,
1173
+ (statement) => statement.index === scriptResult.failedStatementIndex,
1317
1174
  );
1318
1175
  throw new Error(failedStatement?.error ?? 'Script execution failed.');
1319
1176
  }
@@ -1332,17 +1189,13 @@ export default function SqlitePanel() {
1332
1189
  // is looking at this modal. Only surface the restore failure when
1333
1190
  // the drop itself succeeded, since that's a new, silent problem.
1334
1191
  if (!dropError) {
1335
- throw restoreError instanceof Error
1336
- ? restoreError
1337
- : new Error(String(restoreError));
1192
+ throw restoreError instanceof Error ? restoreError : new Error(String(restoreError));
1338
1193
  }
1339
1194
  }
1340
1195
  }
1341
1196
 
1342
1197
  if (dropError) {
1343
- throw dropError instanceof Error
1344
- ? dropError
1345
- : new Error(String(dropError));
1198
+ throw dropError instanceof Error ? dropError : new Error(String(dropError));
1346
1199
  }
1347
1200
  },
1348
1201
  [requestQuery, requestScriptExecution],
@@ -1376,8 +1229,7 @@ export default function SqlitePanel() {
1376
1229
  }, [activeDrop, dropAllEntities, dropSelectedEntity, refreshExplorerData]);
1377
1230
 
1378
1231
  const getActiveStatement = useCallback(() => {
1379
- const cursorPosition =
1380
- editorRef.current?.getSelection().start ?? querySelection.start;
1232
+ const cursorPosition = editorRef.current?.getSelection().start ?? querySelection.start;
1381
1233
  const currentStatement = getStatementAtCursor(queryInput, cursorPosition);
1382
1234
  const start = currentStatement?.start ?? 0;
1383
1235
  const end = currentStatement?.end ?? queryInput.length;
@@ -1486,25 +1338,18 @@ export default function SqlitePanel() {
1486
1338
  execution.failedStatementIndex == null
1487
1339
  ? null
1488
1340
  : (execution.statements.find(
1489
- (statement) =>
1490
- statement.index === execution.failedStatementIndex,
1341
+ (statement) => statement.index === execution.failedStatementIndex,
1491
1342
  ) ?? null);
1492
1343
 
1493
1344
  setQueryExecution(execution);
1494
- setSelectedQueryStatementIndex(
1495
- getDefaultSelectedQueryStatementIndex(execution),
1496
- );
1345
+ setSelectedQueryStatementIndex(getDefaultSelectedQueryStatementIndex(execution));
1497
1346
 
1498
1347
  if (failedStatement?.error) {
1499
1348
  setQueryError(failedStatement.error);
1500
- setQueryErrorLine(
1501
- getLineNumberAtPosition(queryInput, failedStatement.start),
1502
- );
1349
+ setQueryErrorLine(getLineNumberAtPosition(queryInput, failedStatement.start));
1503
1350
  }
1504
1351
 
1505
- setQueryMessage(
1506
- getScriptResultSummary(execution) ?? 'Script execution completed.',
1507
- );
1352
+ setQueryMessage(getScriptResultSummary(execution) ?? 'Script execution completed.');
1508
1353
 
1509
1354
  if (hasMutatingStatements(execution)) {
1510
1355
  await refreshWorkspace();
@@ -1513,9 +1358,7 @@ export default function SqlitePanel() {
1513
1358
  setQueryExecution(null);
1514
1359
  setSelectedQueryStatementIndex(null);
1515
1360
  setQueryError(safeError(error));
1516
- setQueryErrorLine(
1517
- getLineNumberAtPosition(queryInput, querySelection.start),
1518
- );
1361
+ setQueryErrorLine(getLineNumberAtPosition(queryInput, querySelection.start));
1519
1362
  setQueryMessage('Execution failed.');
1520
1363
  } finally {
1521
1364
  setQueryLoading(false);
@@ -1537,22 +1380,12 @@ export default function SqlitePanel() {
1537
1380
 
1538
1381
  const handleRunCurrentStatement = useCallback(async () => {
1539
1382
  try {
1540
- await runSingleStatement(
1541
- getActiveStatement(),
1542
- 'Running current statement',
1543
- );
1383
+ await runSingleStatement(getActiveStatement(), 'Running current statement');
1544
1384
  } catch (error) {
1545
1385
  setQueryError(safeError(error));
1546
- setQueryErrorLine(
1547
- getLineNumberAtPosition(queryInput, querySelection.start),
1548
- );
1386
+ setQueryErrorLine(getLineNumberAtPosition(queryInput, querySelection.start));
1549
1387
  }
1550
- }, [
1551
- getActiveStatement,
1552
- queryInput,
1553
- querySelection.start,
1554
- runSingleStatement,
1555
- ]);
1388
+ }, [getActiveStatement, queryInput, querySelection.start, runSingleStatement]);
1556
1389
 
1557
1390
  const handleSaveQuery = useCallback(() => {
1558
1391
  const fileName = `${slugifyFileName(selectedEntity?.name ?? 'query')}.sql`;
@@ -1595,9 +1428,7 @@ export default function SqlitePanel() {
1595
1428
  setQueryInput(formatted);
1596
1429
  setQueryError(null);
1597
1430
  setQueryErrorLine(null);
1598
- setQueryMessage(
1599
- formatted ? 'Formatted query.' : 'Cleared query formatting.',
1600
- );
1431
+ setQueryMessage(formatted ? 'Formatted query.' : 'Cleared query formatting.');
1601
1432
  } catch (error) {
1602
1433
  setQueryError(safeError(error));
1603
1434
  setQueryErrorLine(null);
@@ -1628,13 +1459,7 @@ export default function SqlitePanel() {
1628
1459
  const columns = parseColumns(result);
1629
1460
 
1630
1461
  setQueryColumnCache((current) =>
1631
- setSqlEditorCachedColumns(
1632
- current,
1633
- selectedDatabaseId,
1634
- schemaName,
1635
- entityName,
1636
- columns,
1637
- ),
1462
+ setSqlEditorCachedColumns(current, selectedDatabaseId, schemaName, entityName, columns),
1638
1463
  );
1639
1464
 
1640
1465
  return columns;
@@ -1652,24 +1477,18 @@ export default function SqlitePanel() {
1652
1477
  return null;
1653
1478
  }
1654
1479
 
1655
- const aliases = extractSqlEditorAliases(
1656
- context.state.doc.sliceString(0, context.pos),
1657
- );
1480
+ const aliases = extractSqlEditorAliases(context.state.doc.sliceString(0, context.pos));
1658
1481
  const entity = resolveSqlEditorEntityReference({
1659
1482
  aliases,
1660
1483
  entities,
1661
1484
  request,
1662
- selectedSchemaName:
1663
- selectedEntity?.schemaName ?? defaultCompletionSchemaName ?? null,
1485
+ selectedSchemaName: selectedEntity?.schemaName ?? defaultCompletionSchemaName ?? null,
1664
1486
  });
1665
1487
  if (!entity) {
1666
1488
  return null;
1667
1489
  }
1668
1490
 
1669
- const columns = await ensureQueryEntityColumns(
1670
- entity.schemaName,
1671
- entity.name,
1672
- );
1491
+ const columns = await ensureQueryEntityColumns(entity.schemaName, entity.name);
1673
1492
  if (context.aborted || columns.length === 0) {
1674
1493
  return null;
1675
1494
  }
@@ -1681,12 +1500,7 @@ export default function SqlitePanel() {
1681
1500
  validFor: /^[A-Za-z_][\w$]*$/,
1682
1501
  };
1683
1502
  },
1684
- [
1685
- defaultCompletionSchemaName,
1686
- ensureQueryEntityColumns,
1687
- entities,
1688
- selectedEntity?.schemaName,
1689
- ],
1503
+ [defaultCompletionSchemaName, ensureQueryEntityColumns, entities, selectedEntity?.schemaName],
1690
1504
  );
1691
1505
 
1692
1506
  const handleSidebarResizeStart = useCallback(
@@ -1777,11 +1591,7 @@ export default function SqlitePanel() {
1777
1591
  }, [refreshExplorerData]);
1778
1592
 
1779
1593
  useEffect(() => {
1780
- if (
1781
- !selectedDatabaseId ||
1782
- selectedExplorerState.loading ||
1783
- !selectedExplorerState.loaded
1784
- ) {
1594
+ if (!selectedDatabaseId || selectedExplorerState.loading || !selectedExplorerState.loaded) {
1785
1595
  return;
1786
1596
  }
1787
1597
 
@@ -1789,9 +1599,7 @@ export default function SqlitePanel() {
1789
1599
  if (
1790
1600
  current &&
1791
1601
  selectedExplorerState.entities.some(
1792
- (entity) =>
1793
- getEntityKey(selectedDatabaseId, entity.schemaName, entity.name) ===
1794
- current,
1602
+ (entity) => getEntityKey(selectedDatabaseId, entity.schemaName, entity.name) === current,
1795
1603
  )
1796
1604
  ) {
1797
1605
  return current;
@@ -1799,11 +1607,7 @@ export default function SqlitePanel() {
1799
1607
 
1800
1608
  const fallbackEntity = selectedExplorerState.entities[0];
1801
1609
  return fallbackEntity
1802
- ? getEntityKey(
1803
- selectedDatabaseId,
1804
- fallbackEntity.schemaName,
1805
- fallbackEntity.name,
1806
- )
1610
+ ? getEntityKey(selectedDatabaseId, fallbackEntity.schemaName, fallbackEntity.name)
1807
1611
  : null;
1808
1612
  });
1809
1613
  }, [
@@ -1843,18 +1647,11 @@ export default function SqlitePanel() {
1843
1647
  }, [loadBrowse, selectedEntityKey]);
1844
1648
 
1845
1649
  useEffect(() => {
1846
- setQueryColumnCache((current) =>
1847
- syncSqlEditorColumnCacheDatabase(current, selectedDatabaseId),
1848
- );
1650
+ setQueryColumnCache((current) => syncSqlEditorColumnCacheDatabase(current, selectedDatabaseId));
1849
1651
  }, [selectedDatabaseId]);
1850
1652
 
1851
1653
  useEffect(() => {
1852
- if (
1853
- !selectedDatabaseId ||
1854
- !selectedEntity ||
1855
- structureLoading ||
1856
- structureError
1857
- ) {
1654
+ if (!selectedDatabaseId || !selectedEntity || structureLoading || structureError) {
1858
1655
  return;
1859
1656
  }
1860
1657
 
@@ -1999,10 +1796,7 @@ export default function SqlitePanel() {
1999
1796
  )
2000
1797
  ) : (
2001
1798
  <div ref={querySplitRef} className="sqlite-query-layout">
2002
- <section
2003
- className="sqlite-query-editor-pane"
2004
- style={{ flex: `0 0 ${editorSplit}%` }}
2005
- >
1799
+ <section className="sqlite-query-editor-pane" style={{ flex: `0 0 ${editorSplit}%` }}>
2006
1800
  {queryTabHeader}
2007
1801
  <div className="sqlite-editor-frame">
2008
1802
  <SqlEditor
@@ -2010,14 +1804,8 @@ export default function SqlitePanel() {
2010
1804
  ariaLabel="SQL query editor"
2011
1805
  completionSchema={editorCompletionSchema}
2012
1806
  completionSource={editorCompletionSource}
2013
- defaultSchema={
2014
- selectedEntity?.schemaName ?? defaultCompletionSchemaName
2015
- }
2016
- defaultTable={
2017
- cachedSelectedEntityColumns.length > 0
2018
- ? selectedEntity?.name
2019
- : undefined
2020
- }
1807
+ defaultSchema={selectedEntity?.schemaName ?? defaultCompletionSchemaName}
1808
+ defaultTable={cachedSelectedEntityColumns.length > 0 ? selectedEntity?.name : undefined}
2021
1809
  errorLine={queryErrorLine}
2022
1810
  onFormat={handleFormatQuery}
2023
1811
  onRun={() => void handleRun()}
@@ -2045,9 +1833,7 @@ export default function SqlitePanel() {
2045
1833
  <div className="sqlite-results-header sqlite-query-results-header">
2046
1834
  <div className="sqlite-toolbar-actions sqlite-query-results-header-main">
2047
1835
  {!queryExecution ? (
2048
- <span className="sqlite-helper-text">
2049
- Run SQL to inspect per-statement results.
2050
- </span>
1836
+ <span className="sqlite-helper-text">Run SQL to inspect per-statement results.</span>
2051
1837
  ) : null}
2052
1838
 
2053
1839
  {queryExecution && queryExecution.statements.length > 1 ? (
@@ -2123,8 +1909,7 @@ export default function SqlitePanel() {
2123
1909
  <div className="sqlite-inline-error" aria-live="polite">
2124
1910
  <div>
2125
1911
  <p className="font-medium text-rose-100">
2126
- {(queryExecution?.totalStatementCount ??
2127
- queryStatements.length) > 1
1912
+ {(queryExecution?.totalStatementCount ?? queryStatements.length) > 1
2128
1913
  ? 'Script Error'
2129
1914
  : 'SQL Error'}
2130
1915
  </p>
@@ -2135,11 +1920,7 @@ export default function SqlitePanel() {
2135
1920
  </p>
2136
1921
  ) : null}
2137
1922
  </div>
2138
- <button
2139
- type="button"
2140
- className={ghostButtonClassName}
2141
- onClick={handleCopyError}
2142
- >
1923
+ <button type="button" className={ghostButtonClassName} onClick={handleCopyError}>
2143
1924
  <Copy aria-hidden="true" className="h-4 w-4" />
2144
1925
  Copy Error
2145
1926
  </button>
@@ -2152,20 +1933,15 @@ export default function SqlitePanel() {
2152
1933
  result={activeQueryResult}
2153
1934
  columnOrder={queryColumnOrder}
2154
1935
  onColumnOrderChange={(nextColumnOrder) =>
2155
- setTableColumnOrder(
2156
- queryTableId,
2157
- queryColumnIds,
2158
- nextColumnOrder,
2159
- [SQLITE_ROW_NUMBER_COLUMN_ID],
2160
- )
1936
+ setTableColumnOrder(queryTableId, queryColumnIds, nextColumnOrder, [
1937
+ SQLITE_ROW_NUMBER_COLUMN_ID,
1938
+ ])
2161
1939
  }
2162
1940
  loading={queryLoading}
2163
1941
  showMetadata={false}
2164
1942
  shellClassName="h-full min-h-0"
2165
1943
  scrollContainerClassName="min-h-0 sqlite-results-scroll-flush"
2166
- emptyTitle={
2167
- selectedQueryStatement?.error ? 'Statement Failed' : 'No Results'
2168
- }
1944
+ emptyTitle={selectedQueryStatement?.error ? 'Statement Failed' : 'No Results'}
2169
1945
  emptyDescription={
2170
1946
  selectedQueryStatement?.error
2171
1947
  ? 'Select another statement to inspect its rows, or fix the error and run again.'
@@ -2192,9 +1968,7 @@ export default function SqlitePanel() {
2192
1968
  disabled={editableColumns.length === 0}
2193
1969
  aria-label={`Edit row ${rowNumber}`}
2194
1970
  title={
2195
- editableColumns.length === 0
2196
- ? 'No editable columns'
2197
- : `Edit row ${rowNumber}`
1971
+ editableColumns.length === 0 ? 'No editable columns' : `Edit row ${rowNumber}`
2198
1972
  }
2199
1973
  onClick={(event) => {
2200
1974
  event.stopPropagation();
@@ -2236,11 +2010,7 @@ export default function SqlitePanel() {
2236
2010
  'database',
2237
2011
  )
2238
2012
  ) : !selectedEntity ? (
2239
- renderEmptyState(
2240
- 'Select A Table',
2241
- 'Choose a table in the sidebar to view its rows.',
2242
- 'table',
2243
- )
2013
+ renderEmptyState('Select A Table', 'Choose a table in the sidebar to view its rows.', 'table')
2244
2014
  ) : (
2245
2015
  <div className="sqlite-content-stack">
2246
2016
  <header className="sqlite-object-header">
@@ -2265,11 +2035,7 @@ export default function SqlitePanel() {
2265
2035
  </div>
2266
2036
  </div>
2267
2037
  {dataSearch.trim() ? (
2268
- <button
2269
- type="button"
2270
- className="sqlite-chip"
2271
- onClick={() => setDataSearch('')}
2272
- >
2038
+ <button type="button" className="sqlite-chip" onClick={() => setDataSearch('')}>
2273
2039
  contains {dataSearch}
2274
2040
  <X aria-hidden="true" className="h-3.5 w-3.5" />
2275
2041
  </button>
@@ -2287,10 +2053,7 @@ export default function SqlitePanel() {
2287
2053
  >
2288
2054
  <RefreshCw
2289
2055
  aria-hidden="true"
2290
- className={joinClassNames(
2291
- 'h-4 w-4',
2292
- browseLoading && 'animate-spin',
2293
- )}
2056
+ className={joinClassNames('h-4 w-4', browseLoading && 'animate-spin')}
2294
2057
  />
2295
2058
  </button>
2296
2059
  </div>
@@ -2319,9 +2082,7 @@ export default function SqlitePanel() {
2319
2082
  showMetadata={false}
2320
2083
  shellClassName="h-full min-h-0"
2321
2084
  scrollContainerClassName="min-h-0 sqlite-results-scroll-flush"
2322
- emptyTitle={
2323
- selectedEntity ? 'No Rows On This Page' : 'No Table Selected'
2324
- }
2085
+ emptyTitle={selectedEntity ? 'No Rows On This Page' : 'No Table Selected'}
2325
2086
  emptyDescription={
2326
2087
  selectedEntity
2327
2088
  ? 'This page does not contain rows.'
@@ -2371,11 +2132,7 @@ export default function SqlitePanel() {
2371
2132
  <button
2372
2133
  type="button"
2373
2134
  className={secondaryButtonClassName}
2374
- onClick={() =>
2375
- setBrowseOffset((current) =>
2376
- Math.max(0, current - browsePageSize),
2377
- )
2378
- }
2135
+ onClick={() => setBrowseOffset((current) => Math.max(0, current - browsePageSize))}
2379
2136
  disabled={browseLoading || !canBrowseBackward}
2380
2137
  >
2381
2138
  Previous
@@ -2383,17 +2140,13 @@ export default function SqlitePanel() {
2383
2140
  <button
2384
2141
  type="button"
2385
2142
  className={secondaryButtonClassName}
2386
- onClick={() =>
2387
- setBrowseOffset((current) => current + browsePageSize)
2388
- }
2143
+ onClick={() => setBrowseOffset((current) => current + browsePageSize)}
2389
2144
  disabled={browseLoading || !canBrowseForward}
2390
2145
  >
2391
2146
  Next
2392
2147
  </button>
2393
2148
  <span className="sqlite-badge sqlite-badge-neutral sqlite-tabular">
2394
- {totalDataPages > 0
2395
- ? `${currentDataPage}/${totalDataPages}`
2396
- : '0/0'}
2149
+ {totalDataPages > 0 ? `${currentDataPage}/${totalDataPages}` : '0/0'}
2397
2150
  </span>
2398
2151
  </div>
2399
2152
  </footer>
@@ -2415,11 +2168,7 @@ export default function SqlitePanel() {
2415
2168
  ) : (
2416
2169
  <div className="sqlite-content-stack">
2417
2170
  <header className="sqlite-object-header">
2418
- <div
2419
- className="sqlite-section-tabs"
2420
- role="tablist"
2421
- aria-label="Structure sections"
2422
- >
2171
+ <div className="sqlite-section-tabs" role="tablist" aria-label="Structure sections">
2423
2172
  {(
2424
2173
  [
2425
2174
  ['columns', 'Columns'],
@@ -2454,19 +2203,14 @@ export default function SqlitePanel() {
2454
2203
  >
2455
2204
  <RefreshCw
2456
2205
  aria-hidden="true"
2457
- className={joinClassNames(
2458
- 'h-4 w-4',
2459
- structureLoading && 'animate-spin',
2460
- )}
2206
+ className={joinClassNames('h-4 w-4', structureLoading && 'animate-spin')}
2461
2207
  />
2462
2208
  </button>
2463
2209
  <button
2464
2210
  type="button"
2465
2211
  className={dangerIconButtonClassName}
2466
2212
  onClick={handleOpenDropEntity}
2467
- aria-label={
2468
- selectedEntity.type === 'view' ? 'Drop view' : 'Drop table'
2469
- }
2213
+ aria-label={selectedEntity.type === 'view' ? 'Drop view' : 'Drop table'}
2470
2214
  title={selectedEntity.type === 'view' ? 'Drop view' : 'Drop table'}
2471
2215
  >
2472
2216
  <Trash2 aria-hidden="true" className="h-4 w-4" />
@@ -2528,19 +2272,10 @@ export default function SqlitePanel() {
2528
2272
  ) : (
2529
2273
  <div className="sqlite-chip-row">
2530
2274
  {primaryKeyColumns
2531
- .sort(
2532
- (left, right) =>
2533
- left.primaryKeyOrder - right.primaryKeyOrder,
2534
- )
2275
+ .sort((left, right) => left.primaryKeyOrder - right.primaryKeyOrder)
2535
2276
  .map((column) => (
2536
- <span
2537
- key={column.name}
2538
- className="sqlite-chip sqlite-chip-static"
2539
- >
2540
- <KeyRound
2541
- aria-hidden="true"
2542
- className="h-3.5 w-3.5"
2543
- />
2277
+ <span key={column.name} className="sqlite-chip sqlite-chip-static">
2278
+ <KeyRound aria-hidden="true" className="h-3.5 w-3.5" />
2544
2279
  {column.name}
2545
2280
  </span>
2546
2281
  ))}
@@ -2557,18 +2292,14 @@ export default function SqlitePanel() {
2557
2292
  ) : (
2558
2293
  <div className="space-y-3">
2559
2294
  {structureState.foreignKeys.map((foreignKey) => (
2560
- <div
2561
- key={`${foreignKey.id}-${foreignKey.seq}`}
2562
- className="sqlite-key-row"
2563
- >
2295
+ <div key={`${foreignKey.id}-${foreignKey.seq}`} className="sqlite-key-row">
2564
2296
  <div>
2565
2297
  <p className="font-medium text-white">
2566
2298
  {foreignKey.from} → {foreignKey.table}
2567
2299
  {foreignKey.to ? `.${foreignKey.to}` : ''}
2568
2300
  </p>
2569
2301
  <p className="sqlite-helper-text">
2570
- Update {foreignKey.onUpdate} · Delete{' '}
2571
- {foreignKey.onDelete}
2302
+ Update {foreignKey.onUpdate} · Delete {foreignKey.onDelete}
2572
2303
  </p>
2573
2304
  </div>
2574
2305
  <span className="sqlite-badge sqlite-badge-neutral">
@@ -2612,11 +2343,7 @@ export default function SqlitePanel() {
2612
2343
  Skip To Workspace
2613
2344
  </a>
2614
2345
  <div className="sqlite-app-body">
2615
- <aside
2616
- ref={sidebarRef}
2617
- className="sqlite-sidebar-wrap"
2618
- style={{ width: sidebarWidth }}
2619
- >
2346
+ <aside ref={sidebarRef} className="sqlite-sidebar-wrap" style={{ width: sidebarWidth }}>
2620
2347
  <section className="sqlite-sidebar-panel">
2621
2348
  <header className="sqlite-sidebar-header">
2622
2349
  <div className="sqlite-toolbar-actions">
@@ -2654,10 +2381,7 @@ export default function SqlitePanel() {
2654
2381
  }
2655
2382
  onClick={handleOpenDropAllEntities}
2656
2383
  disabled={
2657
- !selectedDatabaseId ||
2658
- entities.length === 0 ||
2659
- databaseLoading ||
2660
- entityLoading
2384
+ !selectedDatabaseId || entities.length === 0 || databaseLoading || entityLoading
2661
2385
  }
2662
2386
  >
2663
2387
  <Trash2 aria-hidden="true" className="h-4 w-4" />
@@ -2694,9 +2418,7 @@ export default function SqlitePanel() {
2694
2418
  </div>
2695
2419
  ) : databases.length === 0 ? (
2696
2420
  renderEmptyState(
2697
- databaseError
2698
- ? 'Could Not Load Databases'
2699
- : 'No Databases Found',
2421
+ databaseError ? 'Could Not Load Databases' : 'No Databases Found',
2700
2422
  databaseError ??
2701
2423
  'Expose a SQLite adapter in your app, then refresh to inspect it here.',
2702
2424
  'database',
@@ -2704,12 +2426,9 @@ export default function SqlitePanel() {
2704
2426
  ) : (
2705
2427
  <div className="sqlite-connection-list">
2706
2428
  {databases.map((database) => {
2707
- const isExpanded = expandedDatabaseIds.includes(
2708
- database.id,
2709
- );
2429
+ const isExpanded = expandedDatabaseIds.includes(database.id);
2710
2430
  const databaseExplorerState =
2711
- explorerStateByDatabase[database.id] ??
2712
- DEFAULT_EXPLORER_STATE;
2431
+ explorerStateByDatabase[database.id] ?? DEFAULT_EXPLORER_STATE;
2713
2432
  const databaseExplorerGroups = buildExplorerGroups(
2714
2433
  databaseExplorerState.schemas,
2715
2434
  databaseExplorerState.entities,
@@ -2735,206 +2454,147 @@ export default function SqlitePanel() {
2735
2454
  }}
2736
2455
  >
2737
2456
  {isExpanded ? (
2738
- <ChevronDown
2739
- aria-hidden="true"
2740
- className="h-4 w-4 shrink-0"
2741
- />
2457
+ <ChevronDown aria-hidden="true" className="h-4 w-4 shrink-0" />
2742
2458
  ) : (
2743
- <ChevronRight
2744
- aria-hidden="true"
2745
- className="h-4 w-4 shrink-0"
2746
- />
2459
+ <ChevronRight aria-hidden="true" className="h-4 w-4 shrink-0" />
2747
2460
  )}
2748
- <Database
2749
- aria-hidden="true"
2750
- className="h-4 w-4 shrink-0"
2751
- />
2752
- <span className="min-w-0 truncate font-medium">
2753
- {database.name}
2754
- </span>
2461
+ <Database aria-hidden="true" className="h-4 w-4 shrink-0" />
2462
+ <span className="min-w-0 truncate font-medium">{database.name}</span>
2755
2463
  </button>
2756
2464
 
2757
2465
  {isExpanded ? (
2758
2466
  <div className="sqlite-tree-shell">
2759
- {databaseExplorerState.loading ||
2760
- !databaseExplorerState.loaded ? (
2761
- <div
2762
- className="sqlite-sidebar-skeleton"
2763
- aria-live="polite"
2764
- >
2467
+ {databaseExplorerState.loading || !databaseExplorerState.loaded ? (
2468
+ <div className="sqlite-sidebar-skeleton" aria-live="polite">
2765
2469
  {Array.from({ length: 4 }, (_, index) => (
2766
- <div
2767
- key={index}
2768
- className="sqlite-sidebar-skeleton-row"
2769
- />
2470
+ <div key={index} className="sqlite-sidebar-skeleton-row" />
2770
2471
  ))}
2771
2472
  </div>
2772
2473
  ) : databaseExplorerState.error ? (
2773
- <div
2774
- className="sqlite-inline-error"
2775
- aria-live="polite"
2776
- >
2474
+ <div className="sqlite-inline-error" aria-live="polite">
2777
2475
  <div>
2778
- <p className="font-medium text-rose-100">
2779
- Explorer Load Failed
2780
- </p>
2476
+ <p className="font-medium text-rose-100">Explorer Load Failed</p>
2781
2477
  <p className="mt-1 text-sm text-rose-100/90">
2782
2478
  {databaseExplorerState.error}
2783
2479
  </p>
2784
2480
  </div>
2785
2481
  </div>
2786
2482
  ) : databaseExplorerGroups.length === 0 ? (
2787
- <div className="sqlite-tree-empty">
2788
- No objects match this filter.
2789
- </div>
2483
+ <div className="sqlite-tree-empty">No objects match this filter.</div>
2790
2484
  ) : (
2791
- databaseExplorerGroups.map(
2792
- ({ schema, tables, views }) => {
2793
- const schemaKey = getSchemaKey(
2794
- database.id,
2795
- schema.name,
2796
- );
2797
- const isSchemaExpanded =
2798
- expandedSchemaKeys.includes(schemaKey);
2799
-
2800
- return (
2801
- <div
2802
- key={`${database.id}-${schema.name}`}
2803
- className="sqlite-schema-group"
2804
- >
2805
- <button
2806
- type="button"
2807
- className="sqlite-schema-row"
2808
- onClick={() => {
2809
- setExpandedSchemaKeys((current) =>
2810
- current.includes(schemaKey)
2811
- ? current.filter(
2812
- (value) =>
2813
- value !== schemaKey,
2814
- )
2815
- : [...current, schemaKey],
2816
- );
2817
- }}
2818
- >
2819
- {isSchemaExpanded ? (
2820
- <ChevronDown
2821
- aria-hidden="true"
2822
- className="h-4 w-4"
2823
- />
2824
- ) : (
2825
- <ChevronRight
2826
- aria-hidden="true"
2827
- className="h-4 w-4"
2828
- />
2829
- )}
2830
- <FolderTree
2831
- aria-hidden="true"
2832
- className="h-4 w-4"
2833
- />
2834
- <span className="min-w-0 flex-1 truncate">
2835
- {schema.name}
2836
- </span>
2837
- </button>
2485
+ databaseExplorerGroups.map(({ schema, tables, views }) => {
2486
+ const schemaKey = getSchemaKey(database.id, schema.name);
2487
+ const isSchemaExpanded = expandedSchemaKeys.includes(schemaKey);
2838
2488
 
2489
+ return (
2490
+ <div
2491
+ key={`${database.id}-${schema.name}`}
2492
+ className="sqlite-schema-group"
2493
+ >
2494
+ <button
2495
+ type="button"
2496
+ className="sqlite-schema-row"
2497
+ onClick={() => {
2498
+ setExpandedSchemaKeys((current) =>
2499
+ current.includes(schemaKey)
2500
+ ? current.filter((value) => value !== schemaKey)
2501
+ : [...current, schemaKey],
2502
+ );
2503
+ }}
2504
+ >
2839
2505
  {isSchemaExpanded ? (
2840
- <div className="sqlite-schema-content">
2841
- {tables.length > 0 ? (
2842
- <div className="sqlite-object-section">
2843
- <p className="sqlite-object-section-title">
2844
- Tables
2845
- </p>
2846
- <div className="sqlite-object-list">
2847
- {tables.map((entity) => {
2848
- const isSelected =
2849
- getEntityKey(
2850
- database.id,
2851
- entity.schemaName,
2852
- entity.name,
2853
- ) === selectedEntityKey;
2854
-
2855
- return (
2856
- <button
2857
- key={`${database.id}-${entity.schemaName}-${entity.name}`}
2858
- type="button"
2859
- className={joinClassNames(
2860
- 'sqlite-object-row',
2861
- isSelected &&
2862
- 'is-active',
2863
- )}
2864
- onClick={() => {
2865
- setEntitySelection(
2866
- database.id,
2867
- entity,
2868
- );
2869
- setActiveTab('data');
2870
- }}
2871
- >
2872
- <Table2
2873
- aria-hidden="true"
2874
- className="h-4 w-4 shrink-0"
2875
- />
2876
- <span className="min-w-0 flex-1 truncate text-left">
2877
- {entity.name}
2878
- </span>
2879
- </button>
2880
- );
2881
- })}
2882
- </div>
2506
+ <ChevronDown aria-hidden="true" className="h-4 w-4" />
2507
+ ) : (
2508
+ <ChevronRight aria-hidden="true" className="h-4 w-4" />
2509
+ )}
2510
+ <FolderTree aria-hidden="true" className="h-4 w-4" />
2511
+ <span className="min-w-0 flex-1 truncate">{schema.name}</span>
2512
+ </button>
2513
+
2514
+ {isSchemaExpanded ? (
2515
+ <div className="sqlite-schema-content">
2516
+ {tables.length > 0 ? (
2517
+ <div className="sqlite-object-section">
2518
+ <p className="sqlite-object-section-title">Tables</p>
2519
+ <div className="sqlite-object-list">
2520
+ {tables.map((entity) => {
2521
+ const isSelected =
2522
+ getEntityKey(
2523
+ database.id,
2524
+ entity.schemaName,
2525
+ entity.name,
2526
+ ) === selectedEntityKey;
2527
+
2528
+ return (
2529
+ <button
2530
+ key={`${database.id}-${entity.schemaName}-${entity.name}`}
2531
+ type="button"
2532
+ className={joinClassNames(
2533
+ 'sqlite-object-row',
2534
+ isSelected && 'is-active',
2535
+ )}
2536
+ onClick={() => {
2537
+ setEntitySelection(database.id, entity);
2538
+ setActiveTab('data');
2539
+ }}
2540
+ >
2541
+ <Table2
2542
+ aria-hidden="true"
2543
+ className="h-4 w-4 shrink-0"
2544
+ />
2545
+ <span className="min-w-0 flex-1 truncate text-left">
2546
+ {entity.name}
2547
+ </span>
2548
+ </button>
2549
+ );
2550
+ })}
2883
2551
  </div>
2884
- ) : null}
2885
-
2886
- {views.length > 0 ? (
2887
- <div className="sqlite-object-section">
2888
- <p className="sqlite-object-section-title">
2889
- Views
2890
- </p>
2891
- <div className="sqlite-object-list">
2892
- {views.map((entity) => {
2893
- const isSelected =
2894
- getEntityKey(
2895
- database.id,
2896
- entity.schemaName,
2897
- entity.name,
2898
- ) === selectedEntityKey;
2899
-
2900
- return (
2901
- <button
2902
- key={`${database.id}-${entity.schemaName}-${entity.name}`}
2903
- type="button"
2904
- className={joinClassNames(
2905
- 'sqlite-object-row',
2906
- isSelected &&
2907
- 'is-active',
2908
- )}
2909
- onClick={() => {
2910
- setEntitySelection(
2911
- database.id,
2912
- entity,
2913
- );
2914
- setActiveTab(
2915
- 'structure',
2916
- );
2917
- }}
2918
- >
2919
- <FileCode2
2920
- aria-hidden="true"
2921
- className="h-4 w-4 shrink-0"
2922
- />
2923
- <span className="min-w-0 flex-1 truncate text-left">
2924
- {entity.name}
2925
- </span>
2926
- </button>
2927
- );
2928
- })}
2929
- </div>
2552
+ </div>
2553
+ ) : null}
2554
+
2555
+ {views.length > 0 ? (
2556
+ <div className="sqlite-object-section">
2557
+ <p className="sqlite-object-section-title">Views</p>
2558
+ <div className="sqlite-object-list">
2559
+ {views.map((entity) => {
2560
+ const isSelected =
2561
+ getEntityKey(
2562
+ database.id,
2563
+ entity.schemaName,
2564
+ entity.name,
2565
+ ) === selectedEntityKey;
2566
+
2567
+ return (
2568
+ <button
2569
+ key={`${database.id}-${entity.schemaName}-${entity.name}`}
2570
+ type="button"
2571
+ className={joinClassNames(
2572
+ 'sqlite-object-row',
2573
+ isSelected && 'is-active',
2574
+ )}
2575
+ onClick={() => {
2576
+ setEntitySelection(database.id, entity);
2577
+ setActiveTab('structure');
2578
+ }}
2579
+ >
2580
+ <FileCode2
2581
+ aria-hidden="true"
2582
+ className="h-4 w-4 shrink-0"
2583
+ />
2584
+ <span className="min-w-0 flex-1 truncate text-left">
2585
+ {entity.name}
2586
+ </span>
2587
+ </button>
2588
+ );
2589
+ })}
2930
2590
  </div>
2931
- ) : null}
2932
- </div>
2933
- ) : null}
2934
- </div>
2935
- );
2936
- },
2937
- )
2591
+ </div>
2592
+ ) : null}
2593
+ </div>
2594
+ ) : null}
2595
+ </div>
2596
+ );
2597
+ })
2938
2598
  )}
2939
2599
  </div>
2940
2600
  ) : null}