@imenam/mcp-github 1.1.47 → 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/package.json +1 -1
- package/public/index.html +360 -219
package/package.json
CHANGED
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
|
|
|
@@ -299,11 +443,11 @@
|
|
|
299
443
|
}
|
|
300
444
|
|
|
301
445
|
function renderConfigSelector() {
|
|
302
|
-
configSelector.innerHTML = '<option value=""
|
|
303
|
-
configNames.map(name =>
|
|
446
|
+
configSelector.innerHTML = '<option value="">— Sélectionner —</option>' +
|
|
447
|
+
configNames.map(name =>
|
|
304
448
|
`<option value="${name}" ${name === currentConfigName ? 'selected' : ''}>${name}</option>`
|
|
305
449
|
).join('');
|
|
306
|
-
|
|
450
|
+
|
|
307
451
|
deleteConfigBtn.disabled = !currentConfigName || configNames.length <= 1;
|
|
308
452
|
}
|
|
309
453
|
|
|
@@ -409,7 +553,7 @@
|
|
|
409
553
|
async function fetchRepositories(searchTerm = '') {
|
|
410
554
|
const loadingIndicator = document.getElementById('REPO_LOADING_INDICATOR');
|
|
411
555
|
if (loadingIndicator) loadingIndicator.classList.remove('hidden');
|
|
412
|
-
|
|
556
|
+
|
|
413
557
|
try {
|
|
414
558
|
const url = api(`api/repositories${searchTerm ? `?search=${encodeURIComponent(searchTerm)}` : ''}`);
|
|
415
559
|
const response = await fetch(url);
|
|
@@ -434,13 +578,13 @@
|
|
|
434
578
|
resultsContainer.innerHTML = selectState.repos.map((repo, index) => `
|
|
435
579
|
<div class="search-result-item ${repo === currentRepo ? 'selected' : ''}" data-index="${index}" onclick="selectRepo('${repo}')">
|
|
436
580
|
${repo}
|
|
437
|
-
${repo === currentRepo ? '<span class="float-right
|
|
581
|
+
${repo === currentRepo ? '<span class="float-right">✓</span>' : ''}
|
|
438
582
|
</div>
|
|
439
583
|
`).join('');
|
|
440
584
|
resultsContainer.classList.remove('hidden');
|
|
441
585
|
activeIndex = -1;
|
|
442
586
|
} else {
|
|
443
|
-
resultsContainer.innerHTML = '<div class="
|
|
587
|
+
resultsContainer.innerHTML = '<div class="search-result-item">Aucun résultat</div>';
|
|
444
588
|
resultsContainer.classList.remove('hidden');
|
|
445
589
|
}
|
|
446
590
|
}
|
|
@@ -450,18 +594,18 @@
|
|
|
450
594
|
const searchInput = document.getElementById('REPO_SEARCH');
|
|
451
595
|
const hiddenInput = document.getElementById('TARGET_REPO');
|
|
452
596
|
const resultsContainer = document.getElementById('REPO_RESULTS');
|
|
453
|
-
|
|
597
|
+
|
|
454
598
|
if (searchInput) searchInput.value = repo;
|
|
455
599
|
if (hiddenInput) {
|
|
456
600
|
hiddenInput.value = repo;
|
|
457
601
|
currentConfig.TARGET_REPO = repo;
|
|
458
602
|
}
|
|
459
603
|
if (resultsContainer) resultsContainer.classList.add('hidden');
|
|
460
|
-
|
|
604
|
+
|
|
461
605
|
// Réinitialiser les branches lors du changement de repository
|
|
462
606
|
currentConfig.BASE_BRANCH = '';
|
|
463
607
|
currentConfig.TARGET_BRANCH = '';
|
|
464
|
-
|
|
608
|
+
|
|
465
609
|
// Charger les branches pour ce repo (renderInputs is called inside fetchBranches)
|
|
466
610
|
await fetchBranches(repo);
|
|
467
611
|
};
|
|
@@ -469,11 +613,11 @@
|
|
|
469
613
|
// Fetch branches for a repository
|
|
470
614
|
async function fetchBranches(repo, preserveConfig = false) {
|
|
471
615
|
if (!repo) return [];
|
|
472
|
-
|
|
616
|
+
|
|
473
617
|
selectState.loadingBranches[repo] = true;
|
|
474
618
|
// Use renderInputs directly to avoid overwriting currentConfig from DOM
|
|
475
619
|
renderInputs(currentConfig);
|
|
476
|
-
|
|
620
|
+
|
|
477
621
|
try {
|
|
478
622
|
const url = api(`api/branches?repo=${encodeURIComponent(repo)}`);
|
|
479
623
|
const response = await fetch(url);
|
|
@@ -492,42 +636,42 @@
|
|
|
492
636
|
|
|
493
637
|
// Render select field
|
|
494
638
|
function renderSelectField(field, value, config) {
|
|
495
|
-
let options = '<option value=""
|
|
496
|
-
|
|
639
|
+
let options = '<option value="">— Sélectionner une option —</option>';
|
|
640
|
+
|
|
497
641
|
if (field.id === 'TARGET_REPO') {
|
|
498
642
|
if (selectState.loadingRepos && selectState.repos.length === 0) {
|
|
499
643
|
return `
|
|
500
|
-
<div
|
|
501
|
-
<label for="${field.id}" class="
|
|
502
|
-
<div id="${field.id}_loading" class="
|
|
503
|
-
<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>
|
|
504
648
|
Chargement des dépôts...
|
|
505
649
|
</div>
|
|
506
650
|
</div>
|
|
507
651
|
`;
|
|
508
652
|
}
|
|
509
|
-
|
|
510
|
-
options += selectState.repos.map(repo =>
|
|
653
|
+
|
|
654
|
+
options += selectState.repos.map(repo =>
|
|
511
655
|
`<option value="${repo}" ${value === repo ? 'selected' : ''}>${repo}</option>`
|
|
512
656
|
).join('');
|
|
513
|
-
|
|
657
|
+
|
|
514
658
|
if (value && !selectState.repos.includes(value)) {
|
|
515
659
|
options += `<option value="${value}" selected>${value}</option>`;
|
|
516
660
|
}
|
|
517
661
|
|
|
518
662
|
return `
|
|
519
|
-
<div
|
|
520
|
-
<label for="${field.id}" class="
|
|
663
|
+
<div>
|
|
664
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
521
665
|
<div class="relative">
|
|
522
666
|
<div class="relative">
|
|
523
667
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
524
|
-
<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">
|
|
525
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>
|
|
526
670
|
</svg>
|
|
527
671
|
</div>
|
|
528
|
-
<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 || ''}">
|
|
529
673
|
<div id="REPO_LOADING_INDICATOR" class="absolute inset-y-0 right-0 pr-3 flex items-center hidden">
|
|
530
|
-
<div class="
|
|
674
|
+
<div class="spinner"></div>
|
|
531
675
|
</div>
|
|
532
676
|
</div>
|
|
533
677
|
<div id="REPO_RESULTS" class="search-results hidden"></div>
|
|
@@ -538,29 +682,29 @@
|
|
|
538
682
|
} else if (field.id === 'BASE_BRANCH') {
|
|
539
683
|
const currentRepo = config.TARGET_REPO;
|
|
540
684
|
const branches = selectState.branches[currentRepo] || [];
|
|
541
|
-
|
|
685
|
+
|
|
542
686
|
if (selectState.loadingBranches[currentRepo]) {
|
|
543
687
|
return `
|
|
544
|
-
<div
|
|
545
|
-
<label for="${field.id}" class="
|
|
546
|
-
<div id="${field.id}_loading" class="
|
|
547
|
-
<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>
|
|
548
692
|
Chargement des branches...
|
|
549
693
|
</div>
|
|
550
694
|
</div>
|
|
551
695
|
`;
|
|
552
696
|
}
|
|
553
|
-
|
|
697
|
+
|
|
554
698
|
// Recréer les options avec l'option par défaut sélectionnée si value est vide
|
|
555
|
-
let branchOptions = `<option value="" ${!value ? 'selected' : ''}
|
|
699
|
+
let branchOptions = `<option value="" ${!value ? 'selected' : ''}>— Choisir une branche —</option>`;
|
|
556
700
|
branchOptions += branches.map(branch =>
|
|
557
701
|
`<option value="${branch}" ${value === branch ? 'selected' : ''}>${branch}</option>`
|
|
558
702
|
).join('');
|
|
559
|
-
|
|
703
|
+
|
|
560
704
|
return `
|
|
561
|
-
<div
|
|
562
|
-
<label for="${field.id}" class="
|
|
563
|
-
<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">
|
|
564
708
|
${branchOptions}
|
|
565
709
|
</select>
|
|
566
710
|
</div>
|
|
@@ -568,44 +712,44 @@
|
|
|
568
712
|
} else if (field.id === 'TARGET_BRANCH') {
|
|
569
713
|
const currentRepo = config.TARGET_REPO;
|
|
570
714
|
const branches = selectState.branches[currentRepo] || [];
|
|
571
|
-
|
|
715
|
+
|
|
572
716
|
if (selectState.loadingBranches[currentRepo]) {
|
|
573
717
|
return `
|
|
574
|
-
<div
|
|
575
|
-
<label for="${field.id}" class="
|
|
576
|
-
<div id="${field.id}_loading" class="
|
|
577
|
-
<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>
|
|
578
722
|
Chargement des branches...
|
|
579
723
|
</div>
|
|
580
724
|
</div>
|
|
581
725
|
`;
|
|
582
726
|
}
|
|
583
|
-
|
|
584
|
-
let selectOptions = '<option value=""
|
|
727
|
+
|
|
728
|
+
let selectOptions = '<option value="">— Créer une nouvelle branche —</option>';
|
|
585
729
|
selectOptions += branches.map(branch =>
|
|
586
730
|
`<option value="${branch}" ${value === branch ? 'selected' : ''}>${branch}</option>`
|
|
587
731
|
).join('');
|
|
588
|
-
|
|
732
|
+
|
|
589
733
|
const isCustom = value && !branches.includes(value);
|
|
590
734
|
const shouldShowCustom = isCustom || value === '';
|
|
591
|
-
|
|
735
|
+
|
|
592
736
|
return `
|
|
593
|
-
<div
|
|
594
|
-
<label for="${field.id}" class="
|
|
737
|
+
<div>
|
|
738
|
+
<label for="${field.id}" class="field-label">${field.label}</label>
|
|
595
739
|
<div class="space-y-2">
|
|
596
|
-
<select id="${field.id}" class="
|
|
740
|
+
<select id="${field.id}" class="field-select">
|
|
597
741
|
${selectOptions}
|
|
598
742
|
</select>
|
|
599
|
-
<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'}">
|
|
600
744
|
</div>
|
|
601
745
|
</div>
|
|
602
746
|
`;
|
|
603
747
|
}
|
|
604
|
-
|
|
748
|
+
|
|
605
749
|
return `
|
|
606
|
-
<div
|
|
607
|
-
<label for="${field.id}" class="
|
|
608
|
-
<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">
|
|
609
753
|
${options}
|
|
610
754
|
</select>
|
|
611
755
|
</div>
|
|
@@ -624,7 +768,7 @@
|
|
|
624
768
|
throw new Error(data.error || 'Erreur lors du chargement');
|
|
625
769
|
}
|
|
626
770
|
currentConfig = await response.json();
|
|
627
|
-
|
|
771
|
+
|
|
628
772
|
// Afficher le nom de l'agent si défini
|
|
629
773
|
const agentBadge = document.getElementById('agentNameBadge');
|
|
630
774
|
if (currentConfig.AGENT_NAME) {
|
|
@@ -633,13 +777,13 @@
|
|
|
633
777
|
} else {
|
|
634
778
|
agentBadge.classList.add('hidden');
|
|
635
779
|
}
|
|
636
|
-
|
|
780
|
+
|
|
637
781
|
// Le token est désormais côté serveur, on tente de charger les repos directement
|
|
638
782
|
await fetchRepositories();
|
|
639
783
|
if (currentConfig.TARGET_REPO) {
|
|
640
784
|
await fetchBranches(currentConfig.TARGET_REPO);
|
|
641
785
|
}
|
|
642
|
-
|
|
786
|
+
|
|
643
787
|
renderInputs(currentConfig);
|
|
644
788
|
} catch (error) {
|
|
645
789
|
showStatus(error.message || 'Erreur lors du chargement de la configuration', 'error');
|
|
@@ -650,17 +794,17 @@
|
|
|
650
794
|
function renderInputs(config) {
|
|
651
795
|
// CLONE_DIR en lecture seule (variable d'environnement)
|
|
652
796
|
const cloneDirInfo = config.CLONE_DIR
|
|
653
|
-
? `<div class="
|
|
654
|
-
<span class="text-
|
|
655
|
-
<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>
|
|
656
800
|
</div>`
|
|
657
801
|
: '';
|
|
658
802
|
|
|
659
803
|
inputsContainer.innerHTML = fields.map(field => {
|
|
660
804
|
if (field.type === 'slider') {
|
|
661
805
|
return `
|
|
662
|
-
<div class="
|
|
663
|
-
<label for="${field.id}" class="text
|
|
806
|
+
<div class="toggle-row">
|
|
807
|
+
<label for="${field.id}" class="text">${field.label}</label>
|
|
664
808
|
<label class="switch">
|
|
665
809
|
<input type="checkbox" id="${field.id}" ${config[field.id] === 'true' || config[field.id] === true ? 'checked' : ''}>
|
|
666
810
|
<span class="slider"></span>
|
|
@@ -670,9 +814,9 @@
|
|
|
670
814
|
}
|
|
671
815
|
if (field.type === 'checkbox') {
|
|
672
816
|
return `
|
|
673
|
-
<div class="
|
|
674
|
-
<
|
|
675
|
-
<
|
|
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">
|
|
676
820
|
</div>
|
|
677
821
|
`;
|
|
678
822
|
}
|
|
@@ -680,13 +824,13 @@
|
|
|
680
824
|
return renderSelectField(field, config[field.id] || '', config);
|
|
681
825
|
}
|
|
682
826
|
return `
|
|
683
|
-
<div
|
|
684
|
-
<label for="${field.id}" class="
|
|
685
|
-
<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">
|
|
686
830
|
</div>
|
|
687
831
|
`;
|
|
688
832
|
}).join('') + cloneDirInfo;
|
|
689
|
-
|
|
833
|
+
|
|
690
834
|
if (deleteWorkingDirBtn) {
|
|
691
835
|
deleteWorkingDirBtn.disabled = !config.REPO_PATH;
|
|
692
836
|
}
|
|
@@ -694,7 +838,7 @@
|
|
|
694
838
|
if (cloneBtn) {
|
|
695
839
|
cloneBtn.disabled = !config.TARGET_REPO || !config.TARGET_BRANCH;
|
|
696
840
|
}
|
|
697
|
-
|
|
841
|
+
|
|
698
842
|
setupEventListeners();
|
|
699
843
|
}
|
|
700
844
|
|
|
@@ -722,7 +866,7 @@
|
|
|
722
866
|
const targetBranchSelect = document.getElementById('TARGET_BRANCH');
|
|
723
867
|
const repoSearch = document.getElementById('REPO_SEARCH');
|
|
724
868
|
const resultsContainer = document.getElementById('REPO_RESULTS');
|
|
725
|
-
|
|
869
|
+
|
|
726
870
|
if (repoSearch) {
|
|
727
871
|
// Focus: ouvre la liste avec ce qui est déjà là
|
|
728
872
|
repoSearch.addEventListener('focus', () => {
|
|
@@ -793,7 +937,7 @@
|
|
|
793
937
|
else config[f.id] = inp.value;
|
|
794
938
|
}
|
|
795
939
|
});
|
|
796
|
-
|
|
940
|
+
|
|
797
941
|
try {
|
|
798
942
|
await fetch(api('api/config'), {
|
|
799
943
|
method: 'POST',
|
|
@@ -807,12 +951,12 @@
|
|
|
807
951
|
});
|
|
808
952
|
}
|
|
809
953
|
});
|
|
810
|
-
|
|
954
|
+
|
|
811
955
|
if (targetBranchSelect) {
|
|
812
956
|
targetBranchSelect.addEventListener('change', () => {
|
|
813
957
|
const customInput = document.getElementById('TARGET_BRANCH_custom');
|
|
814
958
|
if (!customInput) return;
|
|
815
|
-
|
|
959
|
+
|
|
816
960
|
const isNewBranch = targetBranchSelect.value === '';
|
|
817
961
|
customInput.classList.toggle('hidden', !isNewBranch);
|
|
818
962
|
if (isNewBranch) {
|
|
@@ -827,19 +971,16 @@
|
|
|
827
971
|
function showStatus(message, type) {
|
|
828
972
|
const container = document.getElementById('toast-container');
|
|
829
973
|
const toast = document.createElement('div');
|
|
830
|
-
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
: '<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>';
|
|
837
|
-
|
|
838
|
-
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'}`;
|
|
839
980
|
toast.innerHTML = `${icon}<span class="flex-1">${message}</span>`;
|
|
840
|
-
|
|
981
|
+
|
|
841
982
|
container.appendChild(toast);
|
|
842
|
-
|
|
983
|
+
|
|
843
984
|
// Supprimer le toast après l'animation (5s total)
|
|
844
985
|
setTimeout(() => {
|
|
845
986
|
toast.remove();
|
|
@@ -898,7 +1039,7 @@
|
|
|
898
1039
|
try {
|
|
899
1040
|
restartBtn.disabled = true;
|
|
900
1041
|
restartBtn.innerHTML = '<span>Redémarrage en cours...</span>';
|
|
901
|
-
|
|
1042
|
+
|
|
902
1043
|
const response = await fetch(api('api/restart'), { method: 'POST' });
|
|
903
1044
|
|
|
904
1045
|
if (response.ok) {
|
|
@@ -923,7 +1064,7 @@
|
|
|
923
1064
|
try {
|
|
924
1065
|
stopBtn.disabled = true;
|
|
925
1066
|
stopBtn.innerHTML = '<span>Arrêt en cours...</span>';
|
|
926
|
-
|
|
1067
|
+
|
|
927
1068
|
const response = await fetch(api('api/stop'), { method: 'POST' });
|
|
928
1069
|
|
|
929
1070
|
if (response.ok) {
|
|
@@ -947,7 +1088,7 @@
|
|
|
947
1088
|
try {
|
|
948
1089
|
deleteWorkingDirBtn.disabled = true;
|
|
949
1090
|
deleteWorkingDirBtn.innerHTML = '<span>Suppression...</span>';
|
|
950
|
-
|
|
1091
|
+
|
|
951
1092
|
const response = await fetch(api('api/delete-working-dir'), { method: 'POST' });
|
|
952
1093
|
|
|
953
1094
|
if (response.ok) {
|
|
@@ -975,7 +1116,7 @@
|
|
|
975
1116
|
try {
|
|
976
1117
|
cloneBtn.disabled = true;
|
|
977
1118
|
cloneBtn.innerHTML = '<span>Clonage...</span>';
|
|
978
|
-
|
|
1119
|
+
|
|
979
1120
|
const response = await fetch(api('api/clone'), { method: 'POST' });
|
|
980
1121
|
|
|
981
1122
|
if (response.ok) {
|