@youtyan/code-viewer 0.2.3 → 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()
@@ -9396,6 +9407,7 @@ ${frontmatter.yaml}
9396
9407
  if (disposed)
9397
9408
  return;
9398
9409
  const dbId = deps.getDbId();
9410
+ const schema = deps.getSchema();
9399
9411
  if (!dbId)
9400
9412
  return;
9401
9413
  const term = input.value.trim();
@@ -9416,6 +9428,7 @@ ${frontmatter.yaml}
9416
9428
  },
9417
9429
  body: JSON.stringify({
9418
9430
  db: dbId,
9431
+ ...schema ? { schema } : {},
9419
9432
  term,
9420
9433
  includeNonText: nonTextCheck.checked
9421
9434
  })
@@ -9494,16 +9507,17 @@ ${frontmatter.yaml}
9494
9507
  return;
9495
9508
  const grouped = new Map;
9496
9509
  for (const h of hits) {
9497
- const existing = grouped.get(h.table) || [];
9510
+ const key = h.schema ? `${h.schema}.${h.table}` : h.table;
9511
+ const existing = grouped.get(key) || [];
9498
9512
  existing.push(h);
9499
- grouped.set(h.table, existing);
9513
+ grouped.set(key, existing);
9500
9514
  }
9501
- for (const [table2, tableHits] of grouped) {
9515
+ for (const [tableLabel, tableHits] of grouped) {
9502
9516
  const section = document.createElement("div");
9503
9517
  section.className = "db-search-table-section";
9504
9518
  const tableHeader = document.createElement("div");
9505
9519
  tableHeader.className = "db-search-table-header";
9506
- tableHeader.textContent = `${table2} (${tableHits.length}件)`;
9520
+ tableHeader.textContent = `${tableLabel} (${tableHits.length}件)`;
9507
9521
  section.appendChild(tableHeader);
9508
9522
  const hitsList = document.createElement("div");
9509
9523
  hitsList.className = "db-search-hits-list";
@@ -9968,7 +9982,13 @@ ${frontmatter.yaml}
9968
9982
  }
9969
9983
  async function refresh() {
9970
9984
  const dbId = callbacks.getDbId();
9971
- 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()}` : "";
9972
9992
  try {
9973
9993
  const res = await fetch(`/_db/history${params}`);
9974
9994
  if (!res.ok)
@@ -10181,13 +10201,14 @@ ${frontmatter.yaml}
10181
10201
  clearConfirmTimer = null;
10182
10202
  }
10183
10203
  try {
10204
+ const schema = callbacks.getSchema();
10184
10205
  await fetch("/_db/history/clear", {
10185
10206
  method: "POST",
10186
10207
  headers: {
10187
10208
  "Content-Type": "application/json",
10188
10209
  "X-Code-Viewer-Action": "1"
10189
10210
  },
10190
- body: JSON.stringify(dbId ? { db: dbId } : {})
10211
+ body: JSON.stringify(dbId ? { db: dbId, ...schema ? { schema } : {} } : {})
10191
10212
  });
10192
10213
  entries = [];
10193
10214
  render();
@@ -11017,6 +11038,7 @@ ${frontmatter.yaml}
11017
11038
  });
11018
11039
  confirmBtn.addEventListener("click", async () => {
11019
11040
  const dbId = deps.getDbId();
11041
+ const schema = deps.getSchema();
11020
11042
  if (!dbId)
11021
11043
  return;
11022
11044
  const tables = getSelectedTables();
@@ -11027,11 +11049,12 @@ ${frontmatter.yaml}
11027
11049
  try {
11028
11050
  await postJson("/_db/snapshot/create", {
11029
11051
  db: dbId,
11052
+ ...schema ? { schema } : {},
11030
11053
  tables,
11031
11054
  note: noteInput.value.trim()
11032
11055
  });
11033
11056
  tableSelector.hidden = true;
11034
- scheduleAutoRefresh(dbId);
11057
+ scheduleAutoRefresh(dbId, schema);
11035
11058
  } catch {} finally {
11036
11059
  if (!disposed) {
11037
11060
  confirmBtn.disabled = false;
@@ -11039,11 +11062,12 @@ ${frontmatter.yaml}
11039
11062
  }
11040
11063
  }
11041
11064
  });
11042
- function scheduleAutoRefresh(dbId) {
11065
+ function scheduleAutoRefresh(dbId, schema) {
11043
11066
  const timer = setTimeout(() => {
11044
11067
  autoRefreshTimers.delete(timer);
11045
- if (disposed || deps.getDbId() !== dbId)
11068
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema) {
11046
11069
  return;
11070
+ }
11047
11071
  refreshAndAutoDiff();
11048
11072
  }, 3000);
11049
11073
  autoRefreshTimers.add(timer);
@@ -11051,17 +11075,22 @@ ${frontmatter.yaml}
11051
11075
  refreshBtn.addEventListener("click", refresh);
11052
11076
  async function refresh() {
11053
11077
  const dbId = deps.getDbId();
11078
+ const schema = deps.getSchema();
11054
11079
  if (!dbId)
11055
11080
  return;
11056
11081
  try {
11057
- 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}`);
11058
11086
  if (snapRes.ok) {
11059
11087
  const data = await snapRes.json();
11060
- if (disposed || deps.getDbId() !== dbId)
11088
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema) {
11061
11089
  return;
11090
+ }
11062
11091
  snapshots = data.snapshots;
