188 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			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>
 |