hostbasket/flowbroker/templates/create_flow.html
2025-05-20 22:08:00 +03:00

188 lines
7.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flowbroker - Create Flow</title>
<link rel="stylesheet" href="/static/style.css">
<style>
.step, .requirement {
border: 1px solid #ddd;
padding: 10px;
margin-bottom: 15px;
border-radius: 4px;
background-color: #f9f9f9;
}
.step h3, .step h4, .requirement h5 {
margin-top: 0;
}
.step .requirementsContainer {
margin-left: 20px;
border-left: 2px solid #007bff;
padding-left: 15px;
}
button.removeStepBtn, button.removeRequirementBtn {
background-color: #dc3545;
margin-top: 5px;
}
button.removeStepBtn:hover, button.removeRequirementBtn:hover {
background-color: #c82333;
}
</style>
</head>
<body>
<h1>Create New Flow</h1>
<form id="createFlowForm" action="/flows" method="post">
<div>
<label for="flow_name">Flow Name:</label>
<input type="text" id="flow_name" name="flow_name" required>
</div>
<hr>
<div id="stepsContainer">
<!-- Steps will be added here by JavaScript -->
</div>
<button type="button" id="addStepBtn" class="addBtn">Add Step</button>
<hr>
<button type="submit">Create Flow</button>
</form>
<p><a href="/">Back to Flows List</a></p>
<!-- Template for a new step -->
<template id="stepTemplate">
<div class="step" data-step-index="">
<h3>Step <span class="step-number"></span></h3>
<button type="button" class="removeStepBtn">Remove This Step</button>
<div>
<label>Step Description (Optional):</label>
<input type="text" name="steps[X].description" class="step-description">
</div>
<h4>Signature Requirements for Step <span class="step-number"></span></h4>
<div class="requirementsContainer" data-step-index="">
<!-- Requirements will be added here -->
</div>
<button type="button" class="addRequirementBtn addBtn" data-step-index="">Add Signature Requirement</button>
</div>
</template>
<!-- Template for a new signature requirement -->
<template id="requirementTemplate">
<div class="requirement" data-req-index="">
<h5>Requirement <span class="req-number"></span></h5>
<button type="button" class="removeRequirementBtn">Remove Requirement</button>
<div>
<label>Message to Sign:</label>
<textarea name="steps[X].requirements[Y].message" rows="2" required class="req-message"></textarea>
</div>
<div>
<label>Required Public Key:</label>
<input type="text" name="steps[X].requirements[Y].public_key" required class="req-pubkey">
</div>
</div>
</template>
<script>
document.addEventListener('DOMContentLoaded', () => {
const stepsContainer = document.getElementById('stepsContainer');
const addStepBtn = document.getElementById('addStepBtn');
const stepTemplate = document.getElementById('stepTemplate');
const requirementTemplate = document.getElementById('requirementTemplate');
const form = document.getElementById('createFlowForm');
const updateIndices = () => {
const steps = stepsContainer.querySelectorAll('.step');
steps.forEach((step, stepIdx) => {
// Update step-level attributes and text
step.dataset.stepIndex = stepIdx;
step.querySelector('.step-number').textContent = stepIdx + 1;
step.querySelector('.step-description').name = `steps[${stepIdx}].description`;
const addReqBtn = step.querySelector('.addRequirementBtn');
if (addReqBtn) addReqBtn.dataset.stepIndex = stepIdx;
const requirements = step.querySelectorAll('.requirementsContainer .requirement');
requirements.forEach((req, reqIdx) => {
// Update requirement-level attributes and text
req.dataset.reqIndex = reqIdx;
req.querySelector('.req-number').textContent = reqIdx + 1;
req.querySelector('.req-message').name = `steps[${stepIdx}].requirements[${reqIdx}].message`;
req.querySelector('.req-pubkey').name = `steps[${stepIdx}].requirements[${reqIdx}].public_key`;
});
});
};
const addRequirement = (currentStepElement, stepIndex) => {
const requirementsContainer = currentStepElement.querySelector('.requirementsContainer');
const reqFragment = requirementTemplate.content.cloneNode(true);
const newRequirement = reqFragment.querySelector('.requirement');
requirementsContainer.appendChild(newRequirement);
updateIndices(); // Update all indices after adding
};
const addStep = () => {
const stepFragment = stepTemplate.content.cloneNode(true);
const newStep = stepFragment.querySelector('.step');
stepsContainer.appendChild(newStep);
// Add at least one requirement to the new step automatically
const currentStepIndex = stepsContainer.querySelectorAll('.step').length - 1;
addRequirement(newStep, currentStepIndex);
updateIndices(); // Update all indices after adding
};
// Event delegation for remove buttons and add requirement button
stepsContainer.addEventListener('click', (event) => {
if (event.target.classList.contains('removeStepBtn')) {
event.target.closest('.step').remove();
if (stepsContainer.querySelectorAll('.step').length === 0) { // Ensure at least one step
addStep();
}
updateIndices();
} else if (event.target.classList.contains('addRequirementBtn')) {
const stepElement = event.target.closest('.step');
const stepIndex = parseInt(stepElement.dataset.stepIndex, 10);
addRequirement(stepElement, stepIndex);
} else if (event.target.classList.contains('removeRequirementBtn')) {
const requirementElement = event.target.closest('.requirement');
const stepElement = event.target.closest('.step');
const requirementsContainer = stepElement.querySelector('.requirementsContainer');
requirementElement.remove();
// Ensure at least one requirement per step
if (requirementsContainer.querySelectorAll('.requirement').length === 0) {
const stepIndex = parseInt(stepElement.dataset.stepIndex, 10);
addRequirement(stepElement, stepIndex);
}
updateIndices();
}
});
addStepBtn.addEventListener('click', addStep);
// Add one step by default when the page loads
if (stepsContainer.children.length === 0) {
addStep();
}
// Optional: Validate that there's at least one step and one requirement before submit
form.addEventListener('submit', (event) => {
if (stepsContainer.querySelectorAll('.step').length === 0) {
alert('Please add at least one step to the flow.');
event.preventDefault();
return;
}
const steps = stepsContainer.querySelectorAll('.step');
for (let i = 0; i < steps.length; i++) {
if (steps[i].querySelectorAll('.requirementsContainer .requirement').length === 0) {
alert(`Step ${i + 1} must have at least one signature requirement.`);
event.preventDefault();
return;
}
}
});
});
</script>
</body>
</html>