@youtyan/code-viewer 0.2.2 → 0.2.4

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/web/app.js CHANGED
@@ -633,12 +633,14 @@
633
633
  }
634
634
  case "/database": {
635
635
  const db = params.get("db") || undefined;
636
+ const schema = params.get("schema") || undefined;
636
637
  const table = params.get("table") || undefined;
637
638
  const tabRaw = params.get("tab");
638
639
  const tab = tabRaw === "data" || tabRaw === "query" || tabRaw === "schema" || tabRaw === "er" || tabRaw === "search" || tabRaw === "snapshot" ? tabRaw : undefined;
639
640
  return {
640
641
  screen: "database",
641
642
  ...db ? { db } : {},
643
+ ...schema ? { schema } : {},
642
644
  ...table ? { table } : {},
643
645
  ...tab ? { tab } : {},
644
646
  range
@@ -694,6 +696,8 @@
694
696
  const params = new URLSearchParams;
695
697
  if (route.db)
696
698
  params.set("db", route.db);
699
+ if (route.schema)
700
+ params.set("schema", route.schema);
697
701
  if (route.table)
698
702
  params.set("table", route.table);
699
703
  if (route.tab)
@@ -7303,6 +7307,8 @@ ${frontmatter.yaml}
7303
7307
  const parts = ["Database"];
7304
7308
  if (entry.target.db)
7305
7309
  parts.push(entry.target.db);
7310
+ if (entry.target.schema)
7311
+ parts.push(entry.target.schema);
7306
7312
  if (entry.target.table)
7307
7313
  parts.push(entry.target.table);
7308
7314
  if (entry.target.tab)
@@ -7326,6 +7332,8 @@ ${frontmatter.yaml}
7326
7332
  const target = entry.target;
7327
7333
  if (target.db && target.db !== route.db)
7328
7334
  return false;
7335
+ if (target.schema && target.schema !== route.schema)
7336
+ return false;
7329
7337
  if (target.table && target.table !== route.table)
7330
7338
  return false;
7331
7339
  if (target.tab && target.tab !== (route.tab || "data"))
@@ -7647,7 +7655,9 @@ ${frontmatter.yaml}
7647
7655
  return firstLine.length > 90 ? `${firstLine.slice(0, 90)}…` : firstLine;
7648
7656
  }
7649
7657
  function databaseAnnotationTitle(target) {
7650
- const parts = [target.table || target.db || "Database"];
7658
+ const parts = [target.table || target.schema || target.db || "Database"];
7659
+ if (target.schema && target.table)
7660
+ parts.unshift(target.schema);
7651
7661
  if (target.tab === "data" && target.data?.search)
7652
7662
  parts.push(`search: ${target.data.search}`);
7653
7663
  else if (target.tab === "query" && target.query?.sql)
@@ -7954,6 +7964,7 @@ ${frontmatter.yaml}
7954
7964
  deps.setRoute({
7955
7965
  screen: "database",
7956
7966
  db: target.db,
7967
+ schema: target.schema,
7957
7968
  table: target.table,
7958
7969
  tab: target.tab,
7959
7970
  range: deps.currentRange()
@@ -8481,6 +8492,9 @@ ${frontmatter.yaml}
8481
8492
  function isMakefileName(name) {
8482
8493
  return /^makefile(?:[.-].+)?$/i.test(name);
8483
8494
  }
8495
+ function isDotenvName(name) {
8496
+ return /^(?:\.?env|.*\.env)(?:[.-].+)?$/i.test(name);
8497
+ }
8484
8498
  function sourceDisplayKind(path) {
8485
8499
  if (isVideo(path))
8486
8500
  return "video";
@@ -8496,6 +8510,8 @@ ${frontmatter.yaml}
8496
8510
  return "text";
8497
8511
  if (TEXT_SOURCE_FILENAMES.has(name))
8498
8512
  return "text";
8513
+ if (isDotenvName(name))
8514
+ return "text";
8499
8515
  if (isDockerfileName(name) || isMakefileName(name))
8500
8516
  return "text";
8501
8517
  return "unsupported";
@@ -9391,6 +9407,7 @@ ${frontmatter.yaml}
9391
9407
  if (disposed)
9392
9408
  return;
9393
9409
  const dbId = deps.getDbId();
9410
+ const schema = deps.getSchema();
9394
9411
  if (!dbId)
9395
9412
  return;
9396
9413
  const term = input.value.trim();
@@ -9411,6 +9428,7 @@ ${frontmatter.yaml}
9411
9428
  },
9412
9429
  body: JSON.stringify({
9413
9430
  db: dbId,
9431
+ ...schema ? { schema } : {},
9414
9432
  term,
9415
9433
  includeNonText: nonTextCheck.checked
9416
9434
  })
@@ -9489,16 +9507,17 @@ ${frontmatter.yaml}
9489
9507
  return;
9490
9508
  const grouped = new Map;
9491
9509
  for (const h of hits) {
9492
- const existing = grouped.get(h.table) || [];
9510
+ const key = h.schema ? `${h.schema}.${h.table}` : h.table;
9511
+ const existing = grouped.get(key) || [];
9493
9512
  existing.push(h);
9494
- grouped.set(h.table, existing);
9513
+ grouped.set(key, existing);
9495
9514
  }
9496
- for (const [table2, tableHits] of grouped) {
9515
+ for (const [tableLabel, tableHits] of grouped) {
9497
9516
  const section = document.createElement("div");
9498
9517
  section.className = "db-search-table-section";
9499
9518
  const tableHeader = document.createElement("div");
9500
9519
  tableHeader.className = "db-search-table-header";
9501
- tableHeader.textContent = `${table2} (${tableHits.length}件)`;
9520
+ tableHeader.textContent = `${tableLabel} (${tableHits.length}件)`;
9502
9521
  section.appendChild(tableHeader);
9503
9522
  const hitsList = document.createElement("div");
9504
9523
  hitsList.className = "db-search-hits-list";
@@ -9963,7 +9982,13 @@ ${frontmatter.yaml}
9963
9982
  }
9964
9983
  async function refresh() {
9965
9984
  const dbId = callbacks.getDbId();
9966
- const params = dbId ? `?db=${encodeURIComponent(dbId)}` : "";
9985
+ const schema = callbacks.getSchema();
9986
+ const searchParams = new URLSearchParams;
9987
+ if (dbId)
9988
+ searchParams.set("db", dbId);
9989
+ if (schema)
9990
+ searchParams.set("schema", schema);
9991
+ const params = searchParams.toString() ? `?${searchParams.toString()}` : "";
9967
9992
  try {
9968
9993
  const res = await fetch(`/_db/history${params}`);
9969
9994
  if (!res.ok)
@@ -10176,13 +10201,14 @@ ${frontmatter.yaml}
10176
10201
  clearConfirmTimer = null;
10177
10202
  }
10178
10203
  try {
10204
+ const schema = callbacks.getSchema();
10179
10205
  await fetch("/_db/history/clear", {
10180
10206
  method: "POST",
10181
10207
  headers: {
10182
10208
  "Content-Type": "application/json",
10183
10209
  "X-Code-Viewer-Action": "1"
10184
10210
  },
10185
- body: JSON.stringify(dbId ? { db: dbId } : {})
10211
+ body: JSON.stringify(dbId ? { db: dbId, ...schema ? { schema } : {} } : {})
10186
10212
  });
10187
10213
  entries = [];
10188
10214
  render();
@@ -11012,6 +11038,7 @@ ${frontmatter.yaml}
11012
11038
  });
11013
11039
  confirmBtn.addEventListener("click", async () => {
11014
11040
  const dbId = deps.getDbId();
11041
+ const schema = deps.getSchema();
11015
11042
  if (!dbId)
11016
11043
  return;
11017
11044
  const tables = getSelectedTables();
@@ -11022,11 +11049,12 @@ ${frontmatter.yaml}
11022
11049
  try {
11023
11050
  await postJson("/_db/snapshot/create", {
11024
11051
  db: dbId,
11052
+ ...schema ? { schema } : {},
11025
11053
  tables,
11026
11054
  note: noteInput.value.trim()
11027
11055
  });
11028
11056
  tableSelector.hidden = true;
11029
- scheduleAutoRefresh(dbId);
11057
+ scheduleAutoRefresh(dbId, schema);
11030
11058
  } catch {} finally {
11031
11059
  if (!disposed) {
11032
11060
  confirmBtn.disabled = false;
@@ -11034,11 +11062,12 @@ ${frontmatter.yaml}
11034
11062
  }
11035
11063
  }
11036
11064
  });
11037
- function scheduleAutoRefresh(dbId) {
11065
+ function scheduleAutoRefresh(dbId, schema) {
11038
11066
  const timer = setTimeout(() => {
11039
11067
  autoRefreshTimers.delete(timer);
11040
- if (disposed || deps.getDbId() !== dbId)
11068
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema) {
11041
11069
  return;
11070
+ }
11042
11071
  refreshAndAutoDiff();
11043
11072
  }, 3000);
11044
11073
  autoRefreshTimers.add(timer);
@@ -11046,17 +11075,22 @@ ${frontmatter.yaml}
11046
11075
  refreshBtn.addEventListener("click", refresh);
11047
11076
  async function refresh() {
11048
11077
  const dbId = deps.getDbId();
11078
+ const schema = deps.getSchema();
11049
11079
  if (!dbId)
11050
11080
  return;
11051
11081
  try {
11052
- const snapRes = await fetch(`/_db/snapshot/list?db=${encodeURIComponent(dbId)}`);
11082
+ const params = new URLSearchParams({ db: dbId });
11083
+ if (schema)
11084
+ params.set("schema", schema);
11085
+ const snapRes = await fetch(`/_db/snapshot/list?${params}`);
11053
11086
  if (snapRes.ok) {
11054
11087
  const data = await snapRes.json();
11055
- if (disposed || deps.getDbId() !== dbId)
11088
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema) {
11056
11089
  return;
11090
+ }
11057
11091
  snapshots = data.snapshots;
11058
11092
  }
11059
- if (disposed || deps.getDbId() !== dbId)
11093
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema)
11060
11094
  return;
11061
11095
  renderMain();
11062
11096
  } catch {}
@@ -11431,8 +11465,11 @@ ${frontmatter.yaml}
11431
11465
  try {
11432
11466
  const parsed = JSON.parse(data);
11433
11467
  const dbId = deps.getDbId();
11468
+ const schema = deps.getSchema();
11434
11469
  if (parsed.dbId && dbId && parsed.dbId !== dbId)
11435
11470
  return;
11471
+ if (parsed.schema && parsed.schema !== schema)
11472
+ return;
11436
11473
  if (parsed.action === "started" && parsed.id) {
11437
11474
  setActiveSnapshotId(parsed.id);
11438
11475
  }
@@ -12395,6 +12432,9 @@ ${frontmatter.yaml}
12395
12432
  function isSqlKind(kind) {
12396
12433
  return kind === "sqlite" || kind === "postgresql" || kind === "mysql";
12397
12434
  }
12435
+ function isPostgresKind(kind) {
12436
+ return kind === "postgresql";
12437
+ }
12398
12438
  function isSqlView(view) {
12399
12439
  return view === "data" || view === "query" || view === "schema" || view === "er" || view === "search" || view === "snapshot";
12400
12440
  }
@@ -12448,14 +12488,19 @@ ${frontmatter.yaml}
12448
12488
  let currentDbInfo = null;
12449
12489
  let schemaCache = null;
12450
12490
  let lastFiles = [];
12491
+ let currentSchema = initial.schema ?? null;
12451
12492
  let currentTable = initial.table ?? null;
12452
12493
  let loadGeneration = 0;
12453
12494
  const dbSelect = document.createElement("select");
12454
12495
  dbSelect.className = "db-file-select";
12455
12496
  dbSelect.title = "Select database file";
12497
+ const schemaSelect = document.createElement("select");
12498
+ schemaSelect.className = "db-file-select db-schema-select";
12499
+ schemaSelect.title = "Select PostgreSQL schema";
12500
+ schemaSelect.hidden = true;
12456
12501
  const dbToolbar = document.createElement("div");
12457
12502
  dbToolbar.className = "db-toolbar";
12458
- dbToolbar.appendChild(dbSelect);
12503
+ dbToolbar.append(dbSelect, schemaSelect);
12459
12504
  const tabBar = document.createElement("div");
12460
12505
  tabBar.className = "db-tab-bar";
12461
12506
  const tabData = createInnerTab("Data", true);
@@ -12546,14 +12591,17 @@ ${frontmatter.yaml}
12546
12591
  const schemaView = createSchemaView();
12547
12592
  const erDiagram = createErDiagram();
12548
12593
  const globalSearchView = createGlobalSearchView({
12549
- getDbId: () => currentDbInfo?.id || null
12594
+ getDbId: () => currentDbInfo?.id || null,
12595
+ getSchema: () => currentSchema
12550
12596
  });
12551
12597
  const snapshotView = createSnapshotView({
12552
12598
  getDbId: () => currentDbInfo?.id || null,
12599
+ getSchema: () => currentSchema,
12553
12600
  getTables: () => schemaCache?.tables || []
12554
12601
  });
12555
12602
  const historyView = createQueryHistoryView({
12556
12603
  getDbId: () => currentDbInfo?.id || null,
12604
+ getSchema: () => currentSchema,
12557
12605
  copySqlToQuery: (sql) => {
12558
12606
  queryEditor.setSql(sql);
12559
12607
  setActiveTab("query");
@@ -12695,6 +12743,7 @@ ${frontmatter.yaml}
12695
12743
  deps.setRoute({
12696
12744
  screen: "database",
12697
12745
  db: currentDbInfo?.id,
12746
+ schema: currentSchema ?? undefined,
12698
12747
  table: currentTable ?? undefined,
12699
12748
  tab: currentTab === "data" ? undefined : currentTab,
12700
12749
  range: deps.currentRange()
@@ -12715,8 +12764,40 @@ ${frontmatter.yaml}
12715
12764
  const data = await res.json();
12716
12765
  return data;
12717
12766
  }
12767
+ function withCurrentSchema(params) {
12768
+ if (currentSchema)
12769
+ params.set("schema", currentSchema);
12770
+ return params;
12771
+ }
12772
+ async function fetchSchemas(dbId, preferredSchema) {
12773
+ const params = new URLSearchParams({ db: dbId });
12774
+ if (preferredSchema)
12775
+ params.set("schema", preferredSchema);
12776
+ const res = await deps.trackLoad(fetch(`/_db/schemas?${params}`));
12777
+ if (!res.ok) {
12778
+ throw new Error(await responseErrorMessage(res, "failed to fetch schemas"));
12779
+ }
12780
+ return await res.json();
12781
+ }
12782
+ function renderSchemaOptions(schemas, selected) {
12783
+ schemaSelect.innerHTML = "";
12784
+ for (const schema of schemas) {
12785
+ const opt = document.createElement("option");
12786
+ opt.value = schema;
12787
+ opt.textContent = schema;
12788
+ schemaSelect.appendChild(opt);
12789
+ }
12790
+ schemaSelect.hidden = schemas.length === 0;
12791
+ schemaSelect.disabled = schemas.length === 0;
12792
+ if (selected && schemas.includes(selected)) {
12793
+ schemaSelect.value = selected;
12794
+ } else if (schemas.length > 0) {
12795
+ schemaSelect.value = schemas[0];
12796
+ }
12797
+ }
12718
12798
  async function fetchSchema(dbId) {
12719
- const res = await deps.trackLoad(fetch(`/_db/schema?db=${encodeURIComponent(dbId)}&includeColumns=1`));
12799
+ const params = withCurrentSchema(new URLSearchParams({ db: dbId, includeColumns: "1" }));
12800
+ const res = await deps.trackLoad(fetch(`/_db/schema?${params}`));
12720
12801
  if (!res.ok) {
12721
12802
  throw new Error(await responseErrorMessage(res, "failed to fetch schema"));
12722
12803
  }
@@ -12731,6 +12812,7 @@ ${frontmatter.yaml}
12731
12812
  offset: String(offset),
12732
12813
  limit: String(limit)
12733
12814
  });
12815
+ withCurrentSchema(params);
12734
12816
  if (sort) {
12735
12817
  params.set("sort", sort.column);
12736
12818
  params.set("dir", sort.direction);
@@ -12755,6 +12837,7 @@ ${frontmatter.yaml}
12755
12837
  },
12756
12838
  body: JSON.stringify({
12757
12839
  db: currentDbInfo.id,
12840
+ ...currentSchema ? { schema: currentSchema } : {},
12758
12841
  sql,
12759
12842
  saveHistory: true,
12760
12843
  source: "browser",
@@ -12769,11 +12852,13 @@ ${frontmatter.yaml}
12769
12852
  historyView.refresh();
12770
12853
  return result;
12771
12854
  }
12772
- async function selectDb(dbId, explorerInitial, generation = loadGeneration, preferredTable) {
12855
+ async function selectDb(dbId, explorerInitial, generation = loadGeneration, preferredSchema, preferredTable) {
12773
12856
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12774
12857
  return;
12775
12858
  currentTable = null;
12776
12859
  if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch") {
12860
+ currentSchema = null;
12861
+ renderSchemaOptions([], null);
12777
12862
  currentTab = "data";
12778
12863
  tableList.render([]);
12779
12864
  grid.clear();
@@ -12799,6 +12884,34 @@ ${frontmatter.yaml}
12799
12884
  tableList.render([]);
12800
12885
  setTableListStatus("Loading schema...");
12801
12886
  grid.clear();
12887
+ if (isPostgresKind(currentDbInfo?.kind)) {
12888
+ const desiredSchema = preferredSchema !== undefined ? preferredSchema : currentSchema;
12889
+ const schemas = await fetchSchemas(dbId, desiredSchema).catch((err) => {
12890
+ if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12891
+ return;
12892
+ const message = errorMessage(err);
12893
+ currentSchema = null;
12894
+ renderSchemaOptions([], null);
12895
+ schemaCache = null;
12896
+ tableList.render([]);
12897
+ setTableListStatus(message, { error: true });
12898
+ grid.showError(message);
12899
+ schemaView.clear();
12900
+ erDiagram.clear();
12901
+ cb.onStateChange();
12902
+ return null;
12903
+ });
12904
+ if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12905
+ return;
12906
+ if (!schemas)
12907
+ return;
12908
+ const schemaNames = schemas.schemas.map((s2) => s2.name);
12909
+ currentSchema = schemas.selectedSchema || desiredSchema || (schemaNames.includes("public") ? "public" : schemaNames[0]) || null;
12910
+ renderSchemaOptions(schemaNames, currentSchema);
12911
+ } else {
12912
+ currentSchema = null;
12913
+ renderSchemaOptions([], null);
12914
+ }
12802
12915
  const schema = await fetchSchema(dbId).catch((err) => {
12803
12916
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12804
12917
  return;
@@ -12817,6 +12930,7 @@ ${frontmatter.yaml}
12817
12930
  return;
12818
12931
  if (!schema)
12819
12932
  return;
12933
+ currentSchema = schema.schema || currentSchema;
12820
12934
  schemaCache = schema;
12821
12935
  tableList.render(schema.tables);
12822
12936
  grid.clear();
@@ -12844,6 +12958,7 @@ ${frontmatter.yaml}
12844
12958
  deps.setRoute({
12845
12959
  screen: "database",
12846
12960
  db: currentDbInfo.id,
12961
+ schema: currentSchema ?? undefined,
12847
12962
  table: table2,
12848
12963
  tab: currentTab === "data" ? undefined : currentTab,
12849
12964
  range: deps.currentRange()
@@ -12874,7 +12989,7 @@ ${frontmatter.yaml}
12874
12989
  }
12875
12990
  if (!currentDbInfo)
12876
12991
  return [];
12877
- const res = await fetch(`/_db/columns?db=${encodeURIComponent(currentDbInfo.id)}&table=${encodeURIComponent(table2)}`);
12992
+ const res = await fetch(`/_db/columns?${withCurrentSchema(new URLSearchParams({ db: currentDbInfo.id, table: table2 }))}`);
12878
12993
  if (!res.ok)
12879
12994
  return [];
12880
12995
  const data = await res.json();
@@ -12892,7 +13007,7 @@ ${frontmatter.yaml}
12892
13007
  return;
12893
13008
  setActiveTab("schema");
12894
13009
  try {
12895
- const res = await fetch(`/_db/ddl?db=${encodeURIComponent(currentDbInfo.id)}&table=${encodeURIComponent(table2)}`);
13010
+ const res = await fetch(`/_db/ddl?${withCurrentSchema(new URLSearchParams({ db: currentDbInfo.id, table: table2 }))}`);
12896
13011
  if (!res.ok)
12897
13012
  return;
12898
13013
  const data = await res.json();
@@ -12925,6 +13040,33 @@ ${frontmatter.yaml}
12925
13040
  dbSelect.addEventListener("change", () => {
12926
13041
  handleDbSelectChange();
12927
13042
  });
13043
+ schemaSelect.addEventListener("change", () => {
13044
+ handleSchemaSelectChange();
13045
+ });
13046
+ async function handleSchemaSelectChange() {
13047
+ if (!currentDbInfo || !isPostgresKind(currentDbInfo.kind))
13048
+ return;
13049
+ const schema = schemaSelect.value || null;
13050
+ if (!schema || schema === currentSchema)
13051
+ return;
13052
+ const dbId = currentDbInfo.id;
13053
+ currentSchema = schema;
13054
+ const generation = ++loadGeneration;
13055
+ clearDockerNotice();
13056
+ await selectDb(dbId, undefined, generation, schema, null);
13057
+ if (generation !== loadGeneration || currentDbInfo?.id !== dbId || currentSchema !== schema) {
13058
+ return;
13059
+ }
13060
+ deps.setRoute({
13061
+ screen: "database",
13062
+ db: dbId,
13063
+ schema,
13064
+ table: currentTable ?? undefined,
13065
+ tab: currentTab === "data" ? undefined : currentTab,
13066
+ range: deps.currentRange()
13067
+ }, true);
13068
+ cb.onStateChange();
13069
+ }
12928
13070
  async function handleDbSelectChange() {
12929
13071
  const dbId = dbSelect.value;
12930
13072
  if (!dbId)
@@ -12939,13 +13081,15 @@ ${frontmatter.yaml}
12939
13081
  sizeBytes: file?.sizeBytes || 0,
12940
13082
  kind: file?.kind || "sqlite"
12941
13083
  };
13084
+ currentSchema = null;
12942
13085
  clearDockerNotice();
12943
- await selectDb(dbId, undefined, generation);
13086
+ await selectDb(dbId, undefined, generation, null);
12944
13087
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12945
13088
  return;
12946
13089
  deps.setRoute({
12947
13090
  screen: "database",
12948
13091
  db: dbId,
13092
+ schema: currentSchema ?? undefined,
12949
13093
  table: currentTable ?? undefined,
12950
13094
  tab: currentTab === "data" ? undefined : currentTab,
12951
13095
  range: deps.currentRange()
@@ -12954,7 +13098,7 @@ ${frontmatter.yaml}
12954
13098
  }
12955
13099
  let pendingRedisInitial = initial.redis;
12956
13100
  let pendingEsInitial = initial.es;
12957
- async function enter(db, table2, view, options = {}) {
13101
+ async function enter(db, schema, table2, view, options = {}) {
12958
13102
  const generation = ++loadGeneration;
12959
13103
  const filesResponse = await fetchDbFiles();
12960
13104
  if (generation !== loadGeneration)
@@ -12992,8 +13136,10 @@ ${frontmatter.yaml}
12992
13136
  if (!db && !autoSelectFirst) {
12993
13137
  dbSelect.value = "";
12994
13138
  currentDbInfo = null;
13139
+ currentSchema = null;
12995
13140
  currentTable = null;
12996
13141
  schemaCache = null;
13142
+ renderSchemaOptions([], null);
12997
13143
  tableList.render([]);
12998
13144
  grid.clear();
12999
13145
  schemaView.clear();
@@ -13013,7 +13159,7 @@ ${frontmatter.yaml}
13013
13159
  };
13014
13160
  pendingRedisInitial = undefined;
13015
13161
  pendingEsInitial = undefined;
13016
- await selectDb(target, explorerInitial, generation, table2);
13162
+ await selectDb(target, explorerInitial, generation, schema !== undefined ? schema : currentSchema, table2);
13017
13163
  if (generation !== loadGeneration || currentDbInfo?.id !== target)
13018
13164
  return;
13019
13165
  if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch") {
@@ -13046,6 +13192,8 @@ ${frontmatter.yaml}
13046
13192
  function applyAnnotationTarget(target) {
13047
13193
  if (!target || target.db !== currentDbInfo?.id)
13048
13194
  return;
13195
+ if (target.schema && target.schema !== currentSchema)
13196
+ return;
13049
13197
  if (target.data) {
13050
13198
  if (target.table && target.table !== currentTable)
13051
13199
  return;
@@ -13082,6 +13230,7 @@ ${frontmatter.yaml}
13082
13230
  const state = {
13083
13231
  id: cb.tabId,
13084
13232
  dbId: currentDbInfo?.id ?? null,
13233
+ schema: currentSchema,
13085
13234
  table: currentTable ?? activeTable?.dataset.table ?? null,
13086
13235
  view: currentTab
13087
13236
  };
@@ -13113,6 +13262,7 @@ ${frontmatter.yaml}
13113
13262
  const target = {
13114
13263
  kind: "database",
13115
13264
  db: currentDbInfo.id,
13265
+ ...currentSchema ? { schema: currentSchema } : {},
13116
13266
  ...currentTable ? { table: currentTable } : {},
13117
13267
  tab: currentTab
13118
13268
  };
@@ -13129,12 +13279,14 @@ ${frontmatter.yaml}
13129
13279
  function getLabel() {
13130
13280
  if (!currentDbInfo)
13131
13281
  return labelFromDbId(initial.dbId);
13282
+ const suffix = currentSchema ? ` / ${currentSchema}` : "";
13132
13283
  if (currentDbInfo.id.startsWith("docker:")) {
13133
13284
  const m = currentDbInfo.name.match(/^(\S+)/);
13134
- return m ? m[1] : currentDbInfo.name;
13285
+ return `${m ? m[1] : currentDbInfo.name}${suffix}`;
13135
13286
  }
13136
13287
  const lastSlash = currentDbInfo.path.lastIndexOf("/");
13137
- return lastSlash >= 0 ? currentDbInfo.path.slice(lastSlash + 1) : currentDbInfo.path;
13288
+ const label = lastSlash >= 0 ? currentDbInfo.path.slice(lastSlash + 1) : currentDbInfo.path;
13289
+ return `${label}${suffix}`;
13138
13290
  }
13139
13291
  function dispose() {
13140
13292
  loadGeneration++;
@@ -13149,6 +13301,7 @@ ${frontmatter.yaml}
13149
13301
  redisExplorer.dispose();
13150
13302
  esExplorer.dispose();
13151
13303
  currentDbInfo = null;
13304
+ currentSchema = null;
13152
13305
  currentTable = null;
13153
13306
  schemaCache = null;
13154
13307
  }
@@ -13294,6 +13447,7 @@ ${frontmatter.yaml}
13294
13447
  deps.setRoute({
13295
13448
  screen: "database",
13296
13449
  db: s2.dbId ?? undefined,
13450
+ schema: s2.schema ?? undefined,
13297
13451
  table: s2.table ?? undefined,
13298
13452
  tab: s2.view === "data" ? undefined : s2.view,
13299
13453
  range: deps.currentRange()
@@ -13314,6 +13468,7 @@ ${frontmatter.yaml}
13314
13468
  for (const tab of tabs) {
13315
13469
  const key = JSON.stringify({
13316
13470
  dbId: tab.dbId,
13471
+ schema: tab.schema ?? null,
13317
13472
  table: tab.table,
13318
13473
  view: tab.view,
13319
13474
  redis: tab.redis ?? null,
@@ -13544,6 +13699,7 @@ ${frontmatter.yaml}
13544
13699
  }
13545
13700
  }, {
13546
13701
  dbId: initial?.dbId ?? null,
13702
+ schema: initial?.schema ?? null,
13547
13703
  table: initial?.table ?? null,
13548
13704
  view: initial?.view ?? undefined,
13549
13705
  sqlDraft: initial?.sqlDraft,
@@ -13572,7 +13728,7 @@ ${frontmatter.yaml}
13572
13728
  if (options.annotationTarget)
13573
13729
  restoring = true;
13574
13730
  try {
13575
- await pane.enter(initial?.dbId || undefined, initial?.table || undefined, initial?.view || undefined, options);
13731
+ await pane.enter(initial?.dbId || undefined, initial?.schema || undefined, initial?.table || undefined, initial?.view || undefined, options);
13576
13732
  refreshChipLabel(id);
13577
13733
  } finally {
13578
13734
  if (options.annotationTarget)
@@ -13609,35 +13765,41 @@ ${frontmatter.yaml}
13609
13765
  newTabBtn.addEventListener("click", () => {
13610
13766
  openTab({ dbId: null, table: null, view: "data" }, { autoSelectFirst: false });
13611
13767
  });
13612
- function routeMatchesState(state, db, table2, view) {
13613
- if (!db && (table2 || view) && !state.dbId)
13768
+ function routeMatchesState(state, db, schema, table2, view) {
13769
+ if (!db && (schema || table2 || view) && !state.dbId)
13614
13770
  return false;
13615
13771
  if (db !== undefined && state.dbId !== db)
13616
13772
  return false;
13773
+ if (schema !== undefined) {
13774
+ const routeSchema = schema || "public";
13775
+ const stateSchema = state.schema || "public";
13776
+ if (stateSchema !== routeSchema)
13777
+ return false;
13778
+ }
13617
13779
  if (table2 !== undefined && state.table !== table2)
13618
13780
  return false;
13619
13781
  if (view !== undefined && state.view !== view)
13620
13782
  return false;
13621
13783
  return true;
13622
13784
  }
13623
- async function applyRouteToTab(db, table2, view, options = {}) {
13624
- async function enterPane(pane, targetDb, targetTable, targetView, enterOptions) {
13785
+ async function applyRouteToTab(db, schema, table2, view, options = {}) {
13786
+ async function enterPane(pane, targetDb, targetSchema, targetTable, targetView, enterOptions) {
13625
13787
  if (!enterOptions?.annotationTarget) {
13626
- await pane.enter(targetDb, targetTable, targetView, enterOptions);
13788
+ await pane.enter(targetDb, targetSchema, targetTable, targetView, enterOptions);
13627
13789
  return;
13628
13790
  }
13629
13791
  restoring = true;
13630
13792
  try {
13631
- await pane.enter(targetDb, targetTable, targetView, enterOptions);
13793
+ await pane.enter(targetDb, targetSchema, targetTable, targetView, enterOptions);
13632
13794
  } finally {
13633
13795
  restoring = false;
13634
13796
  }
13635
13797
  }
13636
13798
  for (const [id2, entry] of tabsById) {
13637
- if (routeMatchesState(entry.pane.getState(), db, table2, view)) {
13799
+ if (routeMatchesState(entry.pane.getState(), db, schema, table2, view)) {
13638
13800
  setActive(id2);
13639
13801
  if (options.annotationTarget) {
13640
- await enterPane(entry.pane, db, table2, view, options);
13802
+ await enterPane(entry.pane, db, schema, table2, view, options);
13641
13803
  if (!mounted)
13642
13804
  return;
13643
13805
  }
@@ -13649,7 +13811,7 @@ ${frontmatter.yaml}
13649
13811
  const targetId = activeTabId;
13650
13812
  const active = tabsById.get(activeTabId);
13651
13813
  if (active) {
13652
- await enterPane(active.pane, db, table2, view, options);
13814
+ await enterPane(active.pane, db, schema, table2, view, options);
13653
13815
  if (!mounted)
13654
13816
  return;
13655
13817
  refreshChipLabel(targetId);
@@ -13658,6 +13820,7 @@ ${frontmatter.yaml}
13658
13820
  }
13659
13821
  const id = openTab({
13660
13822
  dbId: db ?? null,
13823
+ schema: schema ?? null,
13661
13824
  table: table2 ?? null,
13662
13825
  view: view ?? "data"
13663
13826
  }, { autoSelectFirst: db === undefined, ...options });
@@ -13676,7 +13839,17 @@ ${frontmatter.yaml}
13676
13839
  return null;
13677
13840
  }
13678
13841
  }
13679
- async function doEnter(seq, db, table2, view, options = {}) {
13842
+ function parseSseSchema(data) {
13843
+ if (!data)
13844
+ return null;
13845
+ try {
13846
+ const parsed = JSON.parse(data);
13847
+ return typeof parsed.schema === "string" ? parsed.schema : null;
13848
+ } catch {
13849
+ return null;
13850
+ }
13851
+ }
13852
+ async function doEnter(seq, db, schema, table2, view, options = {}) {
13680
13853
  if (seq !== lifecycleSeq)
13681
13854
  return;
13682
13855
  const firstMount = !mounted;
@@ -13739,8 +13912,8 @@ ${frontmatter.yaml}
13739
13912
  } finally {
13740
13913
  restoring = false;
13741
13914
  }
13742
- if (db || table2 || view) {
13743
- await applyRouteToTab(db, table2, view, {
13915
+ if (db || schema || table2 || view) {
13916
+ await applyRouteToTab(db, schema ?? null, table2, view, {
13744
13917
  ...options,
13745
13918
  reuseActiveTab: options.reuseActiveTab ?? true
13746
13919
  });
@@ -13765,6 +13938,7 @@ ${frontmatter.yaml}
13765
13938
  if (tabsById.size === 0) {
13766
13939
  const id = openTab({
13767
13940
  dbId: db || null,
13941
+ schema: schema || null,
13768
13942
  table: table2 || null,
13769
13943
  view: view || "data"
13770
13944
  }, { autoSelectFirst: !db, ...options });
@@ -13780,8 +13954,8 @@ ${frontmatter.yaml}
13780
13954
  const active = tabsById.get(activeTabId);
13781
13955
  if (!active)
13782
13956
  return;
13783
- if (db || table2 || view) {
13784
- await applyRouteToTab(db, table2, view, {
13957
+ if (db || schema || table2 || view) {
13958
+ await applyRouteToTab(db, schema ?? null, table2, view, {
13785
13959
  ...options,
13786
13960
  reuseActiveTab: options.reuseActiveTab ?? true
13787
13961
  });
@@ -13789,9 +13963,9 @@ ${frontmatter.yaml}
13789
13963
  syncActiveRoute();
13790
13964
  }
13791
13965
  }
13792
- async function enter(db, table2, view, options = {}) {
13966
+ async function enter(db, schema, table2, view, options = {}) {
13793
13967
  const seq = lifecycleSeq;
13794
- enterQueue = enterQueue.catch(() => {}).then(() => doEnter(seq, db, table2, view, options));
13968
+ enterQueue = enterQueue.catch(() => {}).then(() => doEnter(seq, db, schema, table2, view, options));
13795
13969
  await enterQueue;
13796
13970
  }
13797
13971
  function leave() {
@@ -13841,8 +14015,12 @@ ${frontmatter.yaml}
13841
14015
  if (!mounted)
13842
14016
  return;
13843
14017
  const dbId = parseSseDbId(data);
14018
+ const schema = parseSseSchema(data);
13844
14019
  for (const [, entry] of tabsById) {
13845
- if (dbId && entry.pane.getState().dbId !== dbId)
14020
+ const state = entry.pane.getState();
14021
+ if (dbId && state.dbId !== dbId)
14022
+ continue;
14023
+ if (schema && state.schema !== schema)
13846
14024
  continue;
13847
14025
  entry.pane.handleSse(event, data);
13848
14026
  }
@@ -23784,7 +23962,7 @@ code-viewer annotate add-db --db app.db --tab query \\
23784
23962
  return Promise.resolve(null);
23785
23963
  }
23786
23964
  if (STATE.route.screen === "database") {
23787
- DATABASE_VIEW.enter(STATE.route.db, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
23965
+ DATABASE_VIEW.enter(STATE.route.db, STATE.route.schema, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
23788
23966
  setStatus("live");
23789
23967
  return Promise.resolve(null);
23790
23968
  }
@@ -23855,7 +24033,7 @@ code-viewer annotate add-db --db app.db --tab query \\
23855
24033
  HISTORY_VIEW.enterHistory();
23856
24034
  } else if (STATE.route.screen === "database") {
23857
24035
  setStatus("live");
23858
- DATABASE_VIEW.enter(STATE.route.db, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
24036
+ DATABASE_VIEW.enter(STATE.route.db, STATE.route.schema, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
23859
24037
  } else
23860
24038
  load();
23861
24039
  syncLineRefPill();
@@ -24005,7 +24183,7 @@ code-viewer annotate add-db --db app.db --tab query \\
24005
24183
  cancelActiveSourceLoad("navigation");
24006
24184
  setPageMode();
24007
24185
  removeStandaloneSource();
24008
- DATABASE_VIEW.enter(STATE.route.db, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
24186
+ DATABASE_VIEW.enter(STATE.route.db, STATE.route.schema, STATE.route.table, STATE.route.tab).then(() => ANNOTATIONS_UI?.applyInlineAnnotations());
24009
24187
  setStatus("live");
24010
24188
  return;
24011
24189
  }
@@ -24123,7 +24301,7 @@ code-viewer annotate add-db --db app.db --tab query \\
24123
24301
  },
24124
24302
  openDatabaseAnnotation: (target) => {
24125
24303
  setStatus("live");
24126
- return DATABASE_VIEW.enter(target.db, target.table, target.tab, {
24304
+ return DATABASE_VIEW.enter(target.db, target.schema, target.table, target.tab, {
24127
24305
  annotationTarget: target,
24128
24306
  reuseActiveTab: true
24129
24307
  });