@deploid/studio 2.0.5 → 2.0.7
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 +5 -3
- package/bin/deploid-studio.cjs +5 -1
- package/dist/main.js +135 -6
- package/dist/main.js.map +1 -1
- package/dist/preload.js +3 -1
- package/dist/preload.js.map +1 -1
- package/dist/renderer/index.html +487 -195
- package/dist/renderer/renderer.js +309 -79
- package/package.json +1 -1
- package/renderer/index.html +487 -195
- package/renderer/renderer.js +309 -79
|
@@ -3,9 +3,20 @@ const pickButton = document.getElementById('pick');
|
|
|
3
3
|
const runButton = document.getElementById('run');
|
|
4
4
|
const stopButton = document.getElementById('stop');
|
|
5
5
|
const cmdInput = document.getElementById('cmd');
|
|
6
|
-
const commandsWrap = document.getElementById('commands');
|
|
7
6
|
const recentWrap = document.getElementById('recentWrap');
|
|
8
7
|
const statusPill = document.getElementById('statusPill');
|
|
8
|
+
const status = document.getElementById('status');
|
|
9
|
+
const runStateTitle = document.getElementById('runStateTitle');
|
|
10
|
+
const projectTitle = document.getElementById('projectTitle');
|
|
11
|
+
const projectSubtitle = document.getElementById('projectSubtitle');
|
|
12
|
+
const metaStatus = document.getElementById('metaStatus');
|
|
13
|
+
const metaArtifacts = document.getElementById('metaArtifacts');
|
|
14
|
+
const metaDevices = document.getElementById('metaDevices');
|
|
15
|
+
const workflowGrid = document.getElementById('workflowGrid');
|
|
16
|
+
const blockersList = document.getElementById('blockersList');
|
|
17
|
+
const quickActionsWrap = document.getElementById('quickActions');
|
|
18
|
+
const artifactsList = document.getElementById('artifactsList');
|
|
19
|
+
const devicesList = document.getElementById('devicesList');
|
|
9
20
|
const logFilter = document.getElementById('logFilter');
|
|
10
21
|
const copyLogsButton = document.getElementById('copyLogs');
|
|
11
22
|
const clearLogsButton = document.getElementById('clearLogs');
|
|
@@ -13,31 +24,75 @@ const kpiTask = document.getElementById('kpiTask');
|
|
|
13
24
|
const kpiRuns = document.getElementById('kpiRuns');
|
|
14
25
|
const kpiResult = document.getElementById('kpiResult');
|
|
15
26
|
const logs = document.getElementById('logs');
|
|
16
|
-
const status = document.getElementById('status');
|
|
17
27
|
|
|
18
28
|
const RECENT_CWDS_KEY = 'deploidStudio.recentCwds';
|
|
19
29
|
const MAX_RECENT_CWDS = 5;
|
|
20
30
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const WORKFLOW_ACTIONS = {
|
|
32
|
+
init: 'init',
|
|
33
|
+
build: 'package',
|
|
34
|
+
release: 'doctor --fix',
|
|
35
|
+
deploy: 'deploy',
|
|
36
|
+
desktop: 'electron'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const ACTION_LIBRARY = [
|
|
40
|
+
{
|
|
41
|
+
key: 'doctor --summary',
|
|
42
|
+
title: 'Refresh readiness',
|
|
43
|
+
description: 'Re-run doctor and rebuild the dashboard state.',
|
|
44
|
+
intent: 'primary'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'doctor --fix',
|
|
48
|
+
title: 'Apply safe fixes',
|
|
49
|
+
description: 'Create missing scaffolding and templates where doctor can do so safely.',
|
|
50
|
+
intent: 'secondary'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: 'assets',
|
|
54
|
+
title: 'Generate assets',
|
|
55
|
+
description: 'Create icons and generated image assets from your configured source.',
|
|
56
|
+
intent: 'secondary'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
key: 'package',
|
|
60
|
+
title: 'Package native shell',
|
|
61
|
+
description: 'Sync the web app into Capacitor and generate the Android project.',
|
|
62
|
+
intent: 'secondary'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: 'build',
|
|
66
|
+
title: 'Build Android output',
|
|
67
|
+
description: 'Compile the APK/AAB artifacts available for deploy or release.',
|
|
68
|
+
intent: 'secondary'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'deploy',
|
|
72
|
+
title: 'Deploy to device',
|
|
73
|
+
description: 'Install the latest debug build on connected Android devices.',
|
|
74
|
+
intent: 'secondary'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
key: 'logs',
|
|
78
|
+
title: 'Tail device logs',
|
|
79
|
+
description: 'Stream device logs when you are in a troubleshooting loop.',
|
|
80
|
+
intent: 'secondary'
|
|
81
|
+
}
|
|
35
82
|
];
|
|
36
83
|
|
|
37
84
|
const logEntries = [];
|
|
38
85
|
let runCount = 0;
|
|
39
|
-
let selectedCommand = '
|
|
86
|
+
let selectedCommand = 'doctor --summary';
|
|
40
87
|
let currentRunHadError = false;
|
|
88
|
+
let currentOverview = null;
|
|
89
|
+
|
|
90
|
+
function emptyState(message) {
|
|
91
|
+
const div = document.createElement('div');
|
|
92
|
+
div.className = 'empty';
|
|
93
|
+
div.textContent = message;
|
|
94
|
+
return div;
|
|
95
|
+
}
|
|
41
96
|
|
|
42
97
|
function appendLog(kind, text) {
|
|
43
98
|
logEntries.push({ kind, text });
|
|
@@ -46,49 +101,17 @@ function appendLog(kind, text) {
|
|
|
46
101
|
|
|
47
102
|
function renderLogs() {
|
|
48
103
|
const filter = logFilter.value;
|
|
49
|
-
|
|
104
|
+
logs.textContent = logEntries
|
|
50
105
|
.filter((entry) => filter === 'all' || entry.kind === filter)
|
|
51
106
|
.map((entry) => entry.text)
|
|
52
107
|
.join('');
|
|
53
|
-
logs.textContent = text;
|
|
54
108
|
logs.scrollTop = logs.scrollHeight;
|
|
55
109
|
}
|
|
56
110
|
|
|
57
|
-
function updateSelectedCommand(command) {
|
|
58
|
-
selectedCommand = command;
|
|
59
|
-
cmdInput.value = command;
|
|
60
|
-
kpiTask.textContent = command;
|
|
61
|
-
for (const el of commandsWrap.querySelectorAll('.command')) {
|
|
62
|
-
el.classList.toggle('active', el.dataset.command === command);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function setRunningState(running) {
|
|
67
|
-
if (running) {
|
|
68
|
-
statusPill.textContent = 'Running';
|
|
69
|
-
statusPill.classList.add('running');
|
|
70
|
-
statusPill.classList.remove('error');
|
|
71
|
-
status.textContent = `Running "${selectedCommand}"...`;
|
|
72
|
-
} else {
|
|
73
|
-
statusPill.textContent = 'Ready';
|
|
74
|
-
statusPill.classList.remove('running');
|
|
75
|
-
status.textContent = 'Ready to run';
|
|
76
|
-
}
|
|
77
|
-
runButton.disabled = running;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function setErrorState(message) {
|
|
81
|
-
statusPill.textContent = 'Needs attention';
|
|
82
|
-
statusPill.classList.remove('running');
|
|
83
|
-
statusPill.classList.add('error');
|
|
84
|
-
status.textContent = message;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
111
|
function getRecentCwds() {
|
|
88
112
|
try {
|
|
89
113
|
const parsed = JSON.parse(localStorage.getItem(RECENT_CWDS_KEY) || '[]');
|
|
90
|
-
|
|
91
|
-
return parsed.filter((entry) => typeof entry === 'string' && entry.length > 0);
|
|
114
|
+
return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === 'string' && entry.length > 0) : [];
|
|
92
115
|
} catch {
|
|
93
116
|
return [];
|
|
94
117
|
}
|
|
@@ -109,44 +132,253 @@ function renderRecentCwds() {
|
|
|
109
132
|
recentWrap.innerHTML = '';
|
|
110
133
|
for (const cwd of recents) {
|
|
111
134
|
const button = document.createElement('button');
|
|
112
|
-
button.className = 'ghost';
|
|
135
|
+
button.className = 'ghost recent-pill';
|
|
113
136
|
button.type = 'button';
|
|
137
|
+
button.textContent = cwd.length > 36 ? `...${cwd.slice(-36)}` : cwd;
|
|
114
138
|
button.title = cwd;
|
|
115
|
-
button.textContent = cwd.length > 34 ? `...${cwd.slice(-34)}` : cwd;
|
|
116
139
|
button.addEventListener('click', () => {
|
|
117
140
|
cwdInput.value = cwd;
|
|
141
|
+
refreshOverview();
|
|
118
142
|
});
|
|
119
143
|
recentWrap.appendChild(button);
|
|
120
144
|
}
|
|
121
145
|
}
|
|
122
146
|
|
|
123
|
-
function
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
function setSelectedCommand(command) {
|
|
148
|
+
selectedCommand = command;
|
|
149
|
+
cmdInput.value = command;
|
|
150
|
+
kpiTask.textContent = command;
|
|
151
|
+
for (const button of quickActionsWrap.querySelectorAll('[data-command]')) {
|
|
152
|
+
button.style.outline = button.dataset.command === command ? '2px solid rgba(255,255,255,0.38)' : 'none';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function setRunningState(running) {
|
|
157
|
+
if (running) {
|
|
158
|
+
statusPill.textContent = 'Running';
|
|
159
|
+
statusPill.className = 'status-chip running';
|
|
160
|
+
runStateTitle.textContent = 'Task in progress';
|
|
161
|
+
status.textContent = `Running "${selectedCommand}" in the selected project.`;
|
|
162
|
+
} else {
|
|
163
|
+
statusPill.textContent = 'Ready';
|
|
164
|
+
statusPill.className = 'status-chip';
|
|
165
|
+
runStateTitle.textContent = currentOverview?.doctor?.ok ? 'Project looks healthy' : 'Action still needed';
|
|
166
|
+
status.textContent = currentOverview
|
|
167
|
+
? 'Dashboard refreshed from project state.'
|
|
168
|
+
: 'Choose a project and Studio will pull readiness, blockers, and quick actions automatically.';
|
|
169
|
+
}
|
|
170
|
+
runButton.disabled = running;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function setErrorState(message) {
|
|
174
|
+
statusPill.textContent = 'Needs attention';
|
|
175
|
+
statusPill.className = 'status-chip error';
|
|
176
|
+
runStateTitle.textContent = 'Last command needs attention';
|
|
177
|
+
status.textContent = message;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function renderWorkflowGrid(workflows = []) {
|
|
181
|
+
workflowGrid.innerHTML = '';
|
|
182
|
+
if (!workflows.length) {
|
|
183
|
+
workflowGrid.appendChild(emptyState('Select a project to populate the workflow board.'));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (const workflow of workflows) {
|
|
188
|
+
const card = document.createElement('div');
|
|
189
|
+
card.className = 'workflow-card';
|
|
190
|
+
const command = WORKFLOW_ACTIONS[workflow.id] || 'doctor --summary';
|
|
191
|
+
card.innerHTML = `
|
|
192
|
+
<div class="workflow-top">
|
|
193
|
+
<div class="workflow-name">${workflow.title}</div>
|
|
194
|
+
<div class="workflow-score">${workflow.score}%</div>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="workflow-state">${workflow.status.toUpperCase()}</div>
|
|
197
|
+
<div class="workflow-note">${workflow.nextAction || 'No blockers detected for this workflow.'}</div>
|
|
198
|
+
<button class="primary workflow-action" data-command="${command}">Run ${command}</button>
|
|
199
|
+
`;
|
|
200
|
+
card.querySelector('button').addEventListener('click', () => {
|
|
201
|
+
setSelectedCommand(command);
|
|
202
|
+
});
|
|
203
|
+
workflowGrid.appendChild(card);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function renderBlockers(checks = []) {
|
|
208
|
+
blockersList.innerHTML = '';
|
|
209
|
+
const issues = checks.filter((check) => check.status !== 'pass').slice(0, 8);
|
|
210
|
+
if (!issues.length) {
|
|
211
|
+
blockersList.appendChild(emptyState('Doctor is not reporting active blockers or warnings.'));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const check of issues) {
|
|
216
|
+
const item = document.createElement('div');
|
|
217
|
+
item.className = 'list-item';
|
|
218
|
+
item.innerHTML = `
|
|
219
|
+
<div class="list-top">
|
|
220
|
+
<div class="list-title">${check.title}</div>
|
|
221
|
+
<div class="badge ${check.status}">${check.status}</div>
|
|
222
|
+
</div>
|
|
223
|
+
<div>${check.message}</div>
|
|
224
|
+
${check.details ? `<div class="artifact-path">${check.details}</div>` : ''}
|
|
225
|
+
`;
|
|
226
|
+
blockersList.appendChild(item);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function computeRecommendedActions(overview) {
|
|
231
|
+
const checks = overview?.doctor?.checks || [];
|
|
232
|
+
const actions = [];
|
|
233
|
+
|
|
234
|
+
if (checks.some((check) => check.id === 'deploid-config' && check.status !== 'pass')) actions.push('init');
|
|
235
|
+
if (checks.some((check) => check.id === 'assets-source' && check.status !== 'pass')) actions.push('doctor --fix');
|
|
236
|
+
if (checks.some((check) => check.id === 'capacitor-config' && check.status !== 'pass')) actions.push('package');
|
|
237
|
+
if (checks.some((check) => check.id === 'android-project' && check.status !== 'pass')) actions.push('package');
|
|
238
|
+
if (checks.some((check) => check.id === 'android-signing' && check.status !== 'pass')) actions.push('doctor --fix');
|
|
239
|
+
if (overview?.devices?.count > 0) actions.push('deploy');
|
|
240
|
+
|
|
241
|
+
actions.push('doctor --summary', 'assets', 'build', 'logs');
|
|
242
|
+
return [...new Set(actions)].slice(0, 6);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderQuickActions(overview) {
|
|
246
|
+
quickActionsWrap.innerHTML = '';
|
|
247
|
+
const recommended = computeRecommendedActions(overview);
|
|
248
|
+
const items = ACTION_LIBRARY.filter((action) => recommended.includes(action.key));
|
|
249
|
+
|
|
250
|
+
for (const action of items) {
|
|
126
251
|
const button = document.createElement('button');
|
|
127
252
|
button.type = 'button';
|
|
128
|
-
button.className = '
|
|
129
|
-
button.dataset.command =
|
|
130
|
-
button.innerHTML =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
253
|
+
button.className = 'quick-action';
|
|
254
|
+
button.dataset.command = action.key;
|
|
255
|
+
button.innerHTML = `<div>${action.title}</div><small>${action.description}</small>`;
|
|
256
|
+
button.addEventListener('click', () => setSelectedCommand(action.key));
|
|
257
|
+
quickActionsWrap.appendChild(button);
|
|
258
|
+
}
|
|
259
|
+
if (!items.length) {
|
|
260
|
+
quickActionsWrap.appendChild(emptyState('No quick actions available until a project overview is loaded.'));
|
|
261
|
+
} else if (!selectedCommand || !recommended.includes(selectedCommand)) {
|
|
262
|
+
setSelectedCommand(items[0].key);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function renderArtifacts(artifacts = []) {
|
|
267
|
+
artifactsList.innerHTML = '';
|
|
268
|
+
if (!artifacts.length) {
|
|
269
|
+
artifactsList.appendChild(emptyState('No APK, AAB, or desktop output is available yet.'));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
for (const artifact of artifacts) {
|
|
274
|
+
const item = document.createElement('div');
|
|
275
|
+
item.className = 'list-item';
|
|
276
|
+
item.innerHTML = `
|
|
277
|
+
<div class="list-top">
|
|
278
|
+
<div class="list-title">${artifact.label}</div>
|
|
279
|
+
<div class="badge pass">${artifact.size}</div>
|
|
134
280
|
</div>
|
|
135
|
-
<div class="
|
|
281
|
+
<div class="artifact-path">${artifact.path}</div>
|
|
136
282
|
`;
|
|
137
|
-
|
|
138
|
-
|
|
283
|
+
artifactsList.appendChild(item);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function renderDevices(overview) {
|
|
288
|
+
devicesList.innerHTML = '';
|
|
289
|
+
const entries = overview?.devices?.entries || [];
|
|
290
|
+
const presence = overview?.presence || {};
|
|
291
|
+
|
|
292
|
+
const presenceItem = document.createElement('div');
|
|
293
|
+
presenceItem.className = 'list-item';
|
|
294
|
+
presenceItem.innerHTML = `
|
|
295
|
+
<div class="list-top">
|
|
296
|
+
<div class="list-title">Project surface</div>
|
|
297
|
+
<div class="badge ${presence.config ? 'pass' : 'warn'}">${presence.config ? 'ready' : 'missing config'}</div>
|
|
298
|
+
</div>
|
|
299
|
+
<div class="device-line">Config: ${presence.config ? 'yes' : 'no'} · Capacitor: ${presence.capacitor ? 'yes' : 'no'} · Android: ${presence.android ? 'yes' : 'no'} · Electron: ${presence.electron ? 'yes' : 'no'}</div>
|
|
300
|
+
`;
|
|
301
|
+
devicesList.appendChild(presenceItem);
|
|
302
|
+
|
|
303
|
+
if (!overview?.devices?.available) {
|
|
304
|
+
devicesList.appendChild(emptyState('ADB is not available in this environment.'));
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!entries.length) {
|
|
309
|
+
devicesList.appendChild(emptyState('ADB is available, but no Android devices are connected.'));
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (const entry of entries) {
|
|
314
|
+
const item = document.createElement('div');
|
|
315
|
+
item.className = 'list-item';
|
|
316
|
+
item.innerHTML = `
|
|
317
|
+
<div class="list-top">
|
|
318
|
+
<div class="list-title">${entry.id}</div>
|
|
319
|
+
<div class="badge ${entry.status === 'device' ? 'pass' : 'warn'}">${entry.status}</div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="device-line">ADB target state for deploy/log workflows.</div>
|
|
322
|
+
`;
|
|
323
|
+
devicesList.appendChild(item);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function renderOverview(overview) {
|
|
328
|
+
currentOverview = overview;
|
|
329
|
+
|
|
330
|
+
if (!overview) {
|
|
331
|
+
projectTitle.textContent = 'Deploid Studio';
|
|
332
|
+
projectSubtitle.textContent = 'Pick a project folder to turn this into a workflow dashboard.';
|
|
333
|
+
metaStatus.textContent = 'No project';
|
|
334
|
+
metaArtifacts.textContent = '0';
|
|
335
|
+
metaDevices.textContent = '0';
|
|
336
|
+
renderWorkflowGrid();
|
|
337
|
+
renderBlockers();
|
|
338
|
+
renderQuickActions(null);
|
|
339
|
+
renderArtifacts();
|
|
340
|
+
renderDevices(null);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
projectTitle.textContent = overview.projectName || 'Deploid project';
|
|
345
|
+
projectSubtitle.textContent = overview.doctor?.ok
|
|
346
|
+
? 'This project is in a healthy state. Use the workflow board to keep moving without dropping into the terminal.'
|
|
347
|
+
: `Studio found ${overview.doctor?.totals?.fail || 0} blockers and ${overview.doctor?.totals?.warn || 0} warnings that should shape your next move.`;
|
|
348
|
+
metaStatus.textContent = overview.doctor?.ok ? 'Healthy' : 'Action needed';
|
|
349
|
+
metaArtifacts.textContent = String((overview.artifacts || []).length);
|
|
350
|
+
metaDevices.textContent = String(overview.devices?.count || 0);
|
|
351
|
+
|
|
352
|
+
renderWorkflowGrid(overview.doctor?.workflows || []);
|
|
353
|
+
renderBlockers(overview.doctor?.checks || []);
|
|
354
|
+
renderQuickActions(overview);
|
|
355
|
+
renderArtifacts(overview.artifacts || []);
|
|
356
|
+
renderDevices(overview);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function refreshOverview() {
|
|
360
|
+
const cwd = cwdInput.value.trim();
|
|
361
|
+
if (!cwd) {
|
|
362
|
+
renderOverview(null);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
const overview = await window.deploidStudio.getProjectOverview(cwd);
|
|
368
|
+
renderOverview(overview);
|
|
369
|
+
} catch {
|
|
370
|
+
renderOverview(null);
|
|
139
371
|
}
|
|
140
|
-
updateSelectedCommand(selectedCommand);
|
|
141
372
|
}
|
|
142
373
|
|
|
143
374
|
runButton.addEventListener('click', async () => {
|
|
144
375
|
const cwd = cwdInput.value.trim();
|
|
145
376
|
if (!cwd) {
|
|
146
|
-
setErrorState('Choose a project folder before running
|
|
147
|
-
appendLog('system', 'Choose a project folder before running
|
|
377
|
+
setErrorState('Choose a project folder before running an action.');
|
|
378
|
+
appendLog('system', 'Choose a project folder before running an action.\n');
|
|
148
379
|
return;
|
|
149
380
|
}
|
|
381
|
+
|
|
150
382
|
const command = cmdInput.value || selectedCommand;
|
|
151
383
|
try {
|
|
152
384
|
addRecentCwd(cwd);
|
|
@@ -168,9 +400,7 @@ stopButton.addEventListener('click', async () => {
|
|
|
168
400
|
});
|
|
169
401
|
|
|
170
402
|
window.deploidStudio.onLog((entry) => {
|
|
171
|
-
if (entry.kind === 'stderr')
|
|
172
|
-
currentRunHadError = true;
|
|
173
|
-
}
|
|
403
|
+
if (entry.kind === 'stderr') currentRunHadError = true;
|
|
174
404
|
appendLog(entry.kind, entry.message);
|
|
175
405
|
});
|
|
176
406
|
|
|
@@ -178,12 +408,11 @@ window.deploidStudio.onState((state) => {
|
|
|
178
408
|
setRunningState(state.running);
|
|
179
409
|
if (!state.running) {
|
|
180
410
|
kpiResult.textContent = currentRunHadError ? 'Warning' : 'Success';
|
|
411
|
+
refreshOverview();
|
|
181
412
|
}
|
|
182
413
|
});
|
|
183
414
|
|
|
184
|
-
logFilter.addEventListener('change',
|
|
185
|
-
renderLogs();
|
|
186
|
-
});
|
|
415
|
+
logFilter.addEventListener('change', renderLogs);
|
|
187
416
|
|
|
188
417
|
clearLogsButton.addEventListener('click', () => {
|
|
189
418
|
logEntries.length = 0;
|
|
@@ -202,18 +431,19 @@ copyLogsButton.addEventListener('click', async () => {
|
|
|
202
431
|
});
|
|
203
432
|
|
|
204
433
|
window.deploidStudio.getDefaultCwd().then((cwd) => {
|
|
205
|
-
if (!cwdInput.value)
|
|
206
|
-
cwdInput.value = cwd;
|
|
207
|
-
}
|
|
434
|
+
if (!cwdInput.value) cwdInput.value = cwd;
|
|
208
435
|
addRecentCwd(cwd);
|
|
436
|
+
renderRecentCwds();
|
|
437
|
+
refreshOverview();
|
|
209
438
|
});
|
|
210
439
|
|
|
211
440
|
pickButton.addEventListener('click', async () => {
|
|
212
|
-
const folder = await window.deploidStudio.chooseProject();
|
|
441
|
+
const folder = await window.deploidStudio.chooseProject(cwdInput.value.trim());
|
|
213
442
|
if (!folder) return;
|
|
214
443
|
cwdInput.value = folder;
|
|
215
444
|
addRecentCwd(folder);
|
|
445
|
+
refreshOverview();
|
|
216
446
|
});
|
|
217
447
|
|
|
218
|
-
renderCommands();
|
|
219
448
|
renderRecentCwds();
|
|
449
|
+
renderOverview(null);
|