11063
11092
  }
11064
- if (disposed || deps.getDbId() !== dbId)
11093
+ if (disposed || deps.getDbId() !== dbId || deps.getSchema() !== schema)
11065
11094
  return;
11066
11095
  renderMain();
11067
11096
  } catch {}
@@ -11436,8 +11465,11 @@ ${frontmatter.yaml}
11436
11465
  try {
11437
11466
  const parsed = JSON.parse(data);
11438
11467
  const dbId = deps.getDbId();
11468
+ const schema = deps.getSchema();
11439
11469
  if (parsed.dbId && dbId && parsed.dbId !== dbId)
11440
11470
  return;
11471
+ if (parsed.schema && parsed.schema !== schema)
11472
+ return;
11441
11473
  if (parsed.action === "started" && parsed.id) {
11442
11474
  setActiveSnapshotId(parsed.id);
11443
11475
  }
@@ -12400,6 +12432,9 @@ ${frontmatter.yaml}
12400
12432
  function isSqlKind(kind) {
12401
12433
  return kind === "sqlite" || kind === "postgresql" || kind === "mysql";
12402
12434
  }
12435
+ function isPostgresKind(kind) {
12436
+ return kind === "postgresql";
12437
+ }
12403
12438
  function isSqlView(view) {
12404
12439
  return view === "data" || view === "query" || view === "schema" || view === "er" || view === "search" || view === "snapshot";
12405
12440
  }
@@ -12453,14 +12488,19 @@ ${frontmatter.yaml}
12453
12488
  let currentDbInfo = null;
12454
12489
  let schemaCache = null;
12455
12490
  let lastFiles = [];
12491
+ let currentSchema = initial.schema ?? null;
12456
12492
  let currentTable = initial.table ?? null;
12457
12493
  let loadGeneration = 0;
12458
12494
  const dbSelect = document.createElement("select");
12459
12495
  dbSelect.className = "db-file-select";
12460
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;
12461
12501
  const dbToolbar = document.createElement("div");
12462
12502
  dbToolbar.className = "db-toolbar";
12463
- dbToolbar.appendChild(dbSelect);
12503
+ dbToolbar.append(dbSelect, schemaSelect);
12464
12504
  const tabBar = document.createElement("div");
12465
12505
  tabBar.className = "db-tab-bar";
12466
12506
  const tabData = createInnerTab("Data", true);
@@ -12551,14 +12591,17 @@ ${frontmatter.yaml}
12551
12591
  const schemaView = createSchemaView();
12552
12592
  const erDiagram = createErDiagram();
12553
12593
  const globalSearchView = createGlobalSearchView({
12554
- getDbId: () => currentDbInfo?.id || null
12594
+ getDbId: () => currentDbInfo?.id || null,
12595
+ getSchema: () => currentSchema
12555
12596
  });
12556
12597
  const snapshotView = createSnapshotView({
12557
12598
  getDbId: () => currentDbInfo?.id || null,
12599
+ getSchema: () => currentSchema,
12558
12600
  getTables: () => schemaCache?.tables || []
12559
12601
  });
12560
12602
  const historyView = createQueryHistoryView({
12561
12603
  getDbId: () => currentDbInfo?.id || null,
12604
+ getSchema: () => currentSchema,
12562
12605
  copySqlToQuery: (sql) => {
12563
12606
  queryEditor.setSql(sql);
12564
12607
  setActiveTab("query");
@@ -12700,6 +12743,7 @@ ${frontmatter.yaml}
12700
12743
  deps.setRoute({
12701
12744
  screen: "database",
12702
12745
  db: currentDbInfo?.id,
12746
+ schema: currentSchema ?? undefined,
12703
12747
  table: currentTable ?? undefined,
12704
12748
  tab: currentTab === "data" ? undefined : currentTab,
12705
12749
  range: deps.currentRange()
@@ -12720,8 +12764,40 @@ ${frontmatter.yaml}
12720
12764
  const data = await res.json();
12721
12765
  return data;
12722
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
+ }
12723
12798
  async function fetchSchema(dbId) {
12724
- 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}`));
12725
12801
  if (!res.ok) {
12726
12802
  throw new Error(await responseErrorMessage(res, "failed to fetch schema"));
12727
12803
  }
@@ -12736,6 +12812,7 @@ ${frontmatter.yaml}
12736
12812
  offset: String(offset),
12737
12813
  limit: String(limit)
12738
12814
  });
12815
+ withCurrentSchema(params);
12739
12816
  if (sort) {
12740
12817
  params.set("sort", sort.column);
12741
12818
  params.set("dir", sort.direction);
@@ -12760,6 +12837,7 @@ ${frontmatter.yaml}
12760
12837
  },
12761
12838
  body: JSON.stringify({
12762
12839
  db: currentDbInfo.id,
12840
+ ...currentSchema ? { schema: currentSchema } : {},
12763
12841
  sql,
12764
12842
  saveHistory: true,
12765
12843
  source: "browser",
@@ -12774,11 +12852,13 @@ ${frontmatter.yaml}
12774
12852
  historyView.refresh();
12775
12853
  return result;
12776
12854
  }
12777
- async function selectDb(dbId, explorerInitial, generation = loadGeneration, preferredTable) {
12855
+ async function selectDb(dbId, explorerInitial, generation = loadGeneration, preferredSchema, preferredTable) {
12778
12856
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12779
12857
  return;
12780
12858
  currentTable = null;
12781
12859
  if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch") {
12860
+ currentSchema = null;
12861
+ renderSchemaOptions([], null);
12782
12862
  currentTab = "data";
12783
12863
  tableList.render([]);
12784
12864
  grid.clear();
@@ -12804,6 +12884,34 @@ ${frontmatter.yaml}
12804
12884
  tableList.render([]);
12805
12885
  setTableListStatus("Loading schema...");
12806
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
+ }
12807
12915
  const schema = await fetchSchema(dbId).catch((err) => {
12808
12916
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12809
12917
  return;
@@ -12822,6 +12930,7 @@ ${frontmatter.yaml}
12822
12930
  return;
12823
12931
  if (!schema)
12824
12932
  return;
12933
+ currentSchema = schema.schema || currentSchema;
12825
12934
  schemaCache = schema;
12826
12935
  tableList.render(schema.tables);
12827
12936
  grid.clear();
@@ -12849,6 +12958,7 @@ ${frontmatter.yaml}
12849
12958
  deps.setRoute({
12850
12959
  screen: "database",
12851
12960
  db: currentDbInfo.id,
12961
+ schema: currentSchema ?? undefined,
12852
12962
  table: table2,
12853
12963
  tab: currentTab === "data" ? undefined : currentTab,
12854
12964
  range: deps.currentRange()
@@ -12879,7 +12989,7 @@ ${frontmatter.yaml}
12879
12989
  }
12880
12990
  if (!currentDbInfo)
12881
12991
  return [];
12882
- 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 }))}`);
12883
12993
  if (!res.ok)
12884
12994
  return [];
12885
12995
  const data = await res.json();
@@ -12897,7 +13007,7 @@ ${frontmatter.yaml}
12897
13007
  return;
12898
13008
  setActiveTab("schema");
12899
13009
  try {
12900
- 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 }))}`);
12901
13011
  if (!res.ok)
12902
13012
  return;
12903
13013
  const data = await res.json();
@@ -12930,6 +13040,33 @@ ${frontmatter.yaml}
12930
13040
  dbSelect.addEventListener("change", () => {
12931
13041
  handleDbSelectChange();
12932
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
+ }
12933
13070
  async function handleDbSelectChange() {
12934
13071
  const dbId = dbSelect.value;
12935
13072
  if (!dbId)
@@ -12944,13 +13081,15 @@ ${frontmatter.yaml}
12944
13081
  sizeBytes: file?.sizeBytes || 0,
12945
13082
  kind: file?.kind || "sqlite"
12946
13083
  };
13084
+ currentSchema = null;
12947
13085
  clearDockerNotice();
12948
- await selectDb(dbId, undefined, generation);
13086
+ await selectDb(dbId, undefined, generation, null);
12949
13087
  if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
12950
13088
  return;
12951
13089
  deps.setRoute({
12952
13090
  screen: "database",
12953
13091
  db: dbId,
13092
+ schema: currentSchema ?? undefined,
12954
13093
  table: currentTable ?? undefined,
12955
13094
  tab: currentTab === "data" ? undefined : currentTab,
12956
13095
  range: deps.currentRange()
@@ -12959,7 +13098,7 @@ ${frontmatter.yaml}
12959
13098
  }
12960
13099
  let pendingRedisInitial = initial.redis;
12961
13100
  let pendingEsInitial = initial.es;
12962
- async function enter(db, table2, view, options = {}) {
13101
+ async function enter(db, schema, table2, view, options = {}) {
12963
13102
  const generation = ++loadGeneration;
12964
13103
  const filesResponse = await fetchDbFiles();
12965
13104
  if (generation !== loadGeneration)
@@ -12997,8 +13136,10 @@ ${frontmatter.yaml}
12997
13136
  if (!db && !autoSelectFirst) {
12998
13137
  dbSelect.value = "";
12999
13138
  currentDbInfo = null;
13139
+ currentSchema = null;
13000
13140
  currentTable = null;
13001
13141
  schemaCache = null;
13142
+ renderSchemaOptions([], null);
13002
13143
  tableList.render([]);
13003
13144
  grid.clear();
13004
13145
  schemaView.clear();
@@ -13018,7 +13159,7 @@ ${frontmatter.yaml}
13018
13159
  };
13019
13160
  pendingRedisInitial = undefined;
13020
13161
  pendingEsInitial = undefined;
13021
- await selectDb(target, explorerInitial, generation, table2);
13162
+ await selectDb(target, explorerInitial, generation, schema !== undefined ? schema : currentSchema, table2);
13022
13163
  if (generation !== loadGeneration || currentDbInfo?.id !== target)
13023
13164
  return;
13024
13165
  if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch") {
@@ -13051,6 +13192,8 @@ ${frontmatter.yaml}
13051
13192
  function applyAnnotationTarget(target) {
13052
13193
  if (!target || target.db !== currentDbInfo?.id)
13053
13194
  return;
13195
+ if (target.schema && target.schema !== currentSchema)
13196
+ return;
13054
13197
  if (target.data) {
13055
13198
  if (target.table && target.table !== currentTable)
13056
13199
  return;
@@ -13087,6 +13230,7 @@ ${frontmatter.yaml}
13087
13230
  const state = {
13088
13231
  id: cb.tabId,
13089
13232
  dbId: currentDbInfo?.id ?? null,
13233
+ schema: currentSchema,
13090
13234
  table: currentTable ?? activeTable?.dataset.table ?? null,
13091
13235
  view: currentTab
13092
13236
  };
@@ -13118,6 +13262,7 @@ ${frontmatter.yaml}
13118
13262
  const target = {
13119
13263
  kind: "database",
13120
13264
  db: currentDbInfo.id,
13265
+ ...currentSchema ? { schema: currentSchema } : {},
13121
13266
  ...currentTable ? { table: currentTable } : {},
13122
13267
  tab: currentTab
13123
13268
  };
@@ -13134,12 +13279,14 @@ ${frontmatter.yaml}
13134
13279
  function getLabel() {
13135
13280
  if (!currentDbInfo)
13136
13281
  return labelFromDbId(initial.dbId);
13282
+ const suffix = currentSchema ? ` / ${currentSchema}` : "";
13137
13283
  if (currentDbInfo.id.startsWith("docker:")) {
13138
13284
  const m = currentDbInfo.name.match(/^(\S+)/);
13139
- return m ? m[1] : currentDbInfo.name;
13285
+ return `${m ? m[1] : currentDbInfo.name}${suffix}`;
13140
13286
  }
13141
13287
  const lastSlash = currentDbInfo.path.lastIndexOf("/");
13142
- 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}`;
13143
13290
  }
