@youtyan/code-viewer 0.8.9 → 0.9.1
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 +72 -18
- package/dist/code-viewer.js +753 -145
- package/package.json +1 -1
- package/skills/code-viewer-query/SKILL.md +3 -1
- package/web/app.js +307 -138
- package/web/style.css +28 -4
package/web/app.js
CHANGED
|
@@ -7669,15 +7669,24 @@ ${lines.join(`
|
|
|
7669
7669
|
function markdownSlugify(text2) {
|
|
7670
7670
|
return text2.trim().toLowerCase().replace(/[\s ]+/g, "-").replace(/[^\p{L}\p{N}\-_]/gu, "").slice(0, 80) || "section";
|
|
7671
7671
|
}
|
|
7672
|
-
function
|
|
7672
|
+
function resolveMarkdownLinkTarget(currentPath, href) {
|
|
7673
7673
|
if (!href || href.startsWith("#"))
|
|
7674
7674
|
return null;
|
|
7675
7675
|
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href))
|
|
7676
7676
|
return null;
|
|
7677
|
-
const
|
|
7678
|
-
|
|
7677
|
+
const hashAt = href.indexOf("#");
|
|
7678
|
+
const hash = hashAt < 0 ? "" : href.slice(hashAt + 1);
|
|
7679
|
+
const cleanHref = (hashAt < 0 ? href : href.slice(0, hashAt)).replace(/\?.*$/, "");
|
|
7680
|
+
if (!cleanHref)
|
|
7679
7681
|
return null;
|
|
7680
|
-
|
|
7682
|
+
const path = resolveRepoRelative(currentPath, decodeUriComponentSafe(cleanHref));
|
|
7683
|
+
if (path == null)
|
|
7684
|
+
return null;
|
|
7685
|
+
return {
|
|
7686
|
+
path,
|
|
7687
|
+
hash: decodeUriComponentSafe(hash),
|
|
7688
|
+
directory: cleanHref.endsWith("/")
|
|
7689
|
+
};
|
|
7681
7690
|
}
|
|
7682
7691
|
function resolveMarkdownAssetPath(currentPath, src) {
|
|
7683
7692
|
if (!src || src.startsWith("#") || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(src))
|
|
@@ -7685,6 +7694,13 @@ ${lines.join(`
|
|
|
7685
7694
|
const cleanSrc = src.split(/[?#]/, 1)[0];
|
|
7686
7695
|
return resolveRepoRelative(currentPath, cleanSrc);
|
|
7687
7696
|
}
|
|
7697
|
+
function decodeUriComponentSafe(value) {
|
|
7698
|
+
try {
|
|
7699
|
+
return decodeURIComponent(value);
|
|
7700
|
+
} catch {
|
|
7701
|
+
return value;
|
|
7702
|
+
}
|
|
7703
|
+
}
|
|
7688
7704
|
function resolveRepoRelative(currentPath, requestedPath) {
|
|
7689
7705
|
const base2 = currentPath.split("/").slice(0, -1);
|
|
7690
7706
|
const parts = [
|
|
@@ -7780,11 +7796,15 @@ ${lines.join(`
|
|
|
7780
7796
|
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
|
7781
7797
|
const token = tokens[idx];
|
|
7782
7798
|
const href = token.attrGet("href") || "";
|
|
7783
|
-
const
|
|
7784
|
-
if (
|
|
7799
|
+
const link2 = resolveMarkdownLinkTarget(target.path, href);
|
|
7800
|
+
if (link2) {
|
|
7785
7801
|
token.attrSet("href", "#");
|
|
7786
|
-
token.attrSet("data-gdp-md-link",
|
|
7802
|
+
token.attrSet("data-gdp-md-link", link2.path);
|
|
7787
7803
|
token.attrSet("data-gdp-md-ref", target.ref || "worktree");
|
|
7804
|
+
if (link2.hash)
|
|
7805
|
+
token.attrSet("data-gdp-md-hash", link2.hash);
|
|
7806
|
+
if (link2.directory)
|
|
7807
|
+
token.attrSet("data-gdp-md-dir", "1");
|
|
7788
7808
|
} else if (/^(?:https?:)?\/\//i.test(href)) {
|
|
7789
7809
|
token.attrSet("target", "_blank");
|
|
7790
7810
|
token.attrSet("rel", "noopener noreferrer");
|
|
@@ -7899,11 +7919,15 @@ ${frontmatter.yaml}
|
|
|
7899
7919
|
if (!link2)
|
|
7900
7920
|
return;
|
|
7901
7921
|
const path = link2.dataset.gdpMdLink;
|
|
7902
|
-
|
|
7903
|
-
if (!path)
|
|
7922
|
+
if (path == null)
|
|
7904
7923
|
return;
|
|
7905
7924
|
e2.preventDefault();
|
|
7906
|
-
options.onNavigateMarkdown?.(
|
|
7925
|
+
options.onNavigateMarkdown?.({
|
|
7926
|
+
path,
|
|
7927
|
+
ref: link2.dataset.gdpMdRef || target.ref,
|
|
7928
|
+
hash: link2.dataset.gdpMdHash || "",
|
|
7929
|
+
directory: link2.dataset.gdpMdDir === "1"
|
|
7930
|
+
});
|
|
7907
7931
|
});
|
|
7908
7932
|
setupMarkdownScrollSpy(root);
|
|
7909
7933
|
setupMermaidLightbox(root);
|
|
@@ -7986,12 +8010,7 @@ ${frontmatter.yaml}
|
|
|
7986
8010
|
scrollMarkdownSectionIntoView(section, "auto");
|
|
7987
8011
|
}
|
|
7988
8012
|
function decodeHashFragment(hash) {
|
|
7989
|
-
|
|
7990
|
-
try {
|
|
7991
|
-
return decodeURIComponent(value);
|
|
7992
|
-
} catch {
|
|
7993
|
-
return value;
|
|
7994
|
-
}
|
|
8013
|
+
return decodeUriComponentSafe(hash.startsWith("#") ? hash.slice(1) : hash);
|
|
7995
8014
|
}
|
|
7996
8015
|
function scrollMarkdownSectionIntoView(section, behavior) {
|
|
7997
8016
|
const top = section.getBoundingClientRect().top + window.scrollY - markdownAnchorOffset() - 12;
|
|
@@ -10309,11 +10328,21 @@ ${frontmatter.yaml}
|
|
|
10309
10328
|
var KINDS = [
|
|
10310
10329
|
"postgresql",
|
|
10311
10330
|
"mysql",
|
|
10331
|
+
"d1",
|
|
10312
10332
|
"redis",
|
|
10313
10333
|
"elasticsearch",
|
|
10314
10334
|
"s3",
|
|
10315
10335
|
"dynamodb"
|
|
10316
10336
|
];
|
|
10337
|
+
var S3_PROVIDERS = ["custom", "r2"];
|
|
10338
|
+
var R2_ENDPOINT_RE = /^https:\/\/([a-z0-9-]+)\.r2\.cloudflarestorage\.com$/i;
|
|
10339
|
+
var R2_REGION = "auto";
|
|
10340
|
+
function r2EndpointFor(accountId) {
|
|
10341
|
+
return `https://${accountId}.r2.cloudflarestorage.com`;
|
|
10342
|
+
}
|
|
10343
|
+
function r2AccountIdFromEndpoint(endpoint) {
|
|
10344
|
+
return endpoint ? R2_ENDPOINT_RE.exec(endpoint)?.[1] ?? null : null;
|
|
10345
|
+
}
|
|
10317
10346
|
function text2(language) {
|
|
10318
10347
|
return language === "ja" ? {
|
|
10319
10348
|
titleAdd: "データストア接続を追加",
|
|
@@ -10327,6 +10356,12 @@ ${frontmatter.yaml}
|
|
|
10327
10356
|
password: "パスワード",
|
|
10328
10357
|
database: "データベース",
|
|
10329
10358
|
schema: "既定スキーマ(任意)",
|
|
10359
|
+
provider: "プロバイダ",
|
|
10360
|
+
providerCustom: "S3 互換(AWS / MinIO / LocalStack)",
|
|
10361
|
+
providerR2: "Cloudflare R2",
|
|
10362
|
+
accountId: "Cloudflare アカウント ID",
|
|
10363
|
+
databaseId: "データベース ID",
|
|
10364
|
+
apiToken: "API トークン",
|
|
10330
10365
|
endpoint: "エンドポイント URL",
|
|
10331
10366
|
region: "リージョン",
|
|
10332
10367
|
accessKeyId: "アクセスキー ID",
|
|
@@ -10345,7 +10380,9 @@ ${frontmatter.yaml}
|
|
|
10345
10380
|
requestFailed: "接続情報を保存できませんでした",
|
|
10346
10381
|
deleteTitle: "保存済み接続を削除",
|
|
10347
10382
|
deleteBody: "この接続情報を削除します。タブやスナップショットのデータは削除されません。",
|
|
10348
|
-
delete: "削除"
|
|
10383
|
+
delete: "削除",
|
|
10384
|
+
secretsLeftTitle: "資格情報がキーチェーンに残りました",
|
|
10385
|
+
secretsLeftBody: "接続は削除しましたが、キーチェーンから資格情報を削除できませんでした。キーチェーンがロックされている可能性があります。ロックを解除して「キーチェーンアクセス」から code-viewer の項目を削除してください。"
|
|
10349
10386
|
} : {
|
|
10350
10387
|
titleAdd: "Add datastore connection",
|
|
10351
10388
|
titleEdit: "Edit datastore connection",
|
|
@@ -10358,6 +10395,12 @@ ${frontmatter.yaml}
|
|
|
10358
10395
|
password: "Password",
|
|
10359
10396
|
database: "Database",
|
|
10360
10397
|
schema: "Default schema (optional)",
|
|
10398
|
+
provider: "Provider",
|
|
10399
|
+
providerCustom: "S3-compatible (AWS / MinIO / LocalStack)",
|
|
10400
|
+
providerR2: "Cloudflare R2",
|
|
10401
|
+
accountId: "Cloudflare account ID",
|
|
10402
|
+
databaseId: "Database ID",
|
|
10403
|
+
apiToken: "API token",
|
|
10361
10404
|
endpoint: "Endpoint URL",
|
|
10362
10405
|
region: "Region",
|
|
10363
10406
|
accessKeyId: "Access key ID",
|
|
@@ -10376,7 +10419,9 @@ ${frontmatter.yaml}
|
|
|
10376
10419
|
requestFailed: "Failed to save the connection",
|
|
10377
10420
|
deleteTitle: "Delete saved connection",
|
|
10378
10421
|
deleteBody: "This removes the saved connection. Tabs and snapshot data are not deleted.",
|
|
10379
|
-
delete: "Delete"
|
|
10422
|
+
delete: "Delete",
|
|
10423
|
+
secretsLeftTitle: "Credentials left in the keychain",
|
|
10424
|
+
secretsLeftBody: "The connection was removed, but its credentials could not be deleted from the keychain — it may be locked. Unlock it and remove the code-viewer item from Keychain Access."
|
|
10380
10425
|
};
|
|
10381
10426
|
}
|
|
10382
10427
|
function field(labelText, input, required = false, requiredLabel = "Required") {
|
|
@@ -10440,6 +10485,21 @@ ${frontmatter.yaml}
|
|
|
10440
10485
|
database.value = current?.database ?? "";
|
|
10441
10486
|
const schema = input();
|
|
10442
10487
|
schema.value = current?.schema ?? "";
|
|
10488
|
+
const provider = document.createElement("select");
|
|
10489
|
+
for (const value of S3_PROVIDERS) {
|
|
10490
|
+
const option = document.createElement("option");
|
|
10491
|
+
option.value = value;
|
|
10492
|
+
option.textContent = value === "r2" ? labels.providerR2 : labels.providerCustom;
|
|
10493
|
+
provider.appendChild(option);
|
|
10494
|
+
}
|
|
10495
|
+
const currentR2AccountId = r2AccountIdFromEndpoint(current?.endpoint);
|
|
10496
|
+
provider.value = currentR2AccountId ? "r2" : "custom";
|
|
10497
|
+
const accountId = input();
|
|
10498
|
+
accountId.value = current?.accountId ?? currentR2AccountId ?? "";
|
|
10499
|
+
const databaseId = input();
|
|
10500
|
+
databaseId.value = current?.databaseId ?? "";
|
|
10501
|
+
const apiToken = input("password");
|
|
10502
|
+
apiToken.autocomplete = "new-password";
|
|
10443
10503
|
const endpoint = input("url");
|
|
10444
10504
|
endpoint.value = current?.endpoint ?? "http://127.0.0.1:9200";
|
|
10445
10505
|
const region = input();
|
|
@@ -10461,6 +10521,10 @@ ${frontmatter.yaml}
|
|
|
10461
10521
|
password: field(labels.password, password),
|
|
10462
10522
|
database: field(labels.database, database, true, labels.requiredField),
|
|
10463
10523
|
schema: field(labels.schema, schema),
|
|
10524
|
+
provider: field(labels.provider, provider),
|
|
10525
|
+
accountId: field(labels.accountId, accountId, true, labels.requiredField),
|
|
10526
|
+
databaseId: field(labels.databaseId, databaseId, true, labels.requiredField),
|
|
10527
|
+
apiToken: field(labels.apiToken, apiToken, true, labels.requiredField),
|
|
10464
10528
|
endpoint: field(labels.endpoint, endpoint, true, labels.requiredField),
|
|
10465
10529
|
region: field(labels.region, region, true, labels.requiredField),
|
|
10466
10530
|
accessKeyId: field(labels.accessKeyId, accessKeyId, true, labels.requiredField),
|
|
@@ -10469,21 +10533,28 @@ ${frontmatter.yaml}
|
|
|
10469
10533
|
tls: field(labels.tls, tls)
|
|
10470
10534
|
};
|
|
10471
10535
|
form.append(...Object.values(rows));
|
|
10536
|
+
const isR2 = () => kind.value === "s3" && provider.value === "r2";
|
|
10472
10537
|
const syncKind = () => {
|
|
10473
10538
|
const value = kind.value;
|
|
10474
10539
|
const sql = value === "postgresql" || value === "mysql";
|
|
10475
10540
|
const redis = value === "redis";
|
|
10476
10541
|
const http = value === "elasticsearch";
|
|
10477
10542
|
const aws = value === "s3" || value === "dynamodb";
|
|
10543
|
+
const d1 = value === "d1";
|
|
10544
|
+
const r2 = isR2();
|
|
10478
10545
|
rows.host.hidden = !sql && !redis;
|
|
10479
10546
|
rows.port.hidden = !sql && !redis;
|
|
10480
10547
|
rows.user.hidden = !sql;
|
|
10481
10548
|
rows.username.hidden = !redis && !http;
|
|
10482
|
-
rows.password.hidden = aws;
|
|
10549
|
+
rows.password.hidden = aws || d1;
|
|
10483
10550
|
rows.database.hidden = !sql;
|
|
10484
10551
|
rows.schema.hidden = value !== "postgresql";
|
|
10485
|
-
rows.
|
|
10486
|
-
rows.
|
|
10552
|
+
rows.provider.hidden = value !== "s3";
|
|
10553
|
+
rows.accountId.hidden = !d1 && !r2;
|
|
10554
|
+
rows.databaseId.hidden = !d1;
|
|
10555
|
+
rows.apiToken.hidden = !d1;
|
|
10556
|
+
rows.endpoint.hidden = !http && !aws || r2;
|
|
10557
|
+
rows.region.hidden = !aws || r2;
|
|
10487
10558
|
rows.accessKeyId.hidden = !aws;
|
|
10488
10559
|
rows.secretAccessKey.hidden = !aws;
|
|
10489
10560
|
rows.sessionToken.hidden = !aws;
|
|
@@ -10498,8 +10569,11 @@ ${frontmatter.yaml}
|
|
|
10498
10569
|
if (!current && (http || aws)) {
|
|
10499
10570
|
endpoint.value = value === "elasticsearch" ? "http://127.0.0.1:9200" : "http://127.0.0.1:4566";
|
|
10500
10571
|
}
|
|
10572
|
+
if (!current && aws)
|
|
10573
|
+
region.value = r2 ? R2_REGION : "us-east-1";
|
|
10501
10574
|
};
|
|
10502
10575
|
kind.addEventListener("change", syncKind);
|
|
10576
|
+
provider.addEventListener("change", syncKind);
|
|
10503
10577
|
syncKind();
|
|
10504
10578
|
const validateConnection = () => {
|
|
10505
10579
|
const value = kind.value;
|
|
@@ -10516,10 +10590,16 @@ ${frontmatter.yaml}
|
|
|
10516
10590
|
if ((value === "postgresql" || value === "mysql") && (!user.value.trim() || !database.value.trim())) {
|
|
10517
10591
|
return labels.required;
|
|
10518
10592
|
}
|
|
10519
|
-
if (
|
|
10593
|
+
if (value === "d1" && (!accountId.value.trim() || !databaseId.value.trim() || !apiToken.value)) {
|
|
10594
|
+
return labels.required;
|
|
10595
|
+
}
|
|
10596
|
+
if (isR2() && !accountId.value.trim()) {
|
|
10520
10597
|
return labels.required;
|
|
10521
10598
|
}
|
|
10522
|
-
if ((value === "
|
|
10599
|
+
if ((value === "elasticsearch" || value === "s3" && !isR2() || value === "dynamodb") && !endpoint.value.trim()) {
|
|
10600
|
+
return labels.required;
|
|
10601
|
+
}
|
|
10602
|
+
if ((value === "s3" || value === "dynamodb") && (!isR2() && !region.value.trim() || !accessKeyId.value.trim())) {
|
|
10523
10603
|
return labels.required;
|
|
10524
10604
|
}
|
|
10525
10605
|
return null;
|
|
@@ -10555,10 +10635,16 @@ ${frontmatter.yaml}
|
|
|
10555
10635
|
...username.value.trim() || !current ? { username: username.value.trim() || undefined } : {},
|
|
10556
10636
|
...password.value || !current ? { password: password.value } : {}
|
|
10557
10637
|
});
|
|
10638
|
+
} else if (value === "d1") {
|
|
10639
|
+
Object.assign(payload, {
|
|
10640
|
+
accountId: accountId.value.trim(),
|
|
10641
|
+
databaseId: databaseId.value.trim(),
|
|
10642
|
+
apiToken: apiToken.value
|
|
10643
|
+
});
|
|
10558
10644
|
} else {
|
|
10559
10645
|
Object.assign(payload, {
|
|
10560
|
-
endpoint: endpoint.value.trim(),
|
|
10561
|
-
region: region.value.trim(),
|
|
10646
|
+
endpoint: isR2() ? r2EndpointFor(accountId.value.trim()) : endpoint.value.trim(),
|
|
10647
|
+
region: isR2() ? R2_REGION : region.value.trim(),
|
|
10562
10648
|
...accessKeyId.value.trim() || !current ? { accessKeyId: accessKeyId.value.trim() } : {},
|
|
10563
10649
|
...secretAccessKey.value || !current ? { secretAccessKey: secretAccessKey.value } : {},
|
|
10564
10650
|
...sessionToken.value ? { sessionToken: sessionToken.value } : {}
|
|
@@ -10668,6 +10754,13 @@ ${frontmatter.yaml}
|
|
|
10668
10754
|
}));
|
|
10669
10755
|
if (!response.ok)
|
|
10670
10756
|
throw new Error(await response.text() || labels.requestFailed);
|
|
10757
|
+
const body = await response.json().catch(() => ({}));
|
|
10758
|
+
if (body.secretsRemoved === false) {
|
|
10759
|
+
await showAlertDialog({
|
|
10760
|
+
title: labels.secretsLeftTitle,
|
|
10761
|
+
body: labels.secretsLeftBody
|
|
10762
|
+
});
|
|
10763
|
+
}
|
|
10671
10764
|
return true;
|
|
10672
10765
|
}
|
|
10673
10766
|
|
|
@@ -20343,8 +20436,22 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20343
20436
|
function isAbortError2(err) {
|
|
20344
20437
|
return err instanceof DOMException && err.name === "AbortError" || err instanceof Error && err.name === "AbortError";
|
|
20345
20438
|
}
|
|
20439
|
+
var SQL_KINDS = new Set([
|
|
20440
|
+
"sqlite",
|
|
20441
|
+
"postgresql",
|
|
20442
|
+
"mysql",
|
|
20443
|
+
"d1"
|
|
20444
|
+
]);
|
|
20445
|
+
var ROW_EDITABLE_KINDS = new Set([
|
|
20446
|
+
"sqlite",
|
|
20447
|
+
"postgresql",
|
|
20448
|
+
"mysql"
|
|
20449
|
+
]);
|
|
20346
20450
|
function isSqlKind(kind) {
|
|
20347
|
-
return kind
|
|
20451
|
+
return !!kind && SQL_KINDS.has(kind);
|
|
20452
|
+
}
|
|
20453
|
+
function isRowEditableKind(kind) {
|
|
20454
|
+
return !!kind && ROW_EDITABLE_KINDS.has(kind);
|
|
20348
20455
|
}
|
|
20349
20456
|
function isPostgresKind(kind) {
|
|
20350
20457
|
return kind === "postgresql";
|
|
@@ -20700,7 +20807,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20700
20807
|
cb.onStateChange();
|
|
20701
20808
|
},
|
|
20702
20809
|
getText: () => paneText(),
|
|
20703
|
-
getEditable: () =>
|
|
20810
|
+
getEditable: () => isRowEditableKind(currentDbInfo?.kind),
|
|
20704
20811
|
applyMutations: (mutations) => applyRowMutations(mutations),
|
|
20705
20812
|
onRefreshComplete: ({ table: table2, filters }) => {
|
|
20706
20813
|
if (filters.length === 0) {
|
|
@@ -23241,7 +23348,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23241
23348
|
const span = document.createElement("span");
|
|
23242
23349
|
span.className = `badge ${ch}`;
|
|
23243
23350
|
span.textContent = ch;
|
|
23244
|
-
span.title = {
|
|
23351
|
+
span.title = {
|
|
23352
|
+
M: "modified",
|
|
23353
|
+
A: "added",
|
|
23354
|
+
D: "deleted",
|
|
23355
|
+
R: "renamed",
|
|
23356
|
+
U: "untracked",
|
|
23357
|
+
I: "ignored"
|
|
23358
|
+
}[ch] || ch;
|
|
23245
23359
|
return span;
|
|
23246
23360
|
}
|
|
23247
23361
|
function setFileViewed(path, viewed) {
|
|
@@ -26304,6 +26418,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
26304
26418
|
kind: "paragraph",
|
|
26305
26419
|
text: "A file detail page exposes up to four tabs — Preview, Code, Blame, History. For text files Code is the default and ?preview=1 opts in to the Markdown / HTML preview; media files (images, video, audio, PDF) show a Preview tab only, with no Code tab. Blame and History have their own canonical URLs (view=blame, view=history) so deep links and the browser back/forward stay in sync, and they keep the Repository sidebar visible. Opening another file from the repository tree keeps the active tab (a file that cannot be previewed falls back to Code)."
|
|
26306
26420
|
},
|
|
26421
|
+
{
|
|
26422
|
+
kind: "paragraph",
|
|
26423
|
+
text: "Relative links inside a Markdown preview lead to the same destinations as they do on GitHub: another Markdown file opens its file page, an #anchor opens the preview and scrolls to that heading, a non-Markdown file opens in the Code view, and a link to a directory opens that folder in the repository tree."
|
|
26424
|
+
},
|
|
26307
26425
|
{
|
|
26308
26426
|
kind: "paragraph",
|
|
26309
26427
|
text: "When the repository remote is on GitHub, repository and file headers can open the current path there. Selecting source lines also exposes separate actions to copy the AI reference, open the exact GitHub line range, or copy its URL. Markdown and HTML diff cards include a direct Preview shortcut."
|
|
@@ -26314,7 +26432,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
26314
26432
|
},
|
|
26315
26433
|
{
|
|
26316
26434
|
kind: "paragraph",
|
|
26317
|
-
text: 'Symlinks show a distinct icon and a "→ target" label so they are never mistaken for a regular file or folder, and clicking one navigates to its resolved target. A broken symlink is visually flagged and disabled.
|
|
26435
|
+
text: 'Symlinks show a distinct icon and a "→ target" label so they are never mistaken for a regular file or folder, and clicking one navigates to its resolved target. A broken symlink is visually flagged and disabled.'
|
|
26436
|
+
},
|
|
26437
|
+
{
|
|
26438
|
+
kind: "paragraph",
|
|
26439
|
+
text: "Files with pending git changes show a status badge in the tree instead of the regular type icon: M (modified), A (added — staged for commit), D (deleted), R (renamed), U (untracked — in the worktree but not under version control yet), and I (ignored by a .gitignore rule). U and A stay separate so a file you have never run git add on does not look like one that is already staged. A wholly untracked or ignored directory is badged as a whole and keeps its folder icon, so it stays recognizable while collapsed; its contents inherit the badge unless an ignore rule names a file specifically."
|
|
26318
26440
|
}
|
|
26319
26441
|
]
|
|
26320
26442
|
},
|
|
@@ -26555,7 +26677,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
26555
26677
|
database: {
|
|
26556
26678
|
nav: "Datastores",
|
|
26557
26679
|
title: "Datastore Viewer",
|
|
26558
|
-
intro: "Browse SQLite files, Docker-hosted databases, Redis, Elasticsearch, DynamoDB, and S3-compatible object stores from one local viewer.",
|
|
26680
|
+
intro: "Browse SQLite files, Docker-hosted databases, Cloudflare D1, Redis, Elasticsearch, DynamoDB, and S3-compatible object stores (including Cloudflare R2) from one local viewer.",
|
|
26559
26681
|
groups: [
|
|
26560
26682
|
{
|
|
26561
26683
|
title: "Supported datastores",
|
|
@@ -26565,7 +26687,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
26565
26687
|
rows: [
|
|
26566
26688
|
[
|
|
26567
26689
|
"Saved connections",
|
|
26568
|
-
"Use + beside the datastore selector to add an arbitrary PostgreSQL, MySQL, Redis, Elasticsearch, S3-compatible, or DynamoDB endpoint. Required fields are marked, and Test connection verifies the current values before saving. Drivers are included, so no database CLI or curl is required. Non-secret settings are saved locally;
|
|
26690
|
+
"Use + beside the datastore selector to add an arbitrary PostgreSQL, MySQL, Cloudflare D1, Redis, Elasticsearch, S3-compatible (including a Cloudflare R2 preset), or DynamoDB endpoint. Required fields are marked, and Test connection verifies the current values before saving. Drivers are included, so no database CLI or curl is required. Non-secret settings are saved locally; credentials are never written into the repository — on macOS they are kept in the Keychain so they survive a restart, and elsewhere they stay in server memory and must be entered again."
|
|
26569
26691
|
],
|
|
26570
26692
|
[
|
|
26571
26693
|
"SQLite",
|
|
@@ -26579,6 +26701,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
26579
26701
|
"PostgreSQL",
|
|
26580
26702
|
"Detected from compose files. Multiple databases per server, plus a schema selector for switching schemas without reopening. Same inline row edit / insert / delete as SQLite. Local Supabase CLI (`supabase start`) projects are also auto-discovered from `supabase/config.toml`, without needing a docker-compose file."
|
|
26581
26703
|
],
|
|
26704
|
+
[
|
|
26705
|
+
"Cloudflare D1",
|
|
26706
|
+
"Added as a saved connection with an account ID, database ID, and API token (needs D1:Read). Browsed over the D1 REST API and reuses the SQL screens — table list, row grid, query editor, schema, ER diagram, snapshots and diffs. Read-only: the query editor accepts SELECT / PRAGMA / EXPLAIN / WITH only, and grid Edit mode is not offered."
|
|
26707
|
+
],
|
|
26582
26708
|
[
|
|
26583
26709
|
"Redis",
|
|
26584
26710
|
"Detected from compose files. Browse DB 0-15, SCAN keys, dedicated string/hash/list panes, JSON view for set/zset/stream. Edit values, delete keys, and create new keys (all types) via in-pane editors. Participates in snapshots and diffs."
|
|
@@ -26592,8 +26718,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
26592
26718
|
"Detected when DynamoDB is enabled on a LocalStack compose service. List tables, browse a Structure tab (key schema, GSI/LSI, and non-key attribute types inferred from loaded items), scan or query items, follow pagination tokens, and open item details with a copyable key. Browsing is read-only."
|
|
26593
26719
|
],
|
|
26594
26720
|
[
|
|
26595
|
-
"S3 / MinIO / LocalStack",
|
|
26596
|
-
"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."
|
|
26721
|
+
"S3 / MinIO / LocalStack / Cloudflare R2",
|
|
26722
|
+
"Detected from compose files, or added as a saved connection. R2 uses the Cloudflare R2 provider preset: enter the account ID and an R2 access key pair, and the endpoint and the required auto signing region are filled in. 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."
|
|
26597
26723
|
]
|
|
26598
26724
|
]
|
|
26599
26725
|
}
|
|
@@ -26987,6 +27113,10 @@ code-viewer query agent-help`
|
|
|
26987
27113
|
kind: "paragraph",
|
|
26988
27114
|
text: "ファイル詳細ページには最大 4 つのタブ (Preview / Code / Blame / History) があります。テキストファイルは Code がデフォルトで、?preview=1 を付けると Markdown / HTML プレビューに切り替わります。画像・動画・音声・PDF などのメディアファイルは Preview タブのみ表示され、Code タブは表示されません。Blame と History はそれぞれ専用 URL (view=blame, view=history) を持つため、ディープリンクとブラウザの戻る / 進むが同期し、いずれも Repository サイドバーは表示されたままです。ツリーから別のファイルを開いても選択中のタブは維持されます (プレビューできないファイルでは Code に戻ります)。"
|
|
26989
27115
|
},
|
|
27116
|
+
{
|
|
27117
|
+
kind: "paragraph",
|
|
27118
|
+
text: "Markdown プレビュー内の相対リンクは GitHub と同じ行き先に解決されます。別の Markdown ファイルはそのファイルページを開き、#見出し 付きのリンクはプレビューを開いて該当見出しまでスクロールし、Markdown 以外のファイルは Code ビュー、ディレクトリへのリンクはリポジトリツリーのそのフォルダを開きます。"
|
|
27119
|
+
},
|
|
26990
27120
|
{
|
|
26991
27121
|
kind: "paragraph",
|
|
26992
27122
|
text: "リポジトリの remote が GitHub の場合、リポジトリとファイルのヘッダーから現在のパスを GitHub で開けます。ソース行を選択すると、AI 参照のコピー、選択行範囲を GitHub で開く、GitHub URL のコピーを個別に選べます。Markdown / HTML の diff カードには直接 Preview を開く導線も表示されます。"
|
|
@@ -26997,7 +27127,11 @@ code-viewer query agent-help`
|
|
|
26997
27127
|
},
|
|
26998
27128
|
{
|
|
26999
27129
|
kind: "paragraph",
|
|
27000
|
-
text: "シンボリックリンクは専用アイコンと「→
|
|
27130
|
+
text: "シンボリックリンクは専用アイコンと「→ リンク先」ラベルで表示されるため通常のファイル/フォルダと区別でき、クリックするとリンク先に遷移します。リンク切れのシンボリックリンクは無効化されたことが分かる表示になります。"
|
|
27131
|
+
},
|
|
27132
|
+
{
|
|
27133
|
+
kind: "paragraph",
|
|
27134
|
+
text: "git の状態があるファイルは、通常の種類アイコンの代わりにステータスバッジがツリーに表示されます。M(変更)、A(追加 — コミット予定としてステージ済み)、D(削除)、R(リネーム)、U(未追跡 — ワークツリーにあるがまだバージョン管理下にない)、I(.gitignore の対象) の 6 種類です。U と A を分けているのは、git add をまだ一度もしていないファイルが、既にステージ済みのファイルと同じ見た目にならないようにするためです。丸ごと未追跡・無視のディレクトリにはディレクトリ単位でバッジが付き、フォルダアイコンは残るので折りたたんだままでも判別できます。配下のファイルはそのバッジを引き継ぎますが、無視ルールが個別に名指ししているファイルはそちらが優先されます。"
|
|
27001
27135
|
}
|
|
27002
27136
|
]
|
|
27003
27137
|
},
|
|
@@ -27238,7 +27372,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
27238
27372
|
database: {
|
|
27239
27373
|
nav: "データストア",
|
|
27240
27374
|
title: "データストアビューア",
|
|
27241
|
-
intro: "SQLite ファイル、Docker 上のデータベース、Redis、Elasticsearch、DynamoDB、S3
|
|
27375
|
+
intro: "SQLite ファイル、Docker 上のデータベース、Cloudflare D1、Redis、Elasticsearch、DynamoDB、S3 互換オブジェクトストア (Cloudflare R2 を含む) をローカルビューアで閲覧できます。",
|
|
27242
27376
|
groups: [
|
|
27243
27377
|
{
|
|
27244
27378
|
title: "対応データストア",
|
|
@@ -27248,7 +27382,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
27248
27382
|
rows: [
|
|
27249
27383
|
[
|
|
27250
27384
|
"保存済み接続",
|
|
27251
|
-
"データストア選択の横にある + から、任意の PostgreSQL、MySQL、Redis、Elasticsearch、S3
|
|
27385
|
+
"データストア選択の横にある + から、任意の PostgreSQL、MySQL、Cloudflare D1、Redis、Elasticsearch、S3 互換 (Cloudflare R2 プリセットあり)、DynamoDB エンドポイントを追加できます。必須項目にはマークが付き、保存前に「接続テスト」で入力内容を確認できます。ドライバーは同梱されているため、データベース CLI や curl は不要です。非機密設定はローカルに保存されます。資格情報はリポジトリ配下には一切書かれず、macOS ではキーチェーンに保存されるため再起動をまたいで保持されます (それ以外の OS ではサーバーメモリのみで、再起動後は再入力が必要です)。"
|
|
27252
27386
|
],
|
|
27253
27387
|
[
|
|
27254
27388
|
"SQLite",
|
|
@@ -27262,6 +27396,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
27262
27396
|
"PostgreSQL",
|
|
27263
27397
|
"compose ファイルから検出。同一サーバー上の複数データベースに対応し、スキーマ切替セレクターで再オープンせずスキーマを切り替えられます。SQLite と同じく行のインライン編集 / 追加 / 削除に対応。ローカルの Supabase CLI (`supabase start`) プロジェクトも `supabase/config.toml` から自動検出され、docker-compose ファイルは不要です。"
|
|
27264
27398
|
],
|
|
27399
|
+
[
|
|
27400
|
+
"Cloudflare D1",
|
|
27401
|
+
"アカウント ID・データベース ID・API トークン (D1:Read 権限が必要) を入力して保存済み接続として追加します。D1 REST API 経由で閲覧し、SQL 系の画面 (テーブル一覧・行グリッド・クエリエディタ・スキーマ・ER 図・スナップショット/差分) をそのまま使えます。閲覧専用で、クエリエディタは SELECT / PRAGMA / EXPLAIN / WITH のみ受け付け、グリッドの Edit モードは表示されません。"
|
|
27402
|
+
],
|
|
27265
27403
|
[
|
|
27266
27404
|
"Redis",
|
|
27267
27405
|
"compose ファイルから検出。DB 0-15 を SCAN し、string/hash/list は専用ペイン、set/zset/stream は JSON ビュー。値の編集 / キー削除 / 新規キー作成 (全タイプ) に対応。スナップショット/差分にも参加します。"
|
|
@@ -27275,8 +27413,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
27275
27413
|
"LocalStack の compose サービスで DynamoDB が有効な場合に検出。テーブル一覧、構造タブ(キースキーマ・GSI/LSI・読み込み済みアイテムから推測した非キー属性の型)、scan / query、継続トークンによるページング、コピー可能なキー付きのアイテム詳細を表示します。閲覧専用です。"
|
|
27276
27414
|
],
|
|
27277
27415
|
[
|
|
27278
|
-
"S3 / MinIO / LocalStack",
|
|
27279
|
-
"compose
|
|
27416
|
+
"S3 / MinIO / LocalStack / Cloudflare R2",
|
|
27417
|
+
"compose ファイルから検出するほか、保存済み接続としても追加できます。R2 は「Cloudflare R2」プロバイダプリセットを選び、アカウント ID と R2 のアクセスキーを入力すればエンドポイントと必須リージョン auto が自動で入ります。フォルダツリー型ブラウザ、prefix/ファイル名検索、更新日時順表示、画像/動画/音声/PDF/Markdown/HTML/テキストのプレビューに対応。テキスト/Markdown/JSON のインライン編集、新規オブジェクトアップロード、オブジェクト削除も可能。LocalStack はホストポート未公開時 `docker exec curl` にフォールバックしますが、MinIO はホストポート公開が必須です。"
|
|
27280
27418
|
]
|
|
27281
27419
|
]
|
|
27282
27420
|
}
|
|
@@ -30831,6 +30969,59 @@ code-viewer query agent-help`
|
|
|
30831
30969
|
return trimmed;
|
|
30832
30970
|
}
|
|
30833
30971
|
|
|
30972
|
+
// web-src/views/markdown-link-navigation.ts
|
|
30973
|
+
async function openMarkdownLink(target, deps) {
|
|
30974
|
+
const ref = target.ref || "worktree";
|
|
30975
|
+
const routeAtClick = currentRouteKey();
|
|
30976
|
+
const directory = await isMarkdownDirectoryLink(target, deps);
|
|
30977
|
+
if (directory === null || currentRouteKey() !== routeAtClick)
|
|
30978
|
+
return;
|
|
30979
|
+
if (directory) {
|
|
30980
|
+
deps.setRoute(deps.repoRoute(ref, target.path));
|
|
30981
|
+
await deps.loadRepo();
|
|
30982
|
+
return;
|
|
30983
|
+
}
|
|
30984
|
+
const anchorInMarkdown = !!target.hash && sourcePreviewKind(target.path) === "markdown";
|
|
30985
|
+
deps.setRoute({
|
|
30986
|
+
screen: "file",
|
|
30987
|
+
path: target.path,
|
|
30988
|
+
ref,
|
|
30989
|
+
view: "blob",
|
|
30990
|
+
...anchorInMarkdown ? { preview: true } : {},
|
|
30991
|
+
range: deps.currentRange()
|
|
30992
|
+
});
|
|
30993
|
+
applyMarkdownLinkHash(target.hash);
|
|
30994
|
+
await deps.renderStandaloneSource({ path: target.path, ref });
|
|
30995
|
+
}
|
|
30996
|
+
function currentRouteKey() {
|
|
30997
|
+
return window.location.pathname + window.location.search;
|
|
30998
|
+
}
|
|
30999
|
+
async function isMarkdownDirectoryLink(target, deps) {
|
|
31000
|
+
if (target.directory)
|
|
31001
|
+
return true;
|
|
31002
|
+
if (!target.path)
|
|
31003
|
+
return true;
|
|
31004
|
+
const name = target.path.split("/").pop() || "";
|
|
31005
|
+
if (/.\.[^.]+$/.test(name))
|
|
31006
|
+
return false;
|
|
31007
|
+
try {
|
|
31008
|
+
const res = await deps.trackLoad(fetch(buildRawFileUrl({ path: target.path, ref: target.ref }), {
|
|
31009
|
+
method: "HEAD"
|
|
31010
|
+
}));
|
|
31011
|
+
return res.status === 404;
|
|
31012
|
+
} catch (err) {
|
|
31013
|
+
if (deps.isAbortError(err))
|
|
31014
|
+
return null;
|
|
31015
|
+
return false;
|
|
31016
|
+
}
|
|
31017
|
+
}
|
|
31018
|
+
function applyMarkdownLinkHash(hash) {
|
|
31019
|
+
if (!hash)
|
|
31020
|
+
return;
|
|
31021
|
+
const base2 = window.location.pathname + window.location.search;
|
|
31022
|
+
history.replaceState(history.state, "", `${base2}#${encodeURIComponent(hash)}`);
|
|
31023
|
+
}
|
|
31024
|
+
|
|
30834
31025
|
// web-src/views/repository-web-link.ts
|
|
30835
31026
|
function createRepositoryWebLink(target, label) {
|
|
30836
31027
|
const link2 = document.createElement("a");
|
|
@@ -31059,6 +31250,43 @@ code-viewer query agent-help`
|
|
|
31059
31250
|
function toggleSidebarHidden() {
|
|
31060
31251
|
applySidebarHidden(!STATE.sidebarHidden);
|
|
31061
31252
|
}
|
|
31253
|
+
function applyDirEntryToNode(node, entry) {
|
|
31254
|
+
node.explicit = true;
|
|
31255
|
+
if (entry.children_omitted === true) {
|
|
31256
|
+
node.children_omitted = true;
|
|
31257
|
+
node.children_omitted_reason = entry.children_omitted_reason;
|
|
31258
|
+
}
|
|
31259
|
+
if (entry.is_symlink) {
|
|
31260
|
+
node.is_symlink = true;
|
|
31261
|
+
node.symlink_target = entry.symlink_target;
|
|
31262
|
+
node.resolved_path = entry.resolved_path;
|
|
31263
|
+
}
|
|
31264
|
+
if (entry.status)
|
|
31265
|
+
node.status = entry.status;
|
|
31266
|
+
}
|
|
31267
|
+
function createTreeDirLabel(dir) {
|
|
31268
|
+
const label = document.createElement("span");
|
|
31269
|
+
label.className = "dir-label";
|
|
31270
|
+
const dn = document.createElement("span");
|
|
31271
|
+
dn.className = "dir-name";
|
|
31272
|
+
dn.textContent = dir.name;
|
|
31273
|
+
dn.title = dir.path;
|
|
31274
|
+
label.appendChild(dn);
|
|
31275
|
+
if (dir.status)
|
|
31276
|
+
label.appendChild(fileBadge(dir.status));
|
|
31277
|
+
if (dir.children_omitted) {
|
|
31278
|
+
const omitted = document.createElement("span");
|
|
31279
|
+
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
31280
|
+
const badge = omittedDirectoryBadge(dir.children_omitted_reason);
|
|
31281
|
+
omitted.textContent = badge.label;
|
|
31282
|
+
omitted.title = badge.title;
|
|
31283
|
+
label.appendChild(omitted);
|
|
31284
|
+
}
|
|
31285
|
+
const dirSymlinkLabel = symlinkTargetLabel(dir);
|
|
31286
|
+
if (dirSymlinkLabel)
|
|
31287
|
+
label.appendChild(dirSymlinkLabel);
|
|
31288
|
+
return label;
|
|
31289
|
+
}
|
|
31062
31290
|
function buildTree(files) {
|
|
31063
31291
|
const root = {
|
|
31064
31292
|
name: "",
|
|
@@ -31090,16 +31318,7 @@ code-viewer query agent-help`
|
|
|
31090
31318
|
node.minOrder = f2.order;
|
|
31091
31319
|
}
|
|
31092
31320
|
if (f2.type === "tree") {
|
|
31093
|
-
node
|
|
31094
|
-
if (f2.children_omitted === true) {
|
|
31095
|
-
node.children_omitted = true;
|
|
31096
|
-
node.children_omitted_reason = f2.children_omitted_reason;
|
|
31097
|
-
}
|
|
31098
|
-
if (f2.is_symlink) {
|
|
31099
|
-
node.is_symlink = true;
|
|
31100
|
-
node.symlink_target = f2.symlink_target;
|
|
31101
|
-
node.resolved_path = f2.resolved_path;
|
|
31102
|
-
}
|
|
31321
|
+
applyDirEntryToNode(node, f2);
|
|
31103
31322
|
continue;
|
|
31104
31323
|
}
|
|
31105
31324
|
node.files.push(f2);
|
|
@@ -31169,25 +31388,7 @@ code-viewer query agent-help`
|
|
|
31169
31388
|
const dirIcon = document.createElement("span");
|
|
31170
31389
|
dirIcon.className = "dir-icon";
|
|
31171
31390
|
li.appendChild(dirIcon);
|
|
31172
|
-
|
|
31173
|
-
label.className = "dir-label";
|
|
31174
|
-
const dn = document.createElement("span");
|
|
31175
|
-
dn.className = "dir-name";
|
|
31176
|
-
dn.textContent = dir.name;
|
|
31177
|
-
dn.title = dir.path;
|
|
31178
|
-
label.appendChild(dn);
|
|
31179
|
-
if (dir.children_omitted) {
|
|
31180
|
-
const omitted = document.createElement("span");
|
|
31181
|
-
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
31182
|
-
const badge = omittedDirectoryBadge(dir.children_omitted_reason);
|
|
31183
|
-
omitted.textContent = badge.label;
|
|
31184
|
-
omitted.title = badge.title;
|
|
31185
|
-
label.appendChild(omitted);
|
|
31186
|
-
}
|
|
31187
|
-
const dirSymlinkLabel = symlinkTargetLabel(dir);
|
|
31188
|
-
if (dirSymlinkLabel)
|
|
31189
|
-
label.appendChild(dirSymlinkLabel);
|
|
31190
|
-
li.appendChild(label);
|
|
31391
|
+
li.appendChild(createTreeDirLabel(dir));
|
|
31191
31392
|
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
31192
31393
|
const collapsed = STATE.collapsedDirs.has(dir.path);
|
|
31193
31394
|
if (collapsed)
|
|
@@ -31284,16 +31485,7 @@ code-viewer query agent-help`
|
|
|
31284
31485
|
node.minOrder = Math.min(node.minOrder, order);
|
|
31285
31486
|
}
|
|
31286
31487
|
if (entry.type === "tree") {
|
|
31287
|
-
node
|
|
31288
|
-
if (entry.children_omitted === true) {
|
|
31289
|
-
node.children_omitted = true;
|
|
31290
|
-
node.children_omitted_reason = entry.children_omitted_reason;
|
|
31291
|
-
}
|
|
31292
|
-
if (entry.is_symlink) {
|
|
31293
|
-
node.is_symlink = true;
|
|
31294
|
-
node.symlink_target = entry.symlink_target;
|
|
31295
|
-
node.resolved_path = entry.resolved_path;
|
|
31296
|
-
}
|
|
31488
|
+
applyDirEntryToNode(node, entry);
|
|
31297
31489
|
return;
|
|
31298
31490
|
}
|
|
31299
31491
|
if (!node.files.some((file) => file.path === entry.path))
|
|
@@ -31377,25 +31569,7 @@ code-viewer query agent-help`
|
|
|
31377
31569
|
const dirIcon = document.createElement("span");
|
|
31378
31570
|
dirIcon.className = "dir-icon";
|
|
31379
31571
|
li.appendChild(dirIcon);
|
|
31380
|
-
|
|
31381
|
-
label.className = "dir-label";
|
|
31382
|
-
const dn = document.createElement("span");
|
|
31383
|
-
dn.className = "dir-name";
|
|
31384
|
-
dn.textContent = dir.name;
|
|
31385
|
-
dn.title = dir.path;
|
|
31386
|
-
label.appendChild(dn);
|
|
31387
|
-
if (dir.children_omitted) {
|
|
31388
|
-
const omitted = document.createElement("span");
|
|
31389
|
-
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
31390
|
-
const badge = omittedDirectoryBadge(dir.children_omitted_reason);
|
|
31391
|
-
omitted.textContent = badge.label;
|
|
31392
|
-
omitted.title = badge.title;
|
|
31393
|
-
label.appendChild(omitted);
|
|
31394
|
-
}
|
|
31395
|
-
const dirSymlinkLabel = symlinkTargetLabel(dir);
|
|
31396
|
-
if (dirSymlinkLabel)
|
|
31397
|
-
label.appendChild(dirSymlinkLabel);
|
|
31398
|
-
li.appendChild(label);
|
|
31572
|
+
li.appendChild(createTreeDirLabel(dir));
|
|
31399
31573
|
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
31400
31574
|
const updateIcon = () => {
|
|
31401
31575
|
setFolderIcon(dirIcon, li.classList.contains("collapsed"));
|
|
@@ -32533,6 +32707,7 @@ code-viewer query agent-help`
|
|
|
32533
32707
|
renderStandaloneSource,
|
|
32534
32708
|
repoFileTargetFromRoute,
|
|
32535
32709
|
trackLoad,
|
|
32710
|
+
isAbortError: isAbortError3,
|
|
32536
32711
|
syncSidebarHeaderHeight,
|
|
32537
32712
|
clearLoadQueue,
|
|
32538
32713
|
getProjectName,
|
|
@@ -32894,6 +33069,17 @@ code-viewer query agent-help`
|
|
|
32894
33069
|
range: currentRange()
|
|
32895
33070
|
};
|
|
32896
33071
|
}
|
|
33072
|
+
function markdownLinkNavigationDeps() {
|
|
33073
|
+
return {
|
|
33074
|
+
setRoute,
|
|
33075
|
+
currentRange,
|
|
33076
|
+
loadRepo,
|
|
33077
|
+
repoRoute,
|
|
33078
|
+
renderStandaloneSource,
|
|
33079
|
+
trackLoad,
|
|
33080
|
+
isAbortError: isAbortError3
|
|
33081
|
+
};
|
|
33082
|
+
}
|
|
32897
33083
|
function createRepoBreadcrumb(target, path) {
|
|
32898
33084
|
const nav = document.createElement("nav");
|
|
32899
33085
|
nav.className = "gdp-file-breadcrumb gdp-repo-breadcrumb";
|
|
@@ -33021,10 +33207,17 @@ code-viewer query agent-help`
|
|
|
33021
33207
|
row.className = nonBrowsableCommit ? `gdp-repo-row ${entry.type} gdp-repo-row-gitlink` : entry.is_symlink ? `gdp-repo-row ${entry.type} symlink-row${brokenSymlink ? " symlink-broken-row gdp-row-disabled" : ""}` : `gdp-repo-row ${entry.type}`;
|
|
33022
33208
|
if (deletedEntry)
|
|
33023
33209
|
row.classList.add("gdp-row-disabled");
|
|
33024
|
-
const
|
|
33210
|
+
const directoryRow = entry.type === "tree";
|
|
33211
|
+
const icon = entry.status && !directoryRow ? fileBadge(entry.status) : repoEntryTypeIcon(entry, browsable, nonBrowsableCommit);
|
|
33025
33212
|
const name = document.createElement("span");
|
|
33026
33213
|
name.className = "name";
|
|
33027
33214
|
name.textContent = entry.name;
|
|
33215
|
+
let nameCell = name;
|
|
33216
|
+
if (directoryRow && entry.status) {
|
|
33217
|
+
nameCell = document.createElement("span");
|
|
33218
|
+
nameCell.className = "name-cell";
|
|
33219
|
+
nameCell.append(name, fileBadge(entry.status));
|
|
33220
|
+
}
|
|
33028
33221
|
if (nonBrowsableCommit) {
|
|
33029
33222
|
row.title = commitEntryMeta(entry.submodule).title;
|
|
33030
33223
|
row.setAttribute("aria-disabled", "true");
|
|
@@ -33033,7 +33226,7 @@ code-viewer query agent-help`
|
|
|
33033
33226
|
}
|
|
33034
33227
|
const metaBlock = createRepoEntryMeta(entry, browsable);
|
|
33035
33228
|
const size = createRepoEntrySize(entry);
|
|
33036
|
-
row.append(icon,
|
|
33229
|
+
row.append(icon, nameCell, metaBlock, size);
|
|
33037
33230
|
row.addEventListener("click", () => {
|
|
33038
33231
|
if (brokenSymlink || deletedEntry)
|
|
33039
33232
|
return;
|
|
@@ -33087,16 +33280,7 @@ code-viewer query agent-help`
|
|
|
33087
33280
|
try {
|
|
33088
33281
|
wrapper.appendChild(await renderMarkdownPreview(meta.readme.text, { path: meta.readme.path, ref: meta.ref }, {
|
|
33089
33282
|
syntaxHighlight: STATE.syntaxHighlight,
|
|
33090
|
-
onNavigateMarkdown: (
|
|
33091
|
-
setRoute({
|
|
33092
|
-
screen: "file",
|
|
33093
|
-
path,
|
|
33094
|
-
ref,
|
|
33095
|
-
view: "blob",
|
|
33096
|
-
range: currentRange()
|
|
33097
|
-
});
|
|
33098
|
-
renderStandaloneSource({ path, ref });
|
|
33099
|
-
}
|
|
33283
|
+
onNavigateMarkdown: (link2) => void openMarkdownLink(link2, markdownLinkNavigationDeps())
|
|
33100
33284
|
}));
|
|
33101
33285
|
} catch {
|
|
33102
33286
|
const fallback = document.createElement("pre");
|
|
@@ -34321,6 +34505,17 @@ code-viewer query agent-help`
|
|
|
34321
34505
|
focusMainSurface,
|
|
34322
34506
|
isPaletteOpen
|
|
34323
34507
|
} = deps;
|
|
34508
|
+
function markdownLinkNavigationDeps() {
|
|
34509
|
+
return {
|
|
34510
|
+
setRoute,
|
|
34511
|
+
currentRange,
|
|
34512
|
+
loadRepo,
|
|
34513
|
+
repoRoute,
|
|
34514
|
+
renderStandaloneSource,
|
|
34515
|
+
trackLoad,
|
|
34516
|
+
isAbortError: isAbortError3
|
|
34517
|
+
};
|
|
34518
|
+
}
|
|
34324
34519
|
const VIRTUAL_SOURCE_LINE_THRESHOLD = 3000;
|
|
34325
34520
|
const VIRTUAL_SOURCE_SIZE_THRESHOLD = 1024 * 1024;
|
|
34326
34521
|
const VIRTUAL_SOURCE_PAGE_SIZE = 2000;
|
|
@@ -34562,16 +34757,7 @@ code-viewer query agent-help`
|
|
|
34562
34757
|
(deps.renderMarkdownPreview ?? renderMarkdownPreview)(textValue, target, {
|
|
34563
34758
|
syntaxHighlight: true,
|
|
34564
34759
|
signal,
|
|
34565
|
-
onNavigateMarkdown: (
|
|
34566
|
-
setRoute({
|
|
34567
|
-
screen: "file",
|
|
34568
|
-
path,
|
|
34569
|
-
ref,
|
|
34570
|
-
view: "blob",
|
|
34571
|
-
range: currentRange()
|
|
34572
|
-
});
|
|
34573
|
-
renderStandaloneSource({ path, ref });
|
|
34574
|
-
}
|
|
34760
|
+
onNavigateMarkdown: (link2) => void openMarkdownLink(link2, markdownLinkNavigationDeps())
|
|
34575
34761
|
}).then((next) => {
|
|
34576
34762
|
if (signal?.aborted || !preview.isConnected || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
34577
34763
|
return;
|
|
@@ -34856,16 +35042,7 @@ code-viewer query agent-help`
|
|
|
34856
35042
|
let preview = previewKind === "html" ? renderHtmlPreview(target, textValue) : await (deps.renderMarkdownPreview ?? renderMarkdownPreview)(textValue, target, {
|
|
34857
35043
|
syntaxHighlight: false,
|
|
34858
35044
|
signal,
|
|
34859
|
-
onNavigateMarkdown: (
|
|
34860
|
-
setRoute({
|
|
34861
|
-
screen: "file",
|
|
34862
|
-
path,
|
|
34863
|
-
ref,
|
|
34864
|
-
view: "blob",
|
|
34865
|
-
range: currentRange()
|
|
34866
|
-
});
|
|
34867
|
-
renderStandaloneSource({ path, ref });
|
|
34868
|
-
}
|
|
35045
|
+
onNavigateMarkdown: (link2) => void openMarkdownLink(link2, markdownLinkNavigationDeps())
|
|
34869
35046
|
});
|
|
34870
35047
|
if (signal?.aborted)
|
|
34871
35048
|
return false;
|
|
@@ -34956,16 +35133,7 @@ code-viewer query agent-help`
|
|
|
34956
35133
|
let preview = previewKind === "html" ? renderHtmlPreview(target, textValue) : await (deps.renderMarkdownPreview ?? renderMarkdownPreview)(textValue, target, {
|
|
34957
35134
|
syntaxHighlight: false,
|
|
34958
35135
|
signal,
|
|
34959
|
-
onNavigateMarkdown: (
|
|
34960
|
-
setRoute({
|
|
34961
|
-
screen: "file",
|
|
34962
|
-
path,
|
|
34963
|
-
ref,
|
|
34964
|
-
view: "blob",
|
|
34965
|
-
range: currentRange()
|
|
34966
|
-
});
|
|
34967
|
-
renderStandaloneSource({ path, ref });
|
|
34968
|
-
}
|
|
35136
|
+
onNavigateMarkdown: (link2) => void openMarkdownLink(link2, markdownLinkNavigationDeps())
|
|
34969
35137
|
});
|
|
34970
35138
|
if (signal?.aborted)
|
|
34971
35139
|
return false;
|
|
@@ -36754,6 +36922,7 @@ code-viewer query agent-help`
|
|
|
36754
36922
|
renderStandaloneSource,
|
|
36755
36923
|
repoFileTargetFromRoute,
|
|
36756
36924
|
trackLoad,
|
|
36925
|
+
isAbortError: isAbortError3,
|
|
36757
36926
|
syncSidebarHeaderHeight,
|
|
36758
36927
|
clearLoadQueue: () => DIFF_VIEW.clearLoadQueue(),
|
|
36759
36928
|
getProjectName: () => PROJECT_NAME,
|