Add executable picker in game edit UI
Build & Deploy / build-and-deploy (push) Successful in 49s

- Added 'executables' (full list) and 'executable' (selected) fields to Game
- Upload now stores ALL discoverable .exe/.com/.bat files in game metadata
- Added setExecutable() to GameService that patches the .jsdos bundle
  (updates dosbox.conf + jsdos.json inside the ZIP) when changing executable
- GameResource PATCH handler delegates executable changes to bundle patching
- GameDetail edit mode shows a radio-button picker of all executables
- Heuristics remain as first-guess default, user can always override
- No re-upload needed to fix wrong executable selection
This commit is contained in:
Hermes Agent
2026-05-29 10:31:25 +02:00
parent e262a46487
commit 02d0c4f377
5 changed files with 251 additions and 1 deletions
+78
View File
@@ -17,6 +17,7 @@
let editPublisher = $state("");
let editDescription = $state("");
let editPlatform = $state("");
let editExecutable = $state("");
// IGDB scrape state
let scraping = $state(false);
@@ -65,6 +66,7 @@
editPublisher = game.publisher || "";
editDescription = game.description || "";
editPlatform = game.platform || "";
editExecutable = game.executable || "";
editing = true;
}
@@ -79,6 +81,7 @@
publisher: editPublisher || undefined,
description: editDescription || undefined,
platform: editPlatform || undefined,
executable: editExecutable || undefined,
});
editing = false;
} catch (e) {
@@ -207,6 +210,25 @@
<option value="windows">Windows</option>
</select>
</div>
{#if game.executables && game.executables.length > 0}
<div class="edit-exec-section">
<span class="edit-exec-label">Main executable:</span>
<div class="edit-exec-list">
{#each game.executables as exe}
<label class="edit-exec-option" class:selected={editExecutable === exe}>
<input
type="radio"
name="executable"
value={exe}
checked={editExecutable === exe}
onchange={() => editExecutable = exe}
/>
<span class="edit-exec-path">{exe}</span>
</label>
{/each}
</div>
</div>
{/if}
<div class="edit-actions">
<button class="btn btn-primary" onclick={saveEdit} disabled={saving}>
{saving ? "Saving..." : "Save"}
@@ -601,6 +623,62 @@
color: #66ff66;
}
/* ─── Executable Picker ────────────────────── */
.edit-exec-section {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.edit-exec-label {
display: block;
font-size: 0.8rem;
color: var(--text-dim);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 8px;
}
.edit-exec-list {
display: flex;
flex-direction: column;
gap: 4px;
max-height: 180px;
overflow-y: auto;
}
.edit-exec-option {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 0.85rem;
font-family: var(--font-mono);
background: var(--surface);
border: 1px solid var(--border);
transition: border-color 0.15s, background 0.15s;
}
.edit-exec-option:hover {
border-color: var(--phosphor-dim);
background: var(--surface-hover);
}
.edit-exec-option.selected {
border-color: var(--phosphor);
background: var(--phosphor-burn);
}
.edit-exec-option input[type="radio"] {
accent-color: var(--phosphor);
margin: 0;
flex-shrink: 0;
}
.edit-exec-path {
word-break: break-all;
color: var(--text);
}
.edit-exec-option.selected .edit-exec-path {
color: var(--phosphor-glow);
}
/* ─── Responsive ────────────────────────────────── */
@media (max-width: 640px) {
.detail { padding: 16px 0; }