13144
13291
  function dispose() {
13145
13292
  loadGeneration++;
@@ -13154,6 +13301,7 @@ ${frontmatter.yaml}
13154
13301
  redisExplorer.dispose();
13155
13302
  esExplorer.dispose();
13156
13303
  currentDbInfo = null;
13304
+ currentSchema = null;
13157
13305
  currentTable = null;
13158
13306
  schemaCache = null;
13159
13307
  }
@@ -13299,6 +13447,7 @@ ${frontmatter.yaml}
13299
13447
  deps.setRoute({
13300
13448
  screen: "database",
13301
13449
  db: s2.dbId ?? undefined,
13450
+ schema: s2.schema ?? undefined,
13302
13451
  table: s2.table ?? undefined,
13303
13452
  tab: s2.view === "data" ? undefined : s2.view,
13304
13453
  range: deps.currentRange()
@@ -13319,6 +13468,7 @@ ${frontmatter.yaml}
13319
13468
  for (const tab of tabs) {
13320
13469
  const key = JSON.stringify({
13321
13470
  dbId: tab.dbId,
13471
+ schema: tab.schema ?? null,
13322
13472
  table: tab.table,
13323
13473
  view: tab.view,
13324
13474
  redis: tab.redis ?? null,
@@ -13549,6 +13699,7 @@ ${frontmatter.yaml}
13549
13699
  }
13550
13700
  }, {
13551
13701
  dbId: initial?.dbId ?? null,
13702
+ schema: initial?.schema ?? null,
13552
13703
  table: initial?.table ?? null,
13553
13704
  view: initial?.view ?? undefined,
13554
13705
  sqlDraft: initial?.sqlDraft,
@@ -13577,7 +13728,7 @@ ${frontmatter.yaml}
13577
13728
  if (options.annotationTarget)
13578
13729
  restoring = true;
13579
13730
  try {
13580
- 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);
13581
13732
  refreshChipLabel(id);
13582
13733
  } finally {
13583
13734
  if (options.annotationTarget)
@@ -13614,35 +13765,41 @@ ${frontmatter.yaml}
13614
13765
  newTabBtn.addEventListener("click", () => {
13615
13766
  openTab({ dbId: null, table: null, view: "data" }, { autoSelectFirst: false });
13616
13767
  });
13617
- function routeMatchesState(state, db, table2, view) {
13618
- if (!db && (table2 || view) && !state.dbId)
13768
+ function routeMatchesState(state, db, schema, table2, view) {
13769
+ if (!db && (schema || table2 || view) && !state.dbId)
13619
13770
  return false;
13620
13771
  if (db !== undefined && state.dbId !== db)
13621
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
+ }
13622
13779
  if (table2 !== undefined && state.table !== table2)
13623
13780
  return false;
13624
13781
  if (view !== undefined && state.view !== view)
13625
13782
  return false;
13626
13783
  return true;
13627
13784
  }
13628
- async function applyRouteToTab(db, table2, view, options = {}) {
13629
- 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) {
13630
13787
  if (!enterOptions?.annotationTarget) {
13631
- await pane.enter(targetDb, targetTable, targetView, enterOptions);
13788
+ await pane.enter(targetDb, targetSchema, targetTable, targetView, enterOptions);
13632
13789
  return;
13633
13790
  }
13634
13791
  restoring = true;
13635
13792
  try {
13636
- await pane.enter(targetDb, targetTable, targetView, enterOptions);
13793
+ await pane.enter(targetDb, targetSchema, targetTable, targetView, enterOptions);
13637
13794
  } finally {
13638
13795
  restoring = false;
13639
13796
  }
13640
13797
  }
13641
13798
  for (const [id2, entry] of tabsById) {
13642
- if (routeMatchesState(entry.pane.getState(), db, table2, view)) {
13799
+ if (routeMatchesState(entry.pane.getState(), db, schema, table2, view)) {
13643
13800
  setActive(id2);
13644
13801
  if (options.annotationTarget) {
13645
- await enterPane(entry.pane, db, table2, view, options);
13802
+ await enterPane(entry.pane, db, schema, table2, view, options);
13646
13803
  if (!mounted)
13647
13804
  return;
13648
13805
  }
@@ -13654,7 +13811,7 @@ ${frontmatter.yaml}
13654
13811
  const targetId = activeTabId;
13655
13812
  const active = tabsById.get(activeTabId);
13656
13813
  if (active) {
13657
- await enterPane(active.pane, db, table2, view, options);
13814
+ await enterPane(active.pane, db, schema, table2, view, options);
13658
13815
  if (!mounted)
13659
13816
  return;
13660
13817
  refreshChipLabel(targetId);
@@ -13663,6 +13820,7 @@ ${frontmatter.yaml}
13663
13820
  }
13664
13821
  const id = openTab({
13665
13822
  dbId: db ?? null,
13823
+ schema: schema ?? null,
13666
13824
  table: table2 ?? null,
13667
13825
  view: view ?? "data"
13668
13826
  }, { autoSelectFirst: db === undefined, ...options });
@@ -13681,7 +13839,17 @@ ${frontmatter.yaml}
13681
13839
  return null;
13682
13840
  }
13683
13841
  }
13684
- 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 = {}) {
13685
13853
  if (seq !== lifecycleSeq)
13686
13854
  return;
13687
13855
  const firstMount = !mounted;
@@ -13744,8 +13912,8 @@ ${frontmatter.yaml}
13744
13912
  } finally {
13745
13913
  restoring = false;
13746
13914
  }
13747
- if (db || table2 || view) {
13748
- await applyRouteToTab(db, table2, view, {
13915
+ if (db || schema || table2 || view) {
13916
+ await applyRouteToTab(db, schema ?? null, table2, view, {
13749
13917
  ...options,
13750
13918
  reuseActiveTab: options.reuseActiveTab ?? true
13751
13919
  });
@@ -13770,6 +13938,7 @@ ${frontmatter.yaml}
13770
13938
  if (tabsById.size === 0) {
13771
13939
  const id = openTab({
13772
13940
  dbId: db || null,
13941
+ schema: schema || null,
13773
13942
  table: table2 || null,
13774
13943
  view: view || "data"
13775
13944
  }, { autoSelectFirst: !db, ...options });
@@ -13785,8 +13954,8 @@ ${frontmatter.yaml}
13785
13954
  const active = tabsById.get(activeTabId);
13786
13955
  if (!active)
13787
13956
  return;
13788
- if (db || table2 || view) {
13789
- await applyRouteToTab(db, table2, view, {
13957
+ if (db || schema || table2 || view) {
13958
+ await applyRouteToTab(db, schema ?? null, table2, view, {
13790
13959
  ...options,
13791
13960
  reuseActiveTab: options.reuseActiveTab ?? true
13792
13961
  });
@@ -13794,9 +13963,9 @@ ${frontmatter.yaml}
13794
13963
  syncActiveRoute();
13795
13964
  }
13796
13965
  }
13797
- async function enter(db, table2, view, options = {}) {
13966
+ async function enter(db, schema, table2, view, options = {}) {
13798
13967
  const seq = lifecycleSeq;
13799
- enterQueue = enterQueue.catch(() => {}).then(() => doEnter(seq, db, table2, view, options));
13968
+ enterQueue = enterQueue.catch(() => {}).then(() => doEnter(seq, db, schema, table2, view, options));
13800
13969
  await enterQueue;
13801
13970
  }
13802
13971
  function leave() {
@@ -13846,8 +14015,12 @@ ${frontmatter.yaml}
13846
14015
  if (!mounted)
13847
14016
  return;
13848
14017
  const dbId = parseSseDbId(data);
14018
+ const schema = parseSseSchema(data);
13849
14019
  for (const [, entry] of tabsById) {
13850
- 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)
13851
14024
  continue;
13852
14025
  entry.pane.handleSse(event, data);
13853
14026
  }
@@ -23789,7 +23962,7 @@ code-viewer annotate add-db --db app.db --tab query \\
23789
23962
  return Promise.resolve(null);
23790
23963
  }
23791
23964
  if (STATE.route.screen === "database") {
23792
- 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());
23793
23966
  setStatus("live");
23794
23967
  return Promise.resolve(null);
23795
23968
  }
@@ -23860,7 +24033,7 @@ code-viewer annotate add-db --db app.db --tab query \\
23860
24033
  HISTORY_VIEW.enterHistory();
23861
24034
  } else if (STATE.route.screen === "database") {
23862
24035
  setStatus("live");
23863
- 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());
23864
24037
  } else
23865
24038
  load();
23866
24039
  syncLineRefPill();
@@ -24010,7 +24183,7 @@ code-viewer annotate add-db --db app.db --tab query \\
24010
24183
  cancelActiveSourceLoad("navigation");
24011
24184
  setPageMode();
24012
24185
  removeStandaloneSource();
24013
- 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());
24014
24187
  setStatus("live");
24015
24188
  return;
24016
24189
  }
@@ -24128,7 +24301,7 @@ code-viewer annotate add-db --db app.db --tab query \\
24128
24301
  },
24129
24302
  openDatabaseAnnotation: (target) => {
24130
24303
  setStatus("live");
24131
- return DATABASE_VIEW.enter(target.db, target.table, target.tab, {
24304
+ return DATABASE_VIEW.enter(target.db, target.schema, target.table, target.tab, {
24132
24305
  annotationTarget: target,
24133
24306
  reuseActiveTab: true
24134
24307
  });