@akiojin/gwt 2.2.0 → 2.4.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 +6 -4
- package/README.md +6 -4
- package/dist/claude.d.ts +1 -0
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +6 -3
- package/dist/claude.js.map +1 -1
- package/dist/cli/ui/components/App.d.ts +6 -4
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +184 -107
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Confirm.js +7 -7
- package/dist/cli/ui/components/common/Confirm.js.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
- package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
- package/dist/cli/ui/components/common/Input.d.ts +2 -2
- package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Input.js +4 -4
- package/dist/cli/ui/components/common/Input.js.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
- package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
- package/dist/cli/ui/components/common/Select.d.ts +1 -1
- package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Select.js +11 -12
- package/dist/cli/ui/components/common/Select.js.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +3 -3
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +18 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js +201 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -0
- package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
- package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
- package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts +11 -1
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.d.ts +6 -0
- package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -0
- package/dist/cli/ui/utils/modelOptions.js +111 -0
- package/dist/cli/ui/utils/modelOptions.js.map +1 -0
- package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
- package/dist/client/index.html +1 -1
- package/dist/codex.d.ts +6 -0
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +11 -4
- package/dist/codex.js.map +1 -1
- package/dist/config/builtin-tools.d.ts +10 -2
- package/dist/config/builtin-tools.d.ts.map +1 -1
- package/dist/config/builtin-tools.js +40 -4
- package/dist/config/builtin-tools.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +4 -3
- package/dist/config/tools.js.map +1 -1
- package/dist/gemini.d.ts +13 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +157 -0
- package/dist/gemini.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -7
- package/dist/index.js.map +1 -1
- package/dist/qwen.d.ts +13 -0
- package/dist/qwen.d.ts.map +1 -0
- package/dist/qwen.js +157 -0
- package/dist/qwen.js.map +1 -0
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js.map +1 -1
- package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
- package/dist/web/client/src/components/BranchGraph.js +1 -1
- package/dist/web/client/src/components/BranchGraph.js.map +1 -1
- package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
- package/dist/web/client/src/components/EnvEditor.js +7 -4
- package/dist/web/client/src/components/EnvEditor.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.js +10 -4
- package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/package.json +2 -1
- package/src/claude.ts +8 -3
- package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
- package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
- package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
- package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
- package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +81 -0
- package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
- package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
- package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
- package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +63 -43
- package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
- package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
- package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
- package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
- package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
- package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
- package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
- package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
- package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
- package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
- package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
- package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
- package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
- package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
- package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
- package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
- package/src/cli/ui/components/App.tsx +317 -150
- package/src/cli/ui/components/common/Confirm.tsx +13 -9
- package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
- package/src/cli/ui/components/common/Input.tsx +12 -4
- package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
- package/src/cli/ui/components/common/Select.tsx +28 -17
- package/src/cli/ui/components/parts/Header.test.tsx +5 -15
- package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +20 -15
- package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
- package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
- package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
- package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +320 -0
- package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
- package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
- package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
- package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
- package/src/cli/ui/types.ts +21 -1
- package/src/cli/ui/utils/modelOptions.test.ts +36 -0
- package/src/cli/ui/utils/modelOptions.ts +122 -0
- package/src/codex.ts +23 -4
- package/src/config/builtin-tools.ts +42 -4
- package/src/config/index.ts +2 -12
- package/src/config/tools.ts +16 -6
- package/src/gemini.ts +207 -0
- package/src/git.ts +2 -1
- package/src/index.ts +86 -6
- package/src/qwen.ts +213 -0
- package/src/services/git.service.ts +2 -1
- package/src/web/client/src/components/BranchGraph.tsx +3 -2
- package/src/web/client/src/components/EnvEditor.tsx +44 -11
- package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
- package/src/web/client/src/pages/BranchListPage.tsx +37 -13
- package/src/web/client/src/pages/ConfigManagementPage.tsx +28 -9
package/src/qwen.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { createChildStdio, getTerminalStreams } from "./utils/terminal.js";
|
|
5
|
+
|
|
6
|
+
const QWEN_CLI_PACKAGE = "@qwen-code/qwen-code@latest";
|
|
7
|
+
|
|
8
|
+
export class QwenError extends Error {
|
|
9
|
+
constructor(
|
|
10
|
+
message: string,
|
|
11
|
+
public cause?: unknown,
|
|
12
|
+
) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "QwenError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function launchQwenCLI(
|
|
19
|
+
worktreePath: string,
|
|
20
|
+
options: {
|
|
21
|
+
skipPermissions?: boolean;
|
|
22
|
+
mode?: "normal" | "continue" | "resume";
|
|
23
|
+
extraArgs?: string[];
|
|
24
|
+
envOverrides?: Record<string, string>;
|
|
25
|
+
model?: string;
|
|
26
|
+
} = {},
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
const terminal = getTerminalStreams();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Check if the worktree path exists
|
|
32
|
+
if (!existsSync(worktreePath)) {
|
|
33
|
+
throw new Error(`Worktree path does not exist: ${worktreePath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log(chalk.blue("🚀 Launching Qwen CLI..."));
|
|
37
|
+
console.log(chalk.gray(` Working directory: ${worktreePath}`));
|
|
38
|
+
|
|
39
|
+
const args: string[] = ["--checkpointing"];
|
|
40
|
+
|
|
41
|
+
if (options.model) {
|
|
42
|
+
args.push("--model", options.model);
|
|
43
|
+
console.log(chalk.green(` 🎯 Model: ${options.model}`));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Handle execution mode
|
|
47
|
+
// Note: Qwen CLI doesn't have explicit continue/resume CLI options at startup.
|
|
48
|
+
// Session management is done via /chat commands during interactive sessions.
|
|
49
|
+
switch (options.mode) {
|
|
50
|
+
case "continue":
|
|
51
|
+
console.log(
|
|
52
|
+
chalk.cyan(
|
|
53
|
+
" ⏭️ Starting session (use /chat resume in the CLI to continue)",
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
break;
|
|
57
|
+
case "resume":
|
|
58
|
+
console.log(
|
|
59
|
+
chalk.cyan(
|
|
60
|
+
" 🔄 Starting session (use /chat resume in the CLI to continue)",
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
break;
|
|
64
|
+
case "normal":
|
|
65
|
+
default:
|
|
66
|
+
console.log(chalk.green(" ✨ Starting new session"));
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Handle skip permissions (YOLO mode)
|
|
71
|
+
if (options.skipPermissions) {
|
|
72
|
+
args.push("--yolo");
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.yellow(" ⚠️ Auto-approving all actions (YOLO mode)"),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Append any pass-through arguments after our flags
|
|
79
|
+
if (options.extraArgs && options.extraArgs.length > 0) {
|
|
80
|
+
args.push(...options.extraArgs);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
terminal.exitRawMode();
|
|
84
|
+
|
|
85
|
+
const baseEnv = {
|
|
86
|
+
...process.env,
|
|
87
|
+
...(options.envOverrides ?? {}),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const childStdio = createChildStdio();
|
|
91
|
+
|
|
92
|
+
// Auto-detect locally installed qwen command
|
|
93
|
+
const hasLocalQwen = await isQwenCommandAvailable();
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
if (hasLocalQwen) {
|
|
97
|
+
// Use locally installed qwen command
|
|
98
|
+
console.log(chalk.green(" ✨ Using locally installed qwen command"));
|
|
99
|
+
await execa("qwen", args, {
|
|
100
|
+
cwd: worktreePath,
|
|
101
|
+
shell: true,
|
|
102
|
+
stdin: childStdio.stdin,
|
|
103
|
+
stdout: childStdio.stdout,
|
|
104
|
+
stderr: childStdio.stderr,
|
|
105
|
+
env: baseEnv,
|
|
106
|
+
} as any);
|
|
107
|
+
} else {
|
|
108
|
+
// Fallback to bunx
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.cyan(" 🔄 Falling back to bunx @qwen-code/qwen-code@latest"),
|
|
111
|
+
);
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.yellow(
|
|
114
|
+
" 💡 Recommended: Install Qwen CLI globally for faster startup",
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
console.log(chalk.yellow(" npm install -g @qwen-code/qwen-code"));
|
|
118
|
+
console.log("");
|
|
119
|
+
// Wait 2 seconds to let user read the message
|
|
120
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
121
|
+
await execa("bunx", [QWEN_CLI_PACKAGE, ...args], {
|
|
122
|
+
cwd: worktreePath,
|
|
123
|
+
shell: true,
|
|
124
|
+
stdin: childStdio.stdin,
|
|
125
|
+
stdout: childStdio.stdout,
|
|
126
|
+
stderr: childStdio.stderr,
|
|
127
|
+
env: baseEnv,
|
|
128
|
+
} as any);
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
childStdio.cleanup();
|
|
132
|
+
}
|
|
133
|
+
} catch (error: any) {
|
|
134
|
+
const hasLocalQwen = await isQwenCommandAvailable();
|
|
135
|
+
let errorMessage: string;
|
|
136
|
+
|
|
137
|
+
if (error.code === "ENOENT") {
|
|
138
|
+
if (hasLocalQwen) {
|
|
139
|
+
errorMessage =
|
|
140
|
+
"qwen command not found. Please ensure Qwen CLI is properly installed.";
|
|
141
|
+
} else {
|
|
142
|
+
errorMessage =
|
|
143
|
+
"bunx command not found. Please ensure Bun is installed so Qwen CLI can run via bunx.";
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
errorMessage = `Failed to launch Qwen CLI: ${error.message || "Unknown error"}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (process.platform === "win32") {
|
|
150
|
+
console.error(chalk.red("\n💡 Windows troubleshooting tips:"));
|
|
151
|
+
if (hasLocalQwen) {
|
|
152
|
+
console.error(
|
|
153
|
+
chalk.yellow(
|
|
154
|
+
" 1. Confirm that Qwen CLI is installed and the 'qwen' command is on PATH",
|
|
155
|
+
),
|
|
156
|
+
);
|
|
157
|
+
console.error(
|
|
158
|
+
chalk.yellow(' 2. Run "qwen --version" to verify the setup'),
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
console.error(
|
|
162
|
+
chalk.yellow(
|
|
163
|
+
" 1. Confirm that Bun is installed and bunx is available",
|
|
164
|
+
),
|
|
165
|
+
);
|
|
166
|
+
console.error(
|
|
167
|
+
chalk.yellow(
|
|
168
|
+
' 2. Run "bunx @qwen-code/qwen-code@latest -- --version" to verify the setup',
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
console.error(
|
|
173
|
+
chalk.yellow(" 3. Restart your terminal or IDE to refresh PATH"),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw new QwenError(errorMessage, error);
|
|
178
|
+
} finally {
|
|
179
|
+
terminal.exitRawMode();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Check if locally installed `qwen` command is available
|
|
185
|
+
* @returns true if `qwen` command exists in PATH, false otherwise
|
|
186
|
+
*/
|
|
187
|
+
async function isQwenCommandAvailable(): Promise<boolean> {
|
|
188
|
+
try {
|
|
189
|
+
const command = process.platform === "win32" ? "where" : "which";
|
|
190
|
+
await execa(command, ["qwen"], { shell: true });
|
|
191
|
+
return true;
|
|
192
|
+
} catch {
|
|
193
|
+
// qwen command not found in PATH
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function isQwenCLIAvailable(): Promise<boolean> {
|
|
199
|
+
try {
|
|
200
|
+
await execa("bunx", [QWEN_CLI_PACKAGE, "--version"], { shell: true });
|
|
201
|
+
return true;
|
|
202
|
+
} catch (error: any) {
|
|
203
|
+
if (error.code === "ENOENT") {
|
|
204
|
+
console.error(chalk.yellow("\n⚠️ bunx command not found"));
|
|
205
|
+
console.error(
|
|
206
|
+
chalk.gray(
|
|
207
|
+
" Install Bun and confirm that bunx is available before continuing",
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -52,7 +52,8 @@ export class GitService {
|
|
|
52
52
|
|
|
53
53
|
private getBranchType(branchName: string): BranchInfo["branchType"] {
|
|
54
54
|
if (branchName.startsWith("feature/")) return "feature";
|
|
55
|
-
if (branchName.startsWith("bugfix/") || branchName.startsWith("bug/"))
|
|
55
|
+
if (branchName.startsWith("bugfix/") || branchName.startsWith("bug/"))
|
|
56
|
+
return "bugfix";
|
|
56
57
|
if (branchName.startsWith("hotfix/")) return "hotfix";
|
|
57
58
|
if (branchName.startsWith("release/")) return "release";
|
|
58
59
|
if (branchName === "main" || branchName === "master") return "main";
|
|
@@ -61,7 +61,7 @@ export function BranchGraph({ branches }: BranchGraphProps) {
|
|
|
61
61
|
|
|
62
62
|
if (!laneMap.has(base)) {
|
|
63
63
|
const baseNode =
|
|
64
|
-
base !== UNKNOWN_BASE ? branchMap.get(base) ?? null : null;
|
|
64
|
+
base !== UNKNOWN_BASE ? (branchMap.get(base) ?? null) : null;
|
|
65
65
|
laneMap.set(base, {
|
|
66
66
|
id: base,
|
|
67
67
|
baseLabel: base === UNKNOWN_BASE ? "ベース不明" : base,
|
|
@@ -103,7 +103,8 @@ export function BranchGraph({ branches }: BranchGraphProps) {
|
|
|
103
103
|
<p className="branch-graph-panel__eyebrow">BRANCH GRAPH</p>
|
|
104
104
|
<h2>ベースブランチの関係をグラフィカルに把握</h2>
|
|
105
105
|
<p>
|
|
106
|
-
baseRef、Git
|
|
106
|
+
baseRef、Git
|
|
107
|
+
upstream、merge-baseヒューリスティクスを用いて推定したベースブランチ単位で
|
|
107
108
|
派生ノードをレーン表示します。
|
|
108
109
|
</p>
|
|
109
110
|
</div>
|
|
@@ -21,7 +21,9 @@ const KEY_PATTERN = /^[A-Z0-9_]+$/;
|
|
|
21
21
|
|
|
22
22
|
export function createEnvRow(variable?: Partial<EnvRow>): EnvRow {
|
|
23
23
|
const row: EnvRow = {
|
|
24
|
-
id:
|
|
24
|
+
id:
|
|
25
|
+
variable?.id ??
|
|
26
|
+
`env-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
25
27
|
key: variable?.key ?? "",
|
|
26
28
|
value: variable?.value ?? "",
|
|
27
29
|
};
|
|
@@ -49,13 +51,20 @@ export function EnvEditor({
|
|
|
49
51
|
allowAdd = true,
|
|
50
52
|
emptyLabel = "環境変数はまだありません",
|
|
51
53
|
}: EnvEditorProps) {
|
|
52
|
-
const handleFieldChange = (
|
|
54
|
+
const handleFieldChange = (
|
|
55
|
+
id: string,
|
|
56
|
+
field: "key" | "value",
|
|
57
|
+
value: string,
|
|
58
|
+
) => {
|
|
53
59
|
onChange(
|
|
54
60
|
rows.map((row) =>
|
|
55
61
|
row.id === id
|
|
56
62
|
? {
|
|
57
63
|
...row,
|
|
58
|
-
[field]:
|
|
64
|
+
[field]:
|
|
65
|
+
field === "key"
|
|
66
|
+
? value.toUpperCase().replace(/[^A-Z0-9_]/g, "_")
|
|
67
|
+
: value,
|
|
59
68
|
}
|
|
60
69
|
: row,
|
|
61
70
|
),
|
|
@@ -75,10 +84,16 @@ export function EnvEditor({
|
|
|
75
84
|
<header className="env-editor__header">
|
|
76
85
|
<div>
|
|
77
86
|
<h3>{title}</h3>
|
|
78
|
-
{description &&
|
|
87
|
+
{description && (
|
|
88
|
+
<p className="env-editor__description">{description}</p>
|
|
89
|
+
)}
|
|
79
90
|
</div>
|
|
80
91
|
{allowAdd && (
|
|
81
|
-
<button
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
className="button button--secondary"
|
|
95
|
+
onClick={handleAdd}
|
|
96
|
+
>
|
|
82
97
|
変数を追加
|
|
83
98
|
</button>
|
|
84
99
|
)}
|
|
@@ -99,29 +114,47 @@ export function EnvEditor({
|
|
|
99
114
|
{rows.map((row) => {
|
|
100
115
|
const keyInvalid = isInvalidKey(row);
|
|
101
116
|
return (
|
|
102
|
-
<tr
|
|
117
|
+
<tr
|
|
118
|
+
key={row.id}
|
|
119
|
+
className={
|
|
120
|
+
keyInvalid ? "env-editor__row--invalid" : undefined
|
|
121
|
+
}
|
|
122
|
+
>
|
|
103
123
|
<td>
|
|
104
124
|
<input
|
|
105
125
|
type="text"
|
|
106
126
|
value={row.key}
|
|
107
|
-
onChange={(event) =>
|
|
127
|
+
onChange={(event) =>
|
|
128
|
+
handleFieldChange(row.id, "key", event.target.value)
|
|
129
|
+
}
|
|
108
130
|
placeholder="EXAMPLE_KEY"
|
|
109
131
|
/>
|
|
110
132
|
{row.importedFromOs && (
|
|
111
|
-
<span
|
|
133
|
+
<span
|
|
134
|
+
className="pill pill--info"
|
|
135
|
+
style={{ marginLeft: "0.5rem" }}
|
|
136
|
+
>
|
|
112
137
|
OSから取り込み
|
|
113
138
|
</span>
|
|
114
139
|
)}
|
|
115
140
|
{row.lastUpdated && (
|
|
116
|
-
<span className="env-editor__meta"
|
|
141
|
+
<span className="env-editor__meta">
|
|
142
|
+
更新: {new Date(row.lastUpdated).toLocaleString()}
|
|
143
|
+
</span>
|
|
144
|
+
)}
|
|
145
|
+
{keyInvalid && (
|
|
146
|
+
<p className="env-editor__error">
|
|
147
|
+
A-Z,0-9,_ のみ使用できます
|
|
148
|
+
</p>
|
|
117
149
|
)}
|
|
118
|
-
{keyInvalid && <p className="env-editor__error">A-Z,0-9,_ のみ使用できます</p>}
|
|
119
150
|
</td>
|
|
120
151
|
<td>
|
|
121
152
|
<input
|
|
122
153
|
type="text"
|
|
123
154
|
value={row.value}
|
|
124
|
-
onChange={(event) =>
|
|
155
|
+
onChange={(event) =>
|
|
156
|
+
handleFieldChange(row.id, "value", event.target.value)
|
|
157
|
+
}
|
|
125
158
|
placeholder="値"
|
|
126
159
|
/>
|
|
127
160
|
</td>
|