@kubohiroya/turbowarp-plus-editor-git 0.16.1 → 0.18.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.ja.md +18 -2
- package/README.md +17 -1
- package/dist/branch-button.d.ts +32 -0
- package/dist/filesystem.d.ts +2 -2
- package/dist/github-pull-requests.d.ts +20 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.js +739 -158
- package/dist/local-operations.d.ts +8 -1
- package/dist/messages.d.ts +16 -2
- package/dist/{project-asset-paths-KV715791.js → project-asset-paths-BzwVf9HE.js} +653 -1
- package/dist/{project-comparison-1rggIJse.js → project-comparison-BXOQcZ73.js} +10 -654
- package/dist/project-source-diff.js +2 -1
- package/dist/pull-request-panel.d.ts +25 -1
- package/dist/remote-operations.d.ts +23 -0
- package/dist/{repository-BYno-5f8.js → repository-ByKRBftJ.js} +370 -14
- package/dist/repository.d.ts +39 -0
- package/dist/repository.js +1 -1
- package/dist/style.css +28 -0
- package/package.json +1 -1
- package/src/branch-button.tsx +216 -0
- package/src/filesystem.ts +2 -1
- package/src/github-pull-requests.ts +7 -0
- package/src/index.tsx +213 -67
- package/src/local-operations.ts +23 -3
- package/src/messages.ts +14 -4
- package/src/pull-request-panel.tsx +125 -14
- package/src/remote-operations.ts +84 -3
- package/src/repository.ts +155 -9
- package/src/style.css +28 -0
- package/test/smart-http-fixture.js +20 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as openProjectSourceTabs, b as useCostumeImage, c as gitHubRepositoryFromOrigin, f as organizeProjectChanges, i as createScratchBlocksDiffLocator, l as ProjectSourceComparison, n as openProjectComparison, o as PullRequestError, p as projectPropertyLabel, r as createScratchBlocksDiffRenderer, s as createGitHubPullRequests, u as ProjectSourceReview, x as CloseButton, y as useAssetImage } from "./project-comparison-BXOQcZ73.js";
|
|
2
2
|
import { n as init_objectSpread2, r as __commonJSMin, t as _objectSpread2$1 } from "./objectSpread2-Dkd68nJH.js";
|
|
3
|
-
import {
|
|
3
|
+
import { f as _objectWithoutProperties$1, l as parseProjectSource, u as readProjectSourceDiff } from "./project-asset-paths-BzwVf9HE.js";
|
|
4
|
+
import { a as pullRequestRef, i as pullRequestBranch, n as openRepository, o as GitPanelError, s as createReadOnlyFs } from "./repository-ByKRBftJ.js";
|
|
4
5
|
import * as m from "react";
|
|
5
|
-
import React, { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import React, { createContext, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
7
|
import { createPortal, render, unmountComponentAtNode } from "react-dom";
|
|
7
8
|
// builtin:esm-external-require-react
|
|
8
9
|
var require_builtin_esm_external_require_react = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -3025,91 +3026,12 @@ function ProjectElementView({ changes, selection, locale, renderBlock, onSelectF
|
|
|
3025
3026
|
onClick: () => onSelectFile(file)
|
|
3026
3027
|
}, file.path, " ", /* @__PURE__ */ React.createElement("small", null, labels.groups[file.group])))))));
|
|
3027
3028
|
}
|
|
3028
|
-
/**
|
|
3029
|
-
* Lays out commits ordered newest first with every child above its parents. Parents missing from `commits`, such as
|
|
3030
|
-
* those on a page not loaded yet or cut off by a shallow clone, keep their lane running to the bottom.
|
|
3031
|
-
*/
|
|
3032
|
-
function layoutHistory(commits) {
|
|
3033
|
-
const lanes = [];
|
|
3034
|
-
let nextColor = 0;
|
|
3035
|
-
const free = () => {
|
|
3036
|
-
const index = lanes.indexOf(null);
|
|
3037
|
-
return index === -1 ? lanes.length : index;
|
|
3038
|
-
};
|
|
3039
|
-
const rows = [];
|
|
3040
|
-
for (const commit of commits) {
|
|
3041
|
-
const segments = [];
|
|
3042
|
-
const before = lanes.slice();
|
|
3043
|
-
const waiting = before.flatMap((lane, index) => (lane === null || lane === void 0 ? void 0 : lane.oid) === commit.oid ? [index] : []);
|
|
3044
|
-
const column = waiting.length ? waiting[0] : free();
|
|
3045
|
-
const color = waiting.length ? before[column].color : nextColor++ % 8;
|
|
3046
|
-
for (const [index, lane] of before.entries()) {
|
|
3047
|
-
if (!lane) continue;
|
|
3048
|
-
segments.push({
|
|
3049
|
-
part: "top",
|
|
3050
|
-
from: index,
|
|
3051
|
-
to: lane.oid === commit.oid ? column : index,
|
|
3052
|
-
color: lane.color
|
|
3053
|
-
});
|
|
3054
|
-
}
|
|
3055
|
-
for (const index of waiting) lanes[index] = null;
|
|
3056
|
-
const parents = [...new Set(commit.parents)];
|
|
3057
|
-
lanes[column] = parents.length ? {
|
|
3058
|
-
oid: parents[0],
|
|
3059
|
-
color
|
|
3060
|
-
} : null;
|
|
3061
|
-
const joins = parents.length ? [{
|
|
3062
|
-
index: column,
|
|
3063
|
-
color
|
|
3064
|
-
}] : [];
|
|
3065
|
-
for (const parent of parents.slice(1)) {
|
|
3066
|
-
let index = lanes.findIndex((lane) => (lane === null || lane === void 0 ? void 0 : lane.oid) === parent);
|
|
3067
|
-
if (index === -1) {
|
|
3068
|
-
index = free();
|
|
3069
|
-
lanes[index] = {
|
|
3070
|
-
oid: parent,
|
|
3071
|
-
color: nextColor++ % 8
|
|
3072
|
-
};
|
|
3073
|
-
}
|
|
3074
|
-
joins.push({
|
|
3075
|
-
index,
|
|
3076
|
-
color: lanes[index].color
|
|
3077
|
-
});
|
|
3078
|
-
}
|
|
3079
|
-
while (lanes.length && lanes[lanes.length - 1] === null) lanes.pop();
|
|
3080
|
-
for (const [index, lane] of before.entries()) if (lane && lane.oid !== commit.oid) segments.push({
|
|
3081
|
-
part: "bottom",
|
|
3082
|
-
from: index,
|
|
3083
|
-
to: index,
|
|
3084
|
-
color: lane.color
|
|
3085
|
-
});
|
|
3086
|
-
for (const join of joins) segments.push({
|
|
3087
|
-
part: "bottom",
|
|
3088
|
-
from: column,
|
|
3089
|
-
to: join.index,
|
|
3090
|
-
color: join.color
|
|
3091
|
-
});
|
|
3092
|
-
const width = Math.max(column + 1, ...segments.map((segment) => Math.max(segment.from, segment.to) + 1));
|
|
3093
|
-
rows.push({
|
|
3094
|
-
oid: commit.oid,
|
|
3095
|
-
column,
|
|
3096
|
-
color,
|
|
3097
|
-
segments,
|
|
3098
|
-
width
|
|
3099
|
-
});
|
|
3100
|
-
}
|
|
3101
|
-
return {
|
|
3102
|
-
rows,
|
|
3103
|
-
width: Math.max(0, ...rows.map((row) => row.width))
|
|
3104
|
-
};
|
|
3105
|
-
}
|
|
3106
3029
|
// src/messages.ts
|
|
3107
3030
|
var messages = {
|
|
3108
3031
|
en: {
|
|
3109
3032
|
pullRequests: "Pull requests",
|
|
3110
3033
|
localChanges: "Local changes",
|
|
3111
3034
|
title: "Local Git",
|
|
3112
|
-
menu: "Local Git…",
|
|
3113
3035
|
close: "Close",
|
|
3114
3036
|
choose: "Choose Repository…",
|
|
3115
3037
|
refresh: "Refresh",
|
|
@@ -3150,6 +3072,10 @@ var messages = {
|
|
|
3150
3072
|
commitMessage: "Write a message for this record.",
|
|
3151
3073
|
switchUnsafe: "Stop the project, and save or record (or undo) every change, before switching branches.",
|
|
3152
3074
|
branchExists: "A branch with this name already exists.",
|
|
3075
|
+
branchConflict: "This name clashes with an existing branch: Git cannot keep both a branch and another branch under its name followed by /, such as pr and pr/7. Rename or delete the other branch with Git, or choose another name.",
|
|
3076
|
+
pullRequestBranch: "The branch pr/<number> already exists with other records, so this version was not opened. The branch is left unchanged. Switch to it in Local changes, or rename or delete it with Git, then open the pull request here again.",
|
|
3077
|
+
openedPullRequest: "Opened pull request #{number} on the local branch {branch}. To go back, switch to {previous} in Local changes.",
|
|
3078
|
+
openedPullRequestDetached: "Opened pull request #{number} on the local branch {branch}. To go back, switch to another branch in Local changes.",
|
|
3153
3079
|
locked: "Another Git tool is working on this repository (a lock file, or a merge, cherry-pick, revert or rebase in progress). Try again after it finishes.",
|
|
3154
3080
|
branchName: "Git cannot use this name for a branch.",
|
|
3155
3081
|
pullUnsafe: "Stop the project, and save or undo unsaved edits and unrecorded changes, before getting changes from GitHub (pull).",
|
|
@@ -3211,13 +3137,16 @@ var messages = {
|
|
|
3211
3137
|
historyCopied: "Copied the commit ID.",
|
|
3212
3138
|
historyCopyFailed: "Could not copy the commit ID.",
|
|
3213
3139
|
historyRefs: "Branches",
|
|
3214
|
-
cancel: "Cancel"
|
|
3140
|
+
cancel: "Cancel",
|
|
3141
|
+
branchMenu: "Branches",
|
|
3142
|
+
openPanel: "Open Local Git",
|
|
3143
|
+
newBranchItem: "New Branch…",
|
|
3144
|
+
newBranchTitle: "New Branch"
|
|
3215
3145
|
},
|
|
3216
3146
|
ja: {
|
|
3217
3147
|
pullRequests: "プルリクエスト",
|
|
3218
3148
|
localChanges: "ローカルの変更",
|
|
3219
3149
|
title: "ローカル Git",
|
|
3220
|
-
menu: "ローカル Git…",
|
|
3221
3150
|
close: "閉じる",
|
|
3222
3151
|
choose: "リポジトリを選択…",
|
|
3223
3152
|
refresh: "再取得",
|
|
@@ -3258,6 +3187,10 @@ var messages = {
|
|
|
3258
3187
|
commitMessage: "この記録の説明を書いてください。",
|
|
3259
3188
|
switchUnsafe: "ブランチを切り替える前に、実行を止め、すべての変更を保存して記録(または取り消し)してください。",
|
|
3260
3189
|
branchExists: "同じ名前のブランチがすでにあります。",
|
|
3190
|
+
branchConflict: "この名前は既存のブランチとぶつかります。Git では、pr と pr/7 のように、あるブランチと、その名前に / を続けたブランチを両方は持てません。Git でもう一方の名前を変えるか消すか、別の名前にしてください。",
|
|
3191
|
+
pullRequestBranch: "ブランチ pr/<番号> が、別の記録を指してすでにあるため、この版を開きませんでした。ブランチはそのままです。「ローカルの変更」で切り替えるか、Git で名前を変えるか消してから、もう一度ここで開いてください。",
|
|
3192
|
+
openedPullRequest: "プルリクエスト #{number} を、ローカルブランチ {branch} で開きました。戻るときは「ローカルの変更」で {previous} に切り替えてください。",
|
|
3193
|
+
openedPullRequestDetached: "プルリクエスト #{number} を、ローカルブランチ {branch} で開きました。戻るときは「ローカルの変更」で別のブランチに切り替えてください。",
|
|
3261
3194
|
locked: "ほかの Git の操作が、このリポジトリを使っています(ロックファイル、またはマージ・cherry-pick・revert・rebase の途中)。終わってから、もう一度試してください。",
|
|
3262
3195
|
branchName: "この名前は Git のブランチ名に使えません。",
|
|
3263
3196
|
pullUnsafe: "GitHub から取り込む前に、実行を止め、保存していない編集とまだ記録していない変更をなくしてください。",
|
|
@@ -3319,10 +3252,369 @@ var messages = {
|
|
|
3319
3252
|
historyCopied: "コミットの ID をコピーしました。",
|
|
3320
3253
|
historyCopyFailed: "コミットの ID をコピーできませんでした。",
|
|
3321
3254
|
historyRefs: "ブランチ",
|
|
3322
|
-
cancel: "キャンセル"
|
|
3255
|
+
cancel: "キャンセル",
|
|
3256
|
+
branchMenu: "ブランチ",
|
|
3257
|
+
openPanel: "ローカル Git を開く",
|
|
3258
|
+
newBranchItem: "新しいブランチ…",
|
|
3259
|
+
newBranchTitle: "新しいブランチ"
|
|
3323
3260
|
}
|
|
3324
3261
|
};
|
|
3325
3262
|
var labelsFor = (locale) => locale.startsWith("ja") ? messages.ja : messages.en;
|
|
3263
|
+
// src/branch-button.tsx
|
|
3264
|
+
var _excluded = ["state", "locale"];
|
|
3265
|
+
var menuItems = "[role=\"menuitem\"], [role=\"menuitemradio\"]";
|
|
3266
|
+
/** Git's branch glyph, drawn in the text color. */
|
|
3267
|
+
function BranchIcon() {
|
|
3268
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
3269
|
+
className: "twgit-branch-icon",
|
|
3270
|
+
viewBox: "0 0 16 16",
|
|
3271
|
+
width: "16",
|
|
3272
|
+
height: "16",
|
|
3273
|
+
"aria-hidden": "true",
|
|
3274
|
+
focusable: "false"
|
|
3275
|
+
}, /* @__PURE__ */ React.createElement("g", {
|
|
3276
|
+
fill: "none",
|
|
3277
|
+
stroke: "currentColor",
|
|
3278
|
+
strokeWidth: "1.5"
|
|
3279
|
+
}, /* @__PURE__ */ React.createElement("circle", {
|
|
3280
|
+
cx: "4.5",
|
|
3281
|
+
cy: "3.5",
|
|
3282
|
+
r: "1.75"
|
|
3283
|
+
}), /* @__PURE__ */ React.createElement("circle", {
|
|
3284
|
+
cx: "4.5",
|
|
3285
|
+
cy: "12.5",
|
|
3286
|
+
r: "1.75"
|
|
3287
|
+
}), /* @__PURE__ */ React.createElement("circle", {
|
|
3288
|
+
cx: "11.5",
|
|
3289
|
+
cy: "5.5",
|
|
3290
|
+
r: "1.75"
|
|
3291
|
+
}), /* @__PURE__ */ React.createElement("path", { d: "M4.5 5.25v5.5M11.5 7.25c0 2.5-2.5 2.75-6 3.75" })));
|
|
3292
|
+
}
|
|
3293
|
+
/**
|
|
3294
|
+
* The current branch as a menu button for the host's menu bar, with the menu of branches. Before a repository is
|
|
3295
|
+
* chosen it reads "Git" and offers to choose one. A detached HEAD shows its short commit ID. The menu moves with the
|
|
3296
|
+
* arrow keys, Home and End; Escape closes it and returns to the button. Without `writable` it lists the branches only.
|
|
3297
|
+
*/
|
|
3298
|
+
function BranchButton(_ref) {
|
|
3299
|
+
var _ref3;
|
|
3300
|
+
let { state, locale = "en" } = _ref, actions = _objectWithoutProperties$1(_ref, _excluded);
|
|
3301
|
+
const labels = labelsFor(locale);
|
|
3302
|
+
const [mode, setMode] = useState("closed");
|
|
3303
|
+
const [initial, setInitial] = useState("checked");
|
|
3304
|
+
const [name, setName] = useState("");
|
|
3305
|
+
const [checkout, setCheckout] = useState(true);
|
|
3306
|
+
const [creating, setCreating] = useState(false);
|
|
3307
|
+
const [createError, setCreateError] = useState("");
|
|
3308
|
+
const root = useRef(null);
|
|
3309
|
+
const trigger = useRef(null);
|
|
3310
|
+
const popup = useRef(null);
|
|
3311
|
+
const mounted = useRef(true);
|
|
3312
|
+
useEffect(() => () => {
|
|
3313
|
+
mounted.current = false;
|
|
3314
|
+
}, []);
|
|
3315
|
+
useLayoutEffect(() => {
|
|
3316
|
+
var _ref2;
|
|
3317
|
+
const element = popup.current;
|
|
3318
|
+
if (!element) return;
|
|
3319
|
+
if (mode === "create") {
|
|
3320
|
+
var _element$querySelecto;
|
|
3321
|
+
(_element$querySelecto = element.querySelector("input")) === null || _element$querySelecto === void 0 || _element$querySelecto.focus();
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
const items = [...element.querySelectorAll(menuItems)];
|
|
3325
|
+
const checked = items.find((item) => item.getAttribute("aria-checked") === "true");
|
|
3326
|
+
(_ref2 = initial === "last" ? items[items.length - 1] : initial === "checked" && checked || items[0]) === null || _ref2 === void 0 || _ref2.focus();
|
|
3327
|
+
}, [mode]);
|
|
3328
|
+
useEffect(() => {
|
|
3329
|
+
if (mode === "closed") return;
|
|
3330
|
+
const node = root.current;
|
|
3331
|
+
const dismiss = (event) => {
|
|
3332
|
+
if (!node.contains(event.target) && !creating) setMode("closed");
|
|
3333
|
+
};
|
|
3334
|
+
node.ownerDocument.addEventListener("pointerdown", dismiss, true);
|
|
3335
|
+
return () => node.ownerDocument.removeEventListener("pointerdown", dismiss, true);
|
|
3336
|
+
}, [mode, creating]);
|
|
3337
|
+
useEffect(() => {
|
|
3338
|
+
var _popup$current;
|
|
3339
|
+
if (!createError || creating) return;
|
|
3340
|
+
const input = (_popup$current = popup.current) === null || _popup$current === void 0 ? void 0 : _popup$current.querySelector("input:not([type])");
|
|
3341
|
+
input === null || input === void 0 || input.focus();
|
|
3342
|
+
input === null || input === void 0 || input.select();
|
|
3343
|
+
}, [createError, creating]);
|
|
3344
|
+
const { branch, head } = state;
|
|
3345
|
+
const unborn = state.repository && !head;
|
|
3346
|
+
const text = !state.repository ? "Git" : branch !== null && branch !== void 0 ? branch : head ? head.slice(0, 7) : labels.unborn;
|
|
3347
|
+
const accessibleName = !state.repository ? labels.title : `${branch ? labels.branch : labels.detached}: ${text}${unborn && branch ? ` (${labels.unborn})` : ""}`;
|
|
3348
|
+
const close = (focus = true) => {
|
|
3349
|
+
var _trigger$current;
|
|
3350
|
+
setMode("closed");
|
|
3351
|
+
if (focus) (_trigger$current = trigger.current) === null || _trigger$current === void 0 || _trigger$current.focus({ preventScroll: true });
|
|
3352
|
+
};
|
|
3353
|
+
const openMenu = (from) => {
|
|
3354
|
+
setInitial(from);
|
|
3355
|
+
setMode("menu");
|
|
3356
|
+
};
|
|
3357
|
+
/** Runs a branch operation and shows its result, or why it did not run, in the panel. */
|
|
3358
|
+
const change = async (operation) => {
|
|
3359
|
+
const result = await operation();
|
|
3360
|
+
if (result.done || result.error) actions.open();
|
|
3361
|
+
};
|
|
3362
|
+
const items = [];
|
|
3363
|
+
if (!state.repository) items.push({
|
|
3364
|
+
id: "choose",
|
|
3365
|
+
label: labels.choose,
|
|
3366
|
+
run: () => {
|
|
3367
|
+
close();
|
|
3368
|
+
actions.choose();
|
|
3369
|
+
}
|
|
3370
|
+
});
|
|
3371
|
+
else {
|
|
3372
|
+
const switching = state.writable && !state.busy;
|
|
3373
|
+
for (const local of state.branches) items.push({
|
|
3374
|
+
id: "branch:" + local,
|
|
3375
|
+
label: local,
|
|
3376
|
+
checked: local === branch,
|
|
3377
|
+
disabled: !state.writable || state.busy && local !== branch,
|
|
3378
|
+
run: () => {
|
|
3379
|
+
close();
|
|
3380
|
+
if (local !== branch && switching) change(() => actions.switchBranch(local));
|
|
3381
|
+
}
|
|
3382
|
+
});
|
|
3383
|
+
if (state.writable) {
|
|
3384
|
+
state.remoteBranches.forEach((remote, index) => items.push({
|
|
3385
|
+
id: "remote:" + remote,
|
|
3386
|
+
label: labels.historyCreateFromRemote.replace("{name}", remote),
|
|
3387
|
+
disabled: state.busy,
|
|
3388
|
+
separatorBefore: index === 0,
|
|
3389
|
+
run: () => {
|
|
3390
|
+
close();
|
|
3391
|
+
if (!state.busy) change(() => actions.createFromRemote(remote));
|
|
3392
|
+
}
|
|
3393
|
+
}));
|
|
3394
|
+
if (head) items.push({
|
|
3395
|
+
id: "create",
|
|
3396
|
+
label: labels.newBranchItem,
|
|
3397
|
+
disabled: state.busy,
|
|
3398
|
+
separatorBefore: true,
|
|
3399
|
+
run: () => {
|
|
3400
|
+
if (state.busy) return;
|
|
3401
|
+
setName("");
|
|
3402
|
+
setCheckout(true);
|
|
3403
|
+
setCreateError("");
|
|
3404
|
+
setMode("create");
|
|
3405
|
+
}
|
|
3406
|
+
});
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
items.push({
|
|
3410
|
+
id: "open",
|
|
3411
|
+
label: labels.openPanel,
|
|
3412
|
+
separatorBefore: items.length > 0 && items[items.length - 1].id !== "create",
|
|
3413
|
+
run: () => {
|
|
3414
|
+
close();
|
|
3415
|
+
actions.open();
|
|
3416
|
+
}
|
|
3417
|
+
});
|
|
3418
|
+
const onMenuKey = (event) => {
|
|
3419
|
+
if (event.key === "Escape") {
|
|
3420
|
+
event.preventDefault();
|
|
3421
|
+
event.stopPropagation();
|
|
3422
|
+
if (!creating) close();
|
|
3423
|
+
return;
|
|
3424
|
+
}
|
|
3425
|
+
if (mode !== "menu") return;
|
|
3426
|
+
if (event.key === "Tab") {
|
|
3427
|
+
close(false);
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
const elements = [...event.currentTarget.querySelectorAll(menuItems)];
|
|
3431
|
+
const index = elements.indexOf(event.target);
|
|
3432
|
+
const target = {
|
|
3433
|
+
ArrowDown: index + 1,
|
|
3434
|
+
ArrowUp: index - 1,
|
|
3435
|
+
Home: 0,
|
|
3436
|
+
End: elements.length - 1
|
|
3437
|
+
}[event.key];
|
|
3438
|
+
if (target === void 0 || !elements.length) return;
|
|
3439
|
+
event.preventDefault();
|
|
3440
|
+
elements[(target + elements.length) % elements.length].focus();
|
|
3441
|
+
};
|
|
3442
|
+
const submit = async (event) => {
|
|
3443
|
+
var _result$error;
|
|
3444
|
+
event.preventDefault();
|
|
3445
|
+
const branchName = name.trim();
|
|
3446
|
+
if (!branchName || creating) return;
|
|
3447
|
+
setCreating(true);
|
|
3448
|
+
setCreateError("");
|
|
3449
|
+
let result;
|
|
3450
|
+
try {
|
|
3451
|
+
result = await actions.createBranch(branchName, checkout);
|
|
3452
|
+
} catch (error) {
|
|
3453
|
+
result = {
|
|
3454
|
+
done: false,
|
|
3455
|
+
error: error instanceof Error && error.message ? error.message : labels.failed
|
|
3456
|
+
};
|
|
3457
|
+
}
|
|
3458
|
+
if (!mounted.current) return;
|
|
3459
|
+
setCreating(false);
|
|
3460
|
+
if (result.done) {
|
|
3461
|
+
close();
|
|
3462
|
+
actions.open();
|
|
3463
|
+
} else setCreateError((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : "");
|
|
3464
|
+
};
|
|
3465
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
3466
|
+
className: "twgit-branch-entry",
|
|
3467
|
+
ref: root,
|
|
3468
|
+
onBlur: (event) => {
|
|
3469
|
+
const next = event.relatedTarget;
|
|
3470
|
+
if (next && !event.currentTarget.contains(next) && !creating) setMode("closed");
|
|
3471
|
+
}
|
|
3472
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
3473
|
+
type: "button",
|
|
3474
|
+
className: "twgit-branch-button",
|
|
3475
|
+
ref: trigger,
|
|
3476
|
+
"aria-label": accessibleName,
|
|
3477
|
+
title: accessibleName,
|
|
3478
|
+
"aria-haspopup": "menu",
|
|
3479
|
+
"aria-expanded": mode === "menu",
|
|
3480
|
+
"data-git-branch": state.repository ? (_ref3 = branch !== null && branch !== void 0 ? branch : head) !== null && _ref3 !== void 0 ? _ref3 : "" : void 0,
|
|
3481
|
+
onClick: () => mode === "closed" ? openMenu("checked") : close(false),
|
|
3482
|
+
onKeyDown: (event) => {
|
|
3483
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
|
|
3484
|
+
event.preventDefault();
|
|
3485
|
+
openMenu(event.key === "ArrowUp" ? "last" : "checked");
|
|
3486
|
+
}
|
|
3487
|
+
}, /* @__PURE__ */ React.createElement(BranchIcon, null), /* @__PURE__ */ React.createElement("span", { className: "twgit-branch-name" }, text), unborn && branch && /* @__PURE__ */ React.createElement("small", { className: "twgit-branch-unborn" }, labels.unborn), /* @__PURE__ */ React.createElement("span", {
|
|
3488
|
+
className: "twgit-branch-caret",
|
|
3489
|
+
"aria-hidden": "true"
|
|
3490
|
+
}, "▾")), mode === "menu" && /* @__PURE__ */ React.createElement("div", {
|
|
3491
|
+
ref: popup,
|
|
3492
|
+
className: "twgit-branch-popup",
|
|
3493
|
+
role: "menu",
|
|
3494
|
+
"aria-label": labels.branchMenu,
|
|
3495
|
+
onKeyDown: onMenuKey
|
|
3496
|
+
}, items.map((item) => /* @__PURE__ */ React.createElement("button", {
|
|
3497
|
+
key: item.id,
|
|
3498
|
+
type: "button",
|
|
3499
|
+
tabIndex: -1,
|
|
3500
|
+
"data-action": item.id,
|
|
3501
|
+
role: item.checked === void 0 ? "menuitem" : "menuitemradio",
|
|
3502
|
+
"aria-checked": item.checked,
|
|
3503
|
+
"aria-disabled": item.disabled || void 0,
|
|
3504
|
+
"data-separator-before": item.separatorBefore || void 0,
|
|
3505
|
+
onClick: () => {
|
|
3506
|
+
if (!item.disabled || item.checked) item.run();
|
|
3507
|
+
}
|
|
3508
|
+
}, item.checked !== void 0 && /* @__PURE__ */ React.createElement("span", {
|
|
3509
|
+
className: "twgit-branch-check",
|
|
3510
|
+
"aria-hidden": "true"
|
|
3511
|
+
}, item.checked ? "✓" : ""), item.label))), mode === "create" && /* @__PURE__ */ React.createElement("div", {
|
|
3512
|
+
ref: popup,
|
|
3513
|
+
className: "twgit-branch-popup",
|
|
3514
|
+
role: "dialog",
|
|
3515
|
+
"aria-label": labels.newBranchTitle,
|
|
3516
|
+
onKeyDown: onMenuKey
|
|
3517
|
+
}, /* @__PURE__ */ React.createElement("form", { onSubmit: (event) => void submit(event) }, /* @__PURE__ */ React.createElement("label", null, labels.newBranch, " ", /* @__PURE__ */ React.createElement("input", {
|
|
3518
|
+
value: name,
|
|
3519
|
+
required: true,
|
|
3520
|
+
disabled: creating,
|
|
3521
|
+
"aria-invalid": createError ? true : void 0,
|
|
3522
|
+
onChange: (event) => setName(event.currentTarget.value)
|
|
3523
|
+
})), /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
|
|
3524
|
+
type: "checkbox",
|
|
3525
|
+
checked: checkout,
|
|
3526
|
+
disabled: creating,
|
|
3527
|
+
onChange: (event) => setCheckout(event.currentTarget.checked)
|
|
3528
|
+
}), " ", labels.switchAfterCreate), createError && /* @__PURE__ */ React.createElement("p", {
|
|
3529
|
+
className: "twgit-graph-form-error",
|
|
3530
|
+
role: "alert"
|
|
3531
|
+
}, createError), /* @__PURE__ */ React.createElement("span", { className: "twgit-graph-form-actions" }, /* @__PURE__ */ React.createElement("button", {
|
|
3532
|
+
type: "submit",
|
|
3533
|
+
disabled: creating || state.busy || !name.trim()
|
|
3534
|
+
}, labels.createBranch), /* @__PURE__ */ React.createElement("button", {
|
|
3535
|
+
type: "button",
|
|
3536
|
+
disabled: creating,
|
|
3537
|
+
onClick: () => close()
|
|
3538
|
+
}, labels.cancel)))));
|
|
3539
|
+
}
|
|
3540
|
+
/**
|
|
3541
|
+
* Lays out commits ordered newest first with every child above its parents. Parents missing from `commits`, such as
|
|
3542
|
+
* those on a page not loaded yet or cut off by a shallow clone, keep their lane running to the bottom.
|
|
3543
|
+
*/
|
|
3544
|
+
function layoutHistory(commits) {
|
|
3545
|
+
const lanes = [];
|
|
3546
|
+
let nextColor = 0;
|
|
3547
|
+
const free = () => {
|
|
3548
|
+
const index = lanes.indexOf(null);
|
|
3549
|
+
return index === -1 ? lanes.length : index;
|
|
3550
|
+
};
|
|
3551
|
+
const rows = [];
|
|
3552
|
+
for (const commit of commits) {
|
|
3553
|
+
const segments = [];
|
|
3554
|
+
const before = lanes.slice();
|
|
3555
|
+
const waiting = before.flatMap((lane, index) => (lane === null || lane === void 0 ? void 0 : lane.oid) === commit.oid ? [index] : []);
|
|
3556
|
+
const column = waiting.length ? waiting[0] : free();
|
|
3557
|
+
const color = waiting.length ? before[column].color : nextColor++ % 8;
|
|
3558
|
+
for (const [index, lane] of before.entries()) {
|
|
3559
|
+
if (!lane) continue;
|
|
3560
|
+
segments.push({
|
|
3561
|
+
part: "top",
|
|
3562
|
+
from: index,
|
|
3563
|
+
to: lane.oid === commit.oid ? column : index,
|
|
3564
|
+
color: lane.color
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
for (const index of waiting) lanes[index] = null;
|
|
3568
|
+
const parents = [...new Set(commit.parents)];
|
|
3569
|
+
lanes[column] = parents.length ? {
|
|
3570
|
+
oid: parents[0],
|
|
3571
|
+
color
|
|
3572
|
+
} : null;
|
|
3573
|
+
const joins = parents.length ? [{
|
|
3574
|
+
index: column,
|
|
3575
|
+
color
|
|
3576
|
+
}] : [];
|
|
3577
|
+
for (const parent of parents.slice(1)) {
|
|
3578
|
+
let index = lanes.findIndex((lane) => (lane === null || lane === void 0 ? void 0 : lane.oid) === parent);
|
|
3579
|
+
if (index === -1) {
|
|
3580
|
+
index = free();
|
|
3581
|
+
lanes[index] = {
|
|
3582
|
+
oid: parent,
|
|
3583
|
+
color: nextColor++ % 8
|
|
3584
|
+
};
|
|
3585
|
+
}
|
|
3586
|
+
joins.push({
|
|
3587
|
+
index,
|
|
3588
|
+
color: lanes[index].color
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3591
|
+
while (lanes.length && lanes[lanes.length - 1] === null) lanes.pop();
|
|
3592
|
+
for (const [index, lane] of before.entries()) if (lane && lane.oid !== commit.oid) segments.push({
|
|
3593
|
+
part: "bottom",
|
|
3594
|
+
from: index,
|
|
3595
|
+
to: index,
|
|
3596
|
+
color: lane.color
|
|
3597
|
+
});
|
|
3598
|
+
for (const join of joins) segments.push({
|
|
3599
|
+
part: "bottom",
|
|
3600
|
+
from: column,
|
|
3601
|
+
to: join.index,
|
|
3602
|
+
color: join.color
|
|
3603
|
+
});
|
|
3604
|
+
const width = Math.max(column + 1, ...segments.map((segment) => Math.max(segment.from, segment.to) + 1));
|
|
3605
|
+
rows.push({
|
|
3606
|
+
oid: commit.oid,
|
|
3607
|
+
column,
|
|
3608
|
+
color,
|
|
3609
|
+
segments,
|
|
3610
|
+
width
|
|
3611
|
+
});
|
|
3612
|
+
}
|
|
3613
|
+
return {
|
|
3614
|
+
rows,
|
|
3615
|
+
width: Math.max(0, ...rows.map((row) => row.width))
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3326
3618
|
// src/history-graph-view.tsx
|
|
3327
3619
|
/** Lane colors that read on light and dark backgrounds. */
|
|
3328
3620
|
var laneColors = [
|
|
@@ -3812,7 +4104,20 @@ var en = {
|
|
|
3812
4104
|
failed: "Could not read GitHub. Try again.",
|
|
3813
4105
|
changed: "The pull request changed while it was being read. Open it again.",
|
|
3814
4106
|
tooManyFiles: "GitHub only returns the first 3,000 changed files. This pull request exceeds that limit.",
|
|
3815
|
-
openTabs: "Open as tabs"
|
|
4107
|
+
openTabs: "Open as tabs",
|
|
4108
|
+
session: "Connect to GitHub again (GitHub connection) to read this pull request.",
|
|
4109
|
+
forbidden: "The GitHub connection is not allowed to read this repository.",
|
|
4110
|
+
pullRequestNotFound: "This repository has no pull request with this number.",
|
|
4111
|
+
network: "Could not reach GitHub through the connection. Check the network and try again.",
|
|
4112
|
+
remoteFailed: "Could not read the pull request through the GitHub connection. Try again.",
|
|
4113
|
+
baseMissing: "The base branch is not on GitHub. Choose another base branch.",
|
|
4114
|
+
viaConnection: "Read through the GitHub connection.",
|
|
4115
|
+
listPrivate: "The list uses the public GitHub API. Enter a pull request number to read it through the connection.",
|
|
4116
|
+
noMetadata: "The title and base branch are not available without the public GitHub API. Choose the base branch to compare with.",
|
|
4117
|
+
base: "Base branch",
|
|
4118
|
+
pullRequest: "Pull request",
|
|
4119
|
+
openLocally: "Open here as {branch}",
|
|
4120
|
+
openLocallyHint: "Creates the local branch {branch} at this version, switches to it and opens the project, so it can be run. Unsaved edits and unrecorded changes stop it. Switch back in Local changes."
|
|
3816
4121
|
};
|
|
3817
4122
|
var ja = {
|
|
3818
4123
|
title: "プルリクエスト",
|
|
@@ -3834,12 +4139,40 @@ var ja = {
|
|
|
3834
4139
|
failed: "GitHub から取得できませんでした。再試行してください。",
|
|
3835
4140
|
changed: "取得中にプルリクエストが更新されました。もう一度開いてください。",
|
|
3836
4141
|
tooManyFiles: "変更ファイルが GitHub API の取得上限である 3,000 件を超えています。",
|
|
3837
|
-
openTabs: "タブで開く"
|
|
4142
|
+
openTabs: "タブで開く",
|
|
4143
|
+
session: "この PR を読むには、GitHub 接続でもう一度接続してください。",
|
|
4144
|
+
forbidden: "GitHub 接続に、このリポジトリを読む権限がありません。",
|
|
4145
|
+
pullRequestNotFound: "このリポジトリに、この番号のプルリクエストはありません。",
|
|
4146
|
+
network: "GitHub 接続で GitHub に届きませんでした。ネットワークを確認して、もう一度試してください。",
|
|
4147
|
+
remoteFailed: "GitHub 接続でプルリクエストを読めませんでした。もう一度試してください。",
|
|
4148
|
+
baseMissing: "ベースのブランチが GitHub にありません。別のベースを選んでください。",
|
|
4149
|
+
viaConnection: "GitHub 接続で取得しました。",
|
|
4150
|
+
listPrivate: "一覧は公開 GitHub API を使います。番号を入れると、GitHub 接続で読みます。",
|
|
4151
|
+
noMetadata: "公開 GitHub API を使えないため、題名とベースのブランチがわかりません。比べるベースのブランチを選んでください。",
|
|
4152
|
+
base: "ベースのブランチ",
|
|
4153
|
+
pullRequest: "プルリクエスト",
|
|
4154
|
+
openLocally: "{branch} として手元で開く",
|
|
4155
|
+
openLocallyHint: "この版にローカルブランチ {branch} を作って切り替え、作品を開き直して実行できるようにします。保存していない編集や記録していない変更があるときは行いません。元に戻すときは「ローカルの変更」で切り替えてください。"
|
|
3838
4156
|
};
|
|
4157
|
+
var gitErrors = [
|
|
4158
|
+
"session",
|
|
4159
|
+
"forbidden",
|
|
4160
|
+
"pullRequestNotFound",
|
|
4161
|
+
"network",
|
|
4162
|
+
"remoteFailed",
|
|
4163
|
+
"baseMissing",
|
|
4164
|
+
"changed"
|
|
4165
|
+
];
|
|
3839
4166
|
function errorMessage(error, labels) {
|
|
3840
|
-
|
|
4167
|
+
if (error instanceof PullRequestError) return labels[error.code];
|
|
4168
|
+
if (error instanceof GitPanelError) {
|
|
4169
|
+
const code = gitErrors.find((code) => code === error.code);
|
|
4170
|
+
return code ? labels[code] : labels.failed;
|
|
4171
|
+
}
|
|
4172
|
+
return labels.failed;
|
|
3841
4173
|
}
|
|
3842
|
-
function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }) {
|
|
4174
|
+
function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs, repository, connection, openLocally }) {
|
|
4175
|
+
var _pr$base$ref, _pr$git, _pr$base$ref2;
|
|
3843
4176
|
const client = useMemo(() => createGitHubPullRequests(name), [name]);
|
|
3844
4177
|
const [page, setPage] = useState(1);
|
|
3845
4178
|
const [listing, setListing] = useState();
|
|
@@ -3847,10 +4180,12 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3847
4180
|
const [selection, setSelection] = useState();
|
|
3848
4181
|
const [loaded, setLoaded] = useState();
|
|
3849
4182
|
const list = (listing === null || listing === void 0 ? void 0 : listing.page) === page ? listing.result : void 0;
|
|
4183
|
+
const [listConnected, setListConnected] = useState(false);
|
|
3850
4184
|
const detail = (loaded === null || loaded === void 0 ? void 0 : loaded.selection) === selection ? loaded === null || loaded === void 0 ? void 0 : loaded.result : void 0;
|
|
3851
4185
|
useEffect(() => {
|
|
3852
4186
|
const controller = new AbortController();
|
|
3853
4187
|
setListing(void 0);
|
|
4188
|
+
setListConnected(!!(connection === null || connection === void 0 ? void 0 : connection.connected()));
|
|
3854
4189
|
client.list(page, controller.signal).then((data) => {
|
|
3855
4190
|
if (!controller.signal.aborted) setListing({
|
|
3856
4191
|
page,
|
|
@@ -3871,7 +4206,8 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3871
4206
|
useEffect(() => {
|
|
3872
4207
|
if (!selection) return;
|
|
3873
4208
|
const controller = new AbortController();
|
|
3874
|
-
|
|
4209
|
+
const load = () => (connection === null || connection === void 0 ? void 0 : connection.connected()) ? loadThroughConnection(selection.number, selection.base, controller.signal) : client.load(selection.number, controller.signal);
|
|
4210
|
+
load().then((data) => {
|
|
3875
4211
|
if (!controller.signal.aborted) setLoaded({
|
|
3876
4212
|
selection,
|
|
3877
4213
|
result: { data }
|
|
@@ -3888,6 +4224,56 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3888
4224
|
selection,
|
|
3889
4225
|
labels
|
|
3890
4226
|
]);
|
|
4227
|
+
const fetched = useRef();
|
|
4228
|
+
/**
|
|
4229
|
+
* Fetches `refs/pull/<number>/head` and the branches over Git Smart HTTP and compares them from local objects. The
|
|
4230
|
+
* public API only adds the title, description and base when it can read the repository; the contents never come
|
|
4231
|
+
* from it, so a private repository is read only through the connection.
|
|
4232
|
+
*/
|
|
4233
|
+
const loadThroughConnection = async (number, chosenBase, signal) => {
|
|
4234
|
+
var _fetched$current, _ref, _ref2, _metadata$title, _metadata$description, _metadata$head$ref;
|
|
4235
|
+
const guard = () => {
|
|
4236
|
+
if (signal.aborted) throw new GitPanelError("changed");
|
|
4237
|
+
};
|
|
4238
|
+
let head, branches, defaultBranch, metadata = null;
|
|
4239
|
+
if (chosenBase !== void 0 && ((_fetched$current = fetched.current) === null || _fetched$current === void 0 ? void 0 : _fetched$current.number) === number) ({head, branches, defaultBranch} = fetched.current);
|
|
4240
|
+
else {
|
|
4241
|
+
metadata = await client.metadata(number, signal).catch((error) => {
|
|
4242
|
+
if (signal.aborted) throw error;
|
|
4243
|
+
return null;
|
|
4244
|
+
});
|
|
4245
|
+
const result = await repository.fetchPullRequest(number, connection.getSession, guard, signal);
|
|
4246
|
+
if (metadata && metadata.head.sha !== result.head) throw new PullRequestError("changed");
|
|
4247
|
+
({head, branches, defaultBranch} = result);
|
|
4248
|
+
fetched.current = {
|
|
4249
|
+
number,
|
|
4250
|
+
head,
|
|
4251
|
+
branches,
|
|
4252
|
+
defaultBranch
|
|
4253
|
+
};
|
|
4254
|
+
}
|
|
4255
|
+
const branch = (_ref = (_ref2 = chosenBase !== null && chosenBase !== void 0 ? chosenBase : metadata === null || metadata === void 0 ? void 0 : metadata.base.ref) !== null && _ref2 !== void 0 ? _ref2 : defaultBranch) !== null && _ref !== void 0 ? _ref : branches[0];
|
|
4256
|
+
const read = await repository.readPullRequest(head, {
|
|
4257
|
+
sha: metadata === null || metadata === void 0 ? void 0 : metadata.base.sha,
|
|
4258
|
+
branch
|
|
4259
|
+
});
|
|
4260
|
+
guard();
|
|
4261
|
+
return {
|
|
4262
|
+
number,
|
|
4263
|
+
title: (_metadata$title = metadata === null || metadata === void 0 ? void 0 : metadata.title) !== null && _metadata$title !== void 0 ? _metadata$title : `${labels.pullRequest} #${number}`,
|
|
4264
|
+
description: (_metadata$description = metadata === null || metadata === void 0 ? void 0 : metadata.description) !== null && _metadata$description !== void 0 ? _metadata$description : "",
|
|
4265
|
+
author: metadata === null || metadata === void 0 ? void 0 : metadata.author,
|
|
4266
|
+
state: metadata === null || metadata === void 0 ? void 0 : metadata.state,
|
|
4267
|
+
head: {
|
|
4268
|
+
sha: head,
|
|
4269
|
+
ref: (_metadata$head$ref = metadata === null || metadata === void 0 ? void 0 : metadata.head.ref) !== null && _metadata$head$ref !== void 0 ? _metadata$head$ref : `pull/${number}/head`
|
|
4270
|
+
},
|
|
4271
|
+
base: read.base,
|
|
4272
|
+
files: read.files,
|
|
4273
|
+
url: "https://github.com/" + name + "/pull/" + number,
|
|
4274
|
+
git: { branches: metadata ? null : branches }
|
|
4275
|
+
};
|
|
4276
|
+
};
|
|
3891
4277
|
const choose = (number) => {
|
|
3892
4278
|
if (!Number.isSafeInteger(number) || number < 1) return;
|
|
3893
4279
|
setSelection({ number });
|
|
@@ -3907,7 +4293,7 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3907
4293
|
max: Number.MAX_SAFE_INTEGER,
|
|
3908
4294
|
value: input,
|
|
3909
4295
|
onChange: (event) => setInput(event.currentTarget.value)
|
|
3910
|
-
})), /* @__PURE__ */ React.createElement("button", { type: "submit" }, labels.openNumber)), !list && /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.loading), (list === null || list === void 0 ? void 0 : list.error) && /* @__PURE__ */ React.createElement("p", { role: "alert" }, list.error), (list === null || list === void 0 ? void 0 : list.data) && /* @__PURE__ */ React.createElement(React.Fragment, null, !list.data.items.length && /* @__PURE__ */ React.createElement("p", null, labels.empty), /* @__PURE__ */ React.createElement("ul", null, list.data.items.map((item) => /* @__PURE__ */ React.createElement("li", { key: item.number }, /* @__PURE__ */ React.createElement("button", {
|
|
4296
|
+
})), /* @__PURE__ */ React.createElement("button", { type: "submit" }, labels.openNumber)), !list && /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.loading), (list === null || list === void 0 ? void 0 : list.error) && (listConnected && list.error === labels.unavailable ? /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.listPrivate) : /* @__PURE__ */ React.createElement("p", { role: "alert" }, list.error)), (list === null || list === void 0 ? void 0 : list.data) && /* @__PURE__ */ React.createElement(React.Fragment, null, !list.data.items.length && /* @__PURE__ */ React.createElement("p", null, labels.empty), /* @__PURE__ */ React.createElement("ul", null, list.data.items.map((item) => /* @__PURE__ */ React.createElement("li", { key: item.number }, /* @__PURE__ */ React.createElement("button", {
|
|
3911
4297
|
className: "twgit-file",
|
|
3912
4298
|
type: "button",
|
|
3913
4299
|
"aria-pressed": (selection === null || selection === void 0 ? void 0 : selection.number) === item.number,
|
|
@@ -3920,7 +4306,17 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3920
4306
|
type: "button",
|
|
3921
4307
|
disabled: !list.data.more,
|
|
3922
4308
|
onClick: () => setPage(page + 1)
|
|
3923
|
-
}, labels.next)))), /* @__PURE__ */ React.createElement("main", { className: "twgit-diff" }, !selection && /* @__PURE__ */ React.createElement("p", null, labels.select), selection && !detail && /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.loading), (detail === null || detail === void 0 ? void 0 : detail.error) && /* @__PURE__ */ React.createElement("p", { role: "alert" }, detail.error), pr && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("p", { className: "twgit-pr-revision" }, /* @__PURE__ */ React.createElement("strong", null, "#", pr.number, " · ", labels[pr.state]), pr.author && /* @__PURE__ */ React.createElement("span", null, pr.author), /* @__PURE__ */ React.createElement("code", { title: pr.head.sha }, pr.head.ref, " → ", pr.base.ref), /* @__PURE__ */ React.createElement("
|
|
4309
|
+
}, labels.next)))), /* @__PURE__ */ React.createElement("main", { className: "twgit-diff" }, !selection && /* @__PURE__ */ React.createElement("p", null, labels.select), selection && !detail && /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.loading), (detail === null || detail === void 0 ? void 0 : detail.error) && /* @__PURE__ */ React.createElement("p", { role: "alert" }, detail.error), pr && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("p", { className: "twgit-pr-revision" }, /* @__PURE__ */ React.createElement("strong", null, "#", pr.number, pr.state && /* @__PURE__ */ React.createElement(React.Fragment, null, " · ", labels[pr.state])), pr.author && /* @__PURE__ */ React.createElement("span", null, pr.author), /* @__PURE__ */ React.createElement("code", { title: pr.head.sha }, pr.head.ref, " → ", (_pr$base$ref = pr.base.ref) !== null && _pr$base$ref !== void 0 ? _pr$base$ref : pr.base.sha.slice(0, 12)), ((_pr$git = pr.git) === null || _pr$git === void 0 ? void 0 : _pr$git.branches) && /* @__PURE__ */ React.createElement("label", null, labels.base, " ", /* @__PURE__ */ React.createElement("select", {
|
|
4310
|
+
"data-git-pr-base": "",
|
|
4311
|
+
value: (_pr$base$ref2 = pr.base.ref) !== null && _pr$base$ref2 !== void 0 ? _pr$base$ref2 : "",
|
|
4312
|
+
onChange: (event) => setSelection({
|
|
4313
|
+
number: pr.number,
|
|
4314
|
+
base: event.currentTarget.value
|
|
4315
|
+
})
|
|
4316
|
+
}, pr.git.branches.map((branch) => /* @__PURE__ */ React.createElement("option", {
|
|
4317
|
+
key: branch,
|
|
4318
|
+
value: branch
|
|
4319
|
+
}, branch)))), /* @__PURE__ */ React.createElement("a", {
|
|
3924
4320
|
href: pr.url,
|
|
3925
4321
|
target: "_blank",
|
|
3926
4322
|
rel: "noreferrer"
|
|
@@ -3943,7 +4339,16 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3943
4339
|
locateBlock: locateFor === null || locateFor === void 0 ? void 0 : locateFor(file.path, pr.head.sha)
|
|
3944
4340
|
}] : [];
|
|
3945
4341
|
}), `${name}#${pr.number}`)
|
|
3946
|
-
}, labels.openTabs)
|
|
4342
|
+
}, labels.openTabs), pr.git && openLocally && /* @__PURE__ */ React.createElement("button", {
|
|
4343
|
+
type: "button",
|
|
4344
|
+
"data-git-open-pr-locally": "",
|
|
4345
|
+
disabled: openLocally.busy,
|
|
4346
|
+
title: labels.openLocallyHint.replace("{branch}", pullRequestBranch(pr.number)),
|
|
4347
|
+
onClick: () => void openLocally.open(pr.number, pr.head.sha)
|
|
4348
|
+
}, labels.openLocally.replace("{branch}", pullRequestBranch(pr.number)))), pr.git && /* @__PURE__ */ React.createElement("p", {
|
|
4349
|
+
className: "twgit-context",
|
|
4350
|
+
role: "status"
|
|
4351
|
+
}, labels.viaConnection, pr.git.branches && /* @__PURE__ */ React.createElement(React.Fragment, null, " ", labels.noMetadata)), /* @__PURE__ */ React.createElement(ProjectSourceReview, {
|
|
3947
4352
|
title: pr.title,
|
|
3948
4353
|
description: pr.description,
|
|
3949
4354
|
files: locateFor ? pr.files.map((file) => "patch" in file ? _objectSpread2$1(_objectSpread2$1({}, file), {}, { locateBlock: locateFor(file.path, pr.head.sha) }) : file) : pr.files,
|
|
@@ -3952,7 +4357,7 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }
|
|
|
3952
4357
|
rememberAs: `${name}#${pr.number}`
|
|
3953
4358
|
}))));
|
|
3954
4359
|
}
|
|
3955
|
-
function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, openTabs }) {
|
|
4360
|
+
function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, openTabs, connection, openLocally }) {
|
|
3956
4361
|
const labels = locale.startsWith("ja") ? ja : en;
|
|
3957
4362
|
const [origin, setOrigin] = useState();
|
|
3958
4363
|
useEffect(() => {
|
|
@@ -3988,7 +4393,10 @@ function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, op
|
|
|
3988
4393
|
locale,
|
|
3989
4394
|
renderBlock,
|
|
3990
4395
|
locateFor,
|
|
3991
|
-
openTabs
|
|
4396
|
+
openTabs,
|
|
4397
|
+
repository,
|
|
4398
|
+
connection,
|
|
4399
|
+
openLocally
|
|
3992
4400
|
});
|
|
3993
4401
|
}
|
|
3994
4402
|
// src/editor-block-locator.ts
|
|
@@ -4029,6 +4437,41 @@ function nextFrame(signal) {
|
|
|
4029
4437
|
}
|
|
4030
4438
|
// src/index.tsx
|
|
4031
4439
|
init_objectSpread2();
|
|
4440
|
+
function createController() {
|
|
4441
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4442
|
+
const controller = {
|
|
4443
|
+
open() {},
|
|
4444
|
+
async refresh() {},
|
|
4445
|
+
async choose() {},
|
|
4446
|
+
async changeBranch() {
|
|
4447
|
+
return { done: false };
|
|
4448
|
+
},
|
|
4449
|
+
branch: {
|
|
4450
|
+
repository: false,
|
|
4451
|
+
branch: void 0,
|
|
4452
|
+
head: null,
|
|
4453
|
+
branches: [],
|
|
4454
|
+
remoteBranches: [],
|
|
4455
|
+
writable: false,
|
|
4456
|
+
busy: false
|
|
4457
|
+
},
|
|
4458
|
+
publish(state) {
|
|
4459
|
+
controller.branch = state;
|
|
4460
|
+
for (const listener of [...listeners]) listener();
|
|
4461
|
+
},
|
|
4462
|
+
follow(listener) {
|
|
4463
|
+
listeners.add(listener);
|
|
4464
|
+
controller.onFollowers(listeners.size);
|
|
4465
|
+
return () => {
|
|
4466
|
+
listeners.delete(listener);
|
|
4467
|
+
controller.onFollowers(listeners.size);
|
|
4468
|
+
};
|
|
4469
|
+
},
|
|
4470
|
+
followers: () => listeners.size,
|
|
4471
|
+
onFollowers() {}
|
|
4472
|
+
};
|
|
4473
|
+
return controller;
|
|
4474
|
+
}
|
|
4032
4475
|
var initial = {
|
|
4033
4476
|
repository: null,
|
|
4034
4477
|
snapshot: null,
|
|
@@ -4042,9 +4485,56 @@ var initial = {
|
|
|
4042
4485
|
busy: false
|
|
4043
4486
|
};
|
|
4044
4487
|
var controllers = /* @__PURE__ */ new WeakMap();
|
|
4488
|
+
var registrations = /* @__PURE__ */ new Set();
|
|
4045
4489
|
var watchInterval = 2e3;
|
|
4490
|
+
/**
|
|
4491
|
+
* Calls `check` every `watchInterval`, when the window regains focus and shortly after a File System Observer reports
|
|
4492
|
+
* a change under `root`, one call at a time and never while the page is hidden. Returns the function that stops it.
|
|
4493
|
+
*/
|
|
4494
|
+
function watchRepository(document, root, check) {
|
|
4495
|
+
const view = document.defaultView;
|
|
4496
|
+
let stopped = false;
|
|
4497
|
+
let checking = false;
|
|
4498
|
+
const run = async () => {
|
|
4499
|
+
if (stopped || checking || document.visibilityState === "hidden") return;
|
|
4500
|
+
checking = true;
|
|
4501
|
+
try {
|
|
4502
|
+
await check(() => stopped);
|
|
4503
|
+
} catch (_unused) {} finally {
|
|
4504
|
+
checking = false;
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
let soon;
|
|
4508
|
+
const schedule = () => {
|
|
4509
|
+
view.clearTimeout(soon);
|
|
4510
|
+
soon = view.setTimeout(() => void run(), 300);
|
|
4511
|
+
};
|
|
4512
|
+
const interval = view.setInterval(() => void run(), watchInterval);
|
|
4513
|
+
const onFocus = () => void run();
|
|
4514
|
+
view.addEventListener("focus", onFocus);
|
|
4515
|
+
document.addEventListener("visibilitychange", onFocus);
|
|
4516
|
+
let observer = null;
|
|
4517
|
+
try {
|
|
4518
|
+
if (view.FileSystemObserver) {
|
|
4519
|
+
observer = new view.FileSystemObserver(schedule);
|
|
4520
|
+
observer.observe(root, { recursive: true }).catch(() => {});
|
|
4521
|
+
}
|
|
4522
|
+
} catch (_unused2) {
|
|
4523
|
+
observer = null;
|
|
4524
|
+
}
|
|
4525
|
+
run();
|
|
4526
|
+
return () => {
|
|
4527
|
+
stopped = true;
|
|
4528
|
+
view.clearInterval(interval);
|
|
4529
|
+
view.clearTimeout(soon);
|
|
4530
|
+
view.removeEventListener("focus", onFocus);
|
|
4531
|
+
document.removeEventListener("visibilitychange", onFocus);
|
|
4532
|
+
observer === null || observer === void 0 || observer.disconnect();
|
|
4533
|
+
};
|
|
4534
|
+
}
|
|
4535
|
+
var sameRefs = (a, b) => !!a && a.branch === b.branch && a.head === b.head && a.branches.join("\n") === b.branches.join("\n") && a.remoteBranches.join("\n") === b.remoteBranches.join("\n");
|
|
4046
4536
|
function GitPanel({ vm, document, host, controller }) {
|
|
4047
|
-
var _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head;
|
|
4537
|
+
var _refs$head, _refs$branches, _refs$remoteBranches, _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head;
|
|
4048
4538
|
const [visible, setVisible] = useState(false);
|
|
4049
4539
|
const [slot, setSlot] = useState(null);
|
|
4050
4540
|
const shown = visible || slot !== null;
|
|
@@ -4217,57 +4707,42 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4217
4707
|
controller.refresh();
|
|
4218
4708
|
}
|
|
4219
4709
|
}, [shown]);
|
|
4710
|
+
const [refs, setRefs] = useState(null);
|
|
4711
|
+
useEffect(() => {
|
|
4712
|
+
if (!state.repository) setRefs(null);
|
|
4713
|
+
else if (state.snapshot) setRefs(refsOf(state.snapshot));
|
|
4714
|
+
}, [state.repository, state.snapshot]);
|
|
4715
|
+
const [followers, setFollowers] = useState(controller.followers());
|
|
4716
|
+
useEffect(() => {
|
|
4717
|
+
controller.onFollowers = setFollowers;
|
|
4718
|
+
setFollowers(controller.followers());
|
|
4719
|
+
return () => {
|
|
4720
|
+
controller.onFollowers = () => {};
|
|
4721
|
+
};
|
|
4722
|
+
}, []);
|
|
4723
|
+
const following = followers > 0;
|
|
4220
4724
|
useEffect(() => {
|
|
4221
4725
|
const repository = state.repository;
|
|
4222
|
-
if (!
|
|
4223
|
-
|
|
4224
|
-
let stopped = false;
|
|
4225
|
-
let checking = false;
|
|
4226
|
-
const check = async () => {
|
|
4726
|
+
if (!repository || !shown && !following) return;
|
|
4727
|
+
return watchRepository(document, repository.root, async (stopped) => {
|
|
4227
4728
|
const { snapshot } = current.current;
|
|
4228
|
-
|
|
4229
|
-
if (
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
handled.current = probe;
|
|
4235
|
-
const { selected, commit } = current.current;
|
|
4236
|
-
if (selected || commit || reviewing.current) setState((previous) => previous.snapshot === snapshot ? _objectSpread2$1(_objectSpread2$1({}, previous), {}, { notice: labelsFor(locale).outdated }) : previous);
|
|
4237
|
-
else await controller.refresh(true);
|
|
4238
|
-
} catch (_unused) {} finally {
|
|
4239
|
-
checking = false;
|
|
4240
|
-
}
|
|
4241
|
-
};
|
|
4242
|
-
let soon;
|
|
4243
|
-
const schedule = () => {
|
|
4244
|
-
view.clearTimeout(soon);
|
|
4245
|
-
soon = view.setTimeout(() => void check(), 300);
|
|
4246
|
-
};
|
|
4247
|
-
const interval = view.setInterval(() => void check(), watchInterval);
|
|
4248
|
-
const onFocus = () => void check();
|
|
4249
|
-
view.addEventListener("focus", onFocus);
|
|
4250
|
-
document.addEventListener("visibilitychange", onFocus);
|
|
4251
|
-
let observer = null;
|
|
4252
|
-
try {
|
|
4253
|
-
if (view.FileSystemObserver) {
|
|
4254
|
-
observer = new view.FileSystemObserver(schedule);
|
|
4255
|
-
observer.observe(repository.root, { recursive: true }).catch(() => {});
|
|
4729
|
+
if (running.current || current.current.repository !== repository) return;
|
|
4730
|
+
if (!(shown && !!dialog.current && dialog.current.getClientRects().length > 0) || !snapshot) {
|
|
4731
|
+
if (!following) return;
|
|
4732
|
+
const next = await repository.refs();
|
|
4733
|
+
if (!stopped() && current.current.repository === repository) setRefs((previous) => sameRefs(previous, next) ? previous : next);
|
|
4734
|
+
return;
|
|
4256
4735
|
}
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
view.clearTimeout(soon);
|
|
4265
|
-
view.removeEventListener("focus", onFocus);
|
|
4266
|
-
document.removeEventListener("visibilitychange", onFocus);
|
|
4267
|
-
observer === null || observer === void 0 || observer.disconnect();
|
|
4268
|
-
};
|
|
4736
|
+
const probe = await repository.probe(snapshot.scope);
|
|
4737
|
+
if (stopped() || probe === "locked" || probe === snapshot.probe || probe === handled.current || current.current.snapshot !== snapshot) return;
|
|
4738
|
+
handled.current = probe;
|
|
4739
|
+
const { selected, commit } = current.current;
|
|
4740
|
+
if (selected || commit || reviewing.current) setState((previous) => previous.snapshot === snapshot ? _objectSpread2$1(_objectSpread2$1({}, previous), {}, { notice: labelsFor(locale).outdated }) : previous);
|
|
4741
|
+
else await controller.refresh(true);
|
|
4742
|
+
});
|
|
4269
4743
|
}, [
|
|
4270
4744
|
shown,
|
|
4745
|
+
following,
|
|
4271
4746
|
state.repository,
|
|
4272
4747
|
locale
|
|
4273
4748
|
]);
|
|
@@ -4282,7 +4757,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4282
4757
|
}, [visible, slot]);
|
|
4283
4758
|
const chooseRoot = async () => {
|
|
4284
4759
|
const view = document.defaultView;
|
|
4285
|
-
|
|
4760
|
+
return run(async () => {
|
|
4286
4761
|
var _host$connectionSetti;
|
|
4287
4762
|
let root;
|
|
4288
4763
|
try {
|
|
@@ -4394,6 +4869,14 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4394
4869
|
};
|
|
4395
4870
|
});
|
|
4396
4871
|
};
|
|
4872
|
+
const pullRequestConnection = useMemo(() => {
|
|
4873
|
+
const settings = host.connectionSettings;
|
|
4874
|
+
const getSession = settings === null || settings === void 0 ? void 0 : settings.getSession;
|
|
4875
|
+
return getSession ? {
|
|
4876
|
+
getSession,
|
|
4877
|
+
connected: () => settings.getView().state.status === "connected"
|
|
4878
|
+
} : void 0;
|
|
4879
|
+
}, [host]);
|
|
4397
4880
|
const [message, setMessage] = useState("");
|
|
4398
4881
|
const localOperation = (operation, notice) => {
|
|
4399
4882
|
const repository = current.current.repository;
|
|
@@ -4433,6 +4916,31 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4433
4916
|
if (operation.kind === "createBranch" && !operation.fromRemote && !at) setNewBranch("");
|
|
4434
4917
|
return result;
|
|
4435
4918
|
};
|
|
4919
|
+
/**
|
|
4920
|
+
* Opens a pull request version fetched over the connection: creates `pr/<number>` at its head (or reuses that
|
|
4921
|
+
* branch when it already points there), switches to it with the same refusals as any switch, and opens the project
|
|
4922
|
+
* folder again from it. The branch the person was on stays, so switching back is an ordinary switch.
|
|
4923
|
+
*/
|
|
4924
|
+
const openPullRequest = async (number, head) => {
|
|
4925
|
+
var _current$current$snap, _current$current$snap2;
|
|
4926
|
+
const repository = current.current.repository;
|
|
4927
|
+
if (!repository) return { done: false };
|
|
4928
|
+
const original = (_current$current$snap = (_current$current$snap2 = current.current.snapshot) === null || _current$current$snap2 === void 0 ? void 0 : _current$current$snap2.branch) !== null && _current$current$snap !== void 0 ? _current$current$snap : null;
|
|
4929
|
+
const name = pullRequestBranch(number);
|
|
4930
|
+
const result = await changeBranch({
|
|
4931
|
+
kind: "createBranch",
|
|
4932
|
+
name,
|
|
4933
|
+
at: head,
|
|
4934
|
+
checkout: true,
|
|
4935
|
+
reuse: true
|
|
4936
|
+
});
|
|
4937
|
+
if (!result.done) return result;
|
|
4938
|
+
const project = current.current.project;
|
|
4939
|
+
if (project !== null && await repository.hasFolder(name, project)) await openProject(project);
|
|
4940
|
+
const notice = (original && original !== name ? labels.openedPullRequest : labels.openedPullRequestDetached).replace("{number}", String(number)).replace("{branch}", name).replace("{previous}", original !== null && original !== void 0 ? original : "");
|
|
4941
|
+
if (alive.current) setState((previous) => previous.error ? previous : _objectSpread2$1(_objectSpread2$1({}, previous), {}, { notice }));
|
|
4942
|
+
return result;
|
|
4943
|
+
};
|
|
4436
4944
|
const [history, setHistory] = useState({
|
|
4437
4945
|
commits: [],
|
|
4438
4946
|
cursor: null,
|
|
@@ -4515,6 +5023,24 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4515
5023
|
state.snapshot,
|
|
4516
5024
|
state.selected
|
|
4517
5025
|
]);
|
|
5026
|
+
controller.changeBranch = changeBranch;
|
|
5027
|
+
controller.choose = async (language) => {
|
|
5028
|
+
setLocale(language);
|
|
5029
|
+
const before = current.current.repository;
|
|
5030
|
+
const result = await chooseRoot();
|
|
5031
|
+
if (!result.done && result.error || current.current.repository !== before) controller.open(language);
|
|
5032
|
+
};
|
|
5033
|
+
const branchState = {
|
|
5034
|
+
repository: !!state.repository,
|
|
5035
|
+
branch: refs === null || refs === void 0 ? void 0 : refs.branch,
|
|
5036
|
+
head: (_refs$head = refs === null || refs === void 0 ? void 0 : refs.head) !== null && _refs$head !== void 0 ? _refs$head : null,
|
|
5037
|
+
branches: (_refs$branches = refs === null || refs === void 0 ? void 0 : refs.branches) !== null && _refs$branches !== void 0 ? _refs$branches : [],
|
|
5038
|
+
remoteBranches: (_refs$remoteBranches = refs === null || refs === void 0 ? void 0 : refs.remoteBranches) !== null && _refs$remoteBranches !== void 0 ? _refs$remoteBranches : [],
|
|
5039
|
+
writable: !!host.localWrite && !!refs,
|
|
5040
|
+
busy: state.busy
|
|
5041
|
+
};
|
|
5042
|
+
const published = JSON.stringify(branchState);
|
|
5043
|
+
useEffect(() => controller.publish(branchState), [published]);
|
|
4518
5044
|
if (!shown) return null;
|
|
4519
5045
|
const groups = state.commit ? ["commit"] : [
|
|
4520
5046
|
"staged",
|
|
@@ -4595,7 +5121,12 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4595
5121
|
locale,
|
|
4596
5122
|
renderBlock: host.renderReviewBlock,
|
|
4597
5123
|
locateFor: reviewLocator,
|
|
4598
|
-
openTabs
|
|
5124
|
+
openTabs,
|
|
5125
|
+
connection: pullRequestConnection,
|
|
5126
|
+
openLocally: branching ? {
|
|
5127
|
+
open: openPullRequest,
|
|
5128
|
+
busy: state.busy
|
|
5129
|
+
} : void 0
|
|
4599
5130
|
}), !review && state.repository && /* @__PURE__ */ React.createElement("div", { className: "twgit-content" }, /* @__PURE__ */ React.createElement("aside", null, state.browser && /* @__PURE__ */ React.createElement("details", null, /* @__PURE__ */ React.createElement("summary", null, labels.browse), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("code", null, state.browser.path || "/")), /* @__PURE__ */ React.createElement("button", {
|
|
4600
5131
|
disabled: state.busy || !state.browser.path,
|
|
4601
5132
|
onClick: () => void browse(state.browser.path.split("/").slice(0, -1).join("/"))
|
|
@@ -4776,15 +5307,21 @@ function upstreamText({ upstream }, labels) {
|
|
|
4776
5307
|
default: return labels.upstreamUnknown;
|
|
4777
5308
|
}
|
|
4778
5309
|
}
|
|
5310
|
+
var refsOf = ({ branch, head, branches, remoteBranches }) => ({
|
|
5311
|
+
branch,
|
|
5312
|
+
head,
|
|
5313
|
+
branches,
|
|
5314
|
+
remoteBranches
|
|
5315
|
+
});
|
|
5316
|
+
var announce = () => {
|
|
5317
|
+
for (const listener of [...registrations]) listener();
|
|
5318
|
+
};
|
|
4779
5319
|
function mountGitPanel({ vm, document, host }) {
|
|
4780
5320
|
var _document$defaultView3;
|
|
4781
5321
|
if (!((_document$defaultView3 = document.defaultView) === null || _document$defaultView3 === void 0 ? void 0 : _document$defaultView3.showDirectoryPicker)) return null;
|
|
4782
5322
|
const root = document.createElement("div");
|
|
4783
5323
|
document.body.append(root);
|
|
4784
|
-
const controller =
|
|
4785
|
-
open() {},
|
|
4786
|
-
async refresh() {}
|
|
4787
|
-
};
|
|
5324
|
+
const controller = createController();
|
|
4788
5325
|
controllers.set(vm, controller);
|
|
4789
5326
|
render(/* @__PURE__ */ React.createElement(GitPanel, {
|
|
4790
5327
|
vm,
|
|
@@ -4792,26 +5329,70 @@ function mountGitPanel({ vm, document, host }) {
|
|
|
4792
5329
|
host,
|
|
4793
5330
|
controller
|
|
4794
5331
|
}), root);
|
|
5332
|
+
announce();
|
|
4795
5333
|
return {
|
|
4796
5334
|
refresh: () => controller.refresh(),
|
|
5335
|
+
open: (locale) => controller.open(locale),
|
|
4797
5336
|
dispose() {
|
|
4798
5337
|
var _host$connectionSetti3;
|
|
4799
5338
|
if (controllers.get(vm) === controller) controllers.delete(vm);
|
|
4800
5339
|
(_host$connectionSetti3 = host.connectionSettings) === null || _host$connectionSetti3 === void 0 || _host$connectionSetti3.disconnect().catch(() => {});
|
|
4801
5340
|
unmountComponentAtNode(root);
|
|
4802
5341
|
root.remove();
|
|
5342
|
+
announce();
|
|
4803
5343
|
}
|
|
4804
5344
|
};
|
|
4805
5345
|
}
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
5346
|
+
/** The branch button of the panel mounted for `vm`, or nothing while no panel is mounted for it. */
|
|
5347
|
+
function BranchEntry({ vm, locale }) {
|
|
5348
|
+
const [controller, setController] = useState(() => controllers.get(vm));
|
|
5349
|
+
useEffect(() => {
|
|
5350
|
+
const update = () => setController(controllers.get(vm));
|
|
5351
|
+
registrations.add(update);
|
|
5352
|
+
update();
|
|
5353
|
+
return () => {
|
|
5354
|
+
registrations.delete(update);
|
|
5355
|
+
};
|
|
5356
|
+
}, [vm]);
|
|
5357
|
+
const [state, setState] = useState(controller === null || controller === void 0 ? void 0 : controller.branch);
|
|
5358
|
+
useEffect(() => {
|
|
5359
|
+
if (!controller) return;
|
|
5360
|
+
const update = () => setState(controller.branch);
|
|
5361
|
+
update();
|
|
5362
|
+
return controller.follow(update);
|
|
5363
|
+
}, [controller]);
|
|
5364
|
+
if (!controller || !state) return null;
|
|
5365
|
+
return /* @__PURE__ */ React.createElement(BranchButton, {
|
|
5366
|
+
state,
|
|
5367
|
+
locale,
|
|
5368
|
+
open: () => controller.open(locale),
|
|
5369
|
+
choose: () => void controller.choose(locale),
|
|
5370
|
+
switchBranch: (name) => controller.changeBranch({
|
|
5371
|
+
kind: "switchBranch",
|
|
5372
|
+
name
|
|
5373
|
+
}),
|
|
5374
|
+
createBranch: (name, checkout) => controller.changeBranch({
|
|
5375
|
+
kind: "createBranch",
|
|
5376
|
+
name,
|
|
5377
|
+
checkout
|
|
5378
|
+
}),
|
|
5379
|
+
createFromRemote: (name) => controller.changeBranch({
|
|
5380
|
+
kind: "createBranch",
|
|
5381
|
+
name,
|
|
5382
|
+
fromRemote: true,
|
|
5383
|
+
checkout: true
|
|
5384
|
+
})
|
|
5385
|
+
});
|
|
5386
|
+
}
|
|
5387
|
+
/**
|
|
5388
|
+
* Renders the button for the host's menu bar that shows the current branch of the panel mounted for `vm` and opens the
|
|
5389
|
+
* menu of branches, the panel and the repository choice. It renders nothing while no panel is mounted for `vm`, such as
|
|
5390
|
+
* when the host does not offer local Git, and shares the panel's repository, operations and checks.
|
|
5391
|
+
*/
|
|
5392
|
+
function renderBranchButton(createElement, { vm, locale = "en" }) {
|
|
5393
|
+
return createElement(BranchEntry, {
|
|
5394
|
+
vm,
|
|
5395
|
+
locale
|
|
5396
|
+
});
|
|
4816
5397
|
}
|
|
4817
|
-
export { GitPanelError, HistoryGraph, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, laneColors, layoutHistory, mountGitPanel, openProjectComparison, openProjectSourceTabs, openRepository,
|
|
5398
|
+
export { BranchButton, GitPanelError, HistoryGraph, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, laneColors, layoutHistory, mountGitPanel, openProjectComparison, openProjectSourceTabs, openRepository, pullRequestBranch, pullRequestRef, renderBranchButton };
|