mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-17 16:10:12 +01:00
feat: implement batch build and comparison
This commit is contained in:
parent
1d95c5cbd0
commit
f1e21873e7
20 changed files with 2691 additions and 6 deletions
8
code/web/templates/build/_batch_progress.html
Normal file
8
code/web/templates/build/_batch_progress.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{# Batch Build Progress Indicator - Multiple Builds Running in Parallel #}
|
||||
<div id="batch-progress-container" style="min-height: 300px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem;">
|
||||
<div hx-get="/build/batch-progress?batch_id={{ batch_id }}"
|
||||
hx-trigger="load, every 1s"
|
||||
hx-swap="innerHTML">
|
||||
{% include "build/_batch_progress_content.html" %}
|
||||
</div>
|
||||
</div>
|
||||
37
code/web/templates/build/_batch_progress_content.html
Normal file
37
code/web/templates/build/_batch_progress_content.html
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{# Batch Build Progress Content (inner content only, for HTMX updates) #}
|
||||
<div style="text-align: center; max-width: 600px;">
|
||||
<h3 style="margin-bottom: 1.5rem;">Building {{ build_count }} Decks...</h3>
|
||||
|
||||
<div style="margin: 2rem 0;">
|
||||
<div style="font-size: 3rem; font-weight: bold; color: var(--primary);">
|
||||
{{ completed }} / {{ build_count }}
|
||||
</div>
|
||||
<div class="muted" style="font-size: 0.9rem; margin-top: 0.5rem;">
|
||||
{{ status }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Progress Bar #}
|
||||
<div style="width: 100%; height: 8px; background: var(--bg-secondary); border-radius: 4px; overflow: hidden; margin: 1.5rem 0;">
|
||||
<div style="height: 100%; background: linear-gradient(90deg, #3b82f6, #8b5cf6); transition: width 0.3s ease; width: {{ progress_pct }}%;"></div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 2rem; padding: 1rem; background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); border-radius: 8px;">
|
||||
<p style="margin: 0; font-size: 0.9rem; line-height: 1.6;">
|
||||
<strong>What's happening?</strong><br>
|
||||
We're running your deck configuration {{ build_count }} times in parallel to see how card selection varies.
|
||||
Each build uses the same commander, themes, and preferences but produces different results due to randomness in card selection.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if has_errors %}
|
||||
<div class="error" style="margin-top: 1rem; text-align: left;">
|
||||
<strong>⚠️ Some builds encountered errors</strong>
|
||||
<p style="font-size: 0.85rem; margin-top: 0.5rem;">{{ error_count }} of {{ build_count }} builds failed. Completed builds will still be available for comparison.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<p class="muted" style="font-size: 0.8rem; margin-top: 1.5rem;">
|
||||
This may take {{ time_estimate|default("1-3 minutes") }} depending on number of decks, theme complexity, and color count...
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -214,11 +214,37 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
{% include "build/_new_deck_skip_controls.html" %}
|
||||
{% if enable_batch_build %}
|
||||
<fieldset>
|
||||
<legend>Build Options</legend>
|
||||
<div style="display:flex; flex-direction:column; gap:0.75rem;">
|
||||
<label style="display:block;">
|
||||
<span>Number of decks to build</span>
|
||||
<small class="muted" style="display:block; font-size:11px; margin-top:.25rem;">Run the same configuration multiple times to see variance in results</small>
|
||||
</label>
|
||||
{% if ideals_ui_mode == 'slider' %}
|
||||
<div style="display:flex; align-items:center; gap:1rem;">
|
||||
<input type="range" name="build_count" id="build_count_slider" min="1" max="10" value="{{ form.build_count if form and form.build_count else 1 }}" style="flex:1;"
|
||||
oninput="document.getElementById('build_count_value').textContent = this.value; updateBuildCountLabel(this.value); updateButtonState(this.value);" />
|
||||
<span id="build_count_value" style="min-width:2.5rem; text-align:center; font-weight:500; font-size:1.1em;">{{ form.build_count if form and form.build_count else 1 }}</span>
|
||||
</div>
|
||||
<small id="build_count_label" class="muted" style="font-size:11px; text-align:center;">Build 1 deck (normal build)</small>
|
||||
{% else %}
|
||||
<input type="number" name="build_count" id="build_count_input" min="1" max="10" value="{{ form.build_count if form and form.build_count else 1 }}" style="width:6rem;"
|
||||
oninput="updateButtonState(this.value);" />
|
||||
<small class="muted" style="font-size:11px;">Enter 1 for normal build, 2-10 to compare multiple results</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
{% else %}
|
||||
{# Hidden input to always send build_count=1 when feature disabled #}
|
||||
<input type="hidden" name="build_count" value="1" />
|
||||
{% endif %}
|
||||
<div class="modal-footer" style="display:flex; gap:.5rem; justify-content:space-between; margin-top:1rem;">
|
||||
<button type="button" class="btn" onclick="this.closest('.modal').remove()">Cancel</button>
|
||||
<div style="display:flex; gap:.5rem;">
|
||||
<button type="submit" name="quick_build" value="1" class="btn-continue" id="quick-build-btn" title="Build entire deck automatically without approval steps">Quick Build</button>
|
||||
<button type="submit" class="btn-continue">Create</button>
|
||||
<button type="submit" class="btn-continue" id="create-btn">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -248,6 +274,63 @@
|
|||
}
|
||||
})();
|
||||
|
||||
// Update build count label based on slider value
|
||||
function updateBuildCountLabel(count) {
|
||||
var label = document.getElementById('build_count_label');
|
||||
if (!label) return;
|
||||
|
||||
count = parseInt(count);
|
||||
if (count === 1) {
|
||||
label.textContent = 'Build 1 deck (normal build)';
|
||||
label.className = 'muted';
|
||||
} else {
|
||||
label.textContent = 'Build ' + count + ' decks and compare results';
|
||||
label.className = 'muted';
|
||||
label.style.color = '#60a5fa';
|
||||
label.style.fontWeight = '500';
|
||||
}
|
||||
}
|
||||
|
||||
// Update button state based on build count
|
||||
function updateButtonState(count) {
|
||||
var quickBuildBtn = document.getElementById('quick-build-btn');
|
||||
var createBtn = document.getElementById('create-btn');
|
||||
|
||||
count = parseInt(count);
|
||||
|
||||
if (count > 1) {
|
||||
// Multi-build: force Quick Build, hide Create button
|
||||
if (createBtn) {
|
||||
createBtn.style.display = 'none';
|
||||
}
|
||||
if (quickBuildBtn) {
|
||||
quickBuildBtn.textContent = 'Build ' + count + ' Decks';
|
||||
quickBuildBtn.title = 'Build ' + count + ' decks automatically and compare results';
|
||||
}
|
||||
} else {
|
||||
// Single build: show both buttons normally
|
||||
if (createBtn) {
|
||||
createBtn.style.display = '';
|
||||
}
|
||||
if (quickBuildBtn) {
|
||||
quickBuildBtn.textContent = 'Quick Build';
|
||||
quickBuildBtn.title = 'Build entire deck automatically without approval steps';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize label and button state on page load
|
||||
(function() {
|
||||
var slider = document.getElementById('build_count_slider');
|
||||
var input = document.getElementById('build_count_input');
|
||||
var initialValue = slider ? slider.value : (input ? input.value : 1);
|
||||
|
||||
if (slider) {
|
||||
updateBuildCountLabel(initialValue);
|
||||
}
|
||||
updateButtonState(initialValue);
|
||||
})();
|
||||
|
||||
// Utility function for parsing card lists
|
||||
function parseCardList(content) {
|
||||
const newlineRegex = /\r?\n/;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue