216 lines
9.3 KiB
PHP
216 lines
9.3 KiB
PHP
<?php
|
|
require_once 'WorkflowEngine.php';
|
|
|
|
$workflowEngine = new WorkflowEngine();
|
|
// TODO: Create a method in WorkflowEngine to get all process definitions
|
|
$pdo = db();
|
|
$stmt = $pdo->query("SELECT * FROM process_definitions ORDER BY name");
|
|
$processes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
?>
|
|
<?php include '_header.php'; ?>
|
|
<?php include '_navbar.php'; ?>
|
|
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<?php include '_sidebar.php'; ?>
|
|
|
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
|
<div class="d-flex justify-content-between align-items-center pt-3 pb-2 mb-3 border-bottom">
|
|
<h1 class="h2">Process Definitions</h1>
|
|
<div class="btn-toolbar mb-2 mb-md-0">
|
|
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#createProcessModal">
|
|
Create Process
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-sm">
|
|
<thead>
|
|
<tr class="text-center">
|
|
<th class="bg-light">Name</th>
|
|
<th class="bg-light">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($processes as $process): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($process['name']) ?></td>
|
|
<td class="text-center">
|
|
<button class="btn btn-sm btn-secondary edit-process-btn"
|
|
data-bs-toggle="modal" data-bs-target="#createProcessModal"
|
|
data-process-id="<?= $process['id'] ?>"
|
|
data-process-name="<?= htmlspecialchars($process['name']) ?>"
|
|
data-process-definition='<?= htmlspecialchars($process['definition_json'] ?? '') ?>'>
|
|
Edit
|
|
</button>
|
|
<!-- TODO: Add delete functionality -->
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create/Edit Process Modal -->
|
|
<div class="modal fade" id="createProcessModal" tabindex="-1" aria-labelledby="createProcessModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="createProcessModalLabel">Create Process</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="createProcessForm" action="_save_process_definition.php" method="post">
|
|
<input type="hidden" name="process_id" id="processId">
|
|
<div class="mb-3">
|
|
<label for="processName" class="form-label">Process Name</label>
|
|
<input type="text" class="form-control" id="processName" name="name" required>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<h5>Statuses</h5>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="initialStatus" class="form-label">Initial Status</label>
|
|
<select class="form-select" id="initialStatus"></select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="statuses-list" class="mb-3"></div>
|
|
<div class="input-group mb-3">
|
|
<input type="text" id="newStatusInput" class="form-control" placeholder="New status name">
|
|
<button class="btn btn-outline-secondary" type="button" id="addStatusBtn">Add Status</button>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<h5>Transitions</h5>
|
|
<div id="transitions-list" class="mb-3"></div>
|
|
<div class="row">
|
|
<div class="col-5">
|
|
<select id="fromStatusSelect" class="form-select"></select>
|
|
</div>
|
|
<div class="col-2 text-center">=></div>
|
|
<div class="col-5">
|
|
<select id="toStatusSelect" class="form-select"></select>
|
|
</div>
|
|
</div>
|
|
<div class="d-grid gap-2 mt-3">
|
|
<button class="btn btn-outline-secondary" type="button" id="addTransitionBtn">Add Transition</button>
|
|
</div>
|
|
|
|
<textarea name="definition_json" id="definitionJson" class="d-none"></textarea>
|
|
|
|
<hr class="mt-4">
|
|
|
|
<button type="submit" class="btn btn-primary">Save Process</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include '_footer.php'; ?>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const createProcessModal = document.getElementById('createProcessModal');
|
|
const modalTitle = createProcessModal.querySelector('.modal-title');
|
|
const form = createProcessModal.querySelector('#createProcessForm');
|
|
const processIdInput = createProcessModal.querySelector('#processId');
|
|
const processNameInput = createProcessModal.querySelector('#processName');
|
|
const definitionJsonTextarea = createProcessModal.querySelector('#definitionJson');
|
|
|
|
function renderProcessDefinition(definition) {
|
|
const statusesList = document.getElementById('statuses-list');
|
|
const transitionsList = document.getElementById('transitions-list');
|
|
const initialStatusSelect = document.getElementById('initialStatus');
|
|
const fromStatusSelect = document.getElementById('fromStatusSelect');
|
|
const toStatusSelect = document.getElementById('toStatusSelect');
|
|
|
|
statusesList.innerHTML = '';
|
|
transitionsList.innerHTML = '';
|
|
initialStatusSelect.innerHTML = '';
|
|
fromStatusSelect.innerHTML = '';
|
|
toStatusSelect.innerHTML = '';
|
|
|
|
if (!definition) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const def = JSON.parse(definition);
|
|
|
|
// Populate statuses
|
|
if (def.nodes) {
|
|
for (const nodeId in def.nodes) {
|
|
const node = def.nodes[nodeId];
|
|
const statusItem = document.createElement('div');
|
|
statusItem.textContent = node.name;
|
|
statusesList.appendChild(statusItem);
|
|
|
|
const option = document.createElement('option');
|
|
option.value = node.id;
|
|
option.textContent = node.name;
|
|
initialStatusSelect.appendChild(option.cloneNode(true));
|
|
fromStatusSelect.appendChild(option.cloneNode(true));
|
|
toStatusSelect.appendChild(option.cloneNode(true));
|
|
}
|
|
}
|
|
|
|
// Set initial status
|
|
if (def.start_node_id) {
|
|
initialStatusSelect.value = def.start_node_id;
|
|
}
|
|
|
|
// Populate transitions
|
|
if (def.transitions) {
|
|
def.transitions.forEach(transition => {
|
|
const transitionItem = document.createElement('div');
|
|
const fromNode = def.nodes[transition.from] ? def.nodes[transition.from].name : 'N/A';
|
|
const toNode = def.nodes[transition.to] ? def.nodes[transition.to].name : 'N/A';
|
|
transitionItem.textContent = `${transition.name}: ${fromNode} => ${toNode}`;
|
|
transitionsList.appendChild(transitionItem);
|
|
});
|
|
}
|
|
} catch (e) {
|
|
console.error('Error parsing process definition:', e);
|
|
// Optionally, display an error message to the user
|
|
}
|
|
}
|
|
|
|
createProcessModal.addEventListener('show.bs.modal', function (event) {
|
|
const button = event.relatedTarget;
|
|
const isEdit = button.classList.contains('edit-process-btn');
|
|
|
|
if (isEdit) {
|
|
const processId = button.dataset.processId;
|
|
const processName = button.dataset.processName;
|
|
const processDefinition = button.dataset.processDefinition;
|
|
|
|
modalTitle.textContent = 'Edit Process';
|
|
form.action = '_save_process_definition.php';
|
|
processIdInput.value = processId;
|
|
processNameInput.value = processName;
|
|
definitionJsonTextarea.value = processDefinition;
|
|
|
|
renderProcessDefinition(processDefinition);
|
|
} else {
|
|
modalTitle.textContent = 'Create Process';
|
|
form.action = '_save_process_definition.php';
|
|
processIdInput.value = '';
|
|
processNameInput.value = '';
|
|
definitionJsonTextarea.value = '';
|
|
renderProcessDefinition(''); // Clear the form
|
|
}
|
|
});
|
|
});
|
|
</script>
|