@youtyan/code-viewer 0.6.9 → 0.7.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/README.md +21 -13
- package/dist/code-viewer.js +2083 -372
- package/package.json +1 -1
- package/web/app.js +1102 -135
- package/web/style.css +182 -0
package/web/app.js
CHANGED
|
@@ -8494,6 +8494,9 @@ ${frontmatter.yaml}
|
|
|
8494
8494
|
let ANNOTATIONS = { version: 1, sessions: [] };
|
|
8495
8495
|
let annotationFollow = deps.getAnnotationFollow();
|
|
8496
8496
|
let activeAnnotationId = null;
|
|
8497
|
+
let refreshAnnotationsInFlight = null;
|
|
8498
|
+
let inlineAnnotationsMounted = false;
|
|
8499
|
+
let databaseAnnotationsMounted = false;
|
|
8497
8500
|
let annotationPanelDismissed = false;
|
|
8498
8501
|
let activeSessionId = new URLSearchParams(window.location.search).get(ANNOTATION_SESSION_PARAM);
|
|
8499
8502
|
const annotationsChangedCallbacks = [];
|
|
@@ -8658,9 +8661,12 @@ ${frontmatter.yaml}
|
|
|
8658
8661
|
return box;
|
|
8659
8662
|
}
|
|
8660
8663
|
function applyDatabaseAnnotations(session) {
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
+
if (databaseAnnotationsMounted) {
|
|
8665
|
+
document.querySelectorAll(".gdp-db-annotation-strip").forEach((el) => {
|
|
8666
|
+
el.remove();
|
|
8667
|
+
});
|
|
8668
|
+
databaseAnnotationsMounted = false;
|
|
8669
|
+
}
|
|
8664
8670
|
if (!session || deps.getRoute().screen !== "database")
|
|
8665
8671
|
return;
|
|
8666
8672
|
const matches = session.entries.filter(databaseAnnotationMatchesRoute);
|
|
@@ -8676,6 +8682,7 @@ ${frontmatter.yaml}
|
|
|
8676
8682
|
strip.appendChild(buildDatabaseAnnotationBlock(entry));
|
|
8677
8683
|
}
|
|
8678
8684
|
root.prepend(strip);
|
|
8685
|
+
databaseAnnotationsMounted = true;
|
|
8679
8686
|
}
|
|
8680
8687
|
function inlineAnnotationTargetRow(entry) {
|
|
8681
8688
|
if (!entry.line)
|
|
@@ -8734,13 +8741,19 @@ ${frontmatter.yaml}
|
|
|
8734
8741
|
return tr;
|
|
8735
8742
|
}
|
|
8736
8743
|
function applyInlineAnnotations() {
|
|
8737
|
-
document.querySelectorAll(".gdp-annotation-row").forEach((row) => {
|
|
8738
|
-
row.remove();
|
|
8739
|
-
});
|
|
8740
8744
|
const session = ANNOTATIONS.sessions.find((s2) => s2.id === activeSessionId);
|
|
8745
|
+
if (!session && !inlineAnnotationsMounted && !databaseAnnotationsMounted)
|
|
8746
|
+
return;
|
|
8747
|
+
if (inlineAnnotationsMounted) {
|
|
8748
|
+
document.querySelectorAll(".gdp-annotation-row").forEach((row) => {
|
|
8749
|
+
row.remove();
|
|
8750
|
+
});
|
|
8751
|
+
inlineAnnotationsMounted = false;
|
|
8752
|
+
}
|
|
8741
8753
|
applyDatabaseAnnotations(session);
|
|
8742
8754
|
if (!session)
|
|
8743
8755
|
return;
|
|
8756
|
+
let mountedInlineRows = false;
|
|
8744
8757
|
for (const entry of session.entries) {
|
|
8745
8758
|
if (entry.target?.kind === "database")
|
|
8746
8759
|
continue;
|
|
@@ -8758,7 +8771,9 @@ ${frontmatter.yaml}
|
|
|
8758
8771
|
sibAnchor = sibAnchor.nextElementSibling;
|
|
8759
8772
|
sibAnchor.after(buildInlineSpacerRow(entry, sibling.cells.length));
|
|
8760
8773
|
}
|
|
8774
|
+
mountedInlineRows = true;
|
|
8761
8775
|
}
|
|
8776
|
+
inlineAnnotationsMounted = mountedInlineRows;
|
|
8762
8777
|
syncInlineAnnotationWidths();
|
|
8763
8778
|
}
|
|
8764
8779
|
function syncInlineAnnotationSpacerHeights() {
|
|
@@ -8883,7 +8898,17 @@ ${frontmatter.yaml}
|
|
|
8883
8898
|
annotationCountEl.hidden = total === 0;
|
|
8884
8899
|
annotationListCountEl.textContent = `${ANNOTATIONS.sessions.length} sessions / ${total} annotations`;
|
|
8885
8900
|
}
|
|
8886
|
-
|
|
8901
|
+
function refreshAnnotations() {
|
|
8902
|
+
if (refreshAnnotationsInFlight)
|
|
8903
|
+
return refreshAnnotationsInFlight;
|
|
8904
|
+
const started = doRefreshAnnotations().finally(() => {
|
|
8905
|
+
if (refreshAnnotationsInFlight === started)
|
|
8906
|
+
refreshAnnotationsInFlight = null;
|
|
8907
|
+
});
|
|
8908
|
+
refreshAnnotationsInFlight = started;
|
|
8909
|
+
return started;
|
|
8910
|
+
}
|
|
8911
|
+
async function doRefreshAnnotations() {
|
|
8887
8912
|
try {
|
|
8888
8913
|
const res = await fetch("/_annotations");
|
|
8889
8914
|
if (!res.ok)
|
|
@@ -10327,6 +10352,24 @@ ${frontmatter.yaml}
|
|
|
10327
10352
|
confirmDeleteObject: (key) => `Delete object "${key}"?`,
|
|
10328
10353
|
editTextHint: "Only text objects can be edited in the browser.",
|
|
10329
10354
|
create: "Create"
|
|
10355
|
+
},
|
|
10356
|
+
dynamodb: {
|
|
10357
|
+
table: "Table",
|
|
10358
|
+
scanMode: "Scan",
|
|
10359
|
+
queryMode: "Query",
|
|
10360
|
+
keyConditionPlaceholder: "Key condition expression, e.g. pk = :pk",
|
|
10361
|
+
filterPlaceholder: "Filter expression (optional)",
|
|
10362
|
+
attributeValuesPlaceholder: '{":pk": {"S": "value"}}',
|
|
10363
|
+
sortAsc: "Ascending",
|
|
10364
|
+
sortDesc: "Descending",
|
|
10365
|
+
selectItem: "Select an item to preview.",
|
|
10366
|
+
noItems: "(no items)",
|
|
10367
|
+
noTables: "(no tables)",
|
|
10368
|
+
copyKey: "Copy key",
|
|
10369
|
+
copied: "Copied",
|
|
10370
|
+
copyFailed: "Copy failed",
|
|
10371
|
+
invalidAttributeValues: "Invalid attribute values JSON",
|
|
10372
|
+
runQuery: "Run"
|
|
10330
10373
|
}
|
|
10331
10374
|
}
|
|
10332
10375
|
};
|
|
@@ -10649,6 +10692,24 @@ ${frontmatter.yaml}
|
|
|
10649
10692
|
confirmDeleteObject: (key) => `オブジェクト "${key}" を削除しますか?`,
|
|
10650
10693
|
editTextHint: "ブラウザで編集できるのはテキストオブジェクトのみです。",
|
|
10651
10694
|
create: "作成"
|
|
10695
|
+
},
|
|
10696
|
+
dynamodb: {
|
|
10697
|
+
table: "テーブル",
|
|
10698
|
+
scanMode: "Scan",
|
|
10699
|
+
queryMode: "Query",
|
|
10700
|
+
keyConditionPlaceholder: "キー条件式 例: pk = :pk",
|
|
10701
|
+
filterPlaceholder: "フィルタ式 (任意)",
|
|
10702
|
+
attributeValuesPlaceholder: '{":pk": {"S": "value"}}',
|
|
10703
|
+
sortAsc: "昇順",
|
|
10704
|
+
sortDesc: "降順",
|
|
10705
|
+
selectItem: "アイテムを選択するとプレビューが表示されます。",
|
|
10706
|
+
noItems: "(アイテムがありません)",
|
|
10707
|
+
noTables: "(テーブルがありません)",
|
|
10708
|
+
copyKey: "キーをコピー",
|
|
10709
|
+
copied: "コピーしました",
|
|
10710
|
+
copyFailed: "コピーに失敗しました",
|
|
10711
|
+
invalidAttributeValues: "属性値の JSON が不正です",
|
|
10712
|
+
runQuery: "実行"
|
|
10652
10713
|
}
|
|
10653
10714
|
}
|
|
10654
10715
|
};
|
|
@@ -10686,6 +10747,706 @@ ${frontmatter.yaml}
|
|
|
10686
10747
|
el.appendChild(empty);
|
|
10687
10748
|
}
|
|
10688
10749
|
|
|
10750
|
+
// web-src/views/database/dynamodb-explorer.ts
|
|
10751
|
+
function unwrapAttributeValue(av) {
|
|
10752
|
+
if (!av)
|
|
10753
|
+
return;
|
|
10754
|
+
if ("S" in av)
|
|
10755
|
+
return av.S;
|
|
10756
|
+
if ("N" in av)
|
|
10757
|
+
return av.N;
|
|
10758
|
+
if ("BOOL" in av)
|
|
10759
|
+
return av.BOOL;
|
|
10760
|
+
if ("NULL" in av)
|
|
10761
|
+
return null;
|
|
10762
|
+
if ("B" in av)
|
|
10763
|
+
return "(binary)";
|
|
10764
|
+
if ("SS" in av)
|
|
10765
|
+
return av.SS;
|
|
10766
|
+
if ("NS" in av)
|
|
10767
|
+
return av.NS;
|
|
10768
|
+
if ("BS" in av)
|
|
10769
|
+
return "(binary set)";
|
|
10770
|
+
if ("L" in av)
|
|
10771
|
+
return av.L.map(unwrapAttributeValue);
|
|
10772
|
+
if ("M" in av) {
|
|
10773
|
+
const out = {};
|
|
10774
|
+
for (const [k, v] of Object.entries(av.M))
|
|
10775
|
+
out[k] = unwrapAttributeValue(v);
|
|
10776
|
+
return out;
|
|
10777
|
+
}
|
|
10778
|
+
return;
|
|
10779
|
+
}
|
|
10780
|
+
function unwrapItem(item) {
|
|
10781
|
+
const out = {};
|
|
10782
|
+
for (const [k, v] of Object.entries(item))
|
|
10783
|
+
out[k] = unwrapAttributeValue(v);
|
|
10784
|
+
return out;
|
|
10785
|
+
}
|
|
10786
|
+
function previewItem(item) {
|
|
10787
|
+
const entries = Object.entries(item).slice(0, 6);
|
|
10788
|
+
const parts = entries.map(([key, rawValue]) => {
|
|
10789
|
+
const value = unwrapAttributeValue(rawValue);
|
|
10790
|
+
const text2 = value !== null && typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
10791
|
+
return `${key}=${text2.length > 40 ? `${text2.slice(0, 40)}...` : text2}`;
|
|
10792
|
+
});
|
|
10793
|
+
return parts.join(" / ");
|
|
10794
|
+
}
|
|
10795
|
+
function extractItemKey(item, keySchema) {
|
|
10796
|
+
if (!keySchema || keySchema.length === 0)
|
|
10797
|
+
return item;
|
|
10798
|
+
const key = {};
|
|
10799
|
+
for (const k of keySchema) {
|
|
10800
|
+
if (item[k.AttributeName] !== undefined)
|
|
10801
|
+
key[k.AttributeName] = item[k.AttributeName];
|
|
10802
|
+
}
|
|
10803
|
+
return Object.keys(key).length > 0 ? key : item;
|
|
10804
|
+
}
|
|
10805
|
+
function itemKeyToken(key) {
|
|
10806
|
+
const sorted = {};
|
|
10807
|
+
for (const k of Object.keys(key).sort())
|
|
10808
|
+
sorted[k] = key[k];
|
|
10809
|
+
return JSON.stringify(sorted);
|
|
10810
|
+
}
|
|
10811
|
+
function parseAttributeValuesJson(raw) {
|
|
10812
|
+
if (!raw.trim())
|
|
10813
|
+
return {};
|
|
10814
|
+
try {
|
|
10815
|
+
const parsed = JSON.parse(raw);
|
|
10816
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10817
|
+
return null;
|
|
10818
|
+
}
|
|
10819
|
+
return parsed;
|
|
10820
|
+
} catch {
|
|
10821
|
+
return null;
|
|
10822
|
+
}
|
|
10823
|
+
}
|
|
10824
|
+
function createDynamoDbExplorer(callbacks = {}) {
|
|
10825
|
+
const text2 = () => (callbacks.getText?.() ?? dbText("en")).explorer;
|
|
10826
|
+
const trackLoad = (promise) => callbacks.trackLoad ? callbacks.trackLoad(promise) : promise;
|
|
10827
|
+
const container = document.createElement("div");
|
|
10828
|
+
container.className = "dynamodb-explorer";
|
|
10829
|
+
const sidebarSlot = document.createElement("div");
|
|
10830
|
+
sidebarSlot.className = "db-explorer-sidebar-slot dynamodb-table-list-pane";
|
|
10831
|
+
const tableListHeader = document.createElement("div");
|
|
10832
|
+
tableListHeader.className = "db-explorer-pane-header";
|
|
10833
|
+
tableListHeader.textContent = text2().dynamodb.table;
|
|
10834
|
+
sidebarSlot.appendChild(tableListHeader);
|
|
10835
|
+
const tableList = document.createElement("div");
|
|
10836
|
+
tableList.className = "dynamodb-table-list";
|
|
10837
|
+
sidebarSlot.appendChild(tableList);
|
|
10838
|
+
const tableMoreBtn = document.createElement("button");
|
|
10839
|
+
tableMoreBtn.type = "button";
|
|
10840
|
+
tableMoreBtn.className = "dynamodb-item-more-btn dynamodb-table-more-btn";
|
|
10841
|
+
tableMoreBtn.textContent = text2().common.loadMore;
|
|
10842
|
+
tableMoreBtn.hidden = true;
|
|
10843
|
+
sidebarSlot.appendChild(tableMoreBtn);
|
|
10844
|
+
const itemListPane = document.createElement("div");
|
|
10845
|
+
itemListPane.className = "dynamodb-item-list-pane";
|
|
10846
|
+
const modeSeg = document.createElement("div");
|
|
10847
|
+
modeSeg.className = "seg dynamodb-mode-seg";
|
|
10848
|
+
const scanModeBtn = document.createElement("button");
|
|
10849
|
+
scanModeBtn.type = "button";
|
|
10850
|
+
scanModeBtn.textContent = text2().dynamodb.scanMode;
|
|
10851
|
+
const queryModeBtn = document.createElement("button");
|
|
10852
|
+
queryModeBtn.type = "button";
|
|
10853
|
+
queryModeBtn.textContent = text2().dynamodb.queryMode;
|
|
10854
|
+
modeSeg.append(scanModeBtn, queryModeBtn);
|
|
10855
|
+
itemListPane.appendChild(modeSeg);
|
|
10856
|
+
const queryForm = document.createElement("form");
|
|
10857
|
+
queryForm.className = "dynamodb-query-form";
|
|
10858
|
+
const keyConditionInput = document.createElement("input");
|
|
10859
|
+
keyConditionInput.type = "text";
|
|
10860
|
+
keyConditionInput.className = "dynamodb-key-condition-input";
|
|
10861
|
+
keyConditionInput.placeholder = text2().dynamodb.keyConditionPlaceholder;
|
|
10862
|
+
keyConditionInput.autocomplete = "off";
|
|
10863
|
+
keyConditionInput.hidden = true;
|
|
10864
|
+
const filterInput = document.createElement("input");
|
|
10865
|
+
filterInput.type = "text";
|
|
10866
|
+
filterInput.className = "dynamodb-filter-input";
|
|
10867
|
+
filterInput.placeholder = text2().dynamodb.filterPlaceholder;
|
|
10868
|
+
filterInput.autocomplete = "off";
|
|
10869
|
+
const attributeValuesInput = document.createElement("textarea");
|
|
10870
|
+
attributeValuesInput.className = "dynamodb-attribute-values-input";
|
|
10871
|
+
attributeValuesInput.placeholder = text2().dynamodb.attributeValuesPlaceholder;
|
|
10872
|
+
attributeValuesInput.rows = 2;
|
|
10873
|
+
const runBtn = document.createElement("button");
|
|
10874
|
+
runBtn.type = "submit";
|
|
10875
|
+
runBtn.className = "db-btn db-btn-primary dynamodb-run-btn";
|
|
10876
|
+
runBtn.textContent = text2().dynamodb.runQuery;
|
|
10877
|
+
queryForm.append(keyConditionInput, filterInput, attributeValuesInput, runBtn);
|
|
10878
|
+
itemListPane.appendChild(queryForm);
|
|
10879
|
+
const queryError = document.createElement("div");
|
|
10880
|
+
queryError.className = "dynamodb-query-error";
|
|
10881
|
+
queryError.hidden = true;
|
|
10882
|
+
itemListPane.appendChild(queryError);
|
|
10883
|
+
const itemStatus = document.createElement("div");
|
|
10884
|
+
itemStatus.className = "dynamodb-item-status";
|
|
10885
|
+
itemListPane.appendChild(itemStatus);
|
|
10886
|
+
const itemList = document.createElement("div");
|
|
10887
|
+
itemList.className = "dynamodb-item-list";
|
|
10888
|
+
itemListPane.appendChild(itemList);
|
|
10889
|
+
const moreBtn = document.createElement("button");
|
|
10890
|
+
moreBtn.type = "button";
|
|
10891
|
+
moreBtn.className = "dynamodb-item-more-btn";
|
|
10892
|
+
moreBtn.textContent = text2().common.loadMore;
|
|
10893
|
+
moreBtn.hidden = true;
|
|
10894
|
+
itemListPane.appendChild(moreBtn);
|
|
10895
|
+
const detailPane = document.createElement("div");
|
|
10896
|
+
detailPane.className = "dynamodb-detail-pane";
|
|
10897
|
+
setPaneEmpty(detailPane, text2().dynamodb.selectItem);
|
|
10898
|
+
container.append(itemListPane, detailPane);
|
|
10899
|
+
let currentDbId = null;
|
|
10900
|
+
let currentTable = null;
|
|
10901
|
+
let currentMode = "scan";
|
|
10902
|
+
let currentScanIndexForward = true;
|
|
10903
|
+
let currentTableInfo = null;
|
|
10904
|
+
let currentTableNextToken;
|
|
10905
|
+
let currentNextToken;
|
|
10906
|
+
let currentItemKeyToken = null;
|
|
10907
|
+
let cumulativeShownCount = 0;
|
|
10908
|
+
let cumulativeScannedCount = 0;
|
|
10909
|
+
let disposed = false;
|
|
10910
|
+
let loadRunId = 0;
|
|
10911
|
+
let itemRunId = 0;
|
|
10912
|
+
let suppressNotify = false;
|
|
10913
|
+
let activeTableRow = null;
|
|
10914
|
+
let activeItemRow = null;
|
|
10915
|
+
const itemsByKeyToken = new Map;
|
|
10916
|
+
const itemRowsByKeyToken = new Map;
|
|
10917
|
+
const tableGuard = createAbortGuard();
|
|
10918
|
+
const tablePageGuard = createAbortGuard();
|
|
10919
|
+
const tableInfoGuard = createAbortGuard();
|
|
10920
|
+
const itemsGuard = createAbortGuard();
|
|
10921
|
+
const itemGuard = createAbortGuard();
|
|
10922
|
+
function notifySelectionChange() {
|
|
10923
|
+
if (suppressNotify)
|
|
10924
|
+
return;
|
|
10925
|
+
callbacks.onSelectionChange?.(getSelection());
|
|
10926
|
+
}
|
|
10927
|
+
function setMode(mode) {
|
|
10928
|
+
currentMode = mode;
|
|
10929
|
+
scanModeBtn.classList.toggle("active", mode === "scan");
|
|
10930
|
+
queryModeBtn.classList.toggle("active", mode === "query");
|
|
10931
|
+
keyConditionInput.hidden = mode !== "query";
|
|
10932
|
+
}
|
|
10933
|
+
function renderTables(tableNames, append = false) {
|
|
10934
|
+
if (!append) {
|
|
10935
|
+
tableList.innerHTML = "";
|
|
10936
|
+
activeTableRow = null;
|
|
10937
|
+
}
|
|
10938
|
+
if (tableNames.length === 0 && !append) {
|
|
10939
|
+
setPaneStatus(tableList, text2().dynamodb.noTables);
|
|
10940
|
+
return;
|
|
10941
|
+
}
|
|
10942
|
+
const fragment = document.createDocumentFragment();
|
|
10943
|
+
for (const name of tableNames) {
|
|
10944
|
+
const row = document.createElement("div");
|
|
10945
|
+
row.className = "dynamodb-table-item";
|
|
10946
|
+
row.dataset.tableName = name;
|
|
10947
|
+
row.textContent = name;
|
|
10948
|
+
row.title = name;
|
|
10949
|
+
fragment.appendChild(row);
|
|
10950
|
+
}
|
|
10951
|
+
tableList.appendChild(fragment);
|
|
10952
|
+
}
|
|
10953
|
+
function highlightActiveTable(name) {
|
|
10954
|
+
if (activeTableRow?.dataset.tableName === name)
|
|
10955
|
+
return;
|
|
10956
|
+
activeTableRow?.classList.remove("active");
|
|
10957
|
+
activeTableRow = tableList.querySelector(`[data-table-name="${CSS.escape(name)}"]`) ?? null;
|
|
10958
|
+
activeTableRow?.classList.add("active");
|
|
10959
|
+
}
|
|
10960
|
+
function highlightActiveItem(token) {
|
|
10961
|
+
if (activeItemRow && activeItemRow.dataset.keyToken === token)
|
|
10962
|
+
return;
|
|
10963
|
+
activeItemRow?.classList.remove("active");
|
|
10964
|
+
activeItemRow = token ? itemRowsByKeyToken.get(token) ?? null : null;
|
|
10965
|
+
activeItemRow?.classList.add("active");
|
|
10966
|
+
}
|
|
10967
|
+
function appendItems(items) {
|
|
10968
|
+
const fragment = document.createDocumentFragment();
|
|
10969
|
+
for (const item of items) {
|
|
10970
|
+
const key = extractItemKey(item, currentTableInfo?.KeySchema);
|
|
10971
|
+
const token = itemKeyToken(key);
|
|
10972
|
+
itemsByKeyToken.set(token, item);
|
|
10973
|
+
const row = document.createElement("div");
|
|
10974
|
+
row.className = "dynamodb-item-row";
|
|
10975
|
+
row.dataset.keyToken = token;
|
|
10976
|
+
itemRowsByKeyToken.set(token, row);
|
|
10977
|
+
const preview = document.createElement("span");
|
|
10978
|
+
preview.className = "dynamodb-item-preview";
|
|
10979
|
+
preview.textContent = previewItem(item);
|
|
10980
|
+
row.appendChild(preview);
|
|
10981
|
+
fragment.appendChild(row);
|
|
10982
|
+
}
|
|
10983
|
+
itemList.appendChild(fragment);
|
|
10984
|
+
}
|
|
10985
|
+
function renderTableInfo() {
|
|
10986
|
+
detailPane.innerHTML = "";
|
|
10987
|
+
if (!currentTableInfo)
|
|
10988
|
+
return;
|
|
10989
|
+
const header = document.createElement("div");
|
|
10990
|
+
header.className = "dynamodb-table-info-header";
|
|
10991
|
+
header.textContent = currentTableInfo.TableName ?? currentTable ?? "";
|
|
10992
|
+
const meta = document.createElement("div");
|
|
10993
|
+
meta.className = "dynamodb-table-info-meta";
|
|
10994
|
+
meta.textContent = [
|
|
10995
|
+
currentTableInfo.TableStatus,
|
|
10996
|
+
currentTableInfo.ItemCount !== undefined ? `${currentTableInfo.ItemCount.toLocaleString()} items` : undefined
|
|
10997
|
+
].filter(Boolean).join(" / ");
|
|
10998
|
+
detailPane.append(header, meta);
|
|
10999
|
+
const keySchema = currentTableInfo.KeySchema ?? [];
|
|
11000
|
+
if (keySchema.length > 0) {
|
|
11001
|
+
const keyList = document.createElement("div");
|
|
11002
|
+
keyList.className = "dynamodb-table-info-keys";
|
|
11003
|
+
keyList.textContent = keySchema.map((k) => `${k.AttributeName} (${k.KeyType})`).join(", ");
|
|
11004
|
+
detailPane.appendChild(keyList);
|
|
11005
|
+
}
|
|
11006
|
+
const empty = document.createElement("div");
|
|
11007
|
+
empty.className = "db-pane-empty dynamodb-table-info-empty";
|
|
11008
|
+
const emptyTitle = document.createElement("div");
|
|
11009
|
+
emptyTitle.className = "db-pane-empty-title";
|
|
11010
|
+
emptyTitle.textContent = text2().dynamodb.selectItem;
|
|
11011
|
+
empty.appendChild(emptyTitle);
|
|
11012
|
+
detailPane.appendChild(empty);
|
|
11013
|
+
}
|
|
11014
|
+
function renderItemDetail(item) {
|
|
11015
|
+
detailPane.innerHTML = "";
|
|
11016
|
+
const header = document.createElement("div");
|
|
11017
|
+
header.className = "dynamodb-item-detail-header";
|
|
11018
|
+
const title = document.createElement("span");
|
|
11019
|
+
title.textContent = currentTable ?? "";
|
|
11020
|
+
const copyBtn = document.createElement("button");
|
|
11021
|
+
copyBtn.type = "button";
|
|
11022
|
+
copyBtn.className = "db-btn db-btn-sm dynamodb-copy-key-btn";
|
|
11023
|
+
copyBtn.textContent = text2().dynamodb.copyKey;
|
|
11024
|
+
const copyStatus = document.createElement("span");
|
|
11025
|
+
copyStatus.className = "dynamodb-copy-status";
|
|
11026
|
+
copyStatus.setAttribute("aria-live", "polite");
|
|
11027
|
+
copyBtn.addEventListener("click", async () => {
|
|
11028
|
+
copyStatus.textContent = "";
|
|
11029
|
+
try {
|
|
11030
|
+
const key = extractItemKey(item, currentTableInfo?.KeySchema);
|
|
11031
|
+
await navigator.clipboard.writeText(JSON.stringify(key));
|
|
11032
|
+
copyStatus.textContent = text2().dynamodb.copied;
|
|
11033
|
+
} catch {
|
|
11034
|
+
copyStatus.textContent = text2().dynamodb.copyFailed;
|
|
11035
|
+
}
|
|
11036
|
+
});
|
|
11037
|
+
header.append(title, copyBtn, copyStatus);
|
|
11038
|
+
detailPane.appendChild(header);
|
|
11039
|
+
const pre = document.createElement("pre");
|
|
11040
|
+
pre.className = "dynamodb-item-source";
|
|
11041
|
+
try {
|
|
11042
|
+
pre.textContent = JSON.stringify(unwrapItem(item), null, 2);
|
|
11043
|
+
} catch {
|
|
11044
|
+
pre.textContent = String(item);
|
|
11045
|
+
}
|
|
11046
|
+
detailPane.appendChild(pre);
|
|
11047
|
+
}
|
|
11048
|
+
function selectItem(item, token) {
|
|
11049
|
+
currentItemKeyToken = token ?? itemKeyToken(extractItemKey(item, currentTableInfo?.KeySchema));
|
|
11050
|
+
highlightActiveItem(currentItemKeyToken);
|
|
11051
|
+
renderItemDetail(item);
|
|
11052
|
+
notifySelectionChange();
|
|
11053
|
+
}
|
|
11054
|
+
async function loadItems(append) {
|
|
11055
|
+
if (!currentDbId || !currentTable || disposed)
|
|
11056
|
+
return;
|
|
11057
|
+
const keyConditionExpression = keyConditionInput.value.trim();
|
|
11058
|
+
const filterExpression = filterInput.value.trim();
|
|
11059
|
+
const attributeValues = parseAttributeValuesJson(attributeValuesInput.value);
|
|
11060
|
+
queryError.hidden = true;
|
|
11061
|
+
if (currentMode === "query" && !keyConditionExpression) {
|
|
11062
|
+
queryError.hidden = false;
|
|
11063
|
+
queryError.textContent = text2().dynamodb.keyConditionPlaceholder;
|
|
11064
|
+
return;
|
|
11065
|
+
}
|
|
11066
|
+
if (attributeValues === null) {
|
|
11067
|
+
queryError.hidden = false;
|
|
11068
|
+
queryError.textContent = text2().dynamodb.invalidAttributeValues;
|
|
11069
|
+
return;
|
|
11070
|
+
}
|
|
11071
|
+
const slot = itemsGuard.start();
|
|
11072
|
+
const requestRunId = loadRunId;
|
|
11073
|
+
const requestDbId = currentDbId;
|
|
11074
|
+
const requestTable = currentTable;
|
|
11075
|
+
const requestMode = currentMode;
|
|
11076
|
+
moreBtn.disabled = true;
|
|
11077
|
+
if (!append) {
|
|
11078
|
+
itemList.innerHTML = "";
|
|
11079
|
+
itemsByKeyToken.clear();
|
|
11080
|
+
itemRowsByKeyToken.clear();
|
|
11081
|
+
activeItemRow = null;
|
|
11082
|
+
currentItemKeyToken = null;
|
|
11083
|
+
currentNextToken = undefined;
|
|
11084
|
+
cumulativeShownCount = 0;
|
|
11085
|
+
cumulativeScannedCount = 0;
|
|
11086
|
+
setPaneStatus(itemList, "Loading items...");
|
|
11087
|
+
if (!currentTableInfo)
|
|
11088
|
+
setPaneEmpty(detailPane, text2().dynamodb.selectItem);
|
|
11089
|
+
}
|
|
11090
|
+
try {
|
|
11091
|
+
const params = new URLSearchParams({
|
|
11092
|
+
db: requestDbId,
|
|
11093
|
+
table: requestTable,
|
|
11094
|
+
mode: requestMode,
|
|
11095
|
+
limit: "200"
|
|
11096
|
+
});
|
|
11097
|
+
if (filterExpression)
|
|
11098
|
+
params.set("filterExpression", filterExpression);
|
|
11099
|
+
if (Object.keys(attributeValues).length > 0) {
|
|
11100
|
+
params.set("expressionAttributeValues", JSON.stringify(attributeValues));
|
|
11101
|
+
}
|
|
11102
|
+
if (requestMode === "query") {
|
|
11103
|
+
params.set("keyConditionExpression", keyConditionExpression);
|
|
11104
|
+
params.set("scanIndexForward", String(currentScanIndexForward));
|
|
11105
|
+
}
|
|
11106
|
+
if (append && currentNextToken) {
|
|
11107
|
+
params.set("exclusiveStartKey", JSON.stringify(currentNextToken));
|
|
11108
|
+
}
|
|
11109
|
+
const res = await trackLoad(fetch(`/_db/dynamodb/items?${params}`, { signal: slot.signal }));
|
|
11110
|
+
if (disposed || slot.isStale())
|
|
11111
|
+
return;
|
|
11112
|
+
if (!res.ok) {
|
|
11113
|
+
const errText = await res.text();
|
|
11114
|
+
setPaneStatus(itemList, `Error: ${errText || res.statusText}`, {
|
|
11115
|
+
error: true
|
|
11116
|
+
});
|
|
11117
|
+
return;
|
|
11118
|
+
}
|
|
11119
|
+
const data = await res.json();
|
|
11120
|
+
if (disposed || slot.isStale() || requestRunId !== loadRunId || requestDbId !== currentDbId || requestTable !== currentTable || requestMode !== currentMode) {
|
|
11121
|
+
return;
|
|
11122
|
+
}
|
|
11123
|
+
if (!append)
|
|
11124
|
+
itemList.innerHTML = "";
|
|
11125
|
+
if (data.items.length === 0 && !append) {
|
|
11126
|
+
setPaneStatus(itemList, text2().dynamodb.noItems);
|
|
11127
|
+
} else {
|
|
11128
|
+
appendItems(data.items);
|
|
11129
|
+
}
|
|
11130
|
+
currentNextToken = data.lastEvaluatedKey;
|
|
11131
|
+
moreBtn.hidden = !data.lastEvaluatedKey;
|
|
11132
|
+
cumulativeShownCount += data.items.length;
|
|
11133
|
+
cumulativeScannedCount += data.scannedCount;
|
|
11134
|
+
itemStatus.textContent = `${cumulativeShownCount.toLocaleString()} shown / ${cumulativeScannedCount.toLocaleString()} scanned`;
|
|
11135
|
+
highlightActiveItem(currentItemKeyToken);
|
|
11136
|
+
} catch (err) {
|
|
11137
|
+
if (slot.isStale())
|
|
11138
|
+
return;
|
|
11139
|
+
setPaneStatus(itemList, `Error: ${err instanceof Error ? err.message : String(err)}`, { error: true });
|
|
11140
|
+
} finally {
|
|
11141
|
+
slot.finish();
|
|
11142
|
+
if (!slot.isStale())
|
|
11143
|
+
moreBtn.disabled = false;
|
|
11144
|
+
}
|
|
11145
|
+
}
|
|
11146
|
+
async function fetchTableInfo(table2) {
|
|
11147
|
+
if (disposed || !currentDbId)
|
|
11148
|
+
return;
|
|
11149
|
+
const slot = tableInfoGuard.start();
|
|
11150
|
+
const requestDbId = currentDbId;
|
|
11151
|
+
try {
|
|
11152
|
+
const params = new URLSearchParams({ db: requestDbId, table: table2 });
|
|
11153
|
+
const res = await trackLoad(fetch(`/_db/dynamodb/table?${params}`, { signal: slot.signal }));
|
|
11154
|
+
if (disposed || slot.isStale())
|
|
11155
|
+
return;
|
|
11156
|
+
if (!res.ok)
|
|
11157
|
+
return;
|
|
11158
|
+
const data = await res.json();
|
|
11159
|
+
if (disposed || slot.isStale() || requestDbId !== currentDbId || currentTable !== table2) {
|
|
11160
|
+
return;
|
|
11161
|
+
}
|
|
11162
|
+
currentTableInfo = data.table;
|
|
11163
|
+
if (!currentItemKeyToken)
|
|
11164
|
+
renderTableInfo();
|
|
11165
|
+
} catch {} finally {
|
|
11166
|
+
slot.finish();
|
|
11167
|
+
}
|
|
11168
|
+
}
|
|
11169
|
+
async function selectItemByKey(key) {
|
|
11170
|
+
if (disposed || !currentDbId || !currentTable)
|
|
11171
|
+
return;
|
|
11172
|
+
const slot = itemGuard.start();
|
|
11173
|
+
const requestRunId = ++itemRunId;
|
|
11174
|
+
const requestDbId = currentDbId;
|
|
11175
|
+
const requestTable = currentTable;
|
|
11176
|
+
try {
|
|
11177
|
+
const params = new URLSearchParams({
|
|
11178
|
+
db: requestDbId,
|
|
11179
|
+
table: requestTable,
|
|
11180
|
+
key: JSON.stringify(key)
|
|
11181
|
+
});
|
|
11182
|
+
const res = await trackLoad(fetch(`/_db/dynamodb/item?${params}`, { signal: slot.signal }));
|
|
11183
|
+
if (disposed || slot.isStale())
|
|
11184
|
+
return;
|
|
11185
|
+
if (!res.ok)
|
|
11186
|
+
return;
|
|
11187
|
+
const data = await res.json();
|
|
11188
|
+
if (disposed || slot.isStale() || requestRunId !== itemRunId || requestDbId !== currentDbId || requestTable !== currentTable || !data.item) {
|
|
11189
|
+
return;
|
|
11190
|
+
}
|
|
11191
|
+
selectItem(data.item);
|
|
11192
|
+
} catch {} finally {
|
|
11193
|
+
slot.finish();
|
|
11194
|
+
}
|
|
11195
|
+
}
|
|
11196
|
+
async function selectTable(name) {
|
|
11197
|
+
if (disposed || !currentDbId)
|
|
11198
|
+
return;
|
|
11199
|
+
currentTable = name;
|
|
11200
|
+
currentTableInfo = null;
|
|
11201
|
+
currentItemKeyToken = null;
|
|
11202
|
+
currentNextToken = undefined;
|
|
11203
|
+
highlightActiveTable(name);
|
|
11204
|
+
notifySelectionChange();
|
|
11205
|
+
setPaneEmpty(detailPane, text2().dynamodb.selectItem);
|
|
11206
|
+
await fetchTableInfo(name);
|
|
11207
|
+
await loadItems(false);
|
|
11208
|
+
}
|
|
11209
|
+
scanModeBtn.addEventListener("click", () => {
|
|
11210
|
+
if (currentMode === "scan")
|
|
11211
|
+
return;
|
|
11212
|
+
setMode("scan");
|
|
11213
|
+
notifySelectionChange();
|
|
11214
|
+
loadItems(false);
|
|
11215
|
+
});
|
|
11216
|
+
queryModeBtn.addEventListener("click", () => {
|
|
11217
|
+
if (currentMode === "query")
|
|
11218
|
+
return;
|
|
11219
|
+
setMode("query");
|
|
11220
|
+
notifySelectionChange();
|
|
11221
|
+
});
|
|
11222
|
+
queryForm.addEventListener("submit", (e2) => {
|
|
11223
|
+
e2.preventDefault();
|
|
11224
|
+
notifySelectionChange();
|
|
11225
|
+
loadItems(false);
|
|
11226
|
+
});
|
|
11227
|
+
for (const input of [keyConditionInput, filterInput]) {
|
|
11228
|
+
input.addEventListener("keydown", (e2) => {
|
|
11229
|
+
if (isImeComposing(e2))
|
|
11230
|
+
return;
|
|
11231
|
+
});
|
|
11232
|
+
}
|
|
11233
|
+
moreBtn.addEventListener("click", () => loadItems(true));
|
|
11234
|
+
tableMoreBtn.addEventListener("click", async () => {
|
|
11235
|
+
if (!currentDbId || !currentTableNextToken || disposed)
|
|
11236
|
+
return;
|
|
11237
|
+
const slot = tablePageGuard.start();
|
|
11238
|
+
const requestDbId = currentDbId;
|
|
11239
|
+
const requestToken = currentTableNextToken;
|
|
11240
|
+
tableMoreBtn.disabled = true;
|
|
11241
|
+
tableMoreBtn.title = "";
|
|
11242
|
+
try {
|
|
11243
|
+
const params = new URLSearchParams({
|
|
11244
|
+
db: requestDbId,
|
|
11245
|
+
exclusiveStartTableName: requestToken
|
|
11246
|
+
});
|
|
11247
|
+
const res = await trackLoad(fetch(`/_db/dynamodb/tables?${params}`, { signal: slot.signal }));
|
|
11248
|
+
if (disposed || slot.isStale() || requestDbId !== currentDbId)
|
|
11249
|
+
return;
|
|
11250
|
+
if (!res.ok) {
|
|
11251
|
+
tableMoreBtn.title = await res.text() || res.statusText;
|
|
11252
|
+
return;
|
|
11253
|
+
}
|
|
11254
|
+
const data = await res.json();
|
|
11255
|
+
if (disposed || slot.isStale() || requestDbId !== currentDbId)
|
|
11256
|
+
return;
|
|
11257
|
+
renderTables(data.tableNames, true);
|
|
11258
|
+
currentTableNextToken = data.lastEvaluatedTableName;
|
|
11259
|
+
tableMoreBtn.hidden = !currentTableNextToken;
|
|
11260
|
+
if (currentTable)
|
|
11261
|
+
highlightActiveTable(currentTable);
|
|
11262
|
+
} catch (err) {
|
|
11263
|
+
if (slot.isStale())
|
|
11264
|
+
return;
|
|
11265
|
+
tableMoreBtn.title = err instanceof Error ? err.message : String(err);
|
|
11266
|
+
} finally {
|
|
11267
|
+
slot.finish();
|
|
11268
|
+
if (!slot.isStale())
|
|
11269
|
+
tableMoreBtn.disabled = false;
|
|
11270
|
+
}
|
|
11271
|
+
});
|
|
11272
|
+
tableList.addEventListener("click", (e2) => {
|
|
11273
|
+
const row = e2.target?.closest(".dynamodb-table-item");
|
|
11274
|
+
if (!row || !tableList.contains(row))
|
|
11275
|
+
return;
|
|
11276
|
+
const name = row.dataset.tableName;
|
|
11277
|
+
if (name)
|
|
11278
|
+
selectTable(name);
|
|
11279
|
+
});
|
|
11280
|
+
itemList.addEventListener("click", (e2) => {
|
|
11281
|
+
const row = e2.target?.closest(".dynamodb-item-row");
|
|
11282
|
+
if (!row || !itemList.contains(row))
|
|
11283
|
+
return;
|
|
11284
|
+
const token = row.dataset.keyToken;
|
|
11285
|
+
if (!token)
|
|
11286
|
+
return;
|
|
11287
|
+
const item = itemsByKeyToken.get(token);
|
|
11288
|
+
if (item)
|
|
11289
|
+
selectItem(item, token);
|
|
11290
|
+
});
|
|
11291
|
+
async function load(dbId, initial) {
|
|
11292
|
+
if (disposed)
|
|
11293
|
+
return;
|
|
11294
|
+
if (currentDbId === dbId && !initial)
|
|
11295
|
+
return;
|
|
11296
|
+
tableGuard.dispose();
|
|
11297
|
+
tablePageGuard.dispose();
|
|
11298
|
+
tableInfoGuard.dispose();
|
|
11299
|
+
itemsGuard.dispose();
|
|
11300
|
+
itemGuard.dispose();
|
|
11301
|
+
const slot = tableGuard.start();
|
|
11302
|
+
const requestRunId = ++loadRunId;
|
|
11303
|
+
currentDbId = dbId;
|
|
11304
|
+
currentTable = null;
|
|
11305
|
+
currentTableInfo = null;
|
|
11306
|
+
currentTableNextToken = undefined;
|
|
11307
|
+
currentItemKeyToken = null;
|
|
11308
|
+
currentNextToken = undefined;
|
|
11309
|
+
setMode(initial?.mode === "query" ? "query" : "scan");
|
|
11310
|
+
currentScanIndexForward = initial?.scanIndexForward ?? true;
|
|
11311
|
+
keyConditionInput.value = initial?.keyConditionExpression ?? "";
|
|
11312
|
+
filterInput.value = initial?.filterExpression ?? "";
|
|
11313
|
+
attributeValuesInput.value = initial?.expressionAttributeValues ?? "";
|
|
11314
|
+
queryError.hidden = true;
|
|
11315
|
+
itemStatus.textContent = "";
|
|
11316
|
+
itemList.innerHTML = "";
|
|
11317
|
+
itemsByKeyToken.clear();
|
|
11318
|
+
itemRowsByKeyToken.clear();
|
|
11319
|
+
activeItemRow = null;
|
|
11320
|
+
moreBtn.hidden = true;
|
|
11321
|
+
tableMoreBtn.hidden = true;
|
|
11322
|
+
setPaneEmpty(detailPane, text2().dynamodb.selectItem);
|
|
11323
|
+
setPaneStatus(tableList, "Loading tables...");
|
|
11324
|
+
try {
|
|
11325
|
+
const res = await trackLoad(fetch(`/_db/dynamodb/tables?db=${encodeURIComponent(dbId)}`, {
|
|
11326
|
+
signal: slot.signal
|
|
11327
|
+
}));
|
|
11328
|
+
if (disposed || slot.isStale())
|
|
11329
|
+
return;
|
|
11330
|
+
if (!res.ok) {
|
|
11331
|
+
const errText = await res.text();
|
|
11332
|
+
setPaneStatus(tableList, `Error: ${errText || res.statusText}`, {
|
|
11333
|
+
error: true
|
|
11334
|
+
});
|
|
11335
|
+
return;
|
|
11336
|
+
}
|
|
11337
|
+
const data = await res.json();
|
|
11338
|
+
if (disposed || slot.isStale() || requestRunId !== loadRunId || currentDbId !== dbId) {
|
|
11339
|
+
return;
|
|
11340
|
+
}
|
|
11341
|
+
renderTables(data.tableNames);
|
|
11342
|
+
currentTableNextToken = data.lastEvaluatedTableName;
|
|
11343
|
+
tableMoreBtn.hidden = !currentTableNextToken;
|
|
11344
|
+
const selected = initial?.table && data.tableNames.includes(initial.table) && initial.table || data.tableNames[0] || null;
|
|
11345
|
+
if (!selected)
|
|
11346
|
+
return;
|
|
11347
|
+
suppressNotify = true;
|
|
11348
|
+
try {
|
|
11349
|
+
await selectTable(selected);
|
|
11350
|
+
if (currentDbId !== dbId)
|
|
11351
|
+
return;
|
|
11352
|
+
if (initial?.itemKey) {
|
|
11353
|
+
try {
|
|
11354
|
+
const key = JSON.parse(initial.itemKey);
|
|
11355
|
+
await selectItemByKey(key);
|
|
11356
|
+
} catch {}
|
|
11357
|
+
}
|
|
11358
|
+
} finally {
|
|
11359
|
+
suppressNotify = false;
|
|
11360
|
+
}
|
|
11361
|
+
notifySelectionChange();
|
|
11362
|
+
} catch (err) {
|
|
11363
|
+
if (slot.isStale())
|
|
11364
|
+
return;
|
|
11365
|
+
setPaneStatus(tableList, `Error: ${err instanceof Error ? err.message : String(err)}`, { error: true });
|
|
11366
|
+
} finally {
|
|
11367
|
+
slot.finish();
|
|
11368
|
+
}
|
|
11369
|
+
}
|
|
11370
|
+
function clear() {
|
|
11371
|
+
tableGuard.dispose();
|
|
11372
|
+
tablePageGuard.dispose();
|
|
11373
|
+
tableInfoGuard.dispose();
|
|
11374
|
+
itemsGuard.dispose();
|
|
11375
|
+
itemGuard.dispose();
|
|
11376
|
+
loadRunId++;
|
|
11377
|
+
itemRunId++;
|
|
11378
|
+
suppressNotify = false;
|
|
11379
|
+
currentDbId = null;
|
|
11380
|
+
currentTable = null;
|
|
11381
|
+
currentTableInfo = null;
|
|
11382
|
+
currentTableNextToken = undefined;
|
|
11383
|
+
currentItemKeyToken = null;
|
|
11384
|
+
currentNextToken = undefined;
|
|
11385
|
+
cumulativeShownCount = 0;
|
|
11386
|
+
cumulativeScannedCount = 0;
|
|
11387
|
+
setMode("scan");
|
|
11388
|
+
keyConditionInput.value = "";
|
|
11389
|
+
filterInput.value = "";
|
|
11390
|
+
attributeValuesInput.value = "";
|
|
11391
|
+
queryError.hidden = true;
|
|
11392
|
+
tableList.innerHTML = "";
|
|
11393
|
+
tableMoreBtn.hidden = true;
|
|
11394
|
+
tableMoreBtn.disabled = false;
|
|
11395
|
+
tableMoreBtn.title = "";
|
|
11396
|
+
activeTableRow = null;
|
|
11397
|
+
itemStatus.textContent = "";
|
|
11398
|
+
itemList.innerHTML = "";
|
|
11399
|
+
itemsByKeyToken.clear();
|
|
11400
|
+
itemRowsByKeyToken.clear();
|
|
11401
|
+
activeItemRow = null;
|
|
11402
|
+
moreBtn.hidden = true;
|
|
11403
|
+
setPaneEmpty(detailPane, text2().dynamodb.selectItem);
|
|
11404
|
+
}
|
|
11405
|
+
setMode("scan");
|
|
11406
|
+
function getSelection() {
|
|
11407
|
+
return {
|
|
11408
|
+
table: currentTable ?? undefined,
|
|
11409
|
+
mode: currentMode,
|
|
11410
|
+
keyConditionExpression: keyConditionInput.value.trim() || undefined,
|
|
11411
|
+
filterExpression: filterInput.value.trim() || undefined,
|
|
11412
|
+
expressionAttributeValues: attributeValuesInput.value.trim() || undefined,
|
|
11413
|
+
scanIndexForward: currentMode === "query" ? currentScanIndexForward : undefined,
|
|
11414
|
+
itemKey: currentItemKeyToken ?? undefined
|
|
11415
|
+
};
|
|
11416
|
+
}
|
|
11417
|
+
function dispose() {
|
|
11418
|
+
disposed = true;
|
|
11419
|
+
clear();
|
|
11420
|
+
}
|
|
11421
|
+
function localize() {
|
|
11422
|
+
const t2 = text2();
|
|
11423
|
+
tableListHeader.textContent = t2.dynamodb.table;
|
|
11424
|
+
scanModeBtn.textContent = t2.dynamodb.scanMode;
|
|
11425
|
+
queryModeBtn.textContent = t2.dynamodb.queryMode;
|
|
11426
|
+
keyConditionInput.placeholder = t2.dynamodb.keyConditionPlaceholder;
|
|
11427
|
+
filterInput.placeholder = t2.dynamodb.filterPlaceholder;
|
|
11428
|
+
attributeValuesInput.placeholder = t2.dynamodb.attributeValuesPlaceholder;
|
|
11429
|
+
runBtn.textContent = t2.dynamodb.runQuery;
|
|
11430
|
+
tableMoreBtn.textContent = t2.common.loadMore;
|
|
11431
|
+
moreBtn.textContent = t2.common.loadMore;
|
|
11432
|
+
if (!activeItemRow) {
|
|
11433
|
+
if (currentTableInfo)
|
|
11434
|
+
renderTableInfo();
|
|
11435
|
+
else
|
|
11436
|
+
setPaneEmpty(detailPane, t2.dynamodb.selectItem);
|
|
11437
|
+
}
|
|
11438
|
+
}
|
|
11439
|
+
return {
|
|
11440
|
+
el: container,
|
|
11441
|
+
sidebarSlot,
|
|
11442
|
+
load,
|
|
11443
|
+
clear,
|
|
11444
|
+
dispose,
|
|
11445
|
+
getSelection,
|
|
11446
|
+
localize
|
|
11447
|
+
};
|
|
11448
|
+
}
|
|
11449
|
+
|
|
10689
11450
|
// web-src/views/database/elasticsearch-explorer.ts
|
|
10690
11451
|
function createElasticsearchExplorer(callbacks = {}) {
|
|
10691
11452
|
const text2 = () => (callbacks.getText?.() ?? dbText("en")).explorer;
|
|
@@ -16386,6 +17147,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16386
17147
|
var ROW_HEIGHT = 28;
|
|
16387
17148
|
var OVERSCAN = 20;
|
|
16388
17149
|
var PAGE_SIZE = 200;
|
|
17150
|
+
var MAX_PAGE_CACHE_PAGES = 32;
|
|
16389
17151
|
var FILTER_DEBOUNCE_MS = 300;
|
|
16390
17152
|
var DEFAULT_COL_WIDTH = 180;
|
|
16391
17153
|
var CELL_PREVIEW_MAX_CHARS = 4000;
|
|
@@ -16520,9 +17282,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16520
17282
|
const filteredEmpty = document.createElement("div");
|
|
16521
17283
|
filteredEmpty.className = "db-pane-empty";
|
|
16522
17284
|
filteredEmpty.hidden = true;
|
|
16523
|
-
const filteredEmptyIcon = document.createElement("div");
|
|
16524
|
-
filteredEmptyIcon.className = "db-pane-empty-icon";
|
|
16525
|
-
filteredEmptyIcon.innerHTML = iconSvg("octicon-search", SEARCH_16_PATH);
|
|
16526
17285
|
const filteredEmptyTitle = document.createElement("div");
|
|
16527
17286
|
filteredEmptyTitle.className = "db-pane-empty-title";
|
|
16528
17287
|
const filteredEmptyHint = document.createElement("div");
|
|
@@ -16542,7 +17301,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16542
17301
|
filteredEmptyAction.hidden = true;
|
|
16543
17302
|
filteredEmptyAction.disabled = true;
|
|
16544
17303
|
filteredEmptyActions.append(filteredEmptyReloadAction, filteredEmptyAction);
|
|
16545
|
-
filteredEmpty.append(
|
|
17304
|
+
filteredEmpty.append(filteredEmptyTitle, filteredEmptyHint, filteredEmptyActions);
|
|
16546
17305
|
const detailPanel = document.createElement("div");
|
|
16547
17306
|
detailPanel.className = "db-grid-detail-panel";
|
|
16548
17307
|
detailPanel.hidden = true;
|
|
@@ -16563,13 +17322,34 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16563
17322
|
function setActiveCell(rowIndex, colIndex) {
|
|
16564
17323
|
activeCellRowIndex = rowIndex;
|
|
16565
17324
|
activeCellColIndex = colIndex;
|
|
16566
|
-
|
|
16567
|
-
|
|
17325
|
+
if (activeCellElement?.isConnected) {
|
|
17326
|
+
activeCellElement.classList.remove("db-grid-cell-active");
|
|
17327
|
+
} else {
|
|
17328
|
+
for (const c2 of body.querySelectorAll(".db-grid-cell-active")) {
|
|
17329
|
+
c2.classList.remove("db-grid-cell-active");
|
|
17330
|
+
}
|
|
16568
17331
|
}
|
|
17332
|
+
activeCellElement = null;
|
|
16569
17333
|
if (rowIndex < 0 || colIndex < 0)
|
|
16570
17334
|
return;
|
|
16571
17335
|
const targetRow = body.children[rowIndex - renderStartRow];
|
|
16572
|
-
targetRow?.children[colIndex + 1]
|
|
17336
|
+
const targetCell = targetRow?.children[colIndex + 1];
|
|
17337
|
+
if (!targetCell)
|
|
17338
|
+
return;
|
|
17339
|
+
targetCell.classList.add("db-grid-cell-active");
|
|
17340
|
+
activeCellElement = targetCell;
|
|
17341
|
+
}
|
|
17342
|
+
function setSelectedRow(rowIndex, row) {
|
|
17343
|
+
selectedRowIndex = rowIndex;
|
|
17344
|
+
if (selectedRowElement?.isConnected) {
|
|
17345
|
+
selectedRowElement.classList.remove("selected");
|
|
17346
|
+
} else {
|
|
17347
|
+
body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
|
|
17348
|
+
r2.classList.remove("selected");
|
|
17349
|
+
});
|
|
17350
|
+
}
|
|
17351
|
+
selectedRowElement = row;
|
|
17352
|
+
row?.classList.add("selected");
|
|
16573
17353
|
}
|
|
16574
17354
|
function clearActiveCell() {
|
|
16575
17355
|
setActiveCell(-1, -1);
|
|
@@ -16631,8 +17411,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16631
17411
|
let isRefreshing = false;
|
|
16632
17412
|
let filterTimer = null;
|
|
16633
17413
|
let selectedRowIndex = -1;
|
|
17414
|
+
let selectedRowElement = null;
|
|
16634
17415
|
let activeCellRowIndex = -1;
|
|
16635
17416
|
let activeCellColIndex = -1;
|
|
17417
|
+
let activeCellElement = null;
|
|
16636
17418
|
let renderStartRow = 0;
|
|
16637
17419
|
const fkColumns = new Set;
|
|
16638
17420
|
let editMode = false;
|
|
@@ -16815,6 +17597,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16815
17597
|
}
|
|
16816
17598
|
function resetSelectionAndDetail() {
|
|
16817
17599
|
selectedRowIndex = -1;
|
|
17600
|
+
selectedRowElement = null;
|
|
16818
17601
|
detailPanel.hidden = true;
|
|
16819
17602
|
clearDetailContent();
|
|
16820
17603
|
}
|
|
@@ -16910,6 +17693,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16910
17693
|
statusEl?.remove();
|
|
16911
17694
|
statusEl = null;
|
|
16912
17695
|
selectedRowIndex = -1;
|
|
17696
|
+
selectedRowElement = null;
|
|
17697
|
+
activeCellElement = null;
|
|
16913
17698
|
closeExportMenu();
|
|
16914
17699
|
hideRelatedPanel();
|
|
16915
17700
|
detailPanel.hidden = true;
|
|
@@ -17433,7 +18218,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17433
18218
|
renderViewport();
|
|
17434
18219
|
}
|
|
17435
18220
|
function ensurePage(pageStart) {
|
|
17436
|
-
if (
|
|
18221
|
+
if (getCachedPage(pageStart) !== undefined)
|
|
17437
18222
|
return Promise.resolve();
|
|
17438
18223
|
const pending = pendingPages.get(pageStart);
|
|
17439
18224
|
if (pending)
|
|
@@ -17444,7 +18229,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17444
18229
|
const promise = callbacks.fetchPage(currentTable, pageStart, PAGE_SIZE, sort, filters, signal).then((data) => {
|
|
17445
18230
|
if (gen !== loadGeneration)
|
|
17446
18231
|
return;
|
|
17447
|
-
|
|
18232
|
+
rememberPage(pageStart, data.rows);
|
|
17448
18233
|
totalRows = data.totalRows;
|
|
17449
18234
|
syncSpacer();
|
|
17450
18235
|
updateStatus();
|
|
@@ -17464,6 +18249,24 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17464
18249
|
pendingPages.set(pageStart, tracked);
|
|
17465
18250
|
return tracked;
|
|
17466
18251
|
}
|
|
18252
|
+
function rememberPage(pageStart, rows) {
|
|
18253
|
+
pageCache.delete(pageStart);
|
|
18254
|
+
pageCache.set(pageStart, rows);
|
|
18255
|
+
while (pageCache.size > MAX_PAGE_CACHE_PAGES) {
|
|
18256
|
+
const oldest = pageCache.keys().next().value;
|
|
18257
|
+
if (oldest === undefined)
|
|
18258
|
+
break;
|
|
18259
|
+
pageCache.delete(oldest);
|
|
18260
|
+
}
|
|
18261
|
+
}
|
|
18262
|
+
function getCachedPage(pageStart) {
|
|
18263
|
+
const rows = pageCache.get(pageStart);
|
|
18264
|
+
if (rows === undefined)
|
|
18265
|
+
return;
|
|
18266
|
+
pageCache.delete(pageStart);
|
|
18267
|
+
pageCache.set(pageStart, rows);
|
|
18268
|
+
return rows;
|
|
18269
|
+
}
|
|
17467
18270
|
function buildEditableCell(colIndex, value, opts) {
|
|
17468
18271
|
const cell = document.createElement("div");
|
|
17469
18272
|
cell.className = "db-grid-cell db-grid-cell-edit";
|
|
@@ -17545,14 +18348,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17545
18348
|
}
|
|
17546
18349
|
function buildDataRow(i2) {
|
|
17547
18350
|
const pageStart = Math.floor(i2 / PAGE_SIZE) * PAGE_SIZE;
|
|
17548
|
-
const pageRows =
|
|
18351
|
+
const pageRows = getCachedPage(pageStart);
|
|
17549
18352
|
const rowData = pageRows ? pageRows[i2 - pageStart] : null;
|
|
17550
18353
|
const row = document.createElement("div");
|
|
17551
18354
|
row.className = "db-grid-row";
|
|
17552
18355
|
if (i2 % 2 === 1)
|
|
17553
18356
|
row.classList.add("alt");
|
|
17554
|
-
if (i2 === selectedRowIndex)
|
|
18357
|
+
if (i2 === selectedRowIndex) {
|
|
17555
18358
|
row.classList.add("selected");
|
|
18359
|
+
selectedRowElement = row;
|
|
18360
|
+
}
|
|
17556
18361
|
const rowIndex = i2;
|
|
17557
18362
|
const rowNum = document.createElement("div");
|
|
17558
18363
|
rowNum.className = "db-grid-cell db-grid-rownum";
|
|
@@ -17601,11 +18406,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17601
18406
|
const fkClickable = fkColumns.has(cellColName) && (!embedded || !!callbacks.onForeignKeyCellClick);
|
|
17602
18407
|
const isEditingThisCell = !ro && i2 === editingCellRow && c2 === editingCellCol;
|
|
17603
18408
|
const activate = () => {
|
|
17604
|
-
|
|
17605
|
-
body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
|
|
17606
|
-
r2.classList.remove("selected");
|
|
17607
|
-
});
|
|
17608
|
-
row.classList.add("selected");
|
|
18409
|
+
setSelectedRow(rowIndex, row);
|
|
17609
18410
|
setActiveCell(rowIndex, cellColIndex);
|
|
17610
18411
|
if (fkClickable) {
|
|
17611
18412
|
if (embedded) {
|
|
@@ -17656,17 +18457,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17656
18457
|
}
|
|
17657
18458
|
if (!isEditingThisCell && i2 === activeCellRowIndex && c2 === activeCellColIndex) {
|
|
17658
18459
|
cellEl.classList.add("db-grid-cell-active");
|
|
18460
|
+
activeCellElement = cellEl;
|
|
17659
18461
|
}
|
|
17660
18462
|
row.appendChild(cellEl);
|
|
17661
18463
|
}
|
|
17662
18464
|
return row;
|
|
17663
18465
|
}
|
|
17664
18466
|
row.addEventListener("click", () => {
|
|
17665
|
-
|
|
17666
|
-
body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
|
|
17667
|
-
r2.classList.remove("selected");
|
|
17668
|
-
});
|
|
17669
|
-
row.classList.add("selected");
|
|
18467
|
+
setSelectedRow(rowIndex, row);
|
|
17670
18468
|
});
|
|
17671
18469
|
for (let c2 = 0;c2 < columnNames.length; c2++) {
|
|
17672
18470
|
const cell = document.createElement("div");
|
|
@@ -17691,11 +18489,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17691
18489
|
}
|
|
17692
18490
|
cell.addEventListener("click", (e2) => {
|
|
17693
18491
|
e2.stopPropagation();
|
|
17694
|
-
|
|
17695
|
-
body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
|
|
17696
|
-
r2.classList.remove("selected");
|
|
17697
|
-
});
|
|
17698
|
-
row.classList.add("selected");
|
|
18492
|
+
setSelectedRow(rowIndex, row);
|
|
17699
18493
|
setActiveCell(rowIndex, cellColIndex);
|
|
17700
18494
|
if (fkClickable) {
|
|
17701
18495
|
if (embedded) {
|
|
@@ -17709,6 +18503,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17709
18503
|
});
|
|
17710
18504
|
if (i2 === activeCellRowIndex && c2 === activeCellColIndex) {
|
|
17711
18505
|
cell.classList.add("db-grid-cell-active");
|
|
18506
|
+
activeCellElement = cell;
|
|
17712
18507
|
}
|
|
17713
18508
|
row.appendChild(cell);
|
|
17714
18509
|
}
|
|
@@ -17780,6 +18575,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17780
18575
|
};
|
|
17781
18576
|
}
|
|
17782
18577
|
body.innerHTML = "";
|
|
18578
|
+
selectedRowElement = null;
|
|
18579
|
+
activeCellElement = null;
|
|
17783
18580
|
body.style.transform = `translateY(${startRow * ROW_HEIGHT}px)`;
|
|
17784
18581
|
for (let i2 = startRow;i2 < endRow; i2++) {
|
|
17785
18582
|
body.appendChild(i2 < totalRows ? buildDataRow(i2) : buildDraftRow(i2 - totalRows));
|
|
@@ -17861,7 +18658,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17861
18658
|
columns = initialData.columns;
|
|
17862
18659
|
columnNames = columns.map((c2) => c2.name);
|
|
17863
18660
|
totalRows = initialData.totalRows;
|
|
17864
|
-
|
|
18661
|
+
rememberPage(0, initialData.rows);
|
|
17865
18662
|
} else {
|
|
17866
18663
|
columns = [];
|
|
17867
18664
|
columnNames = [];
|
|
@@ -18708,7 +19505,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18708
19505
|
snapshotHidden: !sqlMode || tab !== "snapshot",
|
|
18709
19506
|
redisHidden: kind !== "redis",
|
|
18710
19507
|
esHidden: kind !== "elasticsearch",
|
|
18711
|
-
s3Hidden: kind !== "s3"
|
|
19508
|
+
s3Hidden: kind !== "s3",
|
|
19509
|
+
dynamodbHidden: kind !== "dynamodb"
|
|
18712
19510
|
};
|
|
18713
19511
|
}
|
|
18714
19512
|
function normalizeViewForDb(view, db) {
|
|
@@ -19090,7 +19888,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19090
19888
|
});
|
|
19091
19889
|
s3Explorer.el.hidden = true;
|
|
19092
19890
|
s3Explorer.sidebarSlot.hidden = true;
|
|
19093
|
-
|
|
19891
|
+
const dynamodbExplorer = createDynamoDbExplorer({
|
|
19892
|
+
onSelectionChange: () => cb.onStateChange(),
|
|
19893
|
+
getText: () => paneText(),
|
|
19894
|
+
trackLoad: (p2) => deps.trackLoad(p2)
|
|
19895
|
+
});
|
|
19896
|
+
dynamodbExplorer.el.hidden = true;
|
|
19897
|
+
dynamodbExplorer.sidebarSlot.hidden = true;
|
|
19898
|
+
explorerSidebarHost.append(redisExplorer.sidebarSlot, esExplorer.sidebarSlot, s3Explorer.sidebarSlot, dynamodbExplorer.sidebarSlot);
|
|
19094
19899
|
const noDatastoresPane = document.createElement("div");
|
|
19095
19900
|
noDatastoresPane.className = "db-no-datastores";
|
|
19096
19901
|
noDatastoresPane.hidden = true;
|
|
@@ -19114,7 +19919,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19114
19919
|
}
|
|
19115
19920
|
const mainContent = document.createElement("div");
|
|
19116
19921
|
mainContent.className = "db-main-content";
|
|
19117
|
-
mainContent.append(tabBar, grid.el, queryEditor.el, schemaView.el, erDiagram.el, globalSearchView.el, snapshotView.el, redisExplorer.el, esExplorer.el, s3Explorer.el, noDatastoresPane);
|
|
19922
|
+
mainContent.append(tabBar, grid.el, queryEditor.el, schemaView.el, erDiagram.el, globalSearchView.el, snapshotView.el, redisExplorer.el, esExplorer.el, s3Explorer.el, dynamodbExplorer.el, noDatastoresPane);
|
|
19118
19923
|
queryEditor.el.hidden = true;
|
|
19119
19924
|
globalSearchView.el.hidden = true;
|
|
19120
19925
|
snapshotView.el.hidden = true;
|
|
@@ -19242,10 +20047,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19242
20047
|
redisExplorer.el.hidden = visibility.redisHidden;
|
|
19243
20048
|
esExplorer.el.hidden = visibility.esHidden;
|
|
19244
20049
|
s3Explorer.el.hidden = visibility.s3Hidden;
|
|
20050
|
+
dynamodbExplorer.el.hidden = visibility.dynamodbHidden;
|
|
19245
20051
|
redisExplorer.sidebarSlot.hidden = visibility.redisHidden;
|
|
19246
20052
|
esExplorer.sidebarSlot.hidden = visibility.esHidden;
|
|
19247
20053
|
s3Explorer.sidebarSlot.hidden = visibility.s3Hidden;
|
|
19248
|
-
|
|
20054
|
+
dynamodbExplorer.sidebarSlot.hidden = visibility.dynamodbHidden;
|
|
20055
|
+
explorerSidebarHost.hidden = visibility.redisHidden && visibility.esHidden && visibility.s3Hidden && visibility.dynamodbHidden;
|
|
19249
20056
|
if (noDatastoresAvailable) {
|
|
19250
20057
|
toolsSection.hidden = true;
|
|
19251
20058
|
prefsBar.hidden = true;
|
|
@@ -19263,9 +20070,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19263
20070
|
redisExplorer.el.hidden = true;
|
|
19264
20071
|
esExplorer.el.hidden = true;
|
|
19265
20072
|
s3Explorer.el.hidden = true;
|
|
20073
|
+
dynamodbExplorer.el.hidden = true;
|
|
19266
20074
|
redisExplorer.sidebarSlot.hidden = true;
|
|
19267
20075
|
esExplorer.sidebarSlot.hidden = true;
|
|
19268
20076
|
s3Explorer.sidebarSlot.hidden = true;
|
|
20077
|
+
dynamodbExplorer.sidebarSlot.hidden = true;
|
|
19269
20078
|
explorerSidebarHost.hidden = true;
|
|
19270
20079
|
}
|
|
19271
20080
|
if (!sqlMode) {
|
|
@@ -19618,7 +20427,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19618
20427
|
return;
|
|
19619
20428
|
tableSelectGuard.dispose();
|
|
19620
20429
|
currentTable = null;
|
|
19621
|
-
if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch" || currentDbInfo?.kind === "s3") {
|
|
20430
|
+
if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch" || currentDbInfo?.kind === "s3" || currentDbInfo?.kind === "dynamodb") {
|
|
19622
20431
|
currentSchema = null;
|
|
19623
20432
|
renderSchemaOptions([], null);
|
|
19624
20433
|
currentTab = "data";
|
|
@@ -19631,15 +20440,23 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19631
20440
|
if (currentDbInfo.kind === "redis") {
|
|
19632
20441
|
esExplorer.clear();
|
|
19633
20442
|
s3Explorer.clear();
|
|
20443
|
+
dynamodbExplorer.clear();
|
|
19634
20444
|
await redisExplorer.load(dbId, explorerInitial?.redis);
|
|
19635
20445
|
} else if (currentDbInfo.kind === "elasticsearch") {
|
|
19636
20446
|
redisExplorer.clear();
|
|
19637
20447
|
s3Explorer.clear();
|
|
20448
|
+
dynamodbExplorer.clear();
|
|
19638
20449
|
await esExplorer.load(dbId, explorerInitial?.es);
|
|
19639
|
-
} else {
|
|
20450
|
+
} else if (currentDbInfo.kind === "s3") {
|
|
19640
20451
|
redisExplorer.clear();
|
|
19641
20452
|
esExplorer.clear();
|
|
20453
|
+
dynamodbExplorer.clear();
|
|
19642
20454
|
await s3Explorer.load(dbId, explorerInitial?.s3);
|
|
20455
|
+
} else {
|
|
20456
|
+
redisExplorer.clear();
|
|
20457
|
+
esExplorer.clear();
|
|
20458
|
+
s3Explorer.clear();
|
|
20459
|
+
await dynamodbExplorer.load(dbId, explorerInitial?.dynamodb);
|
|
19643
20460
|
}
|
|
19644
20461
|
if (generation !== loadGeneration || currentDbInfo?.id !== dbId)
|
|
19645
20462
|
return;
|
|
@@ -19649,6 +20466,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19649
20466
|
redisExplorer.clear();
|
|
19650
20467
|
esExplorer.clear();
|
|
19651
20468
|
s3Explorer.clear();
|
|
20469
|
+
dynamodbExplorer.clear();
|
|
19652
20470
|
applyVisibility();
|
|
19653
20471
|
tableList.render([]);
|
|
19654
20472
|
setTableListStatus(paneText().nav.loadingSchema);
|
|
@@ -19978,6 +20796,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19978
20796
|
let pendingRedisInitial = initial.redis;
|
|
19979
20797
|
let pendingEsInitial = initial.es;
|
|
19980
20798
|
let pendingS3Initial = initial.s3;
|
|
20799
|
+
let pendingDynamodbInitial = initial.dynamodb;
|
|
19981
20800
|
async function enter(db, schema, table2, view, options = {}) {
|
|
19982
20801
|
const generation = ++loadGeneration;
|
|
19983
20802
|
const filesResponse = await fetchDbFiles();
|
|
@@ -20010,6 +20829,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20010
20829
|
redisExplorer.clear();
|
|
20011
20830
|
esExplorer.clear();
|
|
20012
20831
|
s3Explorer.clear();
|
|
20832
|
+
dynamodbExplorer.clear();
|
|
20013
20833
|
renderNoDatastoresEmpty();
|
|
20014
20834
|
applyVisibility();
|
|
20015
20835
|
cb.onStateChange();
|
|
@@ -20045,6 +20865,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20045
20865
|
redisExplorer.clear();
|
|
20046
20866
|
esExplorer.clear();
|
|
20047
20867
|
s3Explorer.clear();
|
|
20868
|
+
dynamodbExplorer.clear();
|
|
20048
20869
|
setActiveTab("data", false);
|
|
20049
20870
|
cb.onStateChange();
|
|
20050
20871
|
return;
|
|
@@ -20055,15 +20876,17 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20055
20876
|
const explorerInitial = {
|
|
20056
20877
|
redis: pendingRedisInitial,
|
|
20057
20878
|
es: pendingEsInitial,
|
|
20058
|
-
s3: pendingS3Initial
|
|
20879
|
+
s3: pendingS3Initial,
|
|
20880
|
+
dynamodb: pendingDynamodbInitial
|
|
20059
20881
|
};
|
|
20060
20882
|
pendingRedisInitial = undefined;
|
|
20061
20883
|
pendingEsInitial = undefined;
|
|
20062
20884
|
pendingS3Initial = undefined;
|
|
20885
|
+
pendingDynamodbInitial = undefined;
|
|
20063
20886
|
await selectDb(target, explorerInitial, generation, schema !== undefined ? schema : currentSchema, table2, view);
|
|
20064
20887
|
if (generation !== loadGeneration || currentDbInfo?.id !== target)
|
|
20065
20888
|
return;
|
|
20066
|
-
if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch" || currentDbInfo?.kind === "s3") {
|
|
20889
|
+
if (currentDbInfo?.kind === "redis" || currentDbInfo?.kind === "elasticsearch" || currentDbInfo?.kind === "s3" || currentDbInfo?.kind === "dynamodb") {
|
|
20067
20890
|
cb.onStateChange();
|
|
20068
20891
|
return;
|
|
20069
20892
|
}
|
|
@@ -20168,6 +20991,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20168
20991
|
state.es = initial.es;
|
|
20169
20992
|
if (initial.s3)
|
|
20170
20993
|
state.s3 = initial.s3;
|
|
20994
|
+
if (initial.dynamodb)
|
|
20995
|
+
state.dynamodb = initial.dynamodb;
|
|
20171
20996
|
} else if (currentDbInfo?.kind === "redis") {
|
|
20172
20997
|
const sel = redisExplorer.getSelection();
|
|
20173
20998
|
if (sel.dbIndex !== undefined || sel.key !== undefined || sel.keyFilter !== undefined) {
|
|
@@ -20183,6 +21008,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20183
21008
|
if (sel.bucket !== undefined || sel.prefix !== undefined || sel.query !== undefined || sel.key !== undefined || sel.mode !== "prefix" || sel.sort !== "updated-desc" || sel.view === "explorer") {
|
|
20184
21009
|
state.s3 = sel;
|
|
20185
21010
|
}
|
|
21011
|
+
} else if (currentDbInfo?.kind === "dynamodb") {
|
|
21012
|
+
const sel = dynamodbExplorer.getSelection();
|
|
21013
|
+
if (sel.table !== undefined || sel.mode !== "scan" || sel.keyConditionExpression !== undefined || sel.filterExpression !== undefined || sel.expressionAttributeValues !== undefined || sel.itemKey !== undefined) {
|
|
21014
|
+
state.dynamodb = sel;
|
|
21015
|
+
}
|
|
20186
21016
|
}
|
|
20187
21017
|
return state;
|
|
20188
21018
|
}
|
|
@@ -20239,6 +21069,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20239
21069
|
redisExplorer.dispose();
|
|
20240
21070
|
esExplorer.dispose();
|
|
20241
21071
|
s3Explorer.dispose();
|
|
21072
|
+
dynamodbExplorer.dispose();
|
|
20242
21073
|
currentDbInfo = null;
|
|
20243
21074
|
currentSchema = null;
|
|
20244
21075
|
currentTable = null;
|
|
@@ -20259,6 +21090,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20259
21090
|
redisExplorer.localize();
|
|
20260
21091
|
esExplorer.localize();
|
|
20261
21092
|
s3Explorer.localize();
|
|
21093
|
+
dynamodbExplorer.localize();
|
|
20262
21094
|
}
|
|
20263
21095
|
return {
|
|
20264
21096
|
el: container,
|
|
@@ -20671,7 +21503,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20671
21503
|
view: tab.view,
|
|
20672
21504
|
redis: tab.redis ?? null,
|
|
20673
21505
|
es: tab.es ?? null,
|
|
20674
|
-
s3: tab.s3 ?? null
|
|
21506
|
+
s3: tab.s3 ?? null,
|
|
21507
|
+
dynamodb: tab.dynamodb ?? null
|
|
20675
21508
|
});
|
|
20676
21509
|
if (seen.has(key))
|
|
20677
21510
|
continue;
|
|
@@ -20929,7 +21762,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20929
21762
|
detailPanelHeight: initial?.detailPanelHeight,
|
|
20930
21763
|
redis: initial?.redis,
|
|
20931
21764
|
es: initial?.es,
|
|
20932
|
-
s3: initial?.s3
|
|
21765
|
+
s3: initial?.s3,
|
|
21766
|
+
dynamodb: initial?.dynamodb
|
|
20933
21767
|
});
|
|
20934
21768
|
pane.el.hidden = true;
|
|
20935
21769
|
tabsList.appendChild(chip);
|
|
@@ -21620,7 +22454,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21620
22454
|
const card = document.querySelector(diffCardSelector(path));
|
|
21621
22455
|
if (!card?.classList.contains("pending"))
|
|
21622
22456
|
return;
|
|
21623
|
-
const f2 = STATE.files.find((x) => x.path === path);
|
|
22457
|
+
const f2 = card._file || STATE.files.find((x) => x.path === path);
|
|
21624
22458
|
if (!f2)
|
|
21625
22459
|
return;
|
|
21626
22460
|
enqueueLoad(f2, card, 5);
|
|
@@ -21692,7 +22526,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21692
22526
|
};
|
|
21693
22527
|
window.addEventListener("scrollend", onEnd, { once: true });
|
|
21694
22528
|
if (card.classList.contains("pending")) {
|
|
21695
|
-
const f2 = STATE.files.find((x) => x.path === path);
|
|
22529
|
+
const f2 = card._file || STATE.files.find((x) => x.path === path);
|
|
21696
22530
|
if (f2)
|
|
21697
22531
|
enqueueLoad(f2, card, 10);
|
|
21698
22532
|
}
|
|
@@ -21761,7 +22595,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21761
22595
|
const card = entry.target;
|
|
21762
22596
|
if (card.classList.contains("loaded") || card.classList.contains("loading"))
|
|
21763
22597
|
continue;
|
|
21764
|
-
const f2 = STATE.files.find((x) => x.path === card.dataset.path);
|
|
22598
|
+
const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
|
|
21765
22599
|
if (f2)
|
|
21766
22600
|
enqueueLoad(f2, card, 0);
|
|
21767
22601
|
}
|
|
@@ -21829,7 +22663,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21829
22663
|
delete card.dataset.manualMode;
|
|
21830
22664
|
card.style.minHeight = `${file.estimated_height_px || 80}px`;
|
|
21831
22665
|
card._diffData = null;
|
|
21832
|
-
card._file =
|
|
22666
|
+
card._file = file;
|
|
21833
22667
|
}
|
|
21834
22668
|
function renderShell(meta, changedPaths) {
|
|
21835
22669
|
const newFiles = meta.files || [];
|
|
@@ -21995,6 +22829,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21995
22829
|
card.dataset.key = f2.key || f2.path;
|
|
21996
22830
|
card.dataset.sizeClass = f2.size_class || "small";
|
|
21997
22831
|
card.dataset.status = f2.status || "M";
|
|
22832
|
+
card._file = f2;
|
|
21998
22833
|
card.classList.toggle("viewed", STATE.viewedFiles.has(f2.path));
|
|
21999
22834
|
if (f2.estimated_height_px) {
|
|
22000
22835
|
card.style.minHeight = `${f2.estimated_height_px}px`;
|
|
@@ -22018,7 +22853,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22018
22853
|
const card = entry.target;
|
|
22019
22854
|
if (card.classList.contains("loaded") || card.classList.contains("loading"))
|
|
22020
22855
|
return;
|
|
22021
|
-
const f2 = STATE.files.find((x) => x.path === card.dataset.path);
|
|
22856
|
+
const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
|
|
22022
22857
|
if (!f2)
|
|
22023
22858
|
return;
|
|
22024
22859
|
enqueueLoad(f2, card, 0);
|
|
@@ -22034,7 +22869,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22034
22869
|
const rect = card.getBoundingClientRect();
|
|
22035
22870
|
if (rect.top > viewportBottom)
|
|
22036
22871
|
return;
|
|
22037
|
-
const f2 = STATE.files.find((x) => x.path === card.dataset.path);
|
|
22872
|
+
const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
|
|
22038
22873
|
if (f2)
|
|
22039
22874
|
enqueueLoad(f2, card, 0);
|
|
22040
22875
|
});
|
|
@@ -22182,11 +23017,15 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22182
23017
|
card.classList.add("pending");
|
|
22183
23018
|
if (indicator)
|
|
22184
23019
|
indicator.hidden = true;
|
|
22185
|
-
const fresh = STATE.files.find((x) => x.path === card.dataset.path);
|
|
23020
|
+
const fresh = card._file || STATE.files.find((x) => x.path === card.dataset.path);
|
|
22186
23021
|
if (fresh && card.isConnected)
|
|
22187
23022
|
enqueueLoad(fresh, card, 0);
|
|
22188
23023
|
};
|
|
22189
|
-
return trackLoad(fetch(url).then(
|
|
23024
|
+
return trackLoad(fetch(url).then(async (r2) => {
|
|
23025
|
+
if (!r2.ok)
|
|
23026
|
+
throw new Error(await r2.text());
|
|
23027
|
+
return r2.json();
|
|
23028
|
+
})).then(async (data) => {
|
|
22190
23029
|
if (String(myReq) !== card.dataset.reqId)
|
|
22191
23030
|
return;
|
|
22192
23031
|
if (myGen !== getServerGeneration()) {
|
|
@@ -22227,7 +23066,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22227
23066
|
return false;
|
|
22228
23067
|
if (card.classList.contains("loaded"))
|
|
22229
23068
|
return true;
|
|
22230
|
-
const file = STATE.files.find((x) => x.path === path);
|
|
23069
|
+
const file = card._file || STATE.files.find((x) => x.path === path);
|
|
22231
23070
|
if (!file)
|
|
22232
23071
|
return false;
|
|
22233
23072
|
await loadFile(file, card, undefined, { immediate: true });
|
|
@@ -22253,17 +23092,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22253
23092
|
matching: "lines",
|
|
22254
23093
|
outputFormat: layout,
|
|
22255
23094
|
synchronisedScroll: true,
|
|
22256
|
-
highlight:
|
|
23095
|
+
highlight: false,
|
|
22257
23096
|
fileListToggle: false,
|
|
22258
23097
|
fileContentToggle: false
|
|
22259
23098
|
}, hljsRef);
|
|
22260
23099
|
ui.draw();
|
|
22261
23100
|
if (STATE.ignoreWs)
|
|
22262
23101
|
suppressWhitespaceOnlyInlineHighlights(body);
|
|
22263
|
-
if (STATE.syntaxHighlight && file.highlight && hljsRef && typeof ui.highlightCode === "function") {
|
|
22264
|
-
ui.highlightCode();
|
|
22265
|
-
highlightPlaintextSpans(card, file);
|
|
22266
|
-
}
|
|
22267
23102
|
enhanceMediaCard(file, card);
|
|
22268
23103
|
syncSideScrollCard(card);
|
|
22269
23104
|
appendStatSquaresToHeader(card, file);
|
|
@@ -22592,10 +23427,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22592
23427
|
const spans = card.querySelectorAll("tr.gdp-inserted-ctx .d2h-code-line-ctn:not([data-gdp-hl])");
|
|
22593
23428
|
highlightDiffSpans(file, spans);
|
|
22594
23429
|
}
|
|
22595
|
-
function highlightPlaintextSpans(card, file) {
|
|
22596
|
-
const spans = card.querySelectorAll(".d2h-code-line-ctn.hljs.plaintext:not([data-gdp-hl])");
|
|
22597
|
-
highlightDiffSpans(file, spans);
|
|
22598
|
-
}
|
|
22599
23430
|
function highlightDiffSpans(file, spans, deadline) {
|
|
22600
23431
|
if (file.size_class === "huge")
|
|
22601
23432
|
return true;
|
|
@@ -22626,8 +23457,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22626
23457
|
return true;
|
|
22627
23458
|
}
|
|
22628
23459
|
function scheduleIdleHighlight(card, file) {
|
|
22629
|
-
if (file.highlight)
|
|
22630
|
-
return;
|
|
22631
23460
|
if (file.size_class === "huge")
|
|
22632
23461
|
return;
|
|
22633
23462
|
if (!STATE.syntaxHighlight)
|
|
@@ -22683,14 +23512,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22683
23512
|
for (const w of cards) {
|
|
22684
23513
|
const r2 = w.getBoundingClientRect();
|
|
22685
23514
|
if (r2.top <= scanY && r2.bottom > scanY) {
|
|
22686
|
-
const
|
|
22687
|
-
let best = null, bestLen = 0;
|
|
22688
|
-
STATE.files.forEach((f2) => {
|
|
22689
|
-
if ((text2 === f2.path || text2.endsWith(f2.path)) && f2.path.length > bestLen) {
|
|
22690
|
-
best = f2.path;
|
|
22691
|
-
bestLen = f2.path.length;
|
|
22692
|
-
}
|
|
22693
|
-
});
|
|
23515
|
+
const best = w.dataset.path || "";
|
|
22694
23516
|
if (best) {
|
|
22695
23517
|
markActive(best);
|
|
22696
23518
|
const recentlyTouched = performance.now() - (window.__gdpSidebarTouchedAt || 0) < 1500;
|
|
@@ -23275,6 +24097,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23275
24097
|
let generation = 0;
|
|
23276
24098
|
let selectionGeneration = 0;
|
|
23277
24099
|
let selectedSha = "";
|
|
24100
|
+
let activeHistoryRow = null;
|
|
23278
24101
|
let query = "";
|
|
23279
24102
|
let mode = "history";
|
|
23280
24103
|
let routeRef = "HEAD";
|
|
@@ -23387,6 +24210,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23387
24210
|
return absolute;
|
|
23388
24211
|
return `${relative} (${absolute})`;
|
|
23389
24212
|
}
|
|
24213
|
+
function historyItemSelector(sha) {
|
|
24214
|
+
const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(sha) : sha.replace(/["\\]/g, "\\$&");
|
|
24215
|
+
return `.history-item[data-sha="${escaped}"]`;
|
|
24216
|
+
}
|
|
23390
24217
|
function fetchPage(skip, requestGeneration) {
|
|
23391
24218
|
const params = new URLSearchParams;
|
|
23392
24219
|
params.set("ref", ref);
|
|
@@ -23440,6 +24267,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23440
24267
|
html.push(commitRow(commit));
|
|
23441
24268
|
}
|
|
23442
24269
|
list2.innerHTML = html.join("");
|
|
24270
|
+
activeHistoryRow = list2.querySelector(".history-item.active");
|
|
23443
24271
|
syncRefreshStatusText();
|
|
23444
24272
|
}
|
|
23445
24273
|
function syncRefreshButton(button) {
|
|
@@ -23527,9 +24355,15 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23527
24355
|
info.hidden = false;
|
|
23528
24356
|
}
|
|
23529
24357
|
function updateActiveRow() {
|
|
23530
|
-
|
|
23531
|
-
|
|
23532
|
-
}
|
|
24358
|
+
if (activeHistoryRow && (!("isConnected" in activeHistoryRow) || activeHistoryRow.isConnected)) {
|
|
24359
|
+
activeHistoryRow.classList.remove("active");
|
|
24360
|
+
} else {
|
|
24361
|
+
list2.querySelectorAll(".history-item.active").forEach((row) => {
|
|
24362
|
+
row.classList.remove("active");
|
|
24363
|
+
});
|
|
24364
|
+
}
|
|
24365
|
+
activeHistoryRow = selectedSha ? list2.querySelector(historyItemSelector(selectedSha)) : null;
|
|
24366
|
+
activeHistoryRow?.classList.add("active");
|
|
23533
24367
|
}
|
|
23534
24368
|
function isEditableTarget(target) {
|
|
23535
24369
|
return typeof Element === "function" && target instanceof Element && !!target.closest('input, textarea, select, button, [contenteditable="true"]');
|
|
@@ -23720,8 +24554,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23720
24554
|
scrollToSelected();
|
|
23721
24555
|
}
|
|
23722
24556
|
function scrollToSelected() {
|
|
23723
|
-
|
|
23724
|
-
list2.querySelector(`.history-item[data-sha="${escaped}"]`)?.scrollIntoView({ block: "center" });
|
|
24557
|
+
list2.querySelector(historyItemSelector(selectedSha))?.scrollIntoView({ block: "center" });
|
|
23725
24558
|
}
|
|
23726
24559
|
let entering = Promise.resolve();
|
|
23727
24560
|
function enterHistory(options = {}) {
|
|
@@ -23797,6 +24630,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23797
24630
|
generation++;
|
|
23798
24631
|
loading = false;
|
|
23799
24632
|
inFlight = null;
|
|
24633
|
+
if (filterTimer) {
|
|
24634
|
+
clearTimeout(filterTimer);
|
|
24635
|
+
filterTimer = undefined;
|
|
24636
|
+
}
|
|
23800
24637
|
selectionGeneration++;
|
|
23801
24638
|
selectedSha = "";
|
|
23802
24639
|
setBanner("");
|
|
@@ -24697,7 +25534,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
24697
25534
|
database: {
|
|
24698
25535
|
nav: "Datastores",
|
|
24699
25536
|
title: "Datastore Viewer",
|
|
24700
|
-
intro: "Browse
|
|
25537
|
+
intro: "Browse SQLite files, Docker-hosted databases, Redis, Elasticsearch, DynamoDB, and S3-compatible object stores from one local viewer.",
|
|
24701
25538
|
groups: [
|
|
24702
25539
|
{
|
|
24703
25540
|
title: "Supported datastores",
|
|
@@ -24725,6 +25562,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
24725
25562
|
"Elasticsearch",
|
|
24726
25563
|
"Detected from compose files. List indices, view mappings, paginate with search_after, run lucene q= or DSL queries on an allowlist. Edit / create / delete documents with _seq_no / _primary_term optimistic concurrency. Take snapshots/diffs."
|
|
24727
25564
|
],
|
|
25565
|
+
[
|
|
25566
|
+
"DynamoDB / LocalStack",
|
|
25567
|
+
"Detected when DynamoDB is enabled on a LocalStack compose service. List tables, inspect key schemas, scan or query items, follow pagination tokens, and open item details with a copyable key. Browsing is read-only."
|
|
25568
|
+
],
|
|
24728
25569
|
[
|
|
24729
25570
|
"S3 / MinIO / LocalStack",
|
|
24730
25571
|
"Detected from compose files. Folder-tree browse, prefix/filename search, updated-time sort, and previews for images, video, audio, PDF, Markdown, HTML, and text. Edit text/markdown/JSON object bodies inline, upload new objects, and delete existing ones. LocalStack falls back to `docker exec curl` when no host port is published; MinIO requires a published host port."
|
|
@@ -24781,7 +25622,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
24781
25622
|
],
|
|
24782
25623
|
[
|
|
24783
25624
|
"Datastore explorers",
|
|
24784
|
-
"Redis / Elasticsearch / S3 keep the same Multi-DB tab UI but swap the table tree for a key-space / index-tree / folder-tree explorer.
|
|
25625
|
+
"Redis / Elasticsearch / DynamoDB / S3 keep the same Multi-DB tab UI but swap the table tree for a key-space / index-tree / table-list / folder-tree explorer. Redis, Elasticsearch, and S3 provide editing or creation flows; DynamoDB browsing is read-only."
|
|
24785
25626
|
]
|
|
24786
25627
|
]
|
|
24787
25628
|
}
|
|
@@ -25356,7 +26197,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
25356
26197
|
database: {
|
|
25357
26198
|
nav: "データストア",
|
|
25358
26199
|
title: "データストアビューア",
|
|
25359
|
-
intro: "SQLite ファイル、Docker 上のデータベース、Redis、Elasticsearch、S3
|
|
26200
|
+
intro: "SQLite ファイル、Docker 上のデータベース、Redis、Elasticsearch、DynamoDB、S3 互換オブジェクトストアをローカルビューアで閲覧できます。",
|
|
25360
26201
|
groups: [
|
|
25361
26202
|
{
|
|
25362
26203
|
title: "対応データストア",
|
|
@@ -25384,6 +26225,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
25384
26225
|
"Elasticsearch",
|
|
25385
26226
|
"compose ファイルから検出。インデックス一覧、マッピング、search_after ページング、lucene q= と許可リスト経由の DSL、スナップショット/差分に対応。_seq_no / _primary_term 楽観ロックでドキュメントの編集 / 新規作成 / 削除も可能。"
|
|
25386
26227
|
],
|
|
26228
|
+
[
|
|
26229
|
+
"DynamoDB / LocalStack",
|
|
26230
|
+
"LocalStack の compose サービスで DynamoDB が有効な場合に検出。テーブル一覧、キースキーマ、scan / query、継続トークンによるページング、コピー可能なキー付きのアイテム詳細を表示します。閲覧専用です。"
|
|
26231
|
+
],
|
|
25387
26232
|
[
|
|
25388
26233
|
"S3 / MinIO / LocalStack",
|
|
25389
26234
|
"compose ファイルから検出。フォルダツリー型ブラウザ、prefix/ファイル名検索、更新日時順表示、画像/動画/音声/PDF/Markdown/HTML/テキストのプレビューに対応。テキスト/Markdown/JSON のインライン編集、新規オブジェクトアップロード、オブジェクト削除も可能。LocalStack はホストポート未公開時 `docker exec curl` にフォールバックしますが、MinIO はホストポート公開が必須です。"
|
|
@@ -25440,7 +26285,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
25440
26285
|
],
|
|
25441
26286
|
[
|
|
25442
26287
|
"データストア専用エクスプローラ",
|
|
25443
|
-
"Redis / Elasticsearch / S3 はマルチ DB タブ UI を共有しつつ、テーブルツリーをキー空間ツリー / インデックスツリー /
|
|
26288
|
+
"Redis / Elasticsearch / DynamoDB / S3 はマルチ DB タブ UI を共有しつつ、テーブルツリーをキー空間ツリー / インデックスツリー / テーブル一覧 / フォルダツリーに差し替えます。Redis、Elasticsearch、S3 は編集・作成フローを提供し、DynamoDB は閲覧専用です。"
|
|
25444
26289
|
]
|
|
25445
26290
|
]
|
|
25446
26291
|
}
|
|
@@ -31385,11 +32230,106 @@ code-viewer query agent-help`
|
|
|
31385
32230
|
const match2 = computeFuzzyMatch(query, path);
|
|
31386
32231
|
return match2 ? { score: match2.score, ranges: match2.ranges } : null;
|
|
31387
32232
|
}
|
|
31388
|
-
function rankFuzzyPaths(query, items) {
|
|
31389
|
-
|
|
32233
|
+
function rankFuzzyPaths(query, items, limit) {
|
|
32234
|
+
const bounded = Number.isInteger(limit) && limit !== undefined && limit > 0 ? Math.floor(limit) : 0;
|
|
32235
|
+
const compare = (a2, b2) => b2.tier - a2.tier || b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
32236
|
+
if (!bounded) {
|
|
32237
|
+
return items.map((item) => {
|
|
32238
|
+
const match2 = computeFuzzyMatch(query, item.path);
|
|
32239
|
+
return match2 ? { item, score: match2.score, ranges: match2.ranges, tier: match2.tier } : null;
|
|
32240
|
+
}).filter((item) => item !== null).sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
32241
|
+
}
|
|
32242
|
+
const top = [];
|
|
32243
|
+
for (const item of items) {
|
|
31390
32244
|
const match2 = computeFuzzyMatch(query, item.path);
|
|
31391
|
-
|
|
31392
|
-
|
|
32245
|
+
if (!match2)
|
|
32246
|
+
continue;
|
|
32247
|
+
const ranked = {
|
|
32248
|
+
item,
|
|
32249
|
+
score: match2.score,
|
|
32250
|
+
ranges: match2.ranges,
|
|
32251
|
+
tier: match2.tier
|
|
32252
|
+
};
|
|
32253
|
+
pushBoundedTop(top, ranked, bounded, compare);
|
|
32254
|
+
}
|
|
32255
|
+
return top.sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
32256
|
+
}
|
|
32257
|
+
function pushBoundedTop(heap, item, limit, compareBestFirst) {
|
|
32258
|
+
const isWorse = (a2, b2) => compareBestFirst(a2, b2) > 0;
|
|
32259
|
+
const siftUp = (index) => {
|
|
32260
|
+
while (index > 0) {
|
|
32261
|
+
const parent = Math.floor((index - 1) / 2);
|
|
32262
|
+
if (!isWorse(heap[index], heap[parent]))
|
|
32263
|
+
break;
|
|
32264
|
+
[heap[index], heap[parent]] = [heap[parent], heap[index]];
|
|
32265
|
+
index = parent;
|
|
32266
|
+
}
|
|
32267
|
+
};
|
|
32268
|
+
const siftDown = (index) => {
|
|
32269
|
+
while (true) {
|
|
32270
|
+
const left = index * 2 + 1;
|
|
32271
|
+
const right = left + 1;
|
|
32272
|
+
let worst = index;
|
|
32273
|
+
if (left < heap.length && isWorse(heap[left], heap[worst]))
|
|
32274
|
+
worst = left;
|
|
32275
|
+
if (right < heap.length && isWorse(heap[right], heap[worst]))
|
|
32276
|
+
worst = right;
|
|
32277
|
+
if (worst === index)
|
|
32278
|
+
break;
|
|
32279
|
+
[heap[index], heap[worst]] = [heap[worst], heap[index]];
|
|
32280
|
+
index = worst;
|
|
32281
|
+
}
|
|
32282
|
+
};
|
|
32283
|
+
if (heap.length < limit) {
|
|
32284
|
+
heap.push(item);
|
|
32285
|
+
siftUp(heap.length - 1);
|
|
32286
|
+
return;
|
|
32287
|
+
}
|
|
32288
|
+
if (compareBestFirst(item, heap[0]) >= 0)
|
|
32289
|
+
return;
|
|
32290
|
+
heap[0] = item;
|
|
32291
|
+
siftDown(0);
|
|
32292
|
+
}
|
|
32293
|
+
function rankGlobPathMatches(query, items, limit) {
|
|
32294
|
+
const matchPath = createGlobPathMatcher(query);
|
|
32295
|
+
if (!matchPath)
|
|
32296
|
+
return [];
|
|
32297
|
+
const bounded = Number.isInteger(limit) && limit !== undefined && limit > 0 ? Math.floor(limit) : 0;
|
|
32298
|
+
const compare = (a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
32299
|
+
if (!bounded) {
|
|
32300
|
+
return items.map((item) => {
|
|
32301
|
+
const match2 = matchPath(item.path);
|
|
32302
|
+
return match2 ? {
|
|
32303
|
+
item,
|
|
32304
|
+
score: match2.score,
|
|
32305
|
+
ranges: match2.ranges,
|
|
32306
|
+
mode: "glob"
|
|
32307
|
+
} : null;
|
|
32308
|
+
}).filter((item) => item !== null).sort(compare);
|
|
32309
|
+
}
|
|
32310
|
+
const top = [];
|
|
32311
|
+
for (const item of items) {
|
|
32312
|
+
const match2 = matchPath(item.path);
|
|
32313
|
+
if (!match2)
|
|
32314
|
+
continue;
|
|
32315
|
+
const ranked = {
|
|
32316
|
+
item,
|
|
32317
|
+
score: match2.score,
|
|
32318
|
+
ranges: match2.ranges,
|
|
32319
|
+
mode: "glob"
|
|
32320
|
+
};
|
|
32321
|
+
pushBoundedTop(top, ranked, bounded, compare);
|
|
32322
|
+
}
|
|
32323
|
+
return top.sort(compare);
|
|
32324
|
+
}
|
|
32325
|
+
function rankPathMatches(query, items, limit) {
|
|
32326
|
+
if (isGlobPathQuery(query)) {
|
|
32327
|
+
return rankGlobPathMatches(query, items, limit);
|
|
32328
|
+
}
|
|
32329
|
+
return rankFuzzyPaths(query, items, limit).map((item) => ({
|
|
32330
|
+
...item,
|
|
32331
|
+
mode: "fuzzy"
|
|
32332
|
+
}));
|
|
31393
32333
|
}
|
|
31394
32334
|
function isGlobPathQuery(query) {
|
|
31395
32335
|
return /[*?]/.test(query.trim());
|
|
@@ -31434,48 +32374,39 @@ code-viewer query agent-help`
|
|
|
31434
32374
|
}
|
|
31435
32375
|
}
|
|
31436
32376
|
function globMatchPath(query, path) {
|
|
32377
|
+
return createGlobPathMatcher(query)?.(path) ?? null;
|
|
32378
|
+
}
|
|
32379
|
+
function createGlobPathMatcher(query) {
|
|
31437
32380
|
const regex = globToRegExp(query);
|
|
31438
|
-
|
|
31439
|
-
const basename = path.slice(baseStart);
|
|
31440
|
-
if (!regex || !regex.test(path) && (query.includes("/") || !regex.test(basename)))
|
|
32381
|
+
if (!regex)
|
|
31441
32382
|
return null;
|
|
31442
32383
|
const literal = query.replace(/[*?[\]]+/g, " ").trim().split(/\s+/).filter(Boolean);
|
|
31443
|
-
const
|
|
31444
|
-
|
|
31445
|
-
|
|
31446
|
-
const
|
|
31447
|
-
if (
|
|
31448
|
-
|
|
31449
|
-
|
|
31450
|
-
|
|
31451
|
-
|
|
31452
|
-
|
|
31453
|
-
|
|
31454
|
-
|
|
31455
|
-
|
|
31456
|
-
|
|
31457
|
-
|
|
32384
|
+
const suffix = query.replace(/^\*+/, "").toLowerCase();
|
|
32385
|
+
return (path) => {
|
|
32386
|
+
const baseStart = basenameStart(path);
|
|
32387
|
+
const basename = path.slice(baseStart);
|
|
32388
|
+
if (!regex.test(path) && (query.includes("/") || !regex.test(basename)))
|
|
32389
|
+
return null;
|
|
32390
|
+
const ranges = [];
|
|
32391
|
+
const lowerPath = path.toLowerCase();
|
|
32392
|
+
for (const part of literal) {
|
|
32393
|
+
const start = lowerPath.indexOf(part.toLowerCase());
|
|
32394
|
+
if (start >= 0)
|
|
32395
|
+
ranges.push({ start, end: start + part.length });
|
|
32396
|
+
}
|
|
32397
|
+
ranges.sort((a2, b2) => a2.start - b2.start || a2.end - b2.end);
|
|
32398
|
+
const mergedRanges = [];
|
|
32399
|
+
for (const range of ranges) {
|
|
32400
|
+
const last = mergedRanges[mergedRanges.length - 1];
|
|
32401
|
+
if (last && last.end >= range.start) {
|
|
32402
|
+
last.end = Math.max(last.end, range.end);
|
|
32403
|
+
} else {
|
|
32404
|
+
mergedRanges.push({ ...range });
|
|
32405
|
+
}
|
|
31458
32406
|
}
|
|
31459
|
-
|
|
31460
|
-
|
|
31461
|
-
|
|
31462
|
-
}
|
|
31463
|
-
function rankPathMatches(query, items) {
|
|
31464
|
-
if (isGlobPathQuery(query)) {
|
|
31465
|
-
return items.map((item) => {
|
|
31466
|
-
const match2 = globMatchPath(query, item.path);
|
|
31467
|
-
return match2 ? {
|
|
31468
|
-
item,
|
|
31469
|
-
score: match2.score,
|
|
31470
|
-
ranges: match2.ranges,
|
|
31471
|
-
mode: "glob"
|
|
31472
|
-
} : null;
|
|
31473
|
-
}).filter((item) => item !== null).sort((a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path));
|
|
31474
|
-
}
|
|
31475
|
-
return rankFuzzyPaths(query, items).map((item) => ({
|
|
31476
|
-
...item,
|
|
31477
|
-
mode: "fuzzy"
|
|
31478
|
-
}));
|
|
32407
|
+
const score = 1000 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(suffix) ? 50 : 0);
|
|
32408
|
+
return { score, ranges: mergedRanges };
|
|
32409
|
+
};
|
|
31479
32410
|
}
|
|
31480
32411
|
|
|
31481
32412
|
// web-src/core/search-palette.ts
|
|
@@ -31508,6 +32439,7 @@ code-viewer query agent-help`
|
|
|
31508
32439
|
getServerGeneration
|
|
31509
32440
|
} = deps;
|
|
31510
32441
|
let PALETTE = null;
|
|
32442
|
+
let repoFileRequestGeneration = 0;
|
|
31511
32443
|
const REPO_FILE_CACHE = new Map;
|
|
31512
32444
|
function paletteSource() {
|
|
31513
32445
|
if (STATE.route.screen === "diff")
|
|
@@ -31718,7 +32650,6 @@ code-viewer query agent-help`
|
|
|
31718
32650
|
throw new Error("failed to load files");
|
|
31719
32651
|
return r2.json();
|
|
31720
32652
|
}));
|
|
31721
|
-
REPO_FILE_CACHE.set(cacheKey, res);
|
|
31722
32653
|
return res;
|
|
31723
32654
|
}
|
|
31724
32655
|
function diffFilePaletteItems(state, query) {
|
|
@@ -31770,10 +32701,19 @@ code-viewer query agent-help`
|
|
|
31770
32701
|
} else {
|
|
31771
32702
|
state.status.textContent = "Loading files...";
|
|
31772
32703
|
const ref = paletteRef(source);
|
|
31773
|
-
const
|
|
31774
|
-
|
|
32704
|
+
const requestGeneration = ++repoFileRequestGeneration;
|
|
32705
|
+
let response;
|
|
32706
|
+
try {
|
|
32707
|
+
response = await repoPaletteFiles(ref);
|
|
32708
|
+
} catch (err) {
|
|
32709
|
+
if (requestGeneration !== repoFileRequestGeneration)
|
|
32710
|
+
return;
|
|
32711
|
+
throw err;
|
|
32712
|
+
}
|
|
32713
|
+
if (PALETTE !== state || state.input.value !== query || requestGeneration !== repoFileRequestGeneration)
|
|
31775
32714
|
return;
|
|
31776
|
-
|
|
32715
|
+
REPO_FILE_CACHE.set(repoFileCacheKey(ref), response);
|
|
32716
|
+
state.items = limitPaletteResults(rankPathMatches(query, response.files, PALETTE_RESULT_LIMIT)).map((match2) => ({
|
|
31777
32717
|
kind: "file",
|
|
31778
32718
|
path: match2.item.path,
|
|
31779
32719
|
displayPath: match2.item.path,
|
|
@@ -31855,6 +32795,8 @@ code-viewer query agent-help`
|
|
|
31855
32795
|
const query = state.input.value;
|
|
31856
32796
|
if (state.mode === "file") {
|
|
31857
32797
|
updateFilePalette(state, query).catch(() => {
|
|
32798
|
+
if (PALETTE !== state || state.input.value !== query)
|
|
32799
|
+
return;
|
|
31858
32800
|
state.status.textContent = "Search failed";
|
|
31859
32801
|
});
|
|
31860
32802
|
} else {
|
|
@@ -31998,12 +32940,13 @@ code-viewer query agent-help`
|
|
|
31998
32940
|
let sourceShikiLoadPromise = null;
|
|
31999
32941
|
let PREFERRED_SOURCE_TAB = null;
|
|
32000
32942
|
let SOURCE_CURSOR = null;
|
|
32943
|
+
let SOURCE_CURSOR_ROWS = [];
|
|
32001
32944
|
const SOURCE_CURSOR_TOTALS = new Map;
|
|
32002
32945
|
function sourceLineScrollAmount() {
|
|
32003
|
-
const virtualRow =
|
|
32946
|
+
const virtualRow = document.querySelector("#content .gdp-source-virtual:not([hidden]) .gdp-source-virtual-row");
|
|
32004
32947
|
if (virtualRow)
|
|
32005
32948
|
return virtualRow.getBoundingClientRect().height || VIRTUAL_SOURCE_ROW_HEIGHT;
|
|
32006
|
-
const sourceRow =
|
|
32949
|
+
const sourceRow = document.querySelector("#content .gdp-source-table:not([hidden]) tr");
|
|
32007
32950
|
if (sourceRow)
|
|
32008
32951
|
return sourceRow.getBoundingClientRect().height || 20;
|
|
32009
32952
|
const preview = document.querySelector("#content .gdp-markdown-preview:not([hidden])");
|
|
@@ -32020,10 +32963,32 @@ code-viewer query agent-help`
|
|
|
32020
32963
|
return !!SOURCE_CURSOR && sourceTargetsEqual(SOURCE_CURSOR.target, target) && SOURCE_CURSOR.line === line;
|
|
32021
32964
|
}
|
|
32022
32965
|
function syncSourceCursorRows(target) {
|
|
32023
|
-
|
|
32024
|
-
|
|
32025
|
-
|
|
32026
|
-
|
|
32966
|
+
if (SOURCE_CURSOR_ROWS.length === 0 || SOURCE_CURSOR_ROWS.every((row) => !row.isConnected)) {
|
|
32967
|
+
SOURCE_CURSOR_ROWS = Array.from(document.querySelectorAll("#content .gdp-source-table tr.gdp-source-cursor, #content .gdp-source-virtual-row.gdp-source-cursor"));
|
|
32968
|
+
}
|
|
32969
|
+
for (const row of SOURCE_CURSOR_ROWS) {
|
|
32970
|
+
row.classList.remove("gdp-source-cursor");
|
|
32971
|
+
}
|
|
32972
|
+
SOURCE_CURSOR_ROWS = [];
|
|
32973
|
+
if (!SOURCE_CURSOR || !sourceTargetsEqual(SOURCE_CURSOR.target, target))
|
|
32974
|
+
return;
|
|
32975
|
+
const line = String(SOURCE_CURSOR.line);
|
|
32976
|
+
const table2 = document.querySelector("#content .gdp-source-table");
|
|
32977
|
+
const tableRow = table2?.rows[SOURCE_CURSOR.line - 1];
|
|
32978
|
+
if (tableRow?.dataset.line === line) {
|
|
32979
|
+
tableRow.classList.add("gdp-source-cursor");
|
|
32980
|
+
SOURCE_CURSOR_ROWS.push(tableRow);
|
|
32981
|
+
}
|
|
32982
|
+
const windowEl = document.querySelector("#content .gdp-source-virtual-window");
|
|
32983
|
+
if (windowEl) {
|
|
32984
|
+
const firstLine = Number(windowEl.firstElementChild?.dataset.line || "0");
|
|
32985
|
+
const offset = SOURCE_CURSOR.line - firstLine;
|
|
32986
|
+
const row = offset >= 0 ? windowEl.children[offset] : null;
|
|
32987
|
+
if (row?.dataset.line === line) {
|
|
32988
|
+
row.classList.add("gdp-source-cursor");
|
|
32989
|
+
SOURCE_CURSOR_ROWS.push(row);
|
|
32990
|
+
}
|
|
32991
|
+
}
|
|
32027
32992
|
}
|
|
32028
32993
|
function visibleSourceLineFallback() {
|
|
32029
32994
|
const scroller = findMainScrollTarget();
|
|
@@ -35546,7 +36511,7 @@ code-viewer query agent-help`
|
|
|
35546
36511
|
}
|
|
35547
36512
|
let SERVER_GENERATION = 0;
|
|
35548
36513
|
function trackLoad(promise) {
|
|
35549
|
-
return
|
|
36514
|
+
return promise;
|
|
35550
36515
|
}
|
|
35551
36516
|
function escapeHtml3(s2) {
|
|
35552
36517
|
return String(s2 == null ? "" : s2).replace(/[&<>"']/g, (c2) => ({
|
|
@@ -36654,6 +37619,7 @@ code-viewer query agent-help`
|
|
|
36654
37619
|
}, 200);
|
|
36655
37620
|
});
|
|
36656
37621
|
}
|
|
37622
|
+
let diffLoadGeneration = 0;
|
|
36657
37623
|
function load(options = {}) {
|
|
36658
37624
|
if (STATE.route.screen === "help") {
|
|
36659
37625
|
setStatus("live");
|
|
@@ -36688,10 +37654,11 @@ code-viewer query agent-help`
|
|
|
36688
37654
|
}
|
|
36689
37655
|
}
|
|
36690
37656
|
const routeAtRequest = STATE.route;
|
|
37657
|
+
const requestGeneration = ++diffLoadGeneration;
|
|
36691
37658
|
const fromAtRequest = STATE.from;
|
|
36692
37659
|
const toAtRequest = STATE.to;
|
|
36693
37660
|
const ignoreWsAtRequest = STATE.ignoreWs;
|
|
36694
|
-
const isCurrentDiffRequest = () => STATE.route === routeAtRequest && STATE.from === fromAtRequest && STATE.to === toAtRequest && STATE.ignoreWs === ignoreWsAtRequest;
|
|
37661
|
+
const isCurrentDiffRequest = () => requestGeneration === diffLoadGeneration && STATE.route === routeAtRequest && STATE.from === fromAtRequest && STATE.to === toAtRequest && STATE.ignoreWs === ignoreWsAtRequest;
|
|
36695
37662
|
setStatus("refreshing");
|
|
36696
37663
|
const params = new URLSearchParams;
|
|
36697
37664
|
if (STATE.ignoreWs)
|