@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.
Files changed (172) hide show
  1. package/README.ja.md +6 -4
  2. package/README.md +6 -4
  3. package/dist/claude.d.ts +1 -0
  4. package/dist/claude.d.ts.map +1 -1
  5. package/dist/claude.js +6 -3
  6. package/dist/claude.js.map +1 -1
  7. package/dist/cli/ui/components/App.d.ts +6 -4
  8. package/dist/cli/ui/components/App.d.ts.map +1 -1
  9. package/dist/cli/ui/components/App.js +184 -107
  10. package/dist/cli/ui/components/App.js.map +1 -1
  11. package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
  12. package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
  13. package/dist/cli/ui/components/common/Confirm.js +7 -7
  14. package/dist/cli/ui/components/common/Confirm.js.map +1 -1
  15. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
  16. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
  17. package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
  18. package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
  19. package/dist/cli/ui/components/common/Input.d.ts +2 -2
  20. package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
  21. package/dist/cli/ui/components/common/Input.js +4 -4
  22. package/dist/cli/ui/components/common/Input.js.map +1 -1
  23. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
  24. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
  25. package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
  26. package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
  27. package/dist/cli/ui/components/common/Select.d.ts +1 -1
  28. package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
  29. package/dist/cli/ui/components/common/Select.js +11 -12
  30. package/dist/cli/ui/components/common/Select.js.map +1 -1
  31. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +3 -3
  32. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
  33. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
  34. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
  35. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
  36. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
  37. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
  38. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
  39. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
  40. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  41. package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
  42. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  43. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
  44. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
  45. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
  46. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
  47. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +18 -0
  48. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -0
  49. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +201 -0
  50. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -0
  51. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
  52. package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
  53. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
  54. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
  55. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
  56. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
  57. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
  58. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
  59. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
  60. package/dist/cli/ui/types.d.ts +11 -1
  61. package/dist/cli/ui/types.d.ts.map +1 -1
  62. package/dist/cli/ui/utils/modelOptions.d.ts +6 -0
  63. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -0
  64. package/dist/cli/ui/utils/modelOptions.js +111 -0
  65. package/dist/cli/ui/utils/modelOptions.js.map +1 -0
  66. package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
  67. package/dist/client/index.html +1 -1
  68. package/dist/codex.d.ts +6 -0
  69. package/dist/codex.d.ts.map +1 -1
  70. package/dist/codex.js +11 -4
  71. package/dist/codex.js.map +1 -1
  72. package/dist/config/builtin-tools.d.ts +10 -2
  73. package/dist/config/builtin-tools.d.ts.map +1 -1
  74. package/dist/config/builtin-tools.js +40 -4
  75. package/dist/config/builtin-tools.js.map +1 -1
  76. package/dist/config/index.d.ts.map +1 -1
  77. package/dist/config/index.js.map +1 -1
  78. package/dist/config/tools.d.ts.map +1 -1
  79. package/dist/config/tools.js +4 -3
  80. package/dist/config/tools.js.map +1 -1
  81. package/dist/gemini.d.ts +13 -0
  82. package/dist/gemini.d.ts.map +1 -0
  83. package/dist/gemini.js +157 -0
  84. package/dist/gemini.js.map +1 -0
  85. package/dist/git.d.ts.map +1 -1
  86. package/dist/git.js.map +1 -1
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +59 -7
  89. package/dist/index.js.map +1 -1
  90. package/dist/qwen.d.ts +13 -0
  91. package/dist/qwen.d.ts.map +1 -0
  92. package/dist/qwen.js +157 -0
  93. package/dist/qwen.js.map +1 -0
  94. package/dist/services/git.service.d.ts.map +1 -1
  95. package/dist/services/git.service.js.map +1 -1
  96. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  97. package/dist/web/client/src/components/BranchGraph.js +1 -1
  98. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  99. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  100. package/dist/web/client/src/components/EnvEditor.js +7 -4
  101. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  102. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  103. package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
  104. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  105. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  106. package/dist/web/client/src/pages/BranchListPage.js +10 -4
  107. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  108. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  109. package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
  110. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  111. package/package.json +2 -1
  112. package/src/claude.ts +8 -3
  113. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
  114. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
  115. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
  116. package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
  117. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +81 -0
  118. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
  119. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
  120. package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
  121. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +63 -43
  122. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
  123. package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
  124. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
  125. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
  126. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
  127. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
  128. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
  129. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
  130. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
  131. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
  132. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
  133. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
  134. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
  135. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
  136. package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
  137. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
  138. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
  139. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
  140. package/src/cli/ui/components/App.tsx +317 -150
  141. package/src/cli/ui/components/common/Confirm.tsx +13 -9
  142. package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
  143. package/src/cli/ui/components/common/Input.tsx +12 -4
  144. package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
  145. package/src/cli/ui/components/common/Select.tsx +28 -17
  146. package/src/cli/ui/components/parts/Header.test.tsx +5 -15
  147. package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +20 -15
  148. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
  149. package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
  150. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
  151. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +320 -0
  152. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
  153. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
  154. package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
  155. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
  156. package/src/cli/ui/types.ts +21 -1
  157. package/src/cli/ui/utils/modelOptions.test.ts +36 -0
  158. package/src/cli/ui/utils/modelOptions.ts +122 -0
  159. package/src/codex.ts +23 -4
  160. package/src/config/builtin-tools.ts +42 -4
  161. package/src/config/index.ts +2 -12
  162. package/src/config/tools.ts +16 -6
  163. package/src/gemini.ts +207 -0
  164. package/src/git.ts +2 -1
  165. package/src/index.ts +86 -6
  166. package/src/qwen.ts +213 -0
  167. package/src/services/git.service.ts +2 -1
  168. package/src/web/client/src/components/BranchGraph.tsx +3 -2
  169. package/src/web/client/src/components/EnvEditor.tsx +44 -11
  170. package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
  171. package/src/web/client/src/pages/BranchListPage.tsx +37 -13
  172. 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/")) return "bugfix";
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 upstream、merge-baseヒューリスティクスを用いて推定したベースブランチ単位で
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: variable?.id ?? `env-${Date.now()}-${Math.random().toString(36).slice(2)}`,
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 = (id: string, field: "key" | "value", value: string) => {
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]: field === "key" ? value.toUpperCase().replace(/[^A-Z0-9_]/g, "_") : value,
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 && <p className="env-editor__description">{description}</p>}
87
+ {description && (
88
+ <p className="env-editor__description">{description}</p>
89
+ )}
79
90
  </div>
80
91
  {allowAdd && (
81
- <button type="button" className="button button--secondary" onClick={handleAdd}>
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 key={row.id} className={keyInvalid ? "env-editor__row--invalid" : undefined}>
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) => handleFieldChange(row.id, "key", event.target.value)}
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 className="pill pill--info" style={{ marginLeft: "0.5rem" }}>
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">更新: {new Date(row.lastUpdated).toLocaleString()}</span>
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) => handleFieldChange(row.id, "value", event.target.value)}
155
+ onChange={(event) =>
156
+ handleFieldChange(row.id, "value", event.target.value)
157
+ }
125
158
  placeholder="値"
126
159
  />
127
160
  </td>