@imenam/mcp-github 1.1.45 → 1.1.48
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.md +2 -2
- package/dist/__tests__/utils/config.test.d.ts +2 -0
- package/dist/__tests__/utils/config.test.d.ts.map +1 -0
- package/dist/__tests__/utils/config.test.js +212 -0
- package/dist/__tests__/utils/config.test.js.map +1 -0
- package/dist/__tests__/utils/git.test.d.ts +2 -0
- package/dist/__tests__/utils/git.test.d.ts.map +1 -0
- package/dist/__tests__/utils/git.test.js +96 -0
- package/dist/__tests__/utils/git.test.js.map +1 -0
- package/dist/config-server.d.ts.map +1 -1
- package/dist/config-server.js +2 -0
- package/dist/config-server.js.map +1 -1
- package/dist/gui-process.d.ts +7 -0
- package/dist/gui-process.d.ts.map +1 -0
- package/dist/gui-process.js +59 -0
- package/dist/gui-process.js.map +1 -0
- package/dist/handlers/deploy.d.ts +28 -0
- package/dist/handlers/deploy.d.ts.map +1 -0
- package/dist/handlers/deploy.js +78 -0
- package/dist/handlers/deploy.js.map +1 -0
- package/dist/handlers/git.d.ts +39 -0
- package/dist/handlers/git.d.ts.map +1 -0
- package/dist/handlers/git.js +248 -0
- package/dist/handlers/git.js.map +1 -0
- package/dist/handlers/github.d.ts +17 -0
- package/dist/handlers/github.d.ts.map +1 -0
- package/dist/handlers/github.js +80 -0
- package/dist/handlers/github.js.map +1 -0
- package/dist/handlers/info.d.ts +15 -0
- package/dist/handlers/info.d.ts.map +1 -0
- package/dist/handlers/info.js +66 -0
- package/dist/handlers/info.js.map +1 -0
- package/dist/index.js +27 -597
- package/dist/index.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +4 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/git.d.ts +5 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +74 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/ssh.js +1 -1
- package/dist/utils/ssh.js.map +1 -1
- package/package.json +7 -3
- package/public/index.html +362 -219
package/public/index.html
CHANGED
|
@@ -6,17 +6,37 @@
|
|
|
6
6
|
<title>GitHub MCP</title>
|
|
7
7
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
8
|
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #0a0a0b;
|
|
11
|
+
--surface: #141416;
|
|
12
|
+
--surface-2: #1b1b1e;
|
|
13
|
+
--border: #2a2a2e;
|
|
14
|
+
--border-strong: #3a3a3f;
|
|
15
|
+
--text: #ededef;
|
|
16
|
+
--text-dim: #9a9aa2;
|
|
17
|
+
--text-muted: #6b6b73;
|
|
18
|
+
--accent: #4d7cfe;
|
|
19
|
+
--accent-hover: #6a92ff;
|
|
20
|
+
--danger: #e0635e;
|
|
21
|
+
--radius: 8px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
* {
|
|
25
|
+
-webkit-font-smoothing: antialiased;
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
body {
|
|
10
|
-
background-color:
|
|
11
|
-
color:
|
|
29
|
+
background-color: var(--bg);
|
|
30
|
+
color: var(--text);
|
|
31
|
+
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
12
32
|
}
|
|
13
33
|
|
|
14
34
|
/* Layout */
|
|
15
35
|
.app-container {
|
|
16
36
|
display: grid;
|
|
17
|
-
grid-template-columns:
|
|
18
|
-
gap:
|
|
19
|
-
max-width:
|
|
37
|
+
grid-template-columns: 300px 1fr;
|
|
38
|
+
gap: 1.5rem;
|
|
39
|
+
max-width: 1080px;
|
|
20
40
|
margin: 0 auto;
|
|
21
41
|
}
|
|
22
42
|
|
|
@@ -26,179 +46,303 @@
|
|
|
26
46
|
}
|
|
27
47
|
}
|
|
28
48
|
|
|
29
|
-
/*
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
/* Surfaces */
|
|
50
|
+
.card {
|
|
51
|
+
background-color: var(--surface);
|
|
52
|
+
border: 1px solid var(--border);
|
|
53
|
+
border-radius: var(--radius);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.section-label {
|
|
57
|
+
font-size: 0.6875rem;
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
letter-spacing: 0.08em;
|
|
60
|
+
text-transform: uppercase;
|
|
61
|
+
color: var(--text-muted);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.divider {
|
|
65
|
+
border-top: 1px solid var(--border);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Text helpers */
|
|
69
|
+
.text-main { color: var(--text); }
|
|
70
|
+
.text-dim { color: var(--text-dim); }
|
|
71
|
+
.text-muted { color: var(--text-muted); }
|
|
72
|
+
|
|
73
|
+
/* Buttons */
|
|
74
|
+
.btn {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
gap: 0.5rem;
|
|
79
|
+
width: 100%;
|
|
80
|
+
padding: 0.55rem 0.9rem;
|
|
81
|
+
font-size: 0.875rem;
|
|
82
|
+
font-weight: 500;
|
|
83
|
+
border-radius: var(--radius);
|
|
84
|
+
border: 1px solid transparent;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
transition: background-color .15s ease, border-color .15s ease, color .15s ease, opacity .15s ease;
|
|
87
|
+
}
|
|
88
|
+
.btn:disabled {
|
|
89
|
+
opacity: 0.4;
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.btn-primary {
|
|
94
|
+
background-color: var(--accent);
|
|
95
|
+
color: #fff;
|
|
96
|
+
}
|
|
97
|
+
.btn-primary:not(:disabled):hover { background-color: var(--accent-hover); }
|
|
98
|
+
|
|
99
|
+
.btn-secondary {
|
|
100
|
+
background-color: transparent;
|
|
101
|
+
border-color: var(--border);
|
|
102
|
+
color: var(--text-dim);
|
|
103
|
+
}
|
|
104
|
+
.btn-secondary:not(:disabled):hover {
|
|
105
|
+
background-color: var(--surface-2);
|
|
106
|
+
border-color: var(--border-strong);
|
|
107
|
+
color: var(--text);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.btn-danger {
|
|
111
|
+
background-color: transparent;
|
|
112
|
+
border-color: var(--border);
|
|
113
|
+
color: var(--danger);
|
|
114
|
+
}
|
|
115
|
+
.btn-danger:not(:disabled):hover {
|
|
116
|
+
background-color: rgba(224, 99, 94, 0.08);
|
|
117
|
+
border-color: var(--danger);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.btn-icon {
|
|
121
|
+
display: inline-flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
width: 2.25rem;
|
|
125
|
+
padding: 0;
|
|
35
126
|
flex-shrink: 0;
|
|
36
127
|
}
|
|
37
128
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
129
|
+
/* Form fields */
|
|
130
|
+
.field-label {
|
|
131
|
+
display: block;
|
|
132
|
+
font-size: 0.75rem;
|
|
133
|
+
font-weight: 500;
|
|
134
|
+
color: var(--text-dim);
|
|
135
|
+
margin-bottom: 0.4rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.field-input,
|
|
139
|
+
.field-select {
|
|
140
|
+
width: 100%;
|
|
141
|
+
padding: 0.5rem 0.75rem;
|
|
142
|
+
font-size: 0.875rem;
|
|
143
|
+
background-color: var(--bg);
|
|
144
|
+
border: 1px solid var(--border);
|
|
145
|
+
border-radius: var(--radius);
|
|
146
|
+
color: var(--text);
|
|
147
|
+
outline: none;
|
|
148
|
+
transition: border-color .15s ease;
|
|
149
|
+
}
|
|
150
|
+
.field-input::placeholder { color: var(--text-muted); }
|
|
151
|
+
.field-input:focus,
|
|
152
|
+
.field-select:focus { border-color: var(--accent); }
|
|
153
|
+
.field-select { cursor: pointer; }
|
|
154
|
+
|
|
155
|
+
/* Toggle rows */
|
|
156
|
+
.toggle-row {
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: space-between;
|
|
160
|
+
gap: 1rem;
|
|
161
|
+
padding: 0.65rem 0;
|
|
162
|
+
}
|
|
163
|
+
.toggle-row + .toggle-row { border-top: 1px solid var(--border); }
|
|
164
|
+
.toggle-row label.text {
|
|
165
|
+
font-size: 0.875rem;
|
|
166
|
+
color: var(--text-dim);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.info-row {
|
|
170
|
+
display: flex;
|
|
171
|
+
align-items: center;
|
|
172
|
+
justify-content: space-between;
|
|
173
|
+
gap: 1rem;
|
|
174
|
+
padding: 0.65rem 0.75rem;
|
|
175
|
+
background-color: var(--bg);
|
|
176
|
+
border: 1px solid var(--border);
|
|
177
|
+
border-radius: var(--radius);
|
|
42
178
|
}
|
|
43
179
|
|
|
180
|
+
/* iPhone style slider (sober) */
|
|
181
|
+
.switch {
|
|
182
|
+
position: relative;
|
|
183
|
+
display: inline-block;
|
|
184
|
+
width: 40px;
|
|
185
|
+
height: 22px;
|
|
186
|
+
flex-shrink: 0;
|
|
187
|
+
}
|
|
188
|
+
.switch input { opacity: 0; width: 0; height: 0; }
|
|
44
189
|
.slider {
|
|
45
190
|
position: absolute;
|
|
46
191
|
cursor: pointer;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
background-color: #334155;
|
|
52
|
-
transition: .4s;
|
|
53
|
-
border-radius: 24px;
|
|
192
|
+
inset: 0;
|
|
193
|
+
background-color: var(--border-strong);
|
|
194
|
+
transition: .25s;
|
|
195
|
+
border-radius: 22px;
|
|
54
196
|
}
|
|
55
|
-
|
|
56
197
|
.slider:before {
|
|
57
198
|
position: absolute;
|
|
58
199
|
content: "";
|
|
59
|
-
height:
|
|
60
|
-
width:
|
|
200
|
+
height: 16px;
|
|
201
|
+
width: 16px;
|
|
61
202
|
left: 3px;
|
|
62
203
|
bottom: 3px;
|
|
63
|
-
background-color:
|
|
64
|
-
transition: .
|
|
204
|
+
background-color: #fff;
|
|
205
|
+
transition: .25s;
|
|
65
206
|
border-radius: 50%;
|
|
66
207
|
}
|
|
208
|
+
input:checked + .slider { background-color: var(--accent); }
|
|
209
|
+
input:checked + .slider:before { transform: translateX(18px); }
|
|
67
210
|
|
|
68
|
-
|
|
69
|
-
background-color: #2563eb;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
input:checked + .slider:before {
|
|
73
|
-
transform: translateX(20px);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* Custom dropdown styles */
|
|
211
|
+
/* Custom dropdown */
|
|
77
212
|
.search-results {
|
|
78
213
|
position: absolute;
|
|
79
214
|
top: 100%;
|
|
80
215
|
left: 0;
|
|
81
216
|
right: 0;
|
|
82
217
|
z-index: 50;
|
|
83
|
-
background-color:
|
|
84
|
-
border: 1px solid
|
|
85
|
-
border-radius:
|
|
218
|
+
background-color: var(--surface-2);
|
|
219
|
+
border: 1px solid var(--border);
|
|
220
|
+
border-radius: var(--radius);
|
|
86
221
|
margin-top: 0.25rem;
|
|
87
222
|
max-height: 15rem;
|
|
88
223
|
overflow-y: auto;
|
|
89
|
-
box-shadow: 0
|
|
224
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
90
225
|
}
|
|
91
|
-
|
|
92
226
|
.search-result-item {
|
|
93
|
-
padding: 0.5rem
|
|
227
|
+
padding: 0.5rem 0.75rem;
|
|
94
228
|
cursor: pointer;
|
|
95
|
-
transition: background-color
|
|
229
|
+
transition: background-color .12s;
|
|
96
230
|
font-size: 0.875rem;
|
|
231
|
+
color: var(--text-dim);
|
|
97
232
|
}
|
|
98
|
-
|
|
99
233
|
.search-result-item:hover {
|
|
100
|
-
background-color:
|
|
101
|
-
color:
|
|
234
|
+
background-color: var(--surface);
|
|
235
|
+
color: var(--text);
|
|
102
236
|
}
|
|
103
|
-
|
|
104
237
|
.search-result-item.active {
|
|
105
|
-
background-color:
|
|
106
|
-
color:
|
|
107
|
-
outline: 1px solid #3b82f6;
|
|
238
|
+
background-color: var(--surface);
|
|
239
|
+
color: var(--text);
|
|
108
240
|
}
|
|
109
|
-
|
|
110
241
|
.search-result-item.selected {
|
|
111
|
-
background-color:
|
|
112
|
-
color:
|
|
242
|
+
background-color: rgba(77, 124, 254, 0.12);
|
|
243
|
+
color: var(--accent-hover);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Badge */
|
|
247
|
+
.badge {
|
|
248
|
+
display: inline-flex;
|
|
249
|
+
align-items: center;
|
|
250
|
+
padding: 0.15rem 0.6rem;
|
|
251
|
+
font-size: 0.75rem;
|
|
252
|
+
font-weight: 500;
|
|
253
|
+
color: var(--text-dim);
|
|
254
|
+
background-color: var(--surface-2);
|
|
255
|
+
border: 1px solid var(--border);
|
|
256
|
+
border-radius: 999px;
|
|
113
257
|
}
|
|
114
258
|
|
|
259
|
+
/* Spinner */
|
|
260
|
+
.spinner {
|
|
261
|
+
display: inline-block;
|
|
262
|
+
width: 1rem;
|
|
263
|
+
height: 1rem;
|
|
264
|
+
border: 2px solid var(--border-strong);
|
|
265
|
+
border-top-color: var(--accent);
|
|
266
|
+
border-radius: 50%;
|
|
267
|
+
animation: spin 0.7s linear infinite;
|
|
268
|
+
}
|
|
269
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
270
|
+
|
|
115
271
|
/* Toasts */
|
|
116
272
|
.toast {
|
|
117
|
-
|
|
118
|
-
|
|
273
|
+
display: flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
gap: 0.6rem;
|
|
276
|
+
padding: 0.7rem 0.9rem;
|
|
277
|
+
font-size: 0.875rem;
|
|
278
|
+
background-color: var(--surface-2);
|
|
279
|
+
border: 1px solid var(--border);
|
|
280
|
+
border-left-width: 3px;
|
|
281
|
+
border-radius: var(--radius);
|
|
282
|
+
color: var(--text);
|
|
283
|
+
max-width: 22rem;
|
|
284
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
285
|
+
animation: slideIn 0.25s ease-out forwards, fadeOut 0.3s ease-in forwards 4.7s;
|
|
119
286
|
}
|
|
287
|
+
.toast-success { border-left-color: var(--accent); }
|
|
288
|
+
.toast-error { border-left-color: var(--danger); }
|
|
120
289
|
|
|
121
290
|
@keyframes slideIn {
|
|
122
|
-
from { transform: translateX(
|
|
291
|
+
from { transform: translateX(110%); opacity: 0; }
|
|
123
292
|
to { transform: translateX(0); opacity: 1; }
|
|
124
293
|
}
|
|
125
|
-
|
|
126
294
|
@keyframes fadeOut {
|
|
127
295
|
from { opacity: 1; }
|
|
128
296
|
to { opacity: 0; }
|
|
129
297
|
}
|
|
130
298
|
</style>
|
|
131
299
|
</head>
|
|
132
|
-
<body class="min-h-screen p-
|
|
300
|
+
<body class="min-h-screen p-6 md:p-10">
|
|
133
301
|
<div class="app-container">
|
|
134
302
|
<!-- Sidebar -->
|
|
135
|
-
<aside
|
|
136
|
-
<div class="
|
|
137
|
-
<h2 class="
|
|
138
|
-
<svg class="w-6 h-6 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
139
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
|
140
|
-
</svg>
|
|
141
|
-
Configuration
|
|
142
|
-
</h2>
|
|
303
|
+
<aside>
|
|
304
|
+
<div class="card p-5 sticky top-10">
|
|
305
|
+
<h2 class="section-label mb-4">Configuration</h2>
|
|
143
306
|
|
|
144
307
|
<!-- Configuration Selector -->
|
|
145
|
-
<div class="
|
|
146
|
-
<
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
<
|
|
152
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
|
|
153
|
-
</svg>
|
|
154
|
-
</button>
|
|
155
|
-
<button type="button" id="deleteConfigBtn" class="px-3 py-2 bg-red-600 hover:bg-red-700 disabled:bg-slate-700 disabled:cursor-not-allowed rounded-lg transition duration-200" title="Supprimer la configuration" disabled>
|
|
156
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
157
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
158
|
-
</svg>
|
|
159
|
-
</button>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
|
|
163
|
-
<div class="border-t border-slate-700 pt-4 mb-4">
|
|
164
|
-
<h3 class="text-sm font-medium text-slate-400 mb-3">Actions</h3>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="space-y-4">
|
|
168
|
-
<button type="button" onclick="document.getElementById('configForm').requestSubmit()" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200 shadow-lg flex justify-center items-center">
|
|
169
|
-
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
170
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
308
|
+
<div class="flex gap-2 mb-5">
|
|
309
|
+
<select id="configSelector" class="field-select flex-1">
|
|
310
|
+
<option value="">— Sélectionner —</option>
|
|
311
|
+
</select>
|
|
312
|
+
<button type="button" id="newConfigBtn" class="btn btn-secondary btn-icon" title="Nouvelle configuration">
|
|
313
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
314
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
|
|
171
315
|
</svg>
|
|
172
|
-
<span>Sauvegarder</span>
|
|
173
316
|
</button>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"></path>
|
|
317
|
+
<button type="button" id="deleteConfigBtn" class="btn btn-danger btn-icon" title="Supprimer la configuration" disabled>
|
|
318
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
319
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
178
320
|
</svg>
|
|
179
|
-
<span>Cloner le dépôt</span>
|
|
180
321
|
</button>
|
|
322
|
+
</div>
|
|
181
323
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
|
185
|
-
</svg>
|
|
186
|
-
<span>Redémarrer</span>
|
|
187
|
-
</button>
|
|
324
|
+
<div class="divider pt-4">
|
|
325
|
+
<h3 class="section-label mb-3">Actions</h3>
|
|
188
326
|
|
|
189
|
-
<
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
</
|
|
193
|
-
|
|
194
|
-
|
|
327
|
+
<div class="space-y-2.5">
|
|
328
|
+
<button type="button" onclick="document.getElementById('configForm').requestSubmit()" class="btn btn-primary">
|
|
329
|
+
Sauvegarder
|
|
330
|
+
</button>
|
|
331
|
+
|
|
332
|
+
<button type="button" id="cloneBtn" class="btn btn-secondary">
|
|
333
|
+
Cloner le dépôt
|
|
334
|
+
</button>
|
|
335
|
+
|
|
336
|
+
<button type="button" id="restartBtn" class="btn btn-secondary">
|
|
337
|
+
Redémarrer
|
|
338
|
+
</button>
|
|
339
|
+
|
|
340
|
+
<button type="button" id="deleteWorkingDirBtn" class="btn btn-danger">
|
|
341
|
+
Nettoyer le repo
|
|
342
|
+
</button>
|
|
195
343
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
199
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
200
|
-
</svg>
|
|
201
|
-
<span>Arrêter</span>
|
|
344
|
+
<button type="button" id="stopBtn" class="btn btn-danger">
|
|
345
|
+
Arrêter le serveur
|
|
202
346
|
</button>
|
|
203
347
|
</div>
|
|
204
348
|
</div>
|
|
@@ -206,44 +350,44 @@
|
|
|
206
350
|
</aside>
|
|
207
351
|
|
|
208
352
|
<!-- Main Content -->
|
|
209
|
-
<main class="
|
|
210
|
-
<div class="flex items-center gap-
|
|
211
|
-
<h1 class="text-
|
|
212
|
-
<svg class="w-
|
|
213
|
-
<path
|
|
353
|
+
<main class="card p-7">
|
|
354
|
+
<div class="flex items-center gap-3 mb-7">
|
|
355
|
+
<h1 class="text-xl font-semibold text-main flex items-center gap-2.5">
|
|
356
|
+
<svg class="w-5 h-5 text-dim" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
357
|
+
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"></path>
|
|
214
358
|
</svg>
|
|
215
359
|
GitHub MCP
|
|
216
360
|
</h1>
|
|
217
|
-
<span id="agentNameBadge" class="hidden
|
|
361
|
+
<span id="agentNameBadge" class="badge hidden"></span>
|
|
218
362
|
</div>
|
|
219
|
-
|
|
220
|
-
<form id="configForm" class="space-y-
|
|
363
|
+
|
|
364
|
+
<form id="configForm" class="space-y-5">
|
|
221
365
|
<div class="space-y-4" id="inputs">
|
|
222
366
|
<!-- Inputs will be injected here -->
|
|
223
367
|
<div class="flex justify-center p-8">
|
|
224
|
-
<div class="
|
|
368
|
+
<div class="spinner"></div>
|
|
225
369
|
</div>
|
|
226
370
|
</div>
|
|
227
371
|
</form>
|
|
228
372
|
|
|
229
|
-
<div class="mt-8
|
|
230
|
-
|
|
373
|
+
<div class="mt-8 divider pt-4 text-xs text-muted">
|
|
374
|
+
Le serveur MCP doit être redémarré pour appliquer les changements.
|
|
231
375
|
</div>
|
|
232
376
|
</main>
|
|
233
377
|
</div>
|
|
234
378
|
|
|
235
379
|
<!-- Toast Container -->
|
|
236
|
-
<div id="toast-container" class="fixed bottom-
|
|
380
|
+
<div id="toast-container" class="fixed bottom-6 right-6 z-50 flex flex-col gap-2.5"></div>
|
|
237
381
|
|
|
238
382
|
<script>
|
|
239
383
|
// Détection automatique du base path pour fonctionner via proxy
|
|
240
384
|
const pathname = window.location.pathname;
|
|
241
|
-
const BASE_PATH = pathname.includes('.')
|
|
385
|
+
const BASE_PATH = pathname.includes('.')
|
|
242
386
|
? pathname.replace(/\/[^/]*$/, '') // /github-mcp/index.html -> /github-mcp
|
|
243
|
-
: pathname.endsWith('/')
|
|
387
|
+
: pathname.endsWith('/')
|
|
244
388
|
? pathname.slice(0, -1) // /github-mcp/ -> /github-mcp
|
|
245
389
|
: pathname === '/' ? '' : pathname; // /github-mcp -> /github-mcp, / -> ''
|
|
246
|
-
|
|
390
|
+
|
|
247
391
|
// Helper pour construire les URLs d'API
|
|
248
392
|
const api = (endpoint) => `${BASE_PATH}/${endpoint}`.replace(/\/+/g, '/');
|
|
249
393
|
|
|
@@ -258,6 +402,8 @@
|
|
|
258
402
|
{ id: 'TARGET_REPO', label: 'Target Repository', type: 'select', placeholder: 'owner/repo' },
|
|
259
403
|
{ id: 'BASE_BRANCH', label: 'Base Branch', type: 'select', placeholder: 'main' },
|
|
260
404
|
{ id: 'TARGET_BRANCH', label: 'Target Branch', type: 'select', placeholder: 'feature-branch' },
|
|
405
|
+
{ id: 'SSH_REMOTE_PATH', label: 'Chemin distant (SSH_REMOTE_PATH)', type: 'text', placeholder: '/home/user/mon-projet' },
|
|
406
|
+
{ id: 'TEST_COMMAND', label: 'Commande de test (TEST_COMMAND)', type: 'text', placeholder: 'npm test' },
|
|
261
407
|
{ id: 'READ_ONLY', label: 'Mode Lecture Seule', type: 'slider' },
|
|
262
408
|
{ id: 'INCLUDE_PUBLIC', label: 'Inclure les dépôts publics', type: 'slider' },
|
|
263
409
|
{ id: 'INCLUDE_NOT_OWNED', label: 'Inclure les dépôts dont je ne suis pas propriétaire', type: 'slider' }
|
|
@@ -297,11 +443,11 @@
|
|
|
297
443
|
}
|
|
298
444
|
|
|
299
445
|
function renderConfigSelector() {
|
|
300
|
-
configSelector.innerHTML = '<option value=""
|
|
301
|
-
configNames.map(name =>
|
|
446
|
+
configSelector.innerHTML = '<option value="">— Sélectionner —</option>' +
|
|
447
|
+
configNames.map(name =>
|
|
302
448
|
`<option value="${name}" ${name === currentConfigName ? 'selected' : ''}>${name}</option>`
|
|
303
449
|
).join('');
|
|
304
|
-
|
|
450
|
+
|
|
305
451
|
deleteConfigBtn.disabled = !currentConfigName || configNames.length <= 1;
|
|
306
452
|
}
|
|
307
453
|
|
|
@@ -407,7 +553,7 @@
|
|
|
407
553
|
async function fetchRepositories(searchTerm = '') {
|
|
408
554
|
const loadingIndicator = document.getElementById('REPO_LOADING_INDICATOR');
|
|
409
555
|
if (loadingIndicator) loadingIndicator.classList.remove('hidden');
|
|
410
|
-
|
|
556
|
+
|
|
411
557
|
try {
|
|
412
558
|
const url = api(`api/repositories${searchTerm ? `?search=${encodeURIComponent(searchTerm)}` : ''}`);
|
|
413
559
|
const response = await fetch(url);
|
|
@@ -432,13 +578,13 @@
|
|
|
432
578
|
resultsContainer.innerHTML = selectState.repos.map((repo, index) => `
|
|
433
579
|
<div class="search-result-item ${repo === currentRepo ? 'selected' : ''}" data-index="${index}" onclick="selectRepo('${repo}')">
|
|
434
580
|
${repo}
|
|
435
|
-
${repo === currentRepo ? '<span class="float-right
|
|
581
|
+
${repo === currentRepo ? '<span class="float-right">✓</span>' : ''}
|
|
436
582
|
</div>
|
|
437
583
|
`).join('');
|
|
438
584
|
resultsContainer.classList.remove('hidden');
|
|
439
585
|
activeIndex = -1;
|
|
440
586
|
} else {
|
|
441
|
-
resultsContainer.innerHTML = '<div class="
|
|
587
|
+
resultsContainer.innerHTML = '<div class="search-result-item">Aucun résultat</div>';
|
|
442
588
|
resultsContainer.classList.remove('hidden');
|
|
443
589
|
}
|
|
444
590
|
}
|
|
@@ -448,18 +594,18 @@
|
|
|
448
594
|
const searchInput = document.getElementById('REPO_SEARCH');
|
|
449
595
|
const hiddenInput = document.getElementById('TARGET_REPO');
|
|
450
596
|
const resultsContainer = document.getElementById('REPO_RESULTS');
|
|
451
|
-
|
|
597
|
+
|
|
452
598
|
if (searchInput) searchInput.value = repo;
|
|
453
599
|
if (hiddenInput) {
|
|
454
600
|
hiddenInput.value = repo;
|
|
455
601
|
currentConfig.TARGET_REPO = repo;
|
|
456
602
|
}
|
|
457
603
|
if (resultsContainer) resultsContainer.classList.add('hidden');
|
|
458
|
-
|
|
604
|
+
|
|
459
605
|
// Réinitialiser les branches lors du changement de repository
|
|
460
606
|
currentConfig.BASE_BRANCH = '';
|
|
461
607
|
currentConfig.TARGET_BRANCH = '';
|
|
462
|
-
|
|
608
|
+
|
|
463
609
|
// Charger les branches pour ce repo (renderInputs is called inside fetchBranches)
|
|
464
610
|
await fetchBranches(repo);
|
|
465
611
|
};
|
|
@@ -467,11 +613,11 @@
|
|
|
467
613
|
// Fetch branches for a repository
|
|
468
614
|
async function fetchBranches(repo, preserveConfig = false) {
|
|
469
615
|
if (!repo) return [];
|
|
470
|
-
|
|
616
|
+
|
|
471
617
|
selectState.loadingBranches[repo] = true;
|
|
472
618
|
// Use renderInputs directly to avoid overwriting currentConfig from DOM
|
|
473
619
|
renderInputs(currentConfig);
|
|
474
|
-
|
|
620
|
+
|
|
475
621
|
try {
|
|
476
622
|
const url = api(`api/branches?repo=${encodeURIComponent(repo)}`);
|
|
477
623
|
const response = await fetch(url);
|
|
@@ -490,42 +636,42 @@
|
|
|
490
636
|
|
|
491
637
|
// Render select field
|
|
492
638
|
function renderSelectField(field, value, config) {
|
|
493
|
-
let options = '<option value=""
|
|
494
|
-
|
|
639
|
+
let options = '<option value="">— Sélectionner une option —</option>';
|
|
640
|
+
|
|
495
641
|
if (field.id === 'TARGET_REPO') {
|
|
496
642
|
if (selectState.loadingRepos && selectState.repos.length === 0) {
|
|
497
643
|
return `
|
|
498
|
-
<div
|
|
499
|
-
<label for="${field.id}" class="
|
|
500
|
-
<div id="${field.id}_loading" class="
|
|
501
|
-
<div class="
|
|
644
|
+
<div>
|
|
645
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
646
|
+
<div id="${field.id}_loading" class="field-input flex items-center gap-2 text-dim">
|
|
647
|
+
<div class="spinner"></div>
|
|
502
648
|
Chargement des dépôts...
|
|
503
649
|
</div>
|
|
504
650
|
</div>
|
|
505
651
|
`;
|
|
506
652
|
}
|
|
507
|
-
|
|
508
|
-
options += selectState.repos.map(repo =>
|
|
653
|
+
|
|
654
|
+
options += selectState.repos.map(repo =>
|
|
509
655
|
`<option value="${repo}" ${value === repo ? 'selected' : ''}>${repo}</option>`
|
|
510
656
|
).join('');
|
|
511
|
-
|
|
657
|
+
|
|
512
658
|
if (value && !selectState.repos.includes(value)) {
|
|
513
659
|
options += `<option value="${value}" selected>${value}</option>`;
|
|
514
660
|
}
|
|
515
661
|
|
|
516
662
|
return `
|
|
517
|
-
<div
|
|
518
|
-
<label for="${field.id}" class="
|
|
663
|
+
<div>
|
|
664
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
519
665
|
<div class="relative">
|
|
520
666
|
<div class="relative">
|
|
521
667
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
522
|
-
<svg class="h-4 w-4 text-
|
|
668
|
+
<svg class="h-4 w-4 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
523
669
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
524
670
|
</svg>
|
|
525
671
|
</div>
|
|
526
|
-
<input type="text" id="REPO_SEARCH" placeholder="Rechercher un dépôt..." class="
|
|
672
|
+
<input type="text" id="REPO_SEARCH" placeholder="Rechercher un dépôt..." class="field-input" style="padding-left:2.25rem" autocomplete="off" value="${value || ''}">
|
|
527
673
|
<div id="REPO_LOADING_INDICATOR" class="absolute inset-y-0 right-0 pr-3 flex items-center hidden">
|
|
528
|
-
<div class="
|
|
674
|
+
<div class="spinner"></div>
|
|
529
675
|
</div>
|
|
530
676
|
</div>
|
|
531
677
|
<div id="REPO_RESULTS" class="search-results hidden"></div>
|
|
@@ -536,29 +682,29 @@
|
|
|
536
682
|
} else if (field.id === 'BASE_BRANCH') {
|
|
537
683
|
const currentRepo = config.TARGET_REPO;
|
|
538
684
|
const branches = selectState.branches[currentRepo] || [];
|
|
539
|
-
|
|
685
|
+
|
|
540
686
|
if (selectState.loadingBranches[currentRepo]) {
|
|
541
687
|
return `
|
|
542
|
-
<div
|
|
543
|
-
<label for="${field.id}" class="
|
|
544
|
-
<div id="${field.id}_loading" class="
|
|
545
|
-
<div class="
|
|
688
|
+
<div>
|
|
689
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
690
|
+
<div id="${field.id}_loading" class="field-input flex items-center gap-2 text-dim">
|
|
691
|
+
<div class="spinner"></div>
|
|
546
692
|
Chargement des branches...
|
|
547
693
|
</div>
|
|
548
694
|
</div>
|
|
549
695
|
`;
|
|
550
696
|
}
|
|
551
|
-
|
|
697
|
+
|
|
552
698
|
// Recréer les options avec l'option par défaut sélectionnée si value est vide
|
|
553
|
-
let branchOptions = `<option value="" ${!value ? 'selected' : ''}
|
|
699
|
+
let branchOptions = `<option value="" ${!value ? 'selected' : ''}>— Choisir une branche —</option>`;
|
|
554
700
|
branchOptions += branches.map(branch =>
|
|
555
701
|
`<option value="${branch}" ${value === branch ? 'selected' : ''}>${branch}</option>`
|
|
556
702
|
).join('');
|
|
557
|
-
|
|
703
|
+
|
|
558
704
|
return `
|
|
559
|
-
<div
|
|
560
|
-
<label for="${field.id}" class="
|
|
561
|
-
<select id="${field.id}" class="
|
|
705
|
+
<div>
|
|
706
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
707
|
+
<select id="${field.id}" class="field-select">
|
|
562
708
|
${branchOptions}
|
|
563
709
|
</select>
|
|
564
710
|
</div>
|
|
@@ -566,44 +712,44 @@
|
|
|
566
712
|
} else if (field.id === 'TARGET_BRANCH') {
|
|
567
713
|
const currentRepo = config.TARGET_REPO;
|
|
568
714
|
const branches = selectState.branches[currentRepo] || [];
|
|
569
|
-
|
|
715
|
+
|
|
570
716
|
if (selectState.loadingBranches[currentRepo]) {
|
|
571
717
|
return `
|
|
572
|
-
<div
|
|
573
|
-
<label for="${field.id}" class="
|
|
574
|
-
<div id="${field.id}_loading" class="
|
|
575
|
-
<div class="
|
|
718
|
+
<div>
|
|
719
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
720
|
+
<div id="${field.id}_loading" class="field-input flex items-center gap-2 text-dim">
|
|
721
|
+
<div class="spinner"></div>
|
|
576
722
|
Chargement des branches...
|
|
577
723
|
</div>
|
|
578
724
|
</div>
|
|
579
725
|
`;
|
|
580
726
|
}
|
|
581
|
-
|
|
582
|
-
let selectOptions = '<option value=""
|
|
727
|
+
|
|
728
|
+
let selectOptions = '<option value="">— Créer une nouvelle branche —</option>';
|
|
583
729
|
selectOptions += branches.map(branch =>
|
|
584
730
|
`<option value="${branch}" ${value === branch ? 'selected' : ''}>${branch}</option>`
|
|
585
731
|
).join('');
|
|
586
|
-
|
|
732
|
+
|
|
587
733
|
const isCustom = value && !branches.includes(value);
|
|
588
734
|
const shouldShowCustom = isCustom || value === '';
|
|
589
|
-
|
|
735
|
+
|
|
590
736
|
return `
|
|
591
|
-
<div
|
|
592
|
-
<label for="${field.id}" class="
|
|
737
|
+
<div>
|
|
738
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
593
739
|
<div class="space-y-2">
|
|
594
|
-
<select id="${field.id}" class="
|
|
740
|
+
<select id="${field.id}" class="field-select">
|
|
595
741
|
${selectOptions}
|
|
596
742
|
</select>
|
|
597
|
-
<input type="text" id="${field.id}_custom" placeholder="Entrez le nom de la nouvelle branche" value="${isCustom ? value : ''}" class="
|
|
743
|
+
<input type="text" id="${field.id}_custom" placeholder="Entrez le nom de la nouvelle branche" value="${isCustom ? value : ''}" class="field-input ${shouldShowCustom ? '' : 'hidden'}">
|
|
598
744
|
</div>
|
|
599
745
|
</div>
|
|
600
746
|
`;
|
|
601
747
|
}
|
|
602
|
-
|
|
748
|
+
|
|
603
749
|
return `
|
|
604
|
-
<div
|
|
605
|
-
<label for="${field.id}" class="
|
|
606
|
-
<select id="${field.id}" class="
|
|
750
|
+
<div>
|
|
751
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
752
|
+
<select id="${field.id}" class="field-select">
|
|
607
753
|
${options}
|
|
608
754
|
</select>
|
|
609
755
|
</div>
|
|
@@ -622,7 +768,7 @@
|
|
|
622
768
|
throw new Error(data.error || 'Erreur lors du chargement');
|
|
623
769
|
}
|
|
624
770
|
currentConfig = await response.json();
|
|
625
|
-
|
|
771
|
+
|
|
626
772
|
// Afficher le nom de l'agent si défini
|
|
627
773
|
const agentBadge = document.getElementById('agentNameBadge');
|
|
628
774
|
if (currentConfig.AGENT_NAME) {
|
|
@@ -631,13 +777,13 @@
|
|
|
631
777
|
} else {
|
|
632
778
|
agentBadge.classList.add('hidden');
|
|
633
779
|
}
|
|
634
|
-
|
|
780
|
+
|
|
635
781
|
// Le token est désormais côté serveur, on tente de charger les repos directement
|
|
636
782
|
await fetchRepositories();
|
|
637
783
|
if (currentConfig.TARGET_REPO) {
|
|
638
784
|
await fetchBranches(currentConfig.TARGET_REPO);
|
|
639
785
|
}
|
|
640
|
-
|
|
786
|
+
|
|
641
787
|
renderInputs(currentConfig);
|
|
642
788
|
} catch (error) {
|
|
643
789
|
showStatus(error.message || 'Erreur lors du chargement de la configuration', 'error');
|
|
@@ -648,17 +794,17 @@
|
|
|
648
794
|
function renderInputs(config) {
|
|
649
795
|
// CLONE_DIR en lecture seule (variable d'environnement)
|
|
650
796
|
const cloneDirInfo = config.CLONE_DIR
|
|
651
|
-
? `<div class="
|
|
652
|
-
<span class="text-
|
|
653
|
-
<span class="text-
|
|
797
|
+
? `<div class="info-row">
|
|
798
|
+
<span class="text-xs font-medium text-dim">Répertoire de clonage</span>
|
|
799
|
+
<span class="text-xs text-main font-mono">${config.CLONE_DIR}</span>
|
|
654
800
|
</div>`
|
|
655
801
|
: '';
|
|
656
802
|
|
|
657
803
|
inputsContainer.innerHTML = fields.map(field => {
|
|
658
804
|
if (field.type === 'slider') {
|
|
659
805
|
return `
|
|
660
|
-
<div class="
|
|
661
|
-
<label for="${field.id}" class="text
|
|
806
|
+
<div class="toggle-row">
|
|
807
|
+
<label for="${field.id}" class="text">${field.label}</label>
|
|
662
808
|
<label class="switch">
|
|
663
809
|
<input type="checkbox" id="${field.id}" ${config[field.id] === 'true' || config[field.id] === true ? 'checked' : ''}>
|
|
664
810
|
<span class="slider"></span>
|
|
@@ -668,9 +814,9 @@
|
|
|
668
814
|
}
|
|
669
815
|
if (field.type === 'checkbox') {
|
|
670
816
|
return `
|
|
671
|
-
<div class="
|
|
672
|
-
<
|
|
673
|
-
<
|
|
817
|
+
<div class="toggle-row">
|
|
818
|
+
<label for="${field.id}" class="text">${field.label}</label>
|
|
819
|
+
<input type="checkbox" id="${field.id}" ${config[field.id] === 'true' || config[field.id] === true ? 'checked' : ''} class="w-4 h-4">
|
|
674
820
|
</div>
|
|
675
821
|
`;
|
|
676
822
|
}
|
|
@@ -678,13 +824,13 @@
|
|
|
678
824
|
return renderSelectField(field, config[field.id] || '', config);
|
|
679
825
|
}
|
|
680
826
|
return `
|
|
681
|
-
<div
|
|
682
|
-
<label for="${field.id}" class="
|
|
683
|
-
<input type="${field.type}" id="${field.id}" value="${config[field.id] || ''}" placeholder="${field.placeholder}" class="
|
|
827
|
+
<div>
|
|
828
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
829
|
+
<input type="${field.type}" id="${field.id}" value="${config[field.id] || ''}" placeholder="${field.placeholder}" class="field-input">
|
|
684
830
|
</div>
|
|
685
831
|
`;
|
|
686
832
|
}).join('') + cloneDirInfo;
|
|
687
|
-
|
|
833
|
+
|
|
688
834
|
if (deleteWorkingDirBtn) {
|
|
689
835
|
deleteWorkingDirBtn.disabled = !config.REPO_PATH;
|
|
690
836
|
}
|
|
@@ -692,7 +838,7 @@
|
|
|
692
838
|
if (cloneBtn) {
|
|
693
839
|
cloneBtn.disabled = !config.TARGET_REPO || !config.TARGET_BRANCH;
|
|
694
840
|
}
|
|
695
|
-
|
|
841
|
+
|
|
696
842
|
setupEventListeners();
|
|
697
843
|
}
|
|
698
844
|
|
|
@@ -720,7 +866,7 @@
|
|
|
720
866
|
const targetBranchSelect = document.getElementById('TARGET_BRANCH');
|
|
721
867
|
const repoSearch = document.getElementById('REPO_SEARCH');
|
|
722
868
|
const resultsContainer = document.getElementById('REPO_RESULTS');
|
|
723
|
-
|
|
869
|
+
|
|
724
870
|
if (repoSearch) {
|
|
725
871
|
// Focus: ouvre la liste avec ce qui est déjà là
|
|
726
872
|
repoSearch.addEventListener('focus', () => {
|
|
@@ -791,7 +937,7 @@
|
|
|
791
937
|
else config[f.id] = inp.value;
|
|
792
938
|
}
|
|
793
939
|
});
|
|
794
|
-
|
|
940
|
+
|
|
795
941
|
try {
|
|
796
942
|
await fetch(api('api/config'), {
|
|
797
943
|
method: 'POST',
|
|
@@ -805,12 +951,12 @@
|
|
|
805
951
|
});
|
|
806
952
|
}
|
|
807
953
|
});
|
|
808
|
-
|
|
954
|
+
|
|
809
955
|
if (targetBranchSelect) {
|
|
810
956
|
targetBranchSelect.addEventListener('change', () => {
|
|
811
957
|
const customInput = document.getElementById('TARGET_BRANCH_custom');
|
|
812
958
|
if (!customInput) return;
|
|
813
|
-
|
|
959
|
+
|
|
814
960
|
const isNewBranch = targetBranchSelect.value === '';
|
|
815
961
|
customInput.classList.toggle('hidden', !isNewBranch);
|
|
816
962
|
if (isNewBranch) {
|
|
@@ -825,19 +971,16 @@
|
|
|
825
971
|
function showStatus(message, type) {
|
|
826
972
|
const container = document.getElementById('toast-container');
|
|
827
973
|
const toast = document.createElement('div');
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
: '<svg class="w-5 h-5 mr-3 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>';
|
|
835
|
-
|
|
836
|
-
toast.className = `toast flex items-center p-4 rounded-lg border shadow-xl ${bgColor} ${borderColor} ${textColor}`;
|
|
974
|
+
|
|
975
|
+
const icon = type === 'success'
|
|
976
|
+
? '<svg class="w-4 h-4 shrink-0" style="color:var(--accent)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>'
|
|
977
|
+
: '<svg class="w-4 h-4 shrink-0" style="color:var(--danger)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>';
|
|
978
|
+
|
|
979
|
+
toast.className = `toast ${type === 'success' ? 'toast-success' : 'toast-error'}`;
|
|
837
980
|
toast.innerHTML = `${icon}<span class="flex-1">${message}</span>`;
|
|
838
|
-
|
|
981
|
+
|
|
839
982
|
container.appendChild(toast);
|
|
840
|
-
|
|
983
|
+
|
|
841
984
|
// Supprimer le toast après l'animation (5s total)
|
|
842
985
|
setTimeout(() => {
|
|
843
986
|
toast.remove();
|
|
@@ -896,7 +1039,7 @@
|
|
|
896
1039
|
try {
|
|
897
1040
|
restartBtn.disabled = true;
|
|
898
1041
|
restartBtn.innerHTML = '<span>Redémarrage en cours...</span>';
|
|
899
|
-
|
|
1042
|
+
|
|
900
1043
|
const response = await fetch(api('api/restart'), { method: 'POST' });
|
|
901
1044
|
|
|
902
1045
|
if (response.ok) {
|
|
@@ -921,7 +1064,7 @@
|
|
|
921
1064
|
try {
|
|
922
1065
|
stopBtn.disabled = true;
|
|
923
1066
|
stopBtn.innerHTML = '<span>Arrêt en cours...</span>';
|
|
924
|
-
|
|
1067
|
+
|
|
925
1068
|
const response = await fetch(api('api/stop'), { method: 'POST' });
|
|
926
1069
|
|
|
927
1070
|
if (response.ok) {
|
|
@@ -945,7 +1088,7 @@
|
|
|
945
1088
|
try {
|
|
946
1089
|
deleteWorkingDirBtn.disabled = true;
|
|
947
1090
|
deleteWorkingDirBtn.innerHTML = '<span>Suppression...</span>';
|
|
948
|
-
|
|
1091
|
+
|
|
949
1092
|
const response = await fetch(api('api/delete-working-dir'), { method: 'POST' });
|
|
950
1093
|
|
|
951
1094
|
if (response.ok) {
|
|
@@ -973,7 +1116,7 @@
|
|
|
973
1116
|
try {
|
|
974
1117
|
cloneBtn.disabled = true;
|
|
975
1118
|
cloneBtn.innerHTML = '<span>Clonage...</span>';
|
|
976
|
-
|
|
1119
|
+
|
|
977
1120
|
const response = await fetch(api('api/clone'), { method: 'POST' });
|
|
978
1121
|
|
|
979
1122
|
if (response.ok) {
|