@rozenite/sqlite-plugin 2.0.0 → 2.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/CHANGELOG.md +8 -0
- package/dist/devtools/assets/{panel-CsA6Ejak.js → panel-BsdCagVv.js} +3 -3
- package/dist/devtools/panel.html +1 -1
- package/dist/react-native/chunks/index.require.js +4 -16
- package/dist/react-native/chunks/sql.require.js +1 -3
- package/dist/react-native/chunks/useRozeniteSqlitePlugin.require.js +92 -110
- package/dist/react-native/index.d.ts +1 -1
- package/dist/rozenite.json +1 -1
- package/package.json +23 -23
- package/react-native.ts +7 -14
- package/src/react-native/adapters/__tests__/expo-sqlite.test.ts +4 -14
- package/src/react-native/adapters/expo-sqlite.ts +11 -40
- package/src/react-native/adapters/generic.ts +5 -13
- package/src/react-native/adapters/index.ts +1 -4
- package/src/react-native/sqlite-view.ts +2 -8
- package/src/react-native/useRozeniteSqlitePlugin.ts +110 -130
- package/src/react-native/useSqliteAgentTools.ts +6 -18
- package/src/shared/__tests__/bridge-values.test.ts +6 -11
- package/src/shared/__tests__/sql.test.ts +4 -8
- package/src/shared/bridge-values.ts +2 -5
- package/src/shared/sql.ts +3 -7
- package/src/ui/__tests__/sql-editor-utils.test.ts +1 -5
- package/src/ui/__tests__/sqlite-drop-mutations.test.ts +6 -3
- package/src/ui/__tests__/sqlite-row-mutations.test.ts +1 -3
- package/src/ui/__tests__/sqlite-table-column-order.test.ts +4 -19
- package/src/ui/cell-detail-drawer.tsx +1 -6
- package/src/ui/globals.css +14 -65
- package/src/ui/panel.tsx +256 -596
- package/src/ui/query-result-table.tsx +8 -26
- package/src/ui/sql-editor-utils.ts +24 -55
- package/src/ui/sql-editor.tsx +13 -46
- package/src/ui/sqlite-data-table.tsx +11 -28
- package/src/ui/sqlite-drop-modal.tsx +17 -43
- package/src/ui/sqlite-drop-mutations.ts +3 -10
- package/src/ui/sqlite-introspection.ts +9 -25
- package/src/ui/sqlite-row-delete-modal.tsx +5 -12
- package/src/ui/sqlite-row-edit-modal.tsx +22 -64
- package/src/ui/sqlite-row-edit-value.ts +2 -11
- package/src/ui/sqlite-row-mutations.ts +10 -32
- package/src/ui/sqlite-table-column-order.ts +8 -23
- package/src/ui/use-sqlite-requests.ts +46 -86
- package/src/ui/utils.ts +1 -5
- package/src/ui/value-utils.tsx +3 -11
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
|
-
|
|
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
|
|
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
|
|
265
|
-
) => statement?.execution?.result ?? null;
|
|
237
|
+
const getStatementQueryResult = (statement: SqliteScriptStatementResult | null) =>
|
|
238
|
+
statement?.execution?.result ?? null;
|
|
266
239
|
|
|
267
|
-
const getStatementSelectorLabel = (
|
|
268
|
-
statement
|
|
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
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2793
|
-
|
|
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
|
-
<
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
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
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
)
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
}
|
|
2918
|
-
>
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
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
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
)
|
|
2591
|
+
</div>
|
|
2592
|
+
) : null}
|
|
2593
|
+
</div>
|
|
2594
|
+
) : null}
|
|
2595
|
+
</div>
|
|
2596
|
+
);
|
|
2597
|
+
})
|
|
2938
2598
|
)}
|
|
2939
2599
|
</div>
|
|
2940
2600
|
) : null}
|