@kubohiroya/turbowarp-plus-editor-git 0.17.0 → 0.19.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 +13 -3
- package/README.md +12 -2
- package/dist/branch-button.d.ts +47 -0
- package/dist/change-marks.d.ts +8 -0
- package/dist/connection-settings.d.ts +3 -1
- package/dist/github-pull-requests.d.ts +2 -2
- package/dist/github-review-api.d.ts +112 -0
- package/dist/index.d.ts +29 -5
- package/dist/index.js +830 -303
- package/dist/messages.d.ts +109 -2
- package/dist/{project-asset-paths-nL5sV35A.js → project-asset-paths-DNaoWs3E.js} +2 -2
- package/dist/{project-comparison-DjMlwyp8.js → project-comparison-B_3QZ6M-.js} +1414 -33
- package/dist/project-source-diff.d.ts +5 -0
- package/dist/project-source-diff.js +4 -4
- package/dist/project-source-review.d.ts +6 -1
- package/dist/pull-request-panel.d.ts +2 -0
- package/dist/remote-operations.d.ts +1 -1
- package/dist/{repository-xIv0iZkj.js → repository-DXRZEtYk.js} +26 -10
- package/dist/repository.d.ts +7 -0
- package/dist/repository.js +1 -1
- package/dist/review-composer.d.ts +23 -0
- package/dist/review-submit.d.ts +144 -0
- package/dist/{smart-http-BmHEkE7K.js → smart-http-eARzlXHO.js} +101 -2
- package/dist/smart-http.d.ts +2 -0
- package/dist/smart-http.js +1 -1
- package/dist/style.css +51 -0
- package/package.json +1 -1
- package/src/branch-button.tsx +289 -0
- package/src/change-marks.ts +22 -0
- package/src/connection-settings.tsx +9 -2
- package/src/github-review-api.ts +298 -0
- package/src/index.tsx +322 -66
- package/src/messages.ts +80 -4
- package/src/project-source-diff.css +10 -0
- package/src/project-source-diff.tsx +6 -0
- package/src/project-source-review.tsx +33 -5
- package/src/pull-request-panel.tsx +27 -6
- package/src/remote-operations.ts +1 -1
- package/src/repository.ts +22 -8
- package/src/review-composer.tsx +166 -0
- package/src/review-submit.ts +519 -0
- package/src/smart-http.ts +2 -2
- package/src/style.css +41 -0
- package/dist/objectSpread2-Dkd68nJH.js +0 -101
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { l as parseProjectSource, u as readProjectSourceDiff } from "./project-asset-paths-
|
|
4
|
-
import { a as pullRequestRef, i as pullRequestBranch, n as openRepository, o as GitPanelError, s as createReadOnlyFs } from "./repository-
|
|
1
|
+
import { B as CloseButton, E as reviewLabelsFor, M as projectPropertyLabel, O as createGitHubReviewApi, R as useAssetImage, T as labelsFor, a as openProjectSourceTabs, c as gitHubRepositoryFromOrigin, d as PullRequestReviewComposer, i as createScratchBlocksDiffLocator, j as organizeProjectChanges, l as ProjectSourceComparison, n as openProjectComparison, o as PullRequestError, r as createScratchBlocksDiffRenderer, s as createGitHubPullRequests, u as ProjectSourceReview, z as useCostumeImage } from "./project-comparison-B_3QZ6M-.js";
|
|
2
|
+
import { d as __commonJSMin, l as _objectSpread2$1, u as init_objectSpread2 } from "./smart-http-eARzlXHO.js";
|
|
3
|
+
import { f as _objectWithoutProperties$1, l as parseProjectSource, u as readProjectSourceDiff } from "./project-asset-paths-DNaoWs3E.js";
|
|
4
|
+
import { a as pullRequestRef, i as pullRequestBranch, n as openRepository, o as GitPanelError, s as createReadOnlyFs } from "./repository-DXRZEtYk.js";
|
|
5
5
|
import * as m from "react";
|
|
6
|
-
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";
|
|
7
7
|
import { createPortal, render, unmountComponentAtNode } from "react-dom";
|
|
8
8
|
// builtin:esm-external-require-react
|
|
9
9
|
var require_builtin_esm_external_require_react = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -3026,6 +3026,397 @@ function ProjectElementView({ changes, selection, locale, renderBlock, onSelectF
|
|
|
3026
3026
|
onClick: () => onSelectFile(file)
|
|
3027
3027
|
}, file.path, " ", /* @__PURE__ */ React.createElement("small", null, labels.groups[file.group])))))));
|
|
3028
3028
|
}
|
|
3029
|
+
// src/branch-button.tsx
|
|
3030
|
+
init_objectSpread2();
|
|
3031
|
+
var _excluded = ["state", "locale"];
|
|
3032
|
+
var menuItems = "[role=\"menuitem\"], [role=\"menuitemradio\"]";
|
|
3033
|
+
/** How long a snackbar stays when it is neither hovered nor focused. */
|
|
3034
|
+
var snackbarDuration = 6e3;
|
|
3035
|
+
/**
|
|
3036
|
+
* A short result at the bottom of the window, with the project folder's status look. It stays while hovered or
|
|
3037
|
+
* focused, Escape or the close button dismisses it, and focus is never moved into it.
|
|
3038
|
+
*/
|
|
3039
|
+
function Snackbar({ snack, closeLabel, onClose }) {
|
|
3040
|
+
const held = useRef({
|
|
3041
|
+
hover: false,
|
|
3042
|
+
focus: false
|
|
3043
|
+
});
|
|
3044
|
+
const timer = useRef();
|
|
3045
|
+
const hold = (change) => {
|
|
3046
|
+
held.current = _objectSpread2$1(_objectSpread2$1({}, held.current), change);
|
|
3047
|
+
clearTimeout(timer.current);
|
|
3048
|
+
if (!held.current.hover && !held.current.focus) timer.current = setTimeout(() => onClose(false), snackbarDuration);
|
|
3049
|
+
};
|
|
3050
|
+
useEffect(() => {
|
|
3051
|
+
hold({});
|
|
3052
|
+
return () => clearTimeout(timer.current);
|
|
3053
|
+
}, []);
|
|
3054
|
+
return createPortal(/* @__PURE__ */ React.createElement("div", {
|
|
3055
|
+
className: "twgit-snackbar",
|
|
3056
|
+
"data-git-snackbar": "",
|
|
3057
|
+
onMouseEnter: () => hold({ hover: true }),
|
|
3058
|
+
onMouseLeave: () => hold({ hover: false }),
|
|
3059
|
+
onFocus: () => hold({ focus: true }),
|
|
3060
|
+
onBlur: (event) => {
|
|
3061
|
+
if (!event.currentTarget.contains(event.relatedTarget)) hold({ focus: false });
|
|
3062
|
+
},
|
|
3063
|
+
onKeyDown: (event) => {
|
|
3064
|
+
if (event.key !== "Escape") return;
|
|
3065
|
+
event.preventDefault();
|
|
3066
|
+
event.stopPropagation();
|
|
3067
|
+
onClose(true);
|
|
3068
|
+
}
|
|
3069
|
+
}, /* @__PURE__ */ React.createElement("span", { role: snack.alert ? "alert" : "status" }, snack.text), snack.action && /* @__PURE__ */ React.createElement("button", {
|
|
3070
|
+
type: "button",
|
|
3071
|
+
onClick: () => {
|
|
3072
|
+
onClose(true);
|
|
3073
|
+
snack.action.run();
|
|
3074
|
+
}
|
|
3075
|
+
}, snack.action.label), /* @__PURE__ */ React.createElement(CloseButton, {
|
|
3076
|
+
label: closeLabel,
|
|
3077
|
+
onClick: () => onClose(true)
|
|
3078
|
+
})), document.body);
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3081
|
+
* The results of branch operations in a snackbar, as the branch button and the history view tell them: a switch with
|
|
3082
|
+
* Reload Project while a project folder is selected, a new branch, or the reason for a refusal with Open Local Git.
|
|
3083
|
+
* A declined confirmation tells nothing. `restoreFocus` takes the focus back when the snackbar closes from inside.
|
|
3084
|
+
*/
|
|
3085
|
+
function useBranchSnackbar(locale, project, actions, restoreFocus) {
|
|
3086
|
+
const labels = labelsFor(locale);
|
|
3087
|
+
const [snack, setSnack] = useState(null);
|
|
3088
|
+
const snacks = useRef(0);
|
|
3089
|
+
const mounted = useRef(true);
|
|
3090
|
+
useEffect(() => () => {
|
|
3091
|
+
mounted.current = false;
|
|
3092
|
+
}, []);
|
|
3093
|
+
const show = (text, alert, action) => {
|
|
3094
|
+
if (mounted.current) setSnack({
|
|
3095
|
+
id: ++snacks.current,
|
|
3096
|
+
text,
|
|
3097
|
+
alert,
|
|
3098
|
+
action
|
|
3099
|
+
});
|
|
3100
|
+
};
|
|
3101
|
+
const report = (result, switched) => {
|
|
3102
|
+
if (result.done) {
|
|
3103
|
+
if (!switched) show(labels.branchCreated, false);
|
|
3104
|
+
else show(labels.switchedShort, false, project ? {
|
|
3105
|
+
label: labels.reload,
|
|
3106
|
+
run: actions.reload
|
|
3107
|
+
} : void 0);
|
|
3108
|
+
} else if (result.error) show(result.error, true, {
|
|
3109
|
+
label: labels.openPanel,
|
|
3110
|
+
run: actions.open
|
|
3111
|
+
});
|
|
3112
|
+
};
|
|
3113
|
+
return {
|
|
3114
|
+
report,
|
|
3115
|
+
element: snack && /* @__PURE__ */ React.createElement(Snackbar, {
|
|
3116
|
+
key: snack.id,
|
|
3117
|
+
snack,
|
|
3118
|
+
closeLabel: labels.close,
|
|
3119
|
+
onClose: (focus) => {
|
|
3120
|
+
setSnack((previous) => (previous === null || previous === void 0 ? void 0 : previous.id) === snack.id ? null : previous);
|
|
3121
|
+
if (focus) restoreFocus === null || restoreFocus === void 0 || restoreFocus();
|
|
3122
|
+
}
|
|
3123
|
+
})
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
/** Git's branch glyph, drawn in the text color. */
|
|
3127
|
+
function BranchIcon() {
|
|
3128
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
3129
|
+
className: "twgit-branch-icon",
|
|
3130
|
+
viewBox: "0 0 16 16",
|
|
3131
|
+
width: "16",
|
|
3132
|
+
height: "16",
|
|
3133
|
+
"aria-hidden": "true",
|
|
3134
|
+
focusable: "false"
|
|
3135
|
+
}, /* @__PURE__ */ React.createElement("g", {
|
|
3136
|
+
fill: "none",
|
|
3137
|
+
stroke: "currentColor",
|
|
3138
|
+
strokeWidth: "1.5"
|
|
3139
|
+
}, /* @__PURE__ */ React.createElement("circle", {
|
|
3140
|
+
cx: "4.5",
|
|
3141
|
+
cy: "3.5",
|
|
3142
|
+
r: "1.75"
|
|
3143
|
+
}), /* @__PURE__ */ React.createElement("circle", {
|
|
3144
|
+
cx: "4.5",
|
|
3145
|
+
cy: "12.5",
|
|
3146
|
+
r: "1.75"
|
|
3147
|
+
}), /* @__PURE__ */ React.createElement("circle", {
|
|
3148
|
+
cx: "11.5",
|
|
3149
|
+
cy: "5.5",
|
|
3150
|
+
r: "1.75"
|
|
3151
|
+
}), /* @__PURE__ */ React.createElement("path", { d: "M4.5 5.25v5.5M11.5 7.25c0 2.5-2.5 2.75-6 3.75" })));
|
|
3152
|
+
}
|
|
3153
|
+
/**
|
|
3154
|
+
* The current branch as a menu button for the host's menu bar, with the menu of branches. Before a repository is
|
|
3155
|
+
* chosen it reads "Git" and offers to choose one. A detached HEAD shows its short commit ID. The menu moves with the
|
|
3156
|
+
* arrow keys, Home and End; Escape closes it and returns to the button. Without `writable` it lists the branches only.
|
|
3157
|
+
*/
|
|
3158
|
+
function BranchButton(_ref) {
|
|
3159
|
+
var _ref3;
|
|
3160
|
+
let { state, locale = "en" } = _ref, actions = _objectWithoutProperties$1(_ref, _excluded);
|
|
3161
|
+
const labels = labelsFor(locale);
|
|
3162
|
+
const [mode, setMode] = useState("closed");
|
|
3163
|
+
const [initial, setInitial] = useState("checked");
|
|
3164
|
+
const [name, setName] = useState("");
|
|
3165
|
+
const [checkout, setCheckout] = useState(true);
|
|
3166
|
+
const [creating, setCreating] = useState(false);
|
|
3167
|
+
const [createError, setCreateError] = useState("");
|
|
3168
|
+
const root = useRef(null);
|
|
3169
|
+
const trigger = useRef(null);
|
|
3170
|
+
const popup = useRef(null);
|
|
3171
|
+
const mounted = useRef(true);
|
|
3172
|
+
useEffect(() => () => {
|
|
3173
|
+
mounted.current = false;
|
|
3174
|
+
}, []);
|
|
3175
|
+
useLayoutEffect(() => {
|
|
3176
|
+
var _ref2;
|
|
3177
|
+
const element = popup.current;
|
|
3178
|
+
if (!element) return;
|
|
3179
|
+
if (mode === "create") {
|
|
3180
|
+
var _element$querySelecto;
|
|
3181
|
+
(_element$querySelecto = element.querySelector("input")) === null || _element$querySelecto === void 0 || _element$querySelecto.focus();
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
const items = [...element.querySelectorAll(menuItems)];
|
|
3185
|
+
const checked = items.find((item) => item.getAttribute("aria-checked") === "true");
|
|
3186
|
+
(_ref2 = initial === "last" ? items[items.length - 1] : initial === "checked" && checked || items[0]) === null || _ref2 === void 0 || _ref2.focus();
|
|
3187
|
+
}, [mode]);
|
|
3188
|
+
useEffect(() => {
|
|
3189
|
+
if (mode === "closed") return;
|
|
3190
|
+
const node = root.current;
|
|
3191
|
+
const dismiss = (event) => {
|
|
3192
|
+
if (!node.contains(event.target) && !creating) setMode("closed");
|
|
3193
|
+
};
|
|
3194
|
+
node.ownerDocument.addEventListener("pointerdown", dismiss, true);
|
|
3195
|
+
return () => node.ownerDocument.removeEventListener("pointerdown", dismiss, true);
|
|
3196
|
+
}, [mode, creating]);
|
|
3197
|
+
useEffect(() => {
|
|
3198
|
+
var _popup$current;
|
|
3199
|
+
if (!createError || creating) return;
|
|
3200
|
+
const input = (_popup$current = popup.current) === null || _popup$current === void 0 ? void 0 : _popup$current.querySelector("input:not([type])");
|
|
3201
|
+
input === null || input === void 0 || input.focus();
|
|
3202
|
+
input === null || input === void 0 || input.select();
|
|
3203
|
+
}, [createError, creating]);
|
|
3204
|
+
const { branch, head } = state;
|
|
3205
|
+
const unborn = state.repository && !head;
|
|
3206
|
+
const text = !state.repository ? "Git" : branch !== null && branch !== void 0 ? branch : head ? head.slice(0, 7) : labels.unborn;
|
|
3207
|
+
const accessibleName = !state.repository ? labels.title : `${branch ? labels.branch : labels.detached}: ${text}${unborn && branch ? ` (${labels.unborn})` : ""}`;
|
|
3208
|
+
const close = (focus = true) => {
|
|
3209
|
+
var _trigger$current;
|
|
3210
|
+
setMode("closed");
|
|
3211
|
+
if (focus) (_trigger$current = trigger.current) === null || _trigger$current === void 0 || _trigger$current.focus({ preventScroll: true });
|
|
3212
|
+
};
|
|
3213
|
+
const openMenu = (from) => {
|
|
3214
|
+
setInitial(from);
|
|
3215
|
+
setMode("menu");
|
|
3216
|
+
};
|
|
3217
|
+
const { report, element: snackbar } = useBranchSnackbar(locale, state.project, actions, () => {
|
|
3218
|
+
var _trigger$current2;
|
|
3219
|
+
return (_trigger$current2 = trigger.current) === null || _trigger$current2 === void 0 ? void 0 : _trigger$current2.focus({ preventScroll: true });
|
|
3220
|
+
});
|
|
3221
|
+
const change = async (operation) => report(await operation(), true);
|
|
3222
|
+
const items = [];
|
|
3223
|
+
if (!state.repository) items.push({
|
|
3224
|
+
id: "choose",
|
|
3225
|
+
label: labels.choose,
|
|
3226
|
+
run: () => {
|
|
3227
|
+
close();
|
|
3228
|
+
actions.choose();
|
|
3229
|
+
}
|
|
3230
|
+
});
|
|
3231
|
+
else {
|
|
3232
|
+
const switching = state.writable && !state.busy;
|
|
3233
|
+
for (const local of state.branches) items.push({
|
|
3234
|
+
id: "branch:" + local,
|
|
3235
|
+
label: local,
|
|
3236
|
+
checked: local === branch,
|
|
3237
|
+
disabled: !state.writable || state.busy && local !== branch,
|
|
3238
|
+
run: () => {
|
|
3239
|
+
close();
|
|
3240
|
+
if (local !== branch && switching) change(() => actions.switchBranch(local));
|
|
3241
|
+
}
|
|
3242
|
+
});
|
|
3243
|
+
if (state.writable) {
|
|
3244
|
+
state.remoteBranches.forEach((remote, index) => items.push({
|
|
3245
|
+
id: "remote:" + remote,
|
|
3246
|
+
label: labels.historyCreateFromRemote.replace("{name}", remote),
|
|
3247
|
+
disabled: state.busy,
|
|
3248
|
+
separatorBefore: index === 0,
|
|
3249
|
+
run: () => {
|
|
3250
|
+
close();
|
|
3251
|
+
if (!state.busy) change(() => actions.createFromRemote(remote));
|
|
3252
|
+
}
|
|
3253
|
+
}));
|
|
3254
|
+
if (head) items.push({
|
|
3255
|
+
id: "create",
|
|
3256
|
+
label: labels.newBranchItem,
|
|
3257
|
+
disabled: state.busy,
|
|
3258
|
+
separatorBefore: true,
|
|
3259
|
+
run: () => {
|
|
3260
|
+
if (state.busy) return;
|
|
3261
|
+
setName("");
|
|
3262
|
+
setCheckout(true);
|
|
3263
|
+
setCreateError("");
|
|
3264
|
+
setMode("create");
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
items.push({
|
|
3270
|
+
id: "open",
|
|
3271
|
+
label: labels.openPanel,
|
|
3272
|
+
separatorBefore: items.length > 0 && items[items.length - 1].id !== "create",
|
|
3273
|
+
run: () => {
|
|
3274
|
+
close();
|
|
3275
|
+
actions.open();
|
|
3276
|
+
}
|
|
3277
|
+
});
|
|
3278
|
+
const onMenuKey = (event) => {
|
|
3279
|
+
if (event.key === "Escape") {
|
|
3280
|
+
event.preventDefault();
|
|
3281
|
+
event.stopPropagation();
|
|
3282
|
+
if (!creating) close();
|
|
3283
|
+
return;
|
|
3284
|
+
}
|
|
3285
|
+
if (mode !== "menu") return;
|
|
3286
|
+
if (event.key === "Tab") {
|
|
3287
|
+
close(false);
|
|
3288
|
+
return;
|
|
3289
|
+
}
|
|
3290
|
+
const elements = [...event.currentTarget.querySelectorAll(menuItems)];
|
|
3291
|
+
const index = elements.indexOf(event.target);
|
|
3292
|
+
const target = {
|
|
3293
|
+
ArrowDown: index + 1,
|
|
3294
|
+
ArrowUp: index - 1,
|
|
3295
|
+
Home: 0,
|
|
3296
|
+
End: elements.length - 1
|
|
3297
|
+
}[event.key];
|
|
3298
|
+
if (target === void 0 || !elements.length) return;
|
|
3299
|
+
event.preventDefault();
|
|
3300
|
+
elements[(target + elements.length) % elements.length].focus();
|
|
3301
|
+
};
|
|
3302
|
+
const submit = async (event) => {
|
|
3303
|
+
var _result$error;
|
|
3304
|
+
event.preventDefault();
|
|
3305
|
+
const branchName = name.trim();
|
|
3306
|
+
if (!branchName || creating) return;
|
|
3307
|
+
setCreating(true);
|
|
3308
|
+
setCreateError("");
|
|
3309
|
+
let result;
|
|
3310
|
+
try {
|
|
3311
|
+
result = await actions.createBranch(branchName, checkout);
|
|
3312
|
+
} catch (error) {
|
|
3313
|
+
result = {
|
|
3314
|
+
done: false,
|
|
3315
|
+
error: error instanceof Error && error.message ? error.message : labels.failed
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
if (!mounted.current) return;
|
|
3319
|
+
setCreating(false);
|
|
3320
|
+
if (result.done) {
|
|
3321
|
+
close();
|
|
3322
|
+
report(result, checkout);
|
|
3323
|
+
} else setCreateError((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : "");
|
|
3324
|
+
};
|
|
3325
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
3326
|
+
className: "twgit-branch-entry",
|
|
3327
|
+
ref: root,
|
|
3328
|
+
onBlur: (event) => {
|
|
3329
|
+
const next = event.relatedTarget;
|
|
3330
|
+
if (next && !event.currentTarget.contains(next) && !creating) setMode("closed");
|
|
3331
|
+
}
|
|
3332
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
3333
|
+
type: "button",
|
|
3334
|
+
className: "twgit-branch-button",
|
|
3335
|
+
ref: trigger,
|
|
3336
|
+
"aria-label": accessibleName,
|
|
3337
|
+
title: accessibleName,
|
|
3338
|
+
"aria-haspopup": "menu",
|
|
3339
|
+
"aria-expanded": mode === "menu",
|
|
3340
|
+
"data-git-branch": state.repository ? (_ref3 = branch !== null && branch !== void 0 ? branch : head) !== null && _ref3 !== void 0 ? _ref3 : "" : void 0,
|
|
3341
|
+
onClick: () => mode === "closed" ? openMenu("checked") : close(false),
|
|
3342
|
+
onKeyDown: (event) => {
|
|
3343
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
|
|
3344
|
+
event.preventDefault();
|
|
3345
|
+
openMenu(event.key === "ArrowUp" ? "last" : "checked");
|
|
3346
|
+
}
|
|
3347
|
+
}, /* @__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", {
|
|
3348
|
+
className: "twgit-branch-caret",
|
|
3349
|
+
"aria-hidden": "true"
|
|
3350
|
+
}, "▾")), mode === "menu" && /* @__PURE__ */ React.createElement("div", {
|
|
3351
|
+
ref: popup,
|
|
3352
|
+
className: "twgit-branch-popup",
|
|
3353
|
+
role: "menu",
|
|
3354
|
+
"aria-label": labels.branchMenu,
|
|
3355
|
+
onKeyDown: onMenuKey
|
|
3356
|
+
}, items.map((item) => /* @__PURE__ */ React.createElement("button", {
|
|
3357
|
+
key: item.id,
|
|
3358
|
+
type: "button",
|
|
3359
|
+
tabIndex: -1,
|
|
3360
|
+
"data-action": item.id,
|
|
3361
|
+
role: item.checked === void 0 ? "menuitem" : "menuitemradio",
|
|
3362
|
+
"aria-checked": item.checked,
|
|
3363
|
+
"aria-disabled": item.disabled || void 0,
|
|
3364
|
+
"data-separator-before": item.separatorBefore || void 0,
|
|
3365
|
+
onClick: () => {
|
|
3366
|
+
if (!item.disabled || item.checked) item.run();
|
|
3367
|
+
}
|
|
3368
|
+
}, item.checked !== void 0 && /* @__PURE__ */ React.createElement("span", {
|
|
3369
|
+
className: "twgit-branch-check",
|
|
3370
|
+
"aria-hidden": "true"
|
|
3371
|
+
}, item.checked ? "✓" : ""), item.label))), mode === "create" && /* @__PURE__ */ React.createElement("div", {
|
|
3372
|
+
ref: popup,
|
|
3373
|
+
className: "twgit-branch-popup",
|
|
3374
|
+
role: "dialog",
|
|
3375
|
+
"aria-label": labels.newBranchTitle,
|
|
3376
|
+
onKeyDown: onMenuKey
|
|
3377
|
+
}, /* @__PURE__ */ React.createElement("form", { onSubmit: (event) => void submit(event) }, /* @__PURE__ */ React.createElement("label", null, labels.newBranch, " ", /* @__PURE__ */ React.createElement("input", {
|
|
3378
|
+
value: name,
|
|
3379
|
+
required: true,
|
|
3380
|
+
disabled: creating,
|
|
3381
|
+
"aria-invalid": createError ? true : void 0,
|
|
3382
|
+
onChange: (event) => setName(event.currentTarget.value)
|
|
3383
|
+
})), /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
|
|
3384
|
+
type: "checkbox",
|
|
3385
|
+
checked: checkout,
|
|
3386
|
+
disabled: creating,
|
|
3387
|
+
onChange: (event) => setCheckout(event.currentTarget.checked)
|
|
3388
|
+
}), " ", labels.switchAfterCreate), createError && /* @__PURE__ */ React.createElement("p", {
|
|
3389
|
+
className: "twgit-graph-form-error",
|
|
3390
|
+
role: "alert"
|
|
3391
|
+
}, createError), /* @__PURE__ */ React.createElement("span", { className: "twgit-graph-form-actions" }, /* @__PURE__ */ React.createElement("button", {
|
|
3392
|
+
type: "submit",
|
|
3393
|
+
disabled: creating || state.busy || !name.trim()
|
|
3394
|
+
}, labels.createBranch), /* @__PURE__ */ React.createElement("button", {
|
|
3395
|
+
type: "button",
|
|
3396
|
+
disabled: creating,
|
|
3397
|
+
onClick: () => close()
|
|
3398
|
+
}, labels.cancel)))), snackbar);
|
|
3399
|
+
}
|
|
3400
|
+
// src/change-marks.ts
|
|
3401
|
+
/**
|
|
3402
|
+
* The marks of the working tree's changes under `folder` (a path inside the repository, '' for its root), by path
|
|
3403
|
+
* relative to `folder`. A file with both staged and unstaged changes is marked as its working tree stands.
|
|
3404
|
+
*/
|
|
3405
|
+
function changeMarks(changes, folder) {
|
|
3406
|
+
const prefix = folder.replace(/^\/+|\/+$/gu, "");
|
|
3407
|
+
const marks = /* @__PURE__ */ new Map();
|
|
3408
|
+
for (const group of [
|
|
3409
|
+
"staged",
|
|
3410
|
+
"unstaged",
|
|
3411
|
+
"untracked"
|
|
3412
|
+
]) for (const change of changes) {
|
|
3413
|
+
if (change.group !== group) continue;
|
|
3414
|
+
if (prefix && !change.path.startsWith(prefix + "/")) continue;
|
|
3415
|
+
const path = prefix ? change.path.slice(prefix.length + 1) : change.path;
|
|
3416
|
+
marks.set(path, group === "untracked" ? "untracked" : !change.after ? "deleted" : !change.before ? "added" : "modified");
|
|
3417
|
+
}
|
|
3418
|
+
return marks;
|
|
3419
|
+
}
|
|
3029
3420
|
/**
|
|
3030
3421
|
* Lays out commits ordered newest first with every child above its parents. Parents missing from `commits`, such as
|
|
3031
3422
|
* those on a page not loaded yet or cut off by a shallow clone, keep their lane running to the bottom.
|
|
@@ -3104,234 +3495,6 @@ function layoutHistory(commits) {
|
|
|
3104
3495
|
width: Math.max(0, ...rows.map((row) => row.width))
|
|
3105
3496
|
};
|
|
3106
3497
|
}
|
|
3107
|
-
// src/messages.ts
|
|
3108
|
-
var messages = {
|
|
3109
|
-
en: {
|
|
3110
|
-
pullRequests: "Pull requests",
|
|
3111
|
-
localChanges: "Local changes",
|
|
3112
|
-
title: "Local Git",
|
|
3113
|
-
menu: "Local Git…",
|
|
3114
|
-
close: "Close",
|
|
3115
|
-
choose: "Choose Repository…",
|
|
3116
|
-
refresh: "Refresh",
|
|
3117
|
-
empty: "Choose an existing Git repository to inspect its files and history.",
|
|
3118
|
-
repository: "Repository",
|
|
3119
|
-
project: "Project folder",
|
|
3120
|
-
none: "No project selected",
|
|
3121
|
-
root: "Repository root",
|
|
3122
|
-
open: "Open This Project",
|
|
3123
|
-
reload: "Reload Project",
|
|
3124
|
-
up: "Parent folder",
|
|
3125
|
-
browse: "Choose a project inside this repository",
|
|
3126
|
-
replace: "Replace the open project and discard its unsaved changes?",
|
|
3127
|
-
dirty: "The Editor has unsaved changes.",
|
|
3128
|
-
saved: "The Editor has no unsaved changes.",
|
|
3129
|
-
staged: "Changes in the next record",
|
|
3130
|
-
unstaged: "Saved, not yet recorded",
|
|
3131
|
-
untracked: "New files never recorded",
|
|
3132
|
-
commit: "Changes in this record",
|
|
3133
|
-
history: "Records (commits)",
|
|
3134
|
-
worktree: "Saved files",
|
|
3135
|
-
clean: "No saved changes in the selected folder.",
|
|
3136
|
-
branches: "Local branches",
|
|
3137
|
-
unborn: "No records yet",
|
|
3138
|
-
detached: "Detached HEAD",
|
|
3139
|
-
select: "Select a file to view its diff.",
|
|
3140
|
-
binary: "Binary asset",
|
|
3141
|
-
large: "Text preview exceeds its display limit.",
|
|
3142
|
-
bytes: "bytes",
|
|
3143
|
-
mode: "Git file mode",
|
|
3144
|
-
permissions: "Working-tree executable permission changes are unavailable in the browser.",
|
|
3145
|
-
unchanged: "The text is unchanged.",
|
|
3146
|
-
loading: "Reading repository…",
|
|
3147
|
-
invalid: "Choose a repository with a .git directory, and a project inside that repository.",
|
|
3148
|
-
changed: "Files or Git state changed while reading. Refresh to read the current state.",
|
|
3149
|
-
outdated: "The repository changed outside the Editor. Refresh to read the current state.",
|
|
3150
|
-
unsupported: "This repository contains an entry the browser cannot represent.",
|
|
3151
|
-
commitMessage: "Write a message for this record.",
|
|
3152
|
-
switchUnsafe: "Stop the project, and save or record (or undo) every change, before switching branches.",
|
|
3153
|
-
branchExists: "A branch with this name already exists.",
|
|
3154
|
-
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.",
|
|
3155
|
-
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.",
|
|
3156
|
-
openedPullRequest: "Opened pull request #{number} on the local branch {branch}. To go back, switch to {previous} in Local changes.",
|
|
3157
|
-
openedPullRequestDetached: "Opened pull request #{number} on the local branch {branch}. To go back, switch to another branch in Local changes.",
|
|
3158
|
-
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.",
|
|
3159
|
-
branchName: "Git cannot use this name for a branch.",
|
|
3160
|
-
pullUnsafe: "Stop the project, and save or undo unsaved edits and unrecorded changes, before getting changes from GitHub (pull).",
|
|
3161
|
-
diverged: "This branch and GitHub's have both gained records, so they cannot be combined here (pull only fast-forwards). Your branch and files are unchanged.",
|
|
3162
|
-
session: "Reconnect GitHub for this repository and requested permission.",
|
|
3163
|
-
pushUnknown: "It is unknown whether GitHub received the records. Check GitHub (fetch) before sending again.",
|
|
3164
|
-
pushRefresh: "GitHub received the records. Check GitHub (fetch) to update the status.",
|
|
3165
|
-
rollbackFailed: "Some local changes could not be restored. Check the files and the Git details.",
|
|
3166
|
-
remoteFailed: "Could not complete the GitHub operation. Check the connection and try again.",
|
|
3167
|
-
remoteDone: "The GitHub operation finished.",
|
|
3168
|
-
stage: "Add to Next Record",
|
|
3169
|
-
unstage: "Remove from Next Record",
|
|
3170
|
-
stageAll: "Add All Changes to Next Record",
|
|
3171
|
-
commitLabel: "Message for this record",
|
|
3172
|
-
commitButton: "Record (Commit)",
|
|
3173
|
-
committed: "Recorded the changes (commit).",
|
|
3174
|
-
commitAuthor: "Recorded as",
|
|
3175
|
-
saveFirst: "Save the project before adding its changes to the next record.",
|
|
3176
|
-
author: "Set user.name and user.email for this repository in Git before recording. The Editor does not change Git settings.",
|
|
3177
|
-
nothingStaged: "Add changes to the next record first.",
|
|
3178
|
-
switchTo: "Switch",
|
|
3179
|
-
currentBranch: "current",
|
|
3180
|
-
createBranch: "Create Branch",
|
|
3181
|
-
newBranch: "New branch name",
|
|
3182
|
-
switchAfterCreate: "Switch to it",
|
|
3183
|
-
createFromRemote: "Create and Switch",
|
|
3184
|
-
remoteBranches: "Branches on GitHub (origin)",
|
|
3185
|
-
switched: "Switched branches. Use Reload Project to open the files of this branch.",
|
|
3186
|
-
branchCreated: "Created the branch.",
|
|
3187
|
-
projectMissing: "The open project folder is not on this branch. Switch anyway?",
|
|
3188
|
-
pulledProject: "Got the changes from GitHub. Use Reload Project to open the updated files.",
|
|
3189
|
-
confirmPush: "Send the records on this branch to GitHub (push)?",
|
|
3190
|
-
details: "Git details",
|
|
3191
|
-
branch: "Branch",
|
|
3192
|
-
head: "HEAD",
|
|
3193
|
-
groups: "Git groups",
|
|
3194
|
-
added: "Added",
|
|
3195
|
-
modified: "Changed",
|
|
3196
|
-
deleted: "Deleted",
|
|
3197
|
-
gitStaged: "Staged",
|
|
3198
|
-
gitUnstaged: "Unstaged",
|
|
3199
|
-
gitUntracked: "Untracked",
|
|
3200
|
-
upstreamSame: "Same as GitHub",
|
|
3201
|
-
upstreamAhead: "Ahead of GitHub",
|
|
3202
|
-
upstreamBehind: "Behind GitHub",
|
|
3203
|
-
upstreamDiverged: "Diverged from GitHub",
|
|
3204
|
-
upstreamUnknown: "Not checked with GitHub yet",
|
|
3205
|
-
records: "records",
|
|
3206
|
-
checkedAt: "as of the last check",
|
|
3207
|
-
failed: "Could not read the repository. Check folder access and refresh.",
|
|
3208
|
-
historyMore: "Show more",
|
|
3209
|
-
historyLoading: "Reading records…",
|
|
3210
|
-
historyFailed: "Could not read the records.",
|
|
3211
|
-
historyActions: "Actions",
|
|
3212
|
-
historyCreateHere: "Create branch here…",
|
|
3213
|
-
historySwitch: "Switch to {name}",
|
|
3214
|
-
historyCreateFromRemote: "Create and switch to {name}",
|
|
3215
|
-
historyCopy: "Copy commit ID",
|
|
3216
|
-
historyCopied: "Copied the commit ID.",
|
|
3217
|
-
historyCopyFailed: "Could not copy the commit ID.",
|
|
3218
|
-
historyRefs: "Branches",
|
|
3219
|
-
cancel: "Cancel"
|
|
3220
|
-
},
|
|
3221
|
-
ja: {
|
|
3222
|
-
pullRequests: "プルリクエスト",
|
|
3223
|
-
localChanges: "ローカルの変更",
|
|
3224
|
-
title: "ローカル Git",
|
|
3225
|
-
menu: "ローカル Git…",
|
|
3226
|
-
close: "閉じる",
|
|
3227
|
-
choose: "リポジトリを選択…",
|
|
3228
|
-
refresh: "再取得",
|
|
3229
|
-
empty: "既存の Git リポジトリを選び、ファイルの状態と履歴を確認できます。",
|
|
3230
|
-
repository: "リポジトリ",
|
|
3231
|
-
project: "作品フォルダ",
|
|
3232
|
-
none: "作品は未選択",
|
|
3233
|
-
root: "リポジトリルート",
|
|
3234
|
-
open: "この作品を開く",
|
|
3235
|
-
reload: "作品を再読込",
|
|
3236
|
-
up: "上のフォルダ",
|
|
3237
|
-
browse: "リポジトリ内の作品を選択",
|
|
3238
|
-
replace: "保存していない編集を破棄して、別の作品を開きますか?",
|
|
3239
|
-
dirty: "Editor に保存していない編集があります。",
|
|
3240
|
-
saved: "Editor に保存していない編集はありません。",
|
|
3241
|
-
staged: "次の記録に入る変更",
|
|
3242
|
-
unstaged: "保存したが、まだ記録していない変更",
|
|
3243
|
-
untracked: "まだ記録したことのない新しいファイル",
|
|
3244
|
-
commit: "この記録の変更",
|
|
3245
|
-
history: "記録(コミット)の履歴",
|
|
3246
|
-
worktree: "保存したファイル",
|
|
3247
|
-
clean: "対象フォルダに、保存した変更はありません。",
|
|
3248
|
-
branches: "ローカルブランチ",
|
|
3249
|
-
unborn: "まだ記録がありません",
|
|
3250
|
-
detached: "ブランチ未選択の HEAD",
|
|
3251
|
-
select: "ファイルを選ぶと差分を表示します。",
|
|
3252
|
-
binary: "バイナリアセット",
|
|
3253
|
-
large: "テキスト差分の表示上限を超えています。",
|
|
3254
|
-
bytes: "バイト",
|
|
3255
|
-
mode: "Git のファイルモード",
|
|
3256
|
-
permissions: "作業ツリーの実行権限の変更はブラウザーから確認できません。",
|
|
3257
|
-
unchanged: "テキストに変更はありません。",
|
|
3258
|
-
loading: "リポジトリを読込中…",
|
|
3259
|
-
invalid: ".git ディレクトリを持つリポジトリと、その配下の作品を選んでください。",
|
|
3260
|
-
changed: "読込中にファイルまたは Git の状態が変わりました。再取得してください。",
|
|
3261
|
-
outdated: "Editor の外でリポジトリが変更されました。再取得すると最新の状態を読み込みます。",
|
|
3262
|
-
unsupported: "ブラウザーで扱えない種類の Git エントリーがあります。",
|
|
3263
|
-
commitMessage: "この記録の説明を書いてください。",
|
|
3264
|
-
switchUnsafe: "ブランチを切り替える前に、実行を止め、すべての変更を保存して記録(または取り消し)してください。",
|
|
3265
|
-
branchExists: "同じ名前のブランチがすでにあります。",
|
|
3266
|
-
branchConflict: "この名前は既存のブランチとぶつかります。Git では、pr と pr/7 のように、あるブランチと、その名前に / を続けたブランチを両方は持てません。Git でもう一方の名前を変えるか消すか、別の名前にしてください。",
|
|
3267
|
-
pullRequestBranch: "ブランチ pr/<番号> が、別の記録を指してすでにあるため、この版を開きませんでした。ブランチはそのままです。「ローカルの変更」で切り替えるか、Git で名前を変えるか消してから、もう一度ここで開いてください。",
|
|
3268
|
-
openedPullRequest: "プルリクエスト #{number} を、ローカルブランチ {branch} で開きました。戻るときは「ローカルの変更」で {previous} に切り替えてください。",
|
|
3269
|
-
openedPullRequestDetached: "プルリクエスト #{number} を、ローカルブランチ {branch} で開きました。戻るときは「ローカルの変更」で別のブランチに切り替えてください。",
|
|
3270
|
-
locked: "ほかの Git の操作が、このリポジトリを使っています(ロックファイル、またはマージ・cherry-pick・revert・rebase の途中)。終わってから、もう一度試してください。",
|
|
3271
|
-
branchName: "この名前は Git のブランチ名に使えません。",
|
|
3272
|
-
pullUnsafe: "GitHub から取り込む前に、実行を止め、保存していない編集とまだ記録していない変更をなくしてください。",
|
|
3273
|
-
diverged: "このブランチと GitHub の両方に新しい記録があるため、ここでは取り込めません(pull は fast-forward のみ)。ブランチとファイルはそのままです。",
|
|
3274
|
-
session: "このリポジトリと操作に必要な権限で GitHub に接続してください。",
|
|
3275
|
-
pushUnknown: "GitHub が記録を受け取ったか分かりません。送り直す前に「GitHub と確かめる」を使ってください。",
|
|
3276
|
-
pushRefresh: "GitHub が記録を受け取りました。「GitHub と確かめる」で状態を更新してください。",
|
|
3277
|
-
rollbackFailed: "一部のローカルの変更を元に戻せませんでした。ファイルと Git の詳細を確認してください。",
|
|
3278
|
-
remoteFailed: "GitHub との操作を完了できませんでした。接続を確認して、もう一度試してください。",
|
|
3279
|
-
remoteDone: "GitHub との操作が終わりました。",
|
|
3280
|
-
stage: "次の記録に入れる",
|
|
3281
|
-
unstage: "次の記録から外す",
|
|
3282
|
-
stageAll: "すべての変更を次の記録に入れる",
|
|
3283
|
-
commitLabel: "この記録の説明",
|
|
3284
|
-
commitButton: "記録する(コミット)",
|
|
3285
|
-
committed: "変更を記録しました(コミット)。",
|
|
3286
|
-
commitAuthor: "記録する人",
|
|
3287
|
-
saveFirst: "次の記録に入れる前に、作品を保存してください。",
|
|
3288
|
-
author: "記録する前に、Git でこのリポジトリの user.name と user.email を設定してください。Editor は Git の設定を変えません。",
|
|
3289
|
-
nothingStaged: "先に、変更を次の記録に入れてください。",
|
|
3290
|
-
switchTo: "切り替える",
|
|
3291
|
-
currentBranch: "現在",
|
|
3292
|
-
createBranch: "ブランチを作る",
|
|
3293
|
-
newBranch: "新しいブランチの名前",
|
|
3294
|
-
switchAfterCreate: "作ったら切り替える",
|
|
3295
|
-
createFromRemote: "作って切り替える",
|
|
3296
|
-
remoteBranches: "GitHub(origin)のブランチ",
|
|
3297
|
-
switched: "ブランチを切り替えました。「作品を再読込」で、このブランチのファイルを開けます。",
|
|
3298
|
-
branchCreated: "ブランチを作りました。",
|
|
3299
|
-
projectMissing: "開いている作品フォルダは、このブランチにありません。切り替えますか?",
|
|
3300
|
-
pulledProject: "GitHub から取り込みました。「作品を再読込」で更新したファイルを開けます。",
|
|
3301
|
-
confirmPush: "このブランチの記録を GitHub に送りますか(push)?",
|
|
3302
|
-
details: "Git の詳細",
|
|
3303
|
-
branch: "ブランチ",
|
|
3304
|
-
head: "HEAD",
|
|
3305
|
-
groups: "Git の区分",
|
|
3306
|
-
added: "追加",
|
|
3307
|
-
modified: "変更",
|
|
3308
|
-
deleted: "削除",
|
|
3309
|
-
gitStaged: "ステージ済み (staged)",
|
|
3310
|
-
gitUnstaged: "未ステージ (unstaged)",
|
|
3311
|
-
gitUntracked: "未追跡 (untracked)",
|
|
3312
|
-
upstreamSame: "GitHub と同じ",
|
|
3313
|
-
upstreamAhead: "GitHub より進んでいる",
|
|
3314
|
-
upstreamBehind: "GitHub より遅れている",
|
|
3315
|
-
upstreamDiverged: "GitHub と分かれている",
|
|
3316
|
-
upstreamUnknown: "まだ GitHub と確かめていない",
|
|
3317
|
-
records: "件",
|
|
3318
|
-
checkedAt: "最後に確かめた時点",
|
|
3319
|
-
failed: "リポジトリを読み込めませんでした。フォルダへのアクセスを確認し、再取得してください。",
|
|
3320
|
-
historyMore: "さらに表示",
|
|
3321
|
-
historyLoading: "記録を読込中…",
|
|
3322
|
-
historyFailed: "記録を読み込めませんでした。",
|
|
3323
|
-
historyActions: "操作",
|
|
3324
|
-
historyCreateHere: "ここからブランチを作る…",
|
|
3325
|
-
historySwitch: "{name} に切り替える",
|
|
3326
|
-
historyCreateFromRemote: "{name} を作って切り替える",
|
|
3327
|
-
historyCopy: "コミットの ID をコピー",
|
|
3328
|
-
historyCopied: "コミットの ID をコピーしました。",
|
|
3329
|
-
historyCopyFailed: "コミットの ID をコピーできませんでした。",
|
|
3330
|
-
historyRefs: "ブランチ",
|
|
3331
|
-
cancel: "キャンセル"
|
|
3332
|
-
}
|
|
3333
|
-
};
|
|
3334
|
-
var labelsFor = (locale) => locale.startsWith("ja") ? messages.ja : messages.en;
|
|
3335
3498
|
// src/history-graph-view.tsx
|
|
3336
3499
|
/** Lane colors that read on light and dark backgrounds. */
|
|
3337
3500
|
var laneColors = [
|
|
@@ -3722,6 +3885,7 @@ function ConnectionSettings({ settings, locale, readOrigin, runOperation }) {
|
|
|
3722
3885
|
const [, update] = useState(0);
|
|
3723
3886
|
const [busy, setBusy] = useState(false);
|
|
3724
3887
|
const [allowPush, setAllowPush] = useState(false);
|
|
3888
|
+
const [allowReview, setAllowReview] = useState(false);
|
|
3725
3889
|
const [error, setError] = useState(null);
|
|
3726
3890
|
const active = useRef(true);
|
|
3727
3891
|
useEffect(() => {
|
|
@@ -3749,7 +3913,7 @@ function ConnectionSettings({ settings, locale, readOrigin, runOperation }) {
|
|
|
3749
3913
|
const connect = () => run(async () => {
|
|
3750
3914
|
const remote = await (readOrigin === null || readOrigin === void 0 ? void 0 : readOrigin());
|
|
3751
3915
|
if (!remote) throw new Error("INVALID_REMOTE");
|
|
3752
|
-
await settings.connect(remote, allowPush);
|
|
3916
|
+
await (allowReview ? settings.connect(remote, allowPush, true) : settings.connect(remote, allowPush));
|
|
3753
3917
|
});
|
|
3754
3918
|
const connected = !!mode && state.status === "connected";
|
|
3755
3919
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, runOperation && connected && /* @__PURE__ */ React.createElement("span", { className: "twgit-sync" }, [
|
|
@@ -3781,7 +3945,13 @@ function ConnectionSettings({ settings, locale, readOrigin, runOperation }) {
|
|
|
3781
3945
|
checked: allowPush,
|
|
3782
3946
|
disabled: busy || state.status === "connecting" || state.status === "connected",
|
|
3783
3947
|
onChange: (event) => setAllowPush(event.currentTarget.checked)
|
|
3784
|
-
}), " ", labels.allowPush), /* @__PURE__ */ React.createElement("
|
|
3948
|
+
}), " ", labels.allowPush), /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
|
|
3949
|
+
type: "checkbox",
|
|
3950
|
+
"data-git-allow-review": "",
|
|
3951
|
+
checked: allowReview,
|
|
3952
|
+
disabled: busy || state.status === "connecting" || state.status === "connected",
|
|
3953
|
+
onChange: (event) => setAllowReview(event.currentTarget.checked)
|
|
3954
|
+
}), " ", reviewLabelsFor(locale).allowReview), /* @__PURE__ */ React.createElement("button", {
|
|
3785
3955
|
disabled: busy || !readOrigin || state.status === "connecting" || state.status === "connected",
|
|
3786
3956
|
onClick: connect
|
|
3787
3957
|
}, labels.connect), authorization && /* @__PURE__ */ React.createElement("p", null, authorization.userCode && /* @__PURE__ */ React.createElement("code", null, authorization.userCode, " "), /* @__PURE__ */ React.createElement("a", {
|
|
@@ -3888,9 +4058,20 @@ function errorMessage(error, labels) {
|
|
|
3888
4058
|
}
|
|
3889
4059
|
return labels.failed;
|
|
3890
4060
|
}
|
|
3891
|
-
function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs, repository, connection, openLocally }) {
|
|
3892
|
-
var _pr$base$ref, _pr$git, _pr$base$ref2;
|
|
4061
|
+
function PullRequests({ name, remote, labels, locale, renderBlock, locateFor, openTabs, repository, connection, openLocally }) {
|
|
4062
|
+
var _connection$reviewGra, _pr$base$ref, _pr$git, _pr$base$ref2, _connection$reviewGra2;
|
|
3893
4063
|
const client = useMemo(() => createGitHubPullRequests(name), [name]);
|
|
4064
|
+
const reviewApi = useMemo(() => {
|
|
4065
|
+
if (!remote || !connection) return null;
|
|
4066
|
+
try {
|
|
4067
|
+
return createGitHubReviewApi({
|
|
4068
|
+
remote,
|
|
4069
|
+
getSession: connection.getSession
|
|
4070
|
+
});
|
|
4071
|
+
} catch (_unused) {
|
|
4072
|
+
return null;
|
|
4073
|
+
}
|
|
4074
|
+
}, [remote, connection]);
|
|
3894
4075
|
const [page, setPage] = useState(1);
|
|
3895
4076
|
const [listing, setListing] = useState();
|
|
3896
4077
|
const [input, setInput] = useState("");
|
|
@@ -3997,6 +4178,7 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs,
|
|
|
3997
4178
|
setInput(String(number));
|
|
3998
4179
|
};
|
|
3999
4180
|
const pr = detail === null || detail === void 0 ? void 0 : detail.data;
|
|
4181
|
+
const reviewing = !!(pr === null || pr === void 0 ? void 0 : pr.git) && !!reviewApi && !!(connection === null || connection === void 0 ? void 0 : connection.connected()) && !!((_connection$reviewGra = connection.reviewGranted) === null || _connection$reviewGra === void 0 ? void 0 : _connection$reviewGra.call(connection));
|
|
4000
4182
|
return /* @__PURE__ */ React.createElement("div", { className: "twgit-content" }, /* @__PURE__ */ React.createElement("aside", null, /* @__PURE__ */ React.createElement("h3", null, labels.title), /* @__PURE__ */ React.createElement("p", null, name), /* @__PURE__ */ React.createElement("form", {
|
|
4001
4183
|
className: "twgit-pr-number",
|
|
4002
4184
|
onSubmit: (event) => {
|
|
@@ -4045,7 +4227,7 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs,
|
|
|
4045
4227
|
let projects;
|
|
4046
4228
|
try {
|
|
4047
4229
|
projects = readProjectSourceDiff(file.patch, file.beforeSource);
|
|
4048
|
-
} catch (
|
|
4230
|
+
} catch (_unused2) {
|
|
4049
4231
|
return [];
|
|
4050
4232
|
}
|
|
4051
4233
|
return projects ? [{
|
|
@@ -4065,13 +4247,26 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs,
|
|
|
4065
4247
|
}, labels.openLocally.replace("{branch}", pullRequestBranch(pr.number)))), pr.git && /* @__PURE__ */ React.createElement("p", {
|
|
4066
4248
|
className: "twgit-context",
|
|
4067
4249
|
role: "status"
|
|
4068
|
-
}, labels.viaConnection, pr.git.branches && /* @__PURE__ */ React.createElement(React.Fragment, null, " ", labels.noMetadata)), /* @__PURE__ */ React.createElement(
|
|
4250
|
+
}, labels.viaConnection, pr.git.branches && /* @__PURE__ */ React.createElement(React.Fragment, null, " ", labels.noMetadata)), pr.git && (connection === null || connection === void 0 ? void 0 : connection.connected()) && !((_connection$reviewGra2 = connection.reviewGranted) === null || _connection$reviewGra2 === void 0 ? void 0 : _connection$reviewGra2.call(connection)) && /* @__PURE__ */ React.createElement("p", {
|
|
4251
|
+
className: "twgit-context",
|
|
4252
|
+
role: "status"
|
|
4253
|
+
}, reviewLabelsFor(locale).needsGrant), /* @__PURE__ */ React.createElement(ProjectSourceReview, {
|
|
4069
4254
|
title: pr.title,
|
|
4070
4255
|
description: pr.description,
|
|
4071
4256
|
files: locateFor ? pr.files.map((file) => "patch" in file ? _objectSpread2$1(_objectSpread2$1({}, file), {}, { locateBlock: locateFor(file.path, pr.head.sha) }) : file) : pr.files,
|
|
4072
4257
|
renderBlock,
|
|
4073
4258
|
locale,
|
|
4074
|
-
rememberAs: `${name}#${pr.number}
|
|
4259
|
+
rememberAs: `${name}#${pr.number}`,
|
|
4260
|
+
commentAs: reviewing ? `${name}#${pr.number}` : void 0
|
|
4261
|
+
}), reviewing && reviewApi && /* @__PURE__ */ React.createElement(PullRequestReviewComposer, {
|
|
4262
|
+
key: `${name}#${pr.number}`,
|
|
4263
|
+
api: reviewApi,
|
|
4264
|
+
name: `${name}#${pr.number}`,
|
|
4265
|
+
number: pr.number,
|
|
4266
|
+
head: pr.head.sha,
|
|
4267
|
+
changedFiles: pr.files.map((file) => file.path),
|
|
4268
|
+
url: pr.url,
|
|
4269
|
+
locale
|
|
4075
4270
|
}))));
|
|
4076
4271
|
}
|
|
4077
4272
|
function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, openTabs, connection, openLocally }) {
|
|
@@ -4082,7 +4277,8 @@ function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, op
|
|
|
4082
4277
|
repository.readOrigin().then((value) => {
|
|
4083
4278
|
if (active) setOrigin({
|
|
4084
4279
|
repository,
|
|
4085
|
-
name: gitHubRepositoryFromOrigin(value)
|
|
4280
|
+
name: gitHubRepositoryFromOrigin(value),
|
|
4281
|
+
remote: value
|
|
4086
4282
|
});
|
|
4087
4283
|
}, () => {
|
|
4088
4284
|
if (active) setOrigin({
|
|
@@ -4106,6 +4302,7 @@ function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, op
|
|
|
4106
4302
|
return /* @__PURE__ */ React.createElement(PullRequests, {
|
|
4107
4303
|
key: origin.name,
|
|
4108
4304
|
name: origin.name,
|
|
4305
|
+
remote: origin.remote,
|
|
4109
4306
|
labels,
|
|
4110
4307
|
locale,
|
|
4111
4308
|
renderBlock,
|
|
@@ -4154,6 +4351,47 @@ function nextFrame(signal) {
|
|
|
4154
4351
|
}
|
|
4155
4352
|
// src/index.tsx
|
|
4156
4353
|
init_objectSpread2();
|
|
4354
|
+
function createController() {
|
|
4355
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4356
|
+
const controller = {
|
|
4357
|
+
open() {},
|
|
4358
|
+
async refresh() {},
|
|
4359
|
+
async choose() {},
|
|
4360
|
+
async changeBranch() {
|
|
4361
|
+
return { done: false };
|
|
4362
|
+
},
|
|
4363
|
+
reload() {},
|
|
4364
|
+
branch: {
|
|
4365
|
+
repository: false,
|
|
4366
|
+
branch: void 0,
|
|
4367
|
+
head: null,
|
|
4368
|
+
branches: [],
|
|
4369
|
+
remoteBranches: [],
|
|
4370
|
+
writable: false,
|
|
4371
|
+
busy: false,
|
|
4372
|
+
project: false
|
|
4373
|
+
},
|
|
4374
|
+
repository: null,
|
|
4375
|
+
snapshot: null,
|
|
4376
|
+
publish(state, repository, snapshot) {
|
|
4377
|
+
controller.branch = state;
|
|
4378
|
+
controller.repository = repository;
|
|
4379
|
+
controller.snapshot = snapshot;
|
|
4380
|
+
for (const listener of [...listeners]) listener();
|
|
4381
|
+
},
|
|
4382
|
+
follow(listener) {
|
|
4383
|
+
listeners.add(listener);
|
|
4384
|
+
controller.onFollowers(listeners.size);
|
|
4385
|
+
return () => {
|
|
4386
|
+
listeners.delete(listener);
|
|
4387
|
+
controller.onFollowers(listeners.size);
|
|
4388
|
+
};
|
|
4389
|
+
},
|
|
4390
|
+
followers: () => listeners.size,
|
|
4391
|
+
onFollowers() {}
|
|
4392
|
+
};
|
|
4393
|
+
return controller;
|
|
4394
|
+
}
|
|
4157
4395
|
var initial = {
|
|
4158
4396
|
repository: null,
|
|
4159
4397
|
snapshot: null,
|
|
@@ -4167,9 +4405,56 @@ var initial = {
|
|
|
4167
4405
|
busy: false
|
|
4168
4406
|
};
|
|
4169
4407
|
var controllers = /* @__PURE__ */ new WeakMap();
|
|
4408
|
+
var registrations = /* @__PURE__ */ new Set();
|
|
4170
4409
|
var watchInterval = 2e3;
|
|
4410
|
+
/**
|
|
4411
|
+
* Calls `check` every `watchInterval`, when the window regains focus and shortly after a File System Observer reports
|
|
4412
|
+
* a change under `root`, one call at a time and never while the page is hidden. Returns the function that stops it.
|
|
4413
|
+
*/
|
|
4414
|
+
function watchRepository(document, root, check) {
|
|
4415
|
+
const view = document.defaultView;
|
|
4416
|
+
let stopped = false;
|
|
4417
|
+
let checking = false;
|
|
4418
|
+
const run = async () => {
|
|
4419
|
+
if (stopped || checking || document.visibilityState === "hidden") return;
|
|
4420
|
+
checking = true;
|
|
4421
|
+
try {
|
|
4422
|
+
await check(() => stopped);
|
|
4423
|
+
} catch (_unused) {} finally {
|
|
4424
|
+
checking = false;
|
|
4425
|
+
}
|
|
4426
|
+
};
|
|
4427
|
+
let soon;
|
|
4428
|
+
const schedule = () => {
|
|
4429
|
+
view.clearTimeout(soon);
|
|
4430
|
+
soon = view.setTimeout(() => void run(), 300);
|
|
4431
|
+
};
|
|
4432
|
+
const interval = view.setInterval(() => void run(), watchInterval);
|
|
4433
|
+
const onFocus = () => void run();
|
|
4434
|
+
view.addEventListener("focus", onFocus);
|
|
4435
|
+
document.addEventListener("visibilitychange", onFocus);
|
|
4436
|
+
let observer = null;
|
|
4437
|
+
try {
|
|
4438
|
+
if (view.FileSystemObserver) {
|
|
4439
|
+
observer = new view.FileSystemObserver(schedule);
|
|
4440
|
+
observer.observe(root, { recursive: true }).catch(() => {});
|
|
4441
|
+
}
|
|
4442
|
+
} catch (_unused2) {
|
|
4443
|
+
observer = null;
|
|
4444
|
+
}
|
|
4445
|
+
run();
|
|
4446
|
+
return () => {
|
|
4447
|
+
stopped = true;
|
|
4448
|
+
view.clearInterval(interval);
|
|
4449
|
+
view.clearTimeout(soon);
|
|
4450
|
+
view.removeEventListener("focus", onFocus);
|
|
4451
|
+
document.removeEventListener("visibilitychange", onFocus);
|
|
4452
|
+
observer === null || observer === void 0 || observer.disconnect();
|
|
4453
|
+
};
|
|
4454
|
+
}
|
|
4455
|
+
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");
|
|
4171
4456
|
function GitPanel({ vm, document, host, controller }) {
|
|
4172
|
-
var _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head;
|
|
4457
|
+
var _refs$head, _refs$branches, _refs$remoteBranches, _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head;
|
|
4173
4458
|
const [visible, setVisible] = useState(false);
|
|
4174
4459
|
const [slot, setSlot] = useState(null);
|
|
4175
4460
|
const shown = visible || slot !== null;
|
|
@@ -4342,57 +4627,42 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4342
4627
|
controller.refresh();
|
|
4343
4628
|
}
|
|
4344
4629
|
}, [shown]);
|
|
4630
|
+
const [refs, setRefs] = useState(null);
|
|
4631
|
+
useEffect(() => {
|
|
4632
|
+
if (!state.repository) setRefs(null);
|
|
4633
|
+
else if (state.snapshot) setRefs(refsOf(state.snapshot));
|
|
4634
|
+
}, [state.repository, state.snapshot]);
|
|
4635
|
+
const [followers, setFollowers] = useState(controller.followers());
|
|
4636
|
+
useEffect(() => {
|
|
4637
|
+
controller.onFollowers = setFollowers;
|
|
4638
|
+
setFollowers(controller.followers());
|
|
4639
|
+
return () => {
|
|
4640
|
+
controller.onFollowers = () => {};
|
|
4641
|
+
};
|
|
4642
|
+
}, []);
|
|
4643
|
+
const following = followers > 0;
|
|
4345
4644
|
useEffect(() => {
|
|
4346
4645
|
const repository = state.repository;
|
|
4347
|
-
if (!
|
|
4348
|
-
|
|
4349
|
-
let stopped = false;
|
|
4350
|
-
let checking = false;
|
|
4351
|
-
const check = async () => {
|
|
4646
|
+
if (!repository || !shown && !following) return;
|
|
4647
|
+
return watchRepository(document, repository.root, async (stopped) => {
|
|
4352
4648
|
const { snapshot } = current.current;
|
|
4353
|
-
|
|
4354
|
-
if (
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
handled.current = probe;
|
|
4360
|
-
const { selected, commit } = current.current;
|
|
4361
|
-
if (selected || commit || reviewing.current) setState((previous) => previous.snapshot === snapshot ? _objectSpread2$1(_objectSpread2$1({}, previous), {}, { notice: labelsFor(locale).outdated }) : previous);
|
|
4362
|
-
else await controller.refresh(true);
|
|
4363
|
-
} catch (_unused) {} finally {
|
|
4364
|
-
checking = false;
|
|
4365
|
-
}
|
|
4366
|
-
};
|
|
4367
|
-
let soon;
|
|
4368
|
-
const schedule = () => {
|
|
4369
|
-
view.clearTimeout(soon);
|
|
4370
|
-
soon = view.setTimeout(() => void check(), 300);
|
|
4371
|
-
};
|
|
4372
|
-
const interval = view.setInterval(() => void check(), watchInterval);
|
|
4373
|
-
const onFocus = () => void check();
|
|
4374
|
-
view.addEventListener("focus", onFocus);
|
|
4375
|
-
document.addEventListener("visibilitychange", onFocus);
|
|
4376
|
-
let observer = null;
|
|
4377
|
-
try {
|
|
4378
|
-
if (view.FileSystemObserver) {
|
|
4379
|
-
observer = new view.FileSystemObserver(schedule);
|
|
4380
|
-
observer.observe(repository.root, { recursive: true }).catch(() => {});
|
|
4649
|
+
if (running.current || current.current.repository !== repository) return;
|
|
4650
|
+
if (!(shown && !!dialog.current && dialog.current.getClientRects().length > 0) || !snapshot) {
|
|
4651
|
+
if (!following) return;
|
|
4652
|
+
const next = await repository.refs();
|
|
4653
|
+
if (!stopped() && current.current.repository === repository) setRefs((previous) => sameRefs(previous, next) ? previous : next);
|
|
4654
|
+
return;
|
|
4381
4655
|
}
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
view.clearTimeout(soon);
|
|
4390
|
-
view.removeEventListener("focus", onFocus);
|
|
4391
|
-
document.removeEventListener("visibilitychange", onFocus);
|
|
4392
|
-
observer === null || observer === void 0 || observer.disconnect();
|
|
4393
|
-
};
|
|
4656
|
+
const probe = await repository.probe(snapshot.scope);
|
|
4657
|
+
if (stopped() || probe === "locked" || probe === snapshot.probe || probe === handled.current || current.current.snapshot !== snapshot) return;
|
|
4658
|
+
handled.current = probe;
|
|
4659
|
+
const { selected, commit } = current.current;
|
|
4660
|
+
if (selected || commit || reviewing.current) setState((previous) => previous.snapshot === snapshot ? _objectSpread2$1(_objectSpread2$1({}, previous), {}, { notice: labelsFor(locale).outdated }) : previous);
|
|
4661
|
+
else await controller.refresh(true);
|
|
4662
|
+
});
|
|
4394
4663
|
}, [
|
|
4395
4664
|
shown,
|
|
4665
|
+
following,
|
|
4396
4666
|
state.repository,
|
|
4397
4667
|
locale
|
|
4398
4668
|
]);
|
|
@@ -4407,7 +4677,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4407
4677
|
}, [visible, slot]);
|
|
4408
4678
|
const chooseRoot = async () => {
|
|
4409
4679
|
const view = document.defaultView;
|
|
4410
|
-
|
|
4680
|
+
return run(async () => {
|
|
4411
4681
|
var _host$connectionSetti;
|
|
4412
4682
|
let root;
|
|
4413
4683
|
try {
|
|
@@ -4524,7 +4794,8 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4524
4794
|
const getSession = settings === null || settings === void 0 ? void 0 : settings.getSession;
|
|
4525
4795
|
return getSession ? {
|
|
4526
4796
|
getSession,
|
|
4527
|
-
connected: () => settings.getView().state.status === "connected"
|
|
4797
|
+
connected: () => settings.getView().state.status === "connected",
|
|
4798
|
+
reviewGranted: () => settings.getView().review === true
|
|
4528
4799
|
} : void 0;
|
|
4529
4800
|
}, [host]);
|
|
4530
4801
|
const [message, setMessage] = useState("");
|
|
@@ -4673,6 +4944,32 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4673
4944
|
state.snapshot,
|
|
4674
4945
|
state.selected
|
|
4675
4946
|
]);
|
|
4947
|
+
controller.changeBranch = changeBranch;
|
|
4948
|
+
controller.reload = () => {
|
|
4949
|
+
if (current.current.project !== null) openProject(current.current.project);
|
|
4950
|
+
};
|
|
4951
|
+
controller.choose = async (language) => {
|
|
4952
|
+
setLocale(language);
|
|
4953
|
+
const before = current.current.repository;
|
|
4954
|
+
const result = await chooseRoot();
|
|
4955
|
+
if (!result.done && result.error || current.current.repository !== before) controller.open(language);
|
|
4956
|
+
};
|
|
4957
|
+
const branchState = {
|
|
4958
|
+
repository: !!state.repository,
|
|
4959
|
+
branch: refs === null || refs === void 0 ? void 0 : refs.branch,
|
|
4960
|
+
head: (_refs$head = refs === null || refs === void 0 ? void 0 : refs.head) !== null && _refs$head !== void 0 ? _refs$head : null,
|
|
4961
|
+
branches: (_refs$branches = refs === null || refs === void 0 ? void 0 : refs.branches) !== null && _refs$branches !== void 0 ? _refs$branches : [],
|
|
4962
|
+
remoteBranches: (_refs$remoteBranches = refs === null || refs === void 0 ? void 0 : refs.remoteBranches) !== null && _refs$remoteBranches !== void 0 ? _refs$remoteBranches : [],
|
|
4963
|
+
writable: !!host.localWrite && !!refs,
|
|
4964
|
+
busy: state.busy,
|
|
4965
|
+
project: state.project !== null
|
|
4966
|
+
};
|
|
4967
|
+
const published = JSON.stringify(branchState);
|
|
4968
|
+
useEffect(() => controller.publish(branchState, state.repository, state.snapshot), [
|
|
4969
|
+
published,
|
|
4970
|
+
state.repository,
|
|
4971
|
+
state.snapshot
|
|
4972
|
+
]);
|
|
4676
4973
|
if (!shown) return null;
|
|
4677
4974
|
const groups = state.commit ? ["commit"] : [
|
|
4678
4975
|
"staged",
|
|
@@ -4939,15 +5236,21 @@ function upstreamText({ upstream }, labels) {
|
|
|
4939
5236
|
default: return labels.upstreamUnknown;
|
|
4940
5237
|
}
|
|
4941
5238
|
}
|
|
5239
|
+
var refsOf = ({ branch, head, branches, remoteBranches }) => ({
|
|
5240
|
+
branch,
|
|
5241
|
+
head,
|
|
5242
|
+
branches,
|
|
5243
|
+
remoteBranches
|
|
5244
|
+
});
|
|
5245
|
+
var announce = () => {
|
|
5246
|
+
for (const listener of [...registrations]) listener();
|
|
5247
|
+
};
|
|
4942
5248
|
function mountGitPanel({ vm, document, host }) {
|
|
4943
5249
|
var _document$defaultView3;
|
|
4944
5250
|
if (!((_document$defaultView3 = document.defaultView) === null || _document$defaultView3 === void 0 ? void 0 : _document$defaultView3.showDirectoryPicker)) return null;
|
|
4945
5251
|
const root = document.createElement("div");
|
|
4946
5252
|
document.body.append(root);
|
|
4947
|
-
const controller =
|
|
4948
|
-
open() {},
|
|
4949
|
-
async refresh() {}
|
|
4950
|
-
};
|
|
5253
|
+
const controller = createController();
|
|
4951
5254
|
controllers.set(vm, controller);
|
|
4952
5255
|
render(/* @__PURE__ */ React.createElement(GitPanel, {
|
|
4953
5256
|
vm,
|
|
@@ -4955,26 +5258,250 @@ function mountGitPanel({ vm, document, host }) {
|
|
|
4955
5258
|
host,
|
|
4956
5259
|
controller
|
|
4957
5260
|
}), root);
|
|
5261
|
+
announce();
|
|
4958
5262
|
return {
|
|
4959
5263
|
refresh: () => controller.refresh(),
|
|
5264
|
+
open: (locale) => controller.open(locale),
|
|
4960
5265
|
dispose() {
|
|
4961
5266
|
var _host$connectionSetti3;
|
|
4962
5267
|
if (controllers.get(vm) === controller) controllers.delete(vm);
|
|
4963
5268
|
(_host$connectionSetti3 = host.connectionSettings) === null || _host$connectionSetti3 === void 0 || _host$connectionSetti3.disconnect().catch(() => {});
|
|
4964
5269
|
unmountComponentAtNode(root);
|
|
4965
5270
|
root.remove();
|
|
5271
|
+
announce();
|
|
4966
5272
|
}
|
|
4967
5273
|
};
|
|
4968
5274
|
}
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
5275
|
+
/** The branch button of the panel mounted for `vm`, or nothing while no panel is mounted for it. */
|
|
5276
|
+
/** Calls `listener` with the controller of the panel mounted for `vm`, now and whenever it is mounted or disposed. */
|
|
5277
|
+
function findController(vm, listener) {
|
|
5278
|
+
const update = () => listener(controllers.get(vm));
|
|
5279
|
+
registrations.add(update);
|
|
5280
|
+
update();
|
|
5281
|
+
return () => {
|
|
5282
|
+
registrations.delete(update);
|
|
5283
|
+
};
|
|
5284
|
+
}
|
|
5285
|
+
/** The panel mounted for `vm` and what it last published. Following it keeps the closed panel watching the branches. */
|
|
5286
|
+
function useController(vm) {
|
|
5287
|
+
const [controller, setController] = useState(() => controllers.get(vm));
|
|
5288
|
+
useEffect(() => findController(vm, setController), [vm]);
|
|
5289
|
+
const [state, setState] = useState(controller === null || controller === void 0 ? void 0 : controller.branch);
|
|
5290
|
+
useEffect(() => {
|
|
5291
|
+
if (!controller) return;
|
|
5292
|
+
const update = () => setState(controller.branch);
|
|
5293
|
+
update();
|
|
5294
|
+
return controller.follow(update);
|
|
5295
|
+
}, [controller]);
|
|
5296
|
+
return {
|
|
5297
|
+
controller,
|
|
5298
|
+
state
|
|
5299
|
+
};
|
|
5300
|
+
}
|
|
5301
|
+
function BranchEntry({ vm, locale }) {
|
|
5302
|
+
const { controller, state } = useController(vm);
|
|
5303
|
+
if (!controller || !state) return null;
|
|
5304
|
+
return /* @__PURE__ */ React.createElement(BranchButton, {
|
|
5305
|
+
state,
|
|
5306
|
+
locale,
|
|
5307
|
+
open: () => controller.open(locale),
|
|
5308
|
+
choose: () => void controller.choose(locale),
|
|
5309
|
+
reload: () => controller.reload(),
|
|
5310
|
+
switchBranch: (name) => controller.changeBranch({
|
|
5311
|
+
kind: "switchBranch",
|
|
5312
|
+
name
|
|
5313
|
+
}),
|
|
5314
|
+
createBranch: (name, checkout) => controller.changeBranch({
|
|
5315
|
+
kind: "createBranch",
|
|
5316
|
+
name,
|
|
5317
|
+
checkout
|
|
5318
|
+
}),
|
|
5319
|
+
createFromRemote: (name) => controller.changeBranch({
|
|
5320
|
+
kind: "createBranch",
|
|
5321
|
+
name,
|
|
5322
|
+
fromRemote: true,
|
|
5323
|
+
checkout: true
|
|
5324
|
+
})
|
|
5325
|
+
});
|
|
5326
|
+
}
|
|
5327
|
+
/**
|
|
5328
|
+
* Renders the button for the host's menu bar that shows the current branch of the panel mounted for `vm` and opens the
|
|
5329
|
+
* menu of branches, the panel and the repository choice. It renders nothing while no panel is mounted for `vm`, such as
|
|
5330
|
+
* when the host does not offer local Git, and shares the panel's repository, operations and checks.
|
|
5331
|
+
*/
|
|
5332
|
+
function renderBranchButton(createElement, { vm, locale = "en" }) {
|
|
5333
|
+
return createElement(BranchEntry, {
|
|
5334
|
+
vm,
|
|
5335
|
+
locale
|
|
5336
|
+
});
|
|
5337
|
+
}
|
|
5338
|
+
/** The history of the panel's repository, read again whenever its branches move. */
|
|
5339
|
+
function HistoryEntry({ vm, locale }) {
|
|
5340
|
+
const { controller, state } = useController(vm);
|
|
5341
|
+
const labels = labelsFor(locale);
|
|
5342
|
+
const repository = state && (controller === null || controller === void 0 ? void 0 : controller.repository) || null;
|
|
5343
|
+
const [history, setHistory] = useState({
|
|
5344
|
+
commits: [],
|
|
5345
|
+
cursor: null,
|
|
5346
|
+
loading: false,
|
|
5347
|
+
failed: false
|
|
5348
|
+
});
|
|
5349
|
+
const [selected, setSelected] = useState(null);
|
|
5350
|
+
const ticket = useRef(0);
|
|
5351
|
+
const root = useRef(null);
|
|
5352
|
+
const refs = state ? [
|
|
5353
|
+
state.head,
|
|
5354
|
+
...state.branches,
|
|
5355
|
+
"",
|
|
5356
|
+
...state.remoteBranches
|
|
5357
|
+
].join("\n") : "";
|
|
5358
|
+
useEffect(() => {
|
|
5359
|
+
const current = ++ticket.current;
|
|
5360
|
+
if (!repository) {
|
|
5361
|
+
setHistory({
|
|
5362
|
+
commits: [],
|
|
5363
|
+
cursor: null,
|
|
5364
|
+
loading: false,
|
|
5365
|
+
failed: false
|
|
5366
|
+
});
|
|
5367
|
+
return;
|
|
4977
5368
|
}
|
|
4978
|
-
|
|
5369
|
+
setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
5370
|
+
cursor: null,
|
|
5371
|
+
loading: true,
|
|
5372
|
+
failed: false
|
|
5373
|
+
}));
|
|
5374
|
+
repository.history().then((page) => {
|
|
5375
|
+
if (ticket.current === current) setHistory({
|
|
5376
|
+
commits: page.commits,
|
|
5377
|
+
cursor: page.cursor,
|
|
5378
|
+
loading: false,
|
|
5379
|
+
failed: false
|
|
5380
|
+
});
|
|
5381
|
+
}, () => {
|
|
5382
|
+
if (ticket.current === current) setHistory({
|
|
5383
|
+
commits: [],
|
|
5384
|
+
cursor: null,
|
|
5385
|
+
loading: false,
|
|
5386
|
+
failed: true
|
|
5387
|
+
});
|
|
5388
|
+
});
|
|
5389
|
+
}, [repository, refs]);
|
|
5390
|
+
const showMore = () => {
|
|
5391
|
+
if (!repository || !history.cursor || history.loading) return;
|
|
5392
|
+
const current = ticket.current;
|
|
5393
|
+
setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, { loading: true }));
|
|
5394
|
+
repository.history({ after: history.cursor }).then((page) => {
|
|
5395
|
+
if (ticket.current === current) setHistory((previous) => ({
|
|
5396
|
+
commits: [...previous.commits, ...page.commits],
|
|
5397
|
+
cursor: page.cursor,
|
|
5398
|
+
loading: false,
|
|
5399
|
+
failed: false
|
|
5400
|
+
}));
|
|
5401
|
+
}, () => {
|
|
5402
|
+
if (ticket.current === current) setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
5403
|
+
cursor: null,
|
|
5404
|
+
loading: false,
|
|
5405
|
+
failed: true
|
|
5406
|
+
}));
|
|
5407
|
+
});
|
|
5408
|
+
};
|
|
5409
|
+
const { report, element: snackbar } = useBranchSnackbar(locale, !!(state === null || state === void 0 ? void 0 : state.project), {
|
|
5410
|
+
open: () => controller === null || controller === void 0 ? void 0 : controller.open(locale),
|
|
5411
|
+
reload: () => controller === null || controller === void 0 ? void 0 : controller.reload()
|
|
5412
|
+
}, () => {
|
|
5413
|
+
var _root$current;
|
|
5414
|
+
return (_root$current = root.current) === null || _root$current === void 0 || (_root$current = _root$current.querySelector("[tabindex=\"0\"]")) === null || _root$current === void 0 ? void 0 : _root$current.focus({ preventScroll: true });
|
|
5415
|
+
});
|
|
5416
|
+
if (!controller || !state) return null;
|
|
5417
|
+
if (!repository) return /* @__PURE__ */ React.createElement("div", {
|
|
5418
|
+
className: "twgit-history-view",
|
|
5419
|
+
ref: root
|
|
5420
|
+
}, /* @__PURE__ */ React.createElement("p", null, labels.historyViewEmpty), /* @__PURE__ */ React.createElement("button", {
|
|
5421
|
+
type: "button",
|
|
5422
|
+
onClick: () => void controller.choose(locale)
|
|
5423
|
+
}, labels.choose));
|
|
5424
|
+
const change = async (operation) => {
|
|
5425
|
+
const result = await controller.changeBranch(operation);
|
|
5426
|
+
report(result, operation.kind === "switchBranch" || !!operation.checkout);
|
|
5427
|
+
return result;
|
|
5428
|
+
};
|
|
5429
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
5430
|
+
className: "twgit-history-view",
|
|
5431
|
+
ref: root
|
|
5432
|
+
}, /* @__PURE__ */ React.createElement(HistoryGraph, _objectSpread2$1({
|
|
5433
|
+
commits: history.commits,
|
|
5434
|
+
selected,
|
|
5435
|
+
locale,
|
|
5436
|
+
busy: state.busy,
|
|
5437
|
+
onSelect: setSelected,
|
|
5438
|
+
hasMore: !!history.cursor,
|
|
5439
|
+
loadingMore: history.loading,
|
|
5440
|
+
onShowMore: showMore,
|
|
5441
|
+
localBranches: state.branches
|
|
5442
|
+
}, state.writable ? {
|
|
5443
|
+
onCreateBranch: async (oid, name, checkout) => {
|
|
5444
|
+
const result = await controller.changeBranch({
|
|
5445
|
+
kind: "createBranch",
|
|
5446
|
+
name,
|
|
5447
|
+
at: oid,
|
|
5448
|
+
checkout
|
|
5449
|
+
});
|
|
5450
|
+
if (result.done) report(result, checkout);
|
|
5451
|
+
return result;
|
|
5452
|
+
},
|
|
5453
|
+
onSwitchBranch: (name) => change({
|
|
5454
|
+
kind: "switchBranch",
|
|
5455
|
+
name
|
|
5456
|
+
}),
|
|
5457
|
+
onCreateFromRemote: (name) => change({
|
|
5458
|
+
kind: "createBranch",
|
|
5459
|
+
name,
|
|
5460
|
+
fromRemote: true,
|
|
5461
|
+
checkout: true
|
|
5462
|
+
})
|
|
5463
|
+
} : {})), history.loading && !history.commits.length && /* @__PURE__ */ React.createElement("p", { role: "status" }, labels.historyLoading), history.failed && /* @__PURE__ */ React.createElement("p", null, labels.historyFailed), snackbar);
|
|
5464
|
+
}
|
|
5465
|
+
/**
|
|
5466
|
+
* Renders the history graph of the repository chosen in the panel mounted for `vm`, for a side panel of the host. It
|
|
5467
|
+
* follows branch changes made anywhere, offers the graph's branch actions when the panel allows writes and tells their
|
|
5468
|
+
* results in the branch button's snackbar. Before a repository is chosen it offers to choose one; it renders nothing
|
|
5469
|
+
* while no panel is mounted for `vm`.
|
|
5470
|
+
*/
|
|
5471
|
+
function renderHistoryView(createElement, { vm, locale = "en" }) {
|
|
5472
|
+
return createElement(HistoryEntry, {
|
|
5473
|
+
vm,
|
|
5474
|
+
locale
|
|
5475
|
+
});
|
|
5476
|
+
}
|
|
5477
|
+
/**
|
|
5478
|
+
* Follows the Git status of the files under `directory`, as the panel mounted for `vm` last read it, and calls
|
|
5479
|
+
* `listener` with their marks by path relative to `directory`. The marks are empty while no repository is chosen or
|
|
5480
|
+
* `directory` is outside it. Returns the function that stops following.
|
|
5481
|
+
*/
|
|
5482
|
+
function followChangeMarks(vm, directory, listener) {
|
|
5483
|
+
let stopped = false;
|
|
5484
|
+
let read;
|
|
5485
|
+
let unfollow = () => {};
|
|
5486
|
+
const update = async (controller) => {
|
|
5487
|
+
const { repository, snapshot } = controller !== null && controller !== void 0 ? controller : {
|
|
5488
|
+
repository: null,
|
|
5489
|
+
snapshot: null
|
|
5490
|
+
};
|
|
5491
|
+
if (snapshot === read) return;
|
|
5492
|
+
read = snapshot;
|
|
5493
|
+
const path = repository && snapshot ? await repository.root.resolve(directory).catch(() => null) : null;
|
|
5494
|
+
if (!stopped && read === snapshot) listener(path ? changeMarks(snapshot.changes, path.join("/")) : /* @__PURE__ */ new Map());
|
|
5495
|
+
};
|
|
5496
|
+
const unregister = findController(vm, (controller) => {
|
|
5497
|
+
unfollow();
|
|
5498
|
+
unfollow = controller ? controller.follow(() => void update(controller)) : () => {};
|
|
5499
|
+
update(controller);
|
|
5500
|
+
});
|
|
5501
|
+
return () => {
|
|
5502
|
+
stopped = true;
|
|
5503
|
+
unregister();
|
|
5504
|
+
unfollow();
|
|
5505
|
+
};
|
|
4979
5506
|
}
|
|
4980
|
-
export { GitPanelError, HistoryGraph, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, laneColors, layoutHistory, mountGitPanel, openProjectComparison, openProjectSourceTabs, openRepository, pullRequestBranch, pullRequestRef,
|
|
5507
|
+
export { BranchButton, GitPanelError, HistoryGraph, changeMarks, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, followChangeMarks, laneColors, layoutHistory, mountGitPanel, openProjectComparison, openProjectSourceTabs, openRepository, pullRequestBranch, pullRequestRef, renderBranchButton, renderHistoryView };
|