@kubohiroya/turbowarp-plus-editor-git 0.15.0 → 0.16.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 +5 -3
- package/README.md +5 -3
- package/dist/file-diff-view.d.ts +3 -1
- package/dist/filesystem.d.ts +2 -2
- package/dist/history-graph-view.d.ts +40 -0
- package/dist/history-graph.d.ts +44 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.js +693 -30
- package/dist/local-operations.d.ts +14 -0
- package/dist/messages.d.ts +52 -0
- package/dist/{project-comparison-LAyP_beL.js → project-comparison-MU0qD2wo.js} +213 -16
- package/dist/project-source-diff.d.ts +2 -0
- package/dist/project-source-diff.js +2 -2
- package/dist/project-source-review.d.ts +43 -0
- package/dist/project-source-tabs.d.ts +35 -0
- package/dist/pull-request-panel.d.ts +6 -1
- package/dist/{repository-Cx-mxT9l.js → repository-BYno-5f8.js} +491 -4
- package/dist/repository.d.ts +44 -0
- package/dist/repository.js +1 -1
- package/dist/style.css +27 -4
- package/package.json +1 -1
- package/src/file-diff-view.tsx +7 -3
- package/src/filesystem.ts +2 -1
- package/src/history-graph-view.tsx +233 -0
- package/src/history-graph.ts +90 -0
- package/src/index.tsx +135 -16
- package/src/local-operations.ts +59 -4
- package/src/messages.ts +26 -2
- package/src/project-source-diff.tsx +2 -0
- package/src/project-source-review.tsx +127 -15
- package/src/project-source-tabs.tsx +118 -0
- package/src/pull-request-panel.tsx +26 -5
- package/src/repository.ts +155 -1
- package/src/style.css +27 -4
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as parseProjectSource, 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, w as readProjectSourceDiff, y as useAssetImage } from "./project-comparison-MU0qD2wo.js";
|
|
2
2
|
import { n as init_objectSpread2, r as __commonJSMin, t as _objectSpread2$1 } from "./objectSpread2-Dkd68nJH.js";
|
|
3
|
-
import {
|
|
3
|
+
import { a as createReadOnlyFs, i as GitPanelError, n as openRepository } from "./repository-BYno-5f8.js";
|
|
4
4
|
import * as m from "react";
|
|
5
5
|
import React, { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { createPortal, render, unmountComponentAtNode } from "react-dom";
|
|
@@ -2672,19 +2672,21 @@ diffMatchPatch.DIFF_INSERT;
|
|
|
2672
2672
|
var en$3 = {
|
|
2673
2673
|
view: "Show changes as",
|
|
2674
2674
|
blocks: "Blocks",
|
|
2675
|
-
text: "Text"
|
|
2675
|
+
text: "Text",
|
|
2676
|
+
openTabs: "Open as tabs"
|
|
2676
2677
|
};
|
|
2677
2678
|
var ja$3 = {
|
|
2678
2679
|
view: "変更の表示",
|
|
2679
2680
|
blocks: "ブロック",
|
|
2680
|
-
text: "テキスト"
|
|
2681
|
+
text: "テキスト",
|
|
2682
|
+
openTabs: "タブで開く"
|
|
2681
2683
|
};
|
|
2682
2684
|
/** Project sources are the files the panel opens as projects. */
|
|
2683
2685
|
var isProjectSource = (path) => path.split("/").pop() === "project.source.json";
|
|
2684
2686
|
/**
|
|
2685
2687
|
* Shows one changed file. Project sources are compared as blocks by default, with their text diff one switch away.
|
|
2686
2688
|
*/
|
|
2687
|
-
function FileDiffView({ change, diff, labels, locale, renderBlock, loadAsset, locateBlock }) {
|
|
2689
|
+
function FileDiffView({ change, diff, labels, locale, renderBlock, loadAsset, locateBlock, onOpenTabs }) {
|
|
2688
2690
|
var _change$oldMode, _change$newMode;
|
|
2689
2691
|
const [view, setView] = useState("blocks");
|
|
2690
2692
|
const names = locale.startsWith("ja") ? ja$3 : en$3;
|
|
@@ -2708,7 +2710,11 @@ function FileDiffView({ change, diff, labels, locale, renderBlock, loadAsset, lo
|
|
|
2708
2710
|
"aria-pressed": view === mode,
|
|
2709
2711
|
"data-git-view": mode,
|
|
2710
2712
|
onClick: () => setView(mode)
|
|
2711
|
-
}, names[mode]))
|
|
2713
|
+
}, names[mode])), onOpenTabs && /* @__PURE__ */ React.createElement("button", {
|
|
2714
|
+
type: "button",
|
|
2715
|
+
"data-git-open-tabs": "",
|
|
2716
|
+
onClick: () => onOpenTabs(change.before === null ? null : sources.before, change.after === null ? null : sources.after)
|
|
2717
|
+
}, names.openTabs)), sources && view === "blocks" ? /* @__PURE__ */ React.createElement(ProjectSourceComparison, {
|
|
2712
2718
|
renderBlock,
|
|
2713
2719
|
locale,
|
|
2714
2720
|
fallback: text,
|
|
@@ -3019,6 +3025,84 @@ function ProjectElementView({ changes, selection, locale, renderBlock, onSelectF
|
|
|
3019
3025
|
onClick: () => onSelectFile(file)
|
|
3020
3026
|
}, file.path, " ", /* @__PURE__ */ React.createElement("small", null, labels.groups[file.group])))))));
|
|
3021
3027
|
}
|
|
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
|
+
}
|
|
3022
3106
|
// src/messages.ts
|
|
3023
3107
|
var messages = {
|
|
3024
3108
|
en: {
|
|
@@ -3064,6 +3148,10 @@ var messages = {
|
|
|
3064
3148
|
outdated: "The repository changed outside the Editor. Refresh to read the current state.",
|
|
3065
3149
|
unsupported: "This repository contains an entry the browser cannot represent.",
|
|
3066
3150
|
commitMessage: "Write a message for this record.",
|
|
3151
|
+
switchUnsafe: "Stop the project, and save or record (or undo) every change, before switching branches.",
|
|
3152
|
+
branchExists: "A branch with this name already exists.",
|
|
3153
|
+
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
|
+
branchName: "Git cannot use this name for a branch.",
|
|
3067
3155
|
pullUnsafe: "Stop the project, and save or undo unsaved edits and unrecorded changes, before getting changes from GitHub (pull).",
|
|
3068
3156
|
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.",
|
|
3069
3157
|
session: "Reconnect GitHub for this repository and requested permission.",
|
|
@@ -3082,6 +3170,16 @@ var messages = {
|
|
|
3082
3170
|
saveFirst: "Save the project before adding its changes to the next record.",
|
|
3083
3171
|
author: "Set user.name and user.email for this repository in Git before recording. The Editor does not change Git settings.",
|
|
3084
3172
|
nothingStaged: "Add changes to the next record first.",
|
|
3173
|
+
switchTo: "Switch",
|
|
3174
|
+
currentBranch: "current",
|
|
3175
|
+
createBranch: "Create Branch",
|
|
3176
|
+
newBranch: "New branch name",
|
|
3177
|
+
switchAfterCreate: "Switch to it",
|
|
3178
|
+
createFromRemote: "Create and Switch",
|
|
3179
|
+
remoteBranches: "Branches on GitHub (origin)",
|
|
3180
|
+
switched: "Switched branches. Use Reload Project to open the files of this branch.",
|
|
3181
|
+
branchCreated: "Created the branch.",
|
|
3182
|
+
projectMissing: "The open project folder is not on this branch. Switch anyway?",
|
|
3085
3183
|
pulledProject: "Got the changes from GitHub. Use Reload Project to open the updated files.",
|
|
3086
3184
|
confirmPush: "Send the records on this branch to GitHub (push)?",
|
|
3087
3185
|
details: "Git details",
|
|
@@ -3101,7 +3199,19 @@ var messages = {
|
|
|
3101
3199
|
upstreamUnknown: "Not checked with GitHub yet",
|
|
3102
3200
|
records: "records",
|
|
3103
3201
|
checkedAt: "as of the last check",
|
|
3104
|
-
failed: "Could not read the repository. Check folder access and refresh."
|
|
3202
|
+
failed: "Could not read the repository. Check folder access and refresh.",
|
|
3203
|
+
historyMore: "Show more",
|
|
3204
|
+
historyLoading: "Reading records…",
|
|
3205
|
+
historyFailed: "Could not read the records.",
|
|
3206
|
+
historyActions: "Actions",
|
|
3207
|
+
historyCreateHere: "Create branch here…",
|
|
3208
|
+
historySwitch: "Switch to {name}",
|
|
3209
|
+
historyCreateFromRemote: "Create and switch to {name}",
|
|
3210
|
+
historyCopy: "Copy commit ID",
|
|
3211
|
+
historyCopied: "Copied the commit ID.",
|
|
3212
|
+
historyCopyFailed: "Could not copy the commit ID.",
|
|
3213
|
+
historyRefs: "Branches",
|
|
3214
|
+
cancel: "Cancel"
|
|
3105
3215
|
},
|
|
3106
3216
|
ja: {
|
|
3107
3217
|
pullRequests: "プルリクエスト",
|
|
@@ -3146,6 +3256,10 @@ var messages = {
|
|
|
3146
3256
|
outdated: "Editor の外でリポジトリが変更されました。再取得すると最新の状態を読み込みます。",
|
|
3147
3257
|
unsupported: "ブラウザーで扱えない種類の Git エントリーがあります。",
|
|
3148
3258
|
commitMessage: "この記録の説明を書いてください。",
|
|
3259
|
+
switchUnsafe: "ブランチを切り替える前に、実行を止め、すべての変更を保存して記録(または取り消し)してください。",
|
|
3260
|
+
branchExists: "同じ名前のブランチがすでにあります。",
|
|
3261
|
+
locked: "ほかの Git の操作が、このリポジトリを使っています(ロックファイル、またはマージ・cherry-pick・revert・rebase の途中)。終わってから、もう一度試してください。",
|
|
3262
|
+
branchName: "この名前は Git のブランチ名に使えません。",
|
|
3149
3263
|
pullUnsafe: "GitHub から取り込む前に、実行を止め、保存していない編集とまだ記録していない変更をなくしてください。",
|
|
3150
3264
|
diverged: "このブランチと GitHub の両方に新しい記録があるため、ここでは取り込めません(pull は fast-forward のみ)。ブランチとファイルはそのままです。",
|
|
3151
3265
|
session: "このリポジトリと操作に必要な権限で GitHub に接続してください。",
|
|
@@ -3164,6 +3278,16 @@ var messages = {
|
|
|
3164
3278
|
saveFirst: "次の記録に入れる前に、作品を保存してください。",
|
|
3165
3279
|
author: "記録する前に、Git でこのリポジトリの user.name と user.email を設定してください。Editor は Git の設定を変えません。",
|
|
3166
3280
|
nothingStaged: "先に、変更を次の記録に入れてください。",
|
|
3281
|
+
switchTo: "切り替える",
|
|
3282
|
+
currentBranch: "現在",
|
|
3283
|
+
createBranch: "ブランチを作る",
|
|
3284
|
+
newBranch: "新しいブランチの名前",
|
|
3285
|
+
switchAfterCreate: "作ったら切り替える",
|
|
3286
|
+
createFromRemote: "作って切り替える",
|
|
3287
|
+
remoteBranches: "GitHub(origin)のブランチ",
|
|
3288
|
+
switched: "ブランチを切り替えました。「作品を再読込」で、このブランチのファイルを開けます。",
|
|
3289
|
+
branchCreated: "ブランチを作りました。",
|
|
3290
|
+
projectMissing: "開いている作品フォルダは、このブランチにありません。切り替えますか?",
|
|
3167
3291
|
pulledProject: "GitHub から取り込みました。「作品を再読込」で更新したファイルを開けます。",
|
|
3168
3292
|
confirmPush: "このブランチの記録を GitHub に送りますか(push)?",
|
|
3169
3293
|
details: "Git の詳細",
|
|
@@ -3183,10 +3307,354 @@ var messages = {
|
|
|
3183
3307
|
upstreamUnknown: "まだ GitHub と確かめていない",
|
|
3184
3308
|
records: "件",
|
|
3185
3309
|
checkedAt: "最後に確かめた時点",
|
|
3186
|
-
failed: "リポジトリを読み込めませんでした。フォルダへのアクセスを確認し、再取得してください。"
|
|
3310
|
+
failed: "リポジトリを読み込めませんでした。フォルダへのアクセスを確認し、再取得してください。",
|
|
3311
|
+
historyMore: "さらに表示",
|
|
3312
|
+
historyLoading: "記録を読込中…",
|
|
3313
|
+
historyFailed: "記録を読み込めませんでした。",
|
|
3314
|
+
historyActions: "操作",
|
|
3315
|
+
historyCreateHere: "ここからブランチを作る…",
|
|
3316
|
+
historySwitch: "{name} に切り替える",
|
|
3317
|
+
historyCreateFromRemote: "{name} を作って切り替える",
|
|
3318
|
+
historyCopy: "コミットの ID をコピー",
|
|
3319
|
+
historyCopied: "コミットの ID をコピーしました。",
|
|
3320
|
+
historyCopyFailed: "コミットの ID をコピーできませんでした。",
|
|
3321
|
+
historyRefs: "ブランチ",
|
|
3322
|
+
cancel: "キャンセル"
|
|
3187
3323
|
}
|
|
3188
3324
|
};
|
|
3189
3325
|
var labelsFor = (locale) => locale.startsWith("ja") ? messages.ja : messages.en;
|
|
3326
|
+
// src/history-graph-view.tsx
|
|
3327
|
+
/** Lane colors that read on light and dark backgrounds. */
|
|
3328
|
+
var laneColors = [
|
|
3329
|
+
"#2f7ed8",
|
|
3330
|
+
"#d9480f",
|
|
3331
|
+
"#2b9348",
|
|
3332
|
+
"#9c36b5",
|
|
3333
|
+
"#c2255c",
|
|
3334
|
+
"#0c8599",
|
|
3335
|
+
"#b7791f",
|
|
3336
|
+
"#5c7cfa"
|
|
3337
|
+
];
|
|
3338
|
+
var column = 14;
|
|
3339
|
+
var rowHeight = 44;
|
|
3340
|
+
var middle = rowHeight / 2;
|
|
3341
|
+
var x = (index) => column / 2 + index * column;
|
|
3342
|
+
function Lanes({ row, width }) {
|
|
3343
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
3344
|
+
className: "twgit-graph-lanes",
|
|
3345
|
+
"aria-hidden": "true",
|
|
3346
|
+
focusable: "false",
|
|
3347
|
+
width: width * column,
|
|
3348
|
+
height: rowHeight,
|
|
3349
|
+
viewBox: `0 0 ${width * column} ${rowHeight}`
|
|
3350
|
+
}, row.segments.map((segment, index) => {
|
|
3351
|
+
const [top, bottom] = segment.part === "top" ? [0, middle] : [middle, rowHeight];
|
|
3352
|
+
const from = x(segment.from), to = x(segment.to), bend = (top + bottom) / 2;
|
|
3353
|
+
const d = from === to ? `M${from} ${top}V${bottom}` : `M${from} ${top}C${from} ${bend} ${to} ${bend} ${to} ${bottom}`;
|
|
3354
|
+
return /* @__PURE__ */ React.createElement("path", {
|
|
3355
|
+
key: index,
|
|
3356
|
+
d,
|
|
3357
|
+
fill: "none",
|
|
3358
|
+
stroke: laneColors[segment.color % laneColors.length],
|
|
3359
|
+
strokeWidth: 2
|
|
3360
|
+
});
|
|
3361
|
+
}), /* @__PURE__ */ React.createElement("circle", {
|
|
3362
|
+
cx: x(row.column),
|
|
3363
|
+
cy: middle,
|
|
3364
|
+
r: 4.5,
|
|
3365
|
+
fill: laneColors[row.color % laneColors.length],
|
|
3366
|
+
stroke: "Canvas",
|
|
3367
|
+
strokeWidth: 1.5
|
|
3368
|
+
}));
|
|
3369
|
+
}
|
|
3370
|
+
/**
|
|
3371
|
+
* The history as a graph: one row per commit with its lanes drawn in SVG, a button that selects the commit and a
|
|
3372
|
+
* button that opens its actions. ArrowUp and ArrowDown move between commits, Home and End to the ends; Enter or
|
|
3373
|
+
* Space selects; the context menu key or Shift+F10 opens the actions.
|
|
3374
|
+
*/
|
|
3375
|
+
function HistoryGraph(props) {
|
|
3376
|
+
const { commits, selected = null, onSelect, locale = "en", busy = false } = props;
|
|
3377
|
+
const labels = labelsFor(locale);
|
|
3378
|
+
const layout = useMemo(() => layoutHistory(commits), [commits]);
|
|
3379
|
+
const rows = useRef([]);
|
|
3380
|
+
const menuButtons = useRef([]);
|
|
3381
|
+
const popup = useRef(null);
|
|
3382
|
+
const [active, setActive] = useState(null);
|
|
3383
|
+
const [menu, setMenu] = useState(null);
|
|
3384
|
+
const [branchName, setBranchName] = useState("");
|
|
3385
|
+
const [checkout, setCheckout] = useState(true);
|
|
3386
|
+
const [status, setStatus] = useState("");
|
|
3387
|
+
const [creating, setCreating] = useState(false);
|
|
3388
|
+
const [createError, setCreateError] = useState("");
|
|
3389
|
+
const mounted = useRef(true);
|
|
3390
|
+
useEffect(() => () => {
|
|
3391
|
+
mounted.current = false;
|
|
3392
|
+
}, []);
|
|
3393
|
+
const focusIndex = Math.max(0, commits.findIndex((commit) => commit.oid === (active !== null && active !== void 0 ? active : selected)));
|
|
3394
|
+
const locals = useMemo(() => {
|
|
3395
|
+
var _props$localBranches;
|
|
3396
|
+
return new Set((_props$localBranches = props.localBranches) !== null && _props$localBranches !== void 0 ? _props$localBranches : commits.flatMap((commit) => commit.refs.filter((ref) => ref.kind === "branch").map((ref) => ref.name)));
|
|
3397
|
+
}, [commits, props.localBranches]);
|
|
3398
|
+
useEffect(() => {
|
|
3399
|
+
var _element$querySelecto;
|
|
3400
|
+
const element = popup.current;
|
|
3401
|
+
if (!element) return;
|
|
3402
|
+
(_element$querySelecto = element.querySelector((menu === null || menu === void 0 ? void 0 : menu.mode) === "create" ? "input" : "[role=\"menuitem\"]")) === null || _element$querySelecto === void 0 || _element$querySelecto.focus();
|
|
3403
|
+
}, [menu === null || menu === void 0 ? void 0 : menu.oid, menu === null || menu === void 0 ? void 0 : menu.mode]);
|
|
3404
|
+
useEffect(() => {
|
|
3405
|
+
var _popup$current;
|
|
3406
|
+
if (!createError || creating) return;
|
|
3407
|
+
const input = (_popup$current = popup.current) === null || _popup$current === void 0 ? void 0 : _popup$current.querySelector("input:not([type])");
|
|
3408
|
+
input === null || input === void 0 || input.focus();
|
|
3409
|
+
input === null || input === void 0 || input.select();
|
|
3410
|
+
}, [createError, creating]);
|
|
3411
|
+
const date = (timestamp) => (/* @__PURE__ */ new Date(timestamp * 1e3)).toLocaleString(locale, {
|
|
3412
|
+
dateStyle: "medium",
|
|
3413
|
+
timeStyle: "short"
|
|
3414
|
+
});
|
|
3415
|
+
const refName = (ref) => ref.current && ref.kind === "branch" ? `${ref.name} (${labels.currentBranch})` : ref.name;
|
|
3416
|
+
const closeMenu = (focus) => {
|
|
3417
|
+
var _current$index;
|
|
3418
|
+
const index = commits.findIndex((commit) => commit.oid === (menu === null || menu === void 0 ? void 0 : menu.oid));
|
|
3419
|
+
setMenu(null);
|
|
3420
|
+
if (focus && index !== -1) (_current$index = (focus === "menu" ? menuButtons : rows).current[index]) === null || _current$index === void 0 || _current$index.focus();
|
|
3421
|
+
};
|
|
3422
|
+
const actionsFor = (commit) => {
|
|
3423
|
+
const actions = [];
|
|
3424
|
+
if (props.onCreateBranch) actions.push({
|
|
3425
|
+
id: "create",
|
|
3426
|
+
label: labels.historyCreateHere,
|
|
3427
|
+
run: () => {
|
|
3428
|
+
setBranchName("");
|
|
3429
|
+
setCheckout(true);
|
|
3430
|
+
setCreateError("");
|
|
3431
|
+
setMenu({
|
|
3432
|
+
oid: commit.oid,
|
|
3433
|
+
mode: "create"
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
});
|
|
3437
|
+
for (const ref of commit.refs) {
|
|
3438
|
+
if (ref.kind === "branch" && !ref.current && props.onSwitchBranch) {
|
|
3439
|
+
const run = props.onSwitchBranch;
|
|
3440
|
+
actions.push({
|
|
3441
|
+
id: "switch:" + ref.name,
|
|
3442
|
+
label: labels.historySwitch.replace("{name}", ref.name),
|
|
3443
|
+
run: () => {
|
|
3444
|
+
closeMenu("row");
|
|
3445
|
+
run(ref.name);
|
|
3446
|
+
}
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
const name = ref.name.slice(7);
|
|
3450
|
+
if (ref.kind === "remote" && !locals.has(name) && props.onCreateFromRemote) {
|
|
3451
|
+
const run = props.onCreateFromRemote;
|
|
3452
|
+
actions.push({
|
|
3453
|
+
id: "remote:" + name,
|
|
3454
|
+
label: labels.historyCreateFromRemote.replace("{name}", name),
|
|
3455
|
+
run: () => {
|
|
3456
|
+
closeMenu("row");
|
|
3457
|
+
run(name);
|
|
3458
|
+
}
|
|
3459
|
+
});
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
actions.push({
|
|
3463
|
+
id: "copy",
|
|
3464
|
+
label: labels.historyCopy,
|
|
3465
|
+
run: () => {
|
|
3466
|
+
var _globalThis$navigator;
|
|
3467
|
+
closeMenu("menu");
|
|
3468
|
+
const clipboard = (_globalThis$navigator = globalThis.navigator) === null || _globalThis$navigator === void 0 ? void 0 : _globalThis$navigator.clipboard;
|
|
3469
|
+
Promise.resolve().then(() => clipboard.writeText(commit.oid)).then(() => setStatus(labels.historyCopied), () => setStatus(labels.historyCopyFailed));
|
|
3470
|
+
}
|
|
3471
|
+
});
|
|
3472
|
+
return actions;
|
|
3473
|
+
};
|
|
3474
|
+
const onRowKey = (event, index) => {
|
|
3475
|
+
const target = {
|
|
3476
|
+
ArrowDown: index + 1,
|
|
3477
|
+
ArrowUp: index - 1,
|
|
3478
|
+
Home: 0,
|
|
3479
|
+
End: commits.length - 1
|
|
3480
|
+
}[event.key];
|
|
3481
|
+
if (target !== void 0) {
|
|
3482
|
+
var _rows$current$Math$mi;
|
|
3483
|
+
event.preventDefault();
|
|
3484
|
+
(_rows$current$Math$mi = rows.current[Math.min(commits.length - 1, Math.max(0, target))]) === null || _rows$current$Math$mi === void 0 || _rows$current$Math$mi.focus();
|
|
3485
|
+
} else if (event.key === "ContextMenu" || event.key === "F10" && event.shiftKey) {
|
|
3486
|
+
event.preventDefault();
|
|
3487
|
+
setMenu({
|
|
3488
|
+
oid: commits[index].oid,
|
|
3489
|
+
mode: "menu"
|
|
3490
|
+
});
|
|
3491
|
+
}
|
|
3492
|
+
};
|
|
3493
|
+
const onMenuKey = (event) => {
|
|
3494
|
+
if (event.key === "Escape") {
|
|
3495
|
+
event.preventDefault();
|
|
3496
|
+
event.stopPropagation();
|
|
3497
|
+
if (!creating) closeMenu("menu");
|
|
3498
|
+
return;
|
|
3499
|
+
}
|
|
3500
|
+
if ((menu === null || menu === void 0 ? void 0 : menu.mode) !== "menu") return;
|
|
3501
|
+
if (event.key === "Tab") {
|
|
3502
|
+
setMenu(null);
|
|
3503
|
+
return;
|
|
3504
|
+
}
|
|
3505
|
+
const items = [...event.currentTarget.querySelectorAll("[role=\"menuitem\"]:not(:disabled)")];
|
|
3506
|
+
const index = items.indexOf(event.target);
|
|
3507
|
+
const target = {
|
|
3508
|
+
ArrowDown: index + 1,
|
|
3509
|
+
ArrowUp: index - 1,
|
|
3510
|
+
Home: 0,
|
|
3511
|
+
End: items.length - 1
|
|
3512
|
+
}[event.key];
|
|
3513
|
+
if (target === void 0 || !items.length) return;
|
|
3514
|
+
event.preventDefault();
|
|
3515
|
+
items[(target + items.length) % items.length].focus();
|
|
3516
|
+
};
|
|
3517
|
+
const onMenuBlur = (event) => {
|
|
3518
|
+
var _event$currentTarget$;
|
|
3519
|
+
const next = event.relatedTarget;
|
|
3520
|
+
if (!next || !((_event$currentTarget$ = event.currentTarget.parentElement) === null || _event$currentTarget$ === void 0 ? void 0 : _event$currentTarget$.contains(next))) setMenu(null);
|
|
3521
|
+
};
|
|
3522
|
+
const submitBranch = async (event, oid) => {
|
|
3523
|
+
var _result$error;
|
|
3524
|
+
event.preventDefault();
|
|
3525
|
+
const name = branchName.trim();
|
|
3526
|
+
if (!name || !props.onCreateBranch || creating) return;
|
|
3527
|
+
setCreating(true);
|
|
3528
|
+
setCreateError("");
|
|
3529
|
+
let result;
|
|
3530
|
+
try {
|
|
3531
|
+
result = await props.onCreateBranch(oid, name, checkout);
|
|
3532
|
+
} catch (error) {
|
|
3533
|
+
result = {
|
|
3534
|
+
done: false,
|
|
3535
|
+
error: error instanceof Error && error.message ? error.message : labels.failed
|
|
3536
|
+
};
|
|
3537
|
+
}
|
|
3538
|
+
if (!mounted.current) return;
|
|
3539
|
+
setCreating(false);
|
|
3540
|
+
if (!result || result.done) closeMenu("menu");
|
|
3541
|
+
else setCreateError((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : "");
|
|
3542
|
+
};
|
|
3543
|
+
rows.current.length = commits.length;
|
|
3544
|
+
menuButtons.current.length = commits.length;
|
|
3545
|
+
return /* @__PURE__ */ React.createElement("div", { className: "twgit-graph" }, /* @__PURE__ */ React.createElement("ol", { className: "twgit-graph-list" }, commits.map((commit, index) => {
|
|
3546
|
+
const row = layout.rows[index];
|
|
3547
|
+
const refs = commit.refs.map(refName);
|
|
3548
|
+
const name = [
|
|
3549
|
+
commit.message,
|
|
3550
|
+
commit.author,
|
|
3551
|
+
date(commit.timestamp),
|
|
3552
|
+
...refs.length ? [`${labels.historyRefs}: ${refs.join(", ")}`] : []
|
|
3553
|
+
].join(", ");
|
|
3554
|
+
const open = (menu === null || menu === void 0 ? void 0 : menu.oid) === commit.oid ? menu : null;
|
|
3555
|
+
const actions = (open === null || open === void 0 ? void 0 : open.mode) === "menu" ? actionsFor(commit) : [];
|
|
3556
|
+
return /* @__PURE__ */ React.createElement("li", {
|
|
3557
|
+
key: commit.oid,
|
|
3558
|
+
className: "twgit-graph-row"
|
|
3559
|
+
}, /* @__PURE__ */ React.createElement(Lanes, {
|
|
3560
|
+
row,
|
|
3561
|
+
width: layout.width
|
|
3562
|
+
}), /* @__PURE__ */ React.createElement("button", {
|
|
3563
|
+
type: "button",
|
|
3564
|
+
className: "twgit-graph-commit",
|
|
3565
|
+
ref: (element) => {
|
|
3566
|
+
rows.current[index] = element;
|
|
3567
|
+
},
|
|
3568
|
+
tabIndex: index === focusIndex ? 0 : -1,
|
|
3569
|
+
"aria-pressed": selected === commit.oid,
|
|
3570
|
+
"aria-disabled": busy || void 0,
|
|
3571
|
+
"aria-label": name,
|
|
3572
|
+
title: commit.oid,
|
|
3573
|
+
"data-oid": commit.oid,
|
|
3574
|
+
onFocus: () => setActive(commit.oid),
|
|
3575
|
+
onKeyDown: (event) => onRowKey(event, index),
|
|
3576
|
+
onClick: () => {
|
|
3577
|
+
if (!busy) onSelect(commit.oid);
|
|
3578
|
+
}
|
|
3579
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "twgit-graph-subject" }, commit.refs.map((ref) => /* @__PURE__ */ React.createElement("span", {
|
|
3580
|
+
key: ref.kind + ref.name,
|
|
3581
|
+
className: `twgit-graph-ref twgit-graph-ref-${ref.kind}${ref.current ? " twgit-graph-ref-current" : ""}`
|
|
3582
|
+
}, refName(ref))), commit.message), /* @__PURE__ */ React.createElement("span", { className: "twgit-graph-meta" }, commit.author, " · ", date(commit.timestamp))), /* @__PURE__ */ React.createElement("button", {
|
|
3583
|
+
type: "button",
|
|
3584
|
+
className: "twgit-graph-menu-button",
|
|
3585
|
+
ref: (element) => {
|
|
3586
|
+
menuButtons.current[index] = element;
|
|
3587
|
+
},
|
|
3588
|
+
tabIndex: index === focusIndex || open ? 0 : -1,
|
|
3589
|
+
"aria-haspopup": "menu",
|
|
3590
|
+
"aria-expanded": (open === null || open === void 0 ? void 0 : open.mode) === "menu",
|
|
3591
|
+
"aria-label": `${labels.historyActions}: ${commit.message}`,
|
|
3592
|
+
onClick: () => setMenu(open ? null : {
|
|
3593
|
+
oid: commit.oid,
|
|
3594
|
+
mode: "menu"
|
|
3595
|
+
}),
|
|
3596
|
+
onKeyDown: (event) => {
|
|
3597
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
3598
|
+
event.preventDefault();
|
|
3599
|
+
setMenu({
|
|
3600
|
+
oid: commit.oid,
|
|
3601
|
+
mode: "menu"
|
|
3602
|
+
});
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
}, "⋯"), (open === null || open === void 0 ? void 0 : open.mode) === "menu" && /* @__PURE__ */ React.createElement("div", {
|
|
3606
|
+
ref: popup,
|
|
3607
|
+
className: "twgit-graph-popup",
|
|
3608
|
+
role: "menu",
|
|
3609
|
+
"aria-label": labels.historyActions,
|
|
3610
|
+
onKeyDown: onMenuKey,
|
|
3611
|
+
onBlur: onMenuBlur
|
|
3612
|
+
}, actions.map((action) => /* @__PURE__ */ React.createElement("button", {
|
|
3613
|
+
key: action.id,
|
|
3614
|
+
type: "button",
|
|
3615
|
+
role: "menuitem",
|
|
3616
|
+
tabIndex: -1,
|
|
3617
|
+
"data-action": action.id,
|
|
3618
|
+
disabled: busy && action.id !== "copy",
|
|
3619
|
+
onClick: action.run
|
|
3620
|
+
}, action.label))), (open === null || open === void 0 ? void 0 : open.mode) === "create" && /* @__PURE__ */ React.createElement("div", {
|
|
3621
|
+
ref: popup,
|
|
3622
|
+
className: "twgit-graph-popup",
|
|
3623
|
+
role: "dialog",
|
|
3624
|
+
"aria-label": labels.historyCreateHere,
|
|
3625
|
+
onKeyDown: onMenuKey
|
|
3626
|
+
}, /* @__PURE__ */ React.createElement("form", { onSubmit: (event) => void submitBranch(event, commit.oid) }, /* @__PURE__ */ React.createElement("label", null, labels.newBranch, " ", /* @__PURE__ */ React.createElement("input", {
|
|
3627
|
+
value: branchName,
|
|
3628
|
+
required: true,
|
|
3629
|
+
disabled: creating,
|
|
3630
|
+
"aria-invalid": createError ? true : void 0,
|
|
3631
|
+
onChange: (event) => setBranchName(event.currentTarget.value)
|
|
3632
|
+
})), /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
|
|
3633
|
+
type: "checkbox",
|
|
3634
|
+
checked: checkout,
|
|
3635
|
+
disabled: creating,
|
|
3636
|
+
onChange: (event) => setCheckout(event.currentTarget.checked)
|
|
3637
|
+
}), " ", labels.switchAfterCreate), createError && /* @__PURE__ */ React.createElement("p", {
|
|
3638
|
+
className: "twgit-graph-form-error",
|
|
3639
|
+
role: "alert"
|
|
3640
|
+
}, createError), /* @__PURE__ */ React.createElement("span", { className: "twgit-graph-form-actions" }, /* @__PURE__ */ React.createElement("button", {
|
|
3641
|
+
type: "submit",
|
|
3642
|
+
disabled: creating || busy || !branchName.trim()
|
|
3643
|
+
}, labels.createBranch), /* @__PURE__ */ React.createElement("button", {
|
|
3644
|
+
type: "button",
|
|
3645
|
+
disabled: creating,
|
|
3646
|
+
onClick: () => closeMenu("menu")
|
|
3647
|
+
}, labels.cancel)))));
|
|
3648
|
+
})), props.hasMore && props.onShowMore && /* @__PURE__ */ React.createElement("button", {
|
|
3649
|
+
type: "button",
|
|
3650
|
+
className: "twgit-graph-more",
|
|
3651
|
+
disabled: props.loadingMore,
|
|
3652
|
+
onClick: props.onShowMore
|
|
3653
|
+
}, props.loadingMore ? labels.historyLoading : labels.historyMore), /* @__PURE__ */ React.createElement("p", {
|
|
3654
|
+
className: "twgit-graph-status",
|
|
3655
|
+
role: "status"
|
|
3656
|
+
}, status));
|
|
3657
|
+
}
|
|
3190
3658
|
// src/connection-settings.tsx
|
|
3191
3659
|
var en$1 = {
|
|
3192
3660
|
title: "GitHub connection",
|
|
@@ -3343,7 +3811,8 @@ var en = {
|
|
|
3343
3811
|
rateLimit: "The public GitHub API rate limit was reached. Try again after the limit resets.",
|
|
3344
3812
|
failed: "Could not read GitHub. Try again.",
|
|
3345
3813
|
changed: "The pull request changed while it was being read. Open it again.",
|
|
3346
|
-
tooManyFiles: "GitHub only returns the first 3,000 changed files. This pull request exceeds that limit."
|
|
3814
|
+
tooManyFiles: "GitHub only returns the first 3,000 changed files. This pull request exceeds that limit.",
|
|
3815
|
+
openTabs: "Open as tabs"
|
|
3347
3816
|
};
|
|
3348
3817
|
var ja = {
|
|
3349
3818
|
title: "プルリクエスト",
|
|
@@ -3364,12 +3833,13 @@ var ja = {
|
|
|
3364
3833
|
rateLimit: "公開 GitHub API の利用上限に達しました。上限の解除後に再試行してください。",
|
|
3365
3834
|
failed: "GitHub から取得できませんでした。再試行してください。",
|
|
3366
3835
|
changed: "取得中にプルリクエストが更新されました。もう一度開いてください。",
|
|
3367
|
-
tooManyFiles: "変更ファイルが GitHub API の取得上限である 3,000 件を超えています。"
|
|
3836
|
+
tooManyFiles: "変更ファイルが GitHub API の取得上限である 3,000 件を超えています。",
|
|
3837
|
+
openTabs: "タブで開く"
|
|
3368
3838
|
};
|
|
3369
3839
|
function errorMessage(error, labels) {
|
|
3370
3840
|
return error instanceof PullRequestError ? labels[error.code] : labels.failed;
|
|
3371
3841
|
}
|
|
3372
|
-
function PullRequests({ name, labels, locale, renderBlock, locateFor }) {
|
|
3842
|
+
function PullRequests({ name, labels, locale, renderBlock, locateFor, openTabs }) {
|
|
3373
3843
|
const client = useMemo(() => createGitHubPullRequests(name), [name]);
|
|
3374
3844
|
const [page, setPage] = useState(1);
|
|
3375
3845
|
const [listing, setListing] = useState();
|
|
@@ -3454,7 +3924,26 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor }) {
|
|
|
3454
3924
|
href: pr.url,
|
|
3455
3925
|
target: "_blank",
|
|
3456
3926
|
rel: "noreferrer"
|
|
3457
|
-
}, labels.onGitHub)
|
|
3927
|
+
}, labels.onGitHub), openTabs && /* @__PURE__ */ React.createElement("button", {
|
|
3928
|
+
type: "button",
|
|
3929
|
+
"data-git-open-tabs": "",
|
|
3930
|
+
onClick: () => openTabs(`${name}#${pr.number}@${pr.head.sha}`, pr.files.flatMap((file) => {
|
|
3931
|
+
if (!("patch" in file)) return [];
|
|
3932
|
+
let projects;
|
|
3933
|
+
try {
|
|
3934
|
+
projects = readProjectSourceDiff(file.patch, file.beforeSource);
|
|
3935
|
+
} catch (_unused) {
|
|
3936
|
+
return [];
|
|
3937
|
+
}
|
|
3938
|
+
return projects ? [{
|
|
3939
|
+
path: file.path,
|
|
3940
|
+
before: projects[0],
|
|
3941
|
+
after: projects[1],
|
|
3942
|
+
loadAsset: file.loadAsset,
|
|
3943
|
+
locateBlock: locateFor === null || locateFor === void 0 ? void 0 : locateFor(file.path, pr.head.sha)
|
|
3944
|
+
}] : [];
|
|
3945
|
+
}), `${name}#${pr.number}`)
|
|
3946
|
+
}, labels.openTabs)), /* @__PURE__ */ React.createElement(ProjectSourceReview, {
|
|
3458
3947
|
title: pr.title,
|
|
3459
3948
|
description: pr.description,
|
|
3460
3949
|
files: locateFor ? pr.files.map((file) => "patch" in file ? _objectSpread2$1(_objectSpread2$1({}, file), {}, { locateBlock: locateFor(file.path, pr.head.sha) }) : file) : pr.files,
|
|
@@ -3463,7 +3952,7 @@ function PullRequests({ name, labels, locale, renderBlock, locateFor }) {
|
|
|
3463
3952
|
rememberAs: `${name}#${pr.number}`
|
|
3464
3953
|
}))));
|
|
3465
3954
|
}
|
|
3466
|
-
function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor }) {
|
|
3955
|
+
function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor, openTabs }) {
|
|
3467
3956
|
const labels = locale.startsWith("ja") ? ja : en;
|
|
3468
3957
|
const [origin, setOrigin] = useState();
|
|
3469
3958
|
useEffect(() => {
|
|
@@ -3498,7 +3987,8 @@ function PullRequestReviewPanel({ repository, locale, renderBlock, locateFor })
|
|
|
3498
3987
|
labels,
|
|
3499
3988
|
locale,
|
|
3500
3989
|
renderBlock,
|
|
3501
|
-
locateFor
|
|
3990
|
+
locateFor,
|
|
3991
|
+
openTabs
|
|
3502
3992
|
});
|
|
3503
3993
|
}
|
|
3504
3994
|
// src/editor-block-locator.ts
|
|
@@ -3554,7 +4044,7 @@ var initial = {
|
|
|
3554
4044
|
var controllers = /* @__PURE__ */ new WeakMap();
|
|
3555
4045
|
var watchInterval = 2e3;
|
|
3556
4046
|
function GitPanel({ vm, document, host, controller }) {
|
|
3557
|
-
var _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head
|
|
4047
|
+
var _state$snapshot, _state$repository, _state$snapshot$head$, _state$snapshot$head;
|
|
3558
4048
|
const [visible, setVisible] = useState(false);
|
|
3559
4049
|
const [slot, setSlot] = useState(null);
|
|
3560
4050
|
const shown = visible || slot !== null;
|
|
@@ -3587,9 +4077,10 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3587
4077
|
const handled = useRef(null);
|
|
3588
4078
|
const labels = labelsFor(locale);
|
|
3589
4079
|
const background = useRef(null);
|
|
4080
|
+
/** Whether an operation ran to the end, or the message the panel shows for why it did not. */
|
|
3590
4081
|
const run = async (operation, automatic = false) => {
|
|
3591
4082
|
if (running.current && !automatic && background.current) await background.current;
|
|
3592
|
-
if (running.current || !alive.current) return;
|
|
4083
|
+
if (running.current || !alive.current) return { done: false };
|
|
3593
4084
|
let settle = () => {};
|
|
3594
4085
|
if (automatic) background.current = new Promise((resolve) => {
|
|
3595
4086
|
settle = resolve;
|
|
@@ -3604,12 +4095,13 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3604
4095
|
try {
|
|
3605
4096
|
const update = await operation();
|
|
3606
4097
|
if (epoch.current === ticket) setState((previous) => _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, previous), update), {}, { busy: automatic ? previous.busy : false }));
|
|
4098
|
+
return { done: true };
|
|
3607
4099
|
} catch (error) {
|
|
3608
|
-
if (epoch.current !== ticket) return;
|
|
4100
|
+
if (epoch.current !== ticket) return { done: false };
|
|
3609
4101
|
const code = error instanceof GitPanelError ? error.code : "failed";
|
|
3610
4102
|
if (automatic && code === "changed") {
|
|
3611
4103
|
handled.current = null;
|
|
3612
|
-
return;
|
|
4104
|
+
return { done: false };
|
|
3613
4105
|
}
|
|
3614
4106
|
const message = labels[code] || labels.failed;
|
|
3615
4107
|
setState((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
@@ -3617,6 +4109,10 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3617
4109
|
busy: automatic ? previous.busy : false,
|
|
3618
4110
|
diff: null
|
|
3619
4111
|
}));
|
|
4112
|
+
return {
|
|
4113
|
+
done: false,
|
|
4114
|
+
error: message
|
|
4115
|
+
};
|
|
3620
4116
|
} finally {
|
|
3621
4117
|
running.current = false;
|
|
3622
4118
|
if (epoch.current !== ticket && !refreshPending.current && alive.current) setState((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, { busy: false }));
|
|
@@ -3901,13 +4397,15 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3901
4397
|
const [message, setMessage] = useState("");
|
|
3902
4398
|
const localOperation = (operation, notice) => {
|
|
3903
4399
|
const repository = current.current.repository;
|
|
3904
|
-
if (!repository || !host.localWrite) return Promise.resolve();
|
|
4400
|
+
if (!repository || !host.localWrite) return Promise.resolve({ done: false });
|
|
3905
4401
|
return run(async () => {
|
|
3906
4402
|
var _current$current$proj2;
|
|
3907
4403
|
const ticket = epoch.current;
|
|
3908
4404
|
await repository.localOperation(operation, () => {
|
|
4405
|
+
var _host$isProjectRunnin2;
|
|
3909
4406
|
if (epoch.current !== ticket) throw new GitPanelError("changed");
|
|
3910
4407
|
if (operation.kind === "stage" && host.isProjectDirty()) throw new GitPanelError("saveFirst");
|
|
4408
|
+
if ((operation.kind === "switchBranch" || operation.kind === "createBranch" && operation.checkout) && (host.isProjectDirty() || ((_host$isProjectRunnin2 = host.isProjectRunning) === null || _host$isProjectRunnin2 === void 0 ? void 0 : _host$isProjectRunnin2.call(host)))) throw new GitPanelError("switchUnsafe");
|
|
3911
4409
|
});
|
|
3912
4410
|
if (operation.kind === "commit") setMessage("");
|
|
3913
4411
|
const snapshot = await repository.read((_current$current$proj2 = current.current.project) !== null && _current$current$proj2 !== void 0 ? _current$current$proj2 : "");
|
|
@@ -3921,6 +4419,80 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3921
4419
|
};
|
|
3922
4420
|
});
|
|
3923
4421
|
};
|
|
4422
|
+
const [newBranch, setNewBranch] = useState("");
|
|
4423
|
+
const [switchAfterCreate, setSwitchAfterCreate] = useState(true);
|
|
4424
|
+
const changeBranch = async (operation) => {
|
|
4425
|
+
var _document$defaultView2;
|
|
4426
|
+
const repository = current.current.repository;
|
|
4427
|
+
const project = current.current.project;
|
|
4428
|
+
const switching = operation.kind === "switchBranch" || operation.checkout;
|
|
4429
|
+
if (!repository) return { done: false };
|
|
4430
|
+
const at = operation.kind === "createBranch" ? operation.at : void 0;
|
|
4431
|
+
if (switching && project && !(operation.kind === "createBranch" && !operation.fromRemote && !at) && !await (at ? repository.hasFolder(at, project, "commit") : repository.hasFolder(operation.name, project, operation.kind === "createBranch" && operation.fromRemote)) && !((_document$defaultView2 = document.defaultView) === null || _document$defaultView2 === void 0 ? void 0 : _document$defaultView2.confirm(labels.projectMissing))) return { done: false };
|
|
4432
|
+
const result = await localOperation(operation, switching ? labels.switched : labels.branchCreated);
|
|
4433
|
+
if (operation.kind === "createBranch" && !operation.fromRemote && !at) setNewBranch("");
|
|
4434
|
+
return result;
|
|
4435
|
+
};
|
|
4436
|
+
const [history, setHistory] = useState({
|
|
4437
|
+
commits: [],
|
|
4438
|
+
cursor: null,
|
|
4439
|
+
loading: false,
|
|
4440
|
+
failed: false
|
|
4441
|
+
});
|
|
4442
|
+
const historyTicket = useRef(0);
|
|
4443
|
+
useEffect(() => {
|
|
4444
|
+
const ticket = ++historyTicket.current;
|
|
4445
|
+
const repository = state.repository;
|
|
4446
|
+
if (!repository || !state.snapshot) {
|
|
4447
|
+
setHistory({
|
|
4448
|
+
commits: [],
|
|
4449
|
+
cursor: null,
|
|
4450
|
+
loading: false,
|
|
4451
|
+
failed: false
|
|
4452
|
+
});
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4455
|
+
setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
4456
|
+
cursor: null,
|
|
4457
|
+
loading: true,
|
|
4458
|
+
failed: false
|
|
4459
|
+
}));
|
|
4460
|
+
repository.history().then((page) => {
|
|
4461
|
+
if (historyTicket.current === ticket) setHistory({
|
|
4462
|
+
commits: page.commits,
|
|
4463
|
+
cursor: page.cursor,
|
|
4464
|
+
loading: false,
|
|
4465
|
+
failed: false
|
|
4466
|
+
});
|
|
4467
|
+
}, () => {
|
|
4468
|
+
if (historyTicket.current === ticket) setHistory({
|
|
4469
|
+
commits: [],
|
|
4470
|
+
cursor: null,
|
|
4471
|
+
loading: false,
|
|
4472
|
+
failed: true
|
|
4473
|
+
});
|
|
4474
|
+
});
|
|
4475
|
+
}, [state.repository, state.snapshot]);
|
|
4476
|
+
const showMoreHistory = () => {
|
|
4477
|
+
const repository = state.repository;
|
|
4478
|
+
if (!repository || !history.cursor || history.loading) return;
|
|
4479
|
+
const ticket = historyTicket.current;
|
|
4480
|
+
setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, { loading: true }));
|
|
4481
|
+
repository.history({ after: history.cursor }).then((page) => {
|
|
4482
|
+
if (historyTicket.current === ticket) setHistory((previous) => ({
|
|
4483
|
+
commits: [...previous.commits, ...page.commits],
|
|
4484
|
+
cursor: page.cursor,
|
|
4485
|
+
loading: false,
|
|
4486
|
+
failed: false
|
|
4487
|
+
}));
|
|
4488
|
+
}, () => {
|
|
4489
|
+
if (historyTicket.current === ticket) setHistory((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
4490
|
+
cursor: null,
|
|
4491
|
+
loading: false,
|
|
4492
|
+
failed: true
|
|
4493
|
+
}));
|
|
4494
|
+
});
|
|
4495
|
+
};
|
|
3924
4496
|
const focusTrap = (event) => {
|
|
3925
4497
|
if (event.key === "Escape") {
|
|
3926
4498
|
event.stopPropagation();
|
|
@@ -3928,7 +4500,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3928
4500
|
return;
|
|
3929
4501
|
}
|
|
3930
4502
|
if (event.key !== "Tab") return;
|
|
3931
|
-
const items = [...event.currentTarget.querySelectorAll("button:not(:disabled), input:not(:disabled), select:not(:disabled), a[href], summary, [tabindex=\"0\"]")].filter((item) => item.getClientRects().length > 0);
|
|
4503
|
+
const items = [...event.currentTarget.querySelectorAll("button:not(:disabled):not([tabindex=\"-1\"]), input:not(:disabled), select:not(:disabled), a[href], summary, [tabindex=\"0\"]")].filter((item) => item.getClientRects().length > 0);
|
|
3932
4504
|
const first = items[0], last = items[items.length - 1];
|
|
3933
4505
|
if (event.shiftKey && (document.activeElement === first || document.activeElement === event.currentTarget)) {
|
|
3934
4506
|
event.preventDefault();
|
|
@@ -3949,6 +4521,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3949
4521
|
"unstaged",
|
|
3950
4522
|
"untracked"
|
|
3951
4523
|
];
|
|
4524
|
+
const branching = !!host.localWrite && !!state.snapshot;
|
|
3952
4525
|
const writable = !!host.localWrite && !state.commit && !!((_state$snapshot = state.snapshot) === null || _state$snapshot === void 0 ? void 0 : _state$snapshot.branch);
|
|
3953
4526
|
const unrecorded = [...new Set(state.changes.filter((change) => change.group === "unstaged" || change.group === "untracked").map((change) => change.path))];
|
|
3954
4527
|
const staged = state.changes.some((change) => change.group === "staged");
|
|
@@ -3960,6 +4533,29 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3960
4533
|
return locator && path === projectFile && ((_state$snapshot2 = state.snapshot) === null || _state$snapshot2 === void 0 ? void 0 : _state$snapshot2.head) === headSha && !state.changes.length ? locator : void 0;
|
|
3961
4534
|
};
|
|
3962
4535
|
const selection = projectList && !state.selected ? findElement(projectList.list, element) : null;
|
|
4536
|
+
const openTabs = slot && host.openPanel && host.renderReviewBlock ? (key, files, rememberAs) => openProjectSourceTabs(host.openPanel, {
|
|
4537
|
+
key,
|
|
4538
|
+
files,
|
|
4539
|
+
renderBlock: host.renderReviewBlock,
|
|
4540
|
+
locale,
|
|
4541
|
+
rememberAs
|
|
4542
|
+
}) : void 0;
|
|
4543
|
+
const openFileTabs = (change) => openTabs && ((before, after) => {
|
|
4544
|
+
var _state$commit;
|
|
4545
|
+
let files;
|
|
4546
|
+
try {
|
|
4547
|
+
files = [{
|
|
4548
|
+
path: change.path,
|
|
4549
|
+
before: parseProjectSource(before),
|
|
4550
|
+
after: parseProjectSource(after),
|
|
4551
|
+
loadAsset: loadAsset !== null && loadAsset !== void 0 ? loadAsset : void 0,
|
|
4552
|
+
locateBlock: fileLocator(change)
|
|
4553
|
+
}];
|
|
4554
|
+
} catch (_unused3) {
|
|
4555
|
+
return;
|
|
4556
|
+
}
|
|
4557
|
+
openTabs(`${(_state$commit = state.commit) !== null && _state$commit !== void 0 ? _state$commit : change.group}:${change.path}`, files);
|
|
4558
|
+
});
|
|
3963
4559
|
const content = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("header", null, /* @__PURE__ */ React.createElement("h2", null, labels.title), /* @__PURE__ */ React.createElement("button", {
|
|
3964
4560
|
onClick: chooseRoot,
|
|
3965
4561
|
disabled: state.busy
|
|
@@ -3995,7 +4591,8 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3995
4591
|
repository: state.repository,
|
|
3996
4592
|
locale,
|
|
3997
4593
|
renderBlock: host.renderReviewBlock,
|
|
3998
|
-
locateFor: reviewLocator
|
|
4594
|
+
locateFor: reviewLocator,
|
|
4595
|
+
openTabs
|
|
3999
4596
|
}), !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", {
|
|
4000
4597
|
disabled: state.busy || !state.browser.path,
|
|
4001
4598
|
onClick: () => void browse(state.browser.path.split("/").slice(0, -1).join("/"))
|
|
@@ -4010,7 +4607,10 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4010
4607
|
disabled: state.busy,
|
|
4011
4608
|
onClick: () => void controller.refresh()
|
|
4012
4609
|
}, labels.worktree)), projectChanges === "loading" && /* @__PURE__ */ React.createElement("p", { role: "status" }, projectChangeLabels(locale).loading), projectChanges === "unreadable" && /* @__PURE__ */ React.createElement("p", null, projectChangeLabels(locale).unreadable), (() => {
|
|
4013
|
-
const fileList = groups.map((group) => /* @__PURE__ */ React.createElement("section", { key: group }, /* @__PURE__ */ React.createElement("h3", null, labels[group], " · ", state.changes.filter((change) => change.group === group).length), /* @__PURE__ */ React.createElement("ul", null, state.changes.filter((change) => change.group === group).map((change) => /* @__PURE__ */ React.createElement("li", {
|
|
4610
|
+
const fileList = groups.map((group) => /* @__PURE__ */ React.createElement("section", { key: group }, /* @__PURE__ */ React.createElement("h3", null, labels[group], " · ", state.changes.filter((change) => change.group === group).length), /* @__PURE__ */ React.createElement("ul", null, state.changes.filter((change) => change.group === group).map((change) => /* @__PURE__ */ React.createElement("li", {
|
|
4611
|
+
key: change.path,
|
|
4612
|
+
className: writable ? "twgit-file-row" : void 0
|
|
4613
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
4014
4614
|
className: "twgit-file",
|
|
4015
4615
|
"data-git-group": group,
|
|
4016
4616
|
disabled: state.busy,
|
|
@@ -4063,12 +4663,74 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4063
4663
|
author: (_host$localWrite = host.localWrite) === null || _host$localWrite === void 0 || (_host$localWrite$auth = _host$localWrite.author) === null || _host$localWrite$auth === void 0 ? void 0 : _host$localWrite$auth.call(_host$localWrite)
|
|
4064
4664
|
}, labels.committed);
|
|
4065
4665
|
}
|
|
4066
|
-
}, labels.commitButton)),
|
|
4666
|
+
}, labels.commitButton)), branching && state.snapshot && /* @__PURE__ */ React.createElement("section", {
|
|
4667
|
+
className: "twgit-branches",
|
|
4668
|
+
"aria-label": labels.branches
|
|
4669
|
+
}, /* @__PURE__ */ React.createElement("h3", null, labels.branches), /* @__PURE__ */ React.createElement("ul", null, state.snapshot.branches.map((name) => /* @__PURE__ */ React.createElement("li", { key: name }, /* @__PURE__ */ React.createElement("code", null, name), name === state.snapshot.branch ? /* @__PURE__ */ React.createElement("small", null, " · ", labels.currentBranch) : /* @__PURE__ */ React.createElement("button", {
|
|
4670
|
+
type: "button",
|
|
4671
|
+
disabled: state.busy,
|
|
4672
|
+
"aria-label": `${labels.switchTo}: ${name}`,
|
|
4673
|
+
onClick: () => void changeBranch({
|
|
4674
|
+
kind: "switchBranch",
|
|
4675
|
+
name
|
|
4676
|
+
})
|
|
4677
|
+
}, labels.switchTo)))), state.snapshot.head && /* @__PURE__ */ React.createElement("form", { onSubmit: (event) => {
|
|
4678
|
+
event.preventDefault();
|
|
4679
|
+
if (newBranch.trim()) changeBranch({
|
|
4680
|
+
kind: "createBranch",
|
|
4681
|
+
name: newBranch.trim(),
|
|
4682
|
+
checkout: switchAfterCreate
|
|
4683
|
+
});
|
|
4684
|
+
} }, /* @__PURE__ */ React.createElement("label", null, labels.newBranch, " ", /* @__PURE__ */ React.createElement("input", {
|
|
4685
|
+
value: newBranch,
|
|
4067
4686
|
disabled: state.busy,
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4687
|
+
onChange: (event) => setNewBranch(event.currentTarget.value)
|
|
4688
|
+
})), /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
|
|
4689
|
+
type: "checkbox",
|
|
4690
|
+
checked: switchAfterCreate,
|
|
4691
|
+
disabled: state.busy,
|
|
4692
|
+
onChange: (event) => setSwitchAfterCreate(event.currentTarget.checked)
|
|
4693
|
+
}), " ", labels.switchAfterCreate), /* @__PURE__ */ React.createElement("button", {
|
|
4694
|
+
type: "submit",
|
|
4695
|
+
disabled: state.busy || !newBranch.trim()
|
|
4696
|
+
}, labels.createBranch)), state.snapshot.remoteBranches.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h3", null, labels.remoteBranches), /* @__PURE__ */ React.createElement("ul", null, state.snapshot.remoteBranches.map((name) => /* @__PURE__ */ React.createElement("li", { key: name }, /* @__PURE__ */ React.createElement("code", null, "origin/", name), /* @__PURE__ */ React.createElement("button", {
|
|
4697
|
+
type: "button",
|
|
4698
|
+
disabled: state.busy,
|
|
4699
|
+
"aria-label": `${labels.createFromRemote}: origin/${name}`,
|
|
4700
|
+
onClick: () => void changeBranch({
|
|
4701
|
+
kind: "createBranch",
|
|
4702
|
+
name,
|
|
4703
|
+
fromRemote: true,
|
|
4704
|
+
checkout: true
|
|
4705
|
+
})
|
|
4706
|
+
}, labels.createFromRemote)))))), /* @__PURE__ */ React.createElement("h3", null, labels.history), state.snapshot && /* @__PURE__ */ React.createElement(HistoryGraph, _objectSpread2$1({
|
|
4707
|
+
commits: history.commits,
|
|
4708
|
+
selected: state.commit,
|
|
4709
|
+
locale,
|
|
4710
|
+
busy: state.busy,
|
|
4711
|
+
onSelect: (oid) => void selectCommit(oid),
|
|
4712
|
+
hasMore: !!history.cursor,
|
|
4713
|
+
loadingMore: history.loading,
|
|
4714
|
+
onShowMore: showMoreHistory,
|
|
4715
|
+
localBranches: state.snapshot.branches
|
|
4716
|
+
}, branching ? {
|
|
4717
|
+
onCreateBranch: (oid, name, checkout) => changeBranch({
|
|
4718
|
+
kind: "createBranch",
|
|
4719
|
+
name,
|
|
4720
|
+
at: oid,
|
|
4721
|
+
checkout
|
|
4722
|
+
}),
|
|
4723
|
+
onSwitchBranch: (name) => changeBranch({
|
|
4724
|
+
kind: "switchBranch",
|
|
4725
|
+
name
|
|
4726
|
+
}),
|
|
4727
|
+
onCreateFromRemote: (name) => changeBranch({
|
|
4728
|
+
kind: "createBranch",
|
|
4729
|
+
name,
|
|
4730
|
+
fromRemote: true,
|
|
4731
|
+
checkout: true
|
|
4732
|
+
})
|
|
4733
|
+
} : {})), history.loading && !history.commits.length && /* @__PURE__ */ React.createElement("p", null, labels.historyLoading), history.failed && /* @__PURE__ */ React.createElement("p", null, labels.historyFailed)), /* @__PURE__ */ React.createElement("main", { className: "twgit-diff" }, selection && projectList ? /* @__PURE__ */ React.createElement(ProjectElementView, {
|
|
4072
4734
|
changes: projectList,
|
|
4073
4735
|
selection,
|
|
4074
4736
|
locale,
|
|
@@ -4081,6 +4743,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
4081
4743
|
labels,
|
|
4082
4744
|
locale,
|
|
4083
4745
|
locateBlock: fileLocator(state.selected),
|
|
4746
|
+
onOpenTabs: openFileTabs(state.selected),
|
|
4084
4747
|
renderBlock: host.renderReviewBlock,
|
|
4085
4748
|
loadAsset
|
|
4086
4749
|
}) : /* @__PURE__ */ React.createElement("p", null, labels.select))));
|
|
@@ -4111,8 +4774,8 @@ function upstreamText({ upstream }, labels) {
|
|
|
4111
4774
|
}
|
|
4112
4775
|
}
|
|
4113
4776
|
function mountGitPanel({ vm, document, host }) {
|
|
4114
|
-
var _document$
|
|
4115
|
-
if (!((_document$
|
|
4777
|
+
var _document$defaultView3;
|
|
4778
|
+
if (!((_document$defaultView3 = document.defaultView) === null || _document$defaultView3 === void 0 ? void 0 : _document$defaultView3.showDirectoryPicker)) return null;
|
|
4116
4779
|
const root = document.createElement("div");
|
|
4117
4780
|
document.body.append(root);
|
|
4118
4781
|
const controller = {
|
|
@@ -4148,4 +4811,4 @@ function renderGitMenu(createElement, { vm, locale = "en", MenuItem, MenuSection
|
|
|
4148
4811
|
}
|
|
4149
4812
|
}, labelsFor(locale).menu));
|
|
4150
4813
|
}
|
|
4151
|
-
export { GitPanelError, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, mountGitPanel, openProjectComparison, openRepository, renderGitMenu };
|
|
4814
|
+
export { GitPanelError, HistoryGraph, createEditorBlockLocator, createReadOnlyFs, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, laneColors, layoutHistory, mountGitPanel, openProjectComparison, openProjectSourceTabs, openRepository, renderGitMenu };
|