summaryrefslogtreecommitdiffstats
path: root/ogcp/templates/disk_inspector.html
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-08-29 11:55:52 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-09-02 15:05:45 +0200
commitd00e437b8d76bc32732643a92f0ea32fbe0b7901 (patch)
treecf8998b06022b7ca8e29eedb74c0a32b1ecea6b5 /ogcp/templates/disk_inspector.html
parent78a26f947fba1af6b339567cb58e0f852d253137 (diff)
ogcp: add support for multi-disk partition and format
Add support for selecting different disks in the disk inspector. Add disk_inspector.html as a template to show the disk contents of a client. The view can define the variable readonly_disk_inspector to make the view non editable. Use disk_inspector.html in the following views: - client details - partition and format Update code to obtain the partitions of a client to better fit the requirements of disk_inspector.html Remove code to setup the SetupForm as the contents of the disks are now dynamically loaded through javascript.
Diffstat (limited to 'ogcp/templates/disk_inspector.html')
-rw-r--r--ogcp/templates/disk_inspector.html306
1 files changed, 306 insertions, 0 deletions
diff --git a/ogcp/templates/disk_inspector.html b/ogcp/templates/disk_inspector.html
new file mode 100644
index 0000000..90a8996
--- /dev/null
+++ b/ogcp/templates/disk_inspector.html
@@ -0,0 +1,306 @@
+{% if selected_disk is defined and setup_data is defined %}
+
+<form class="form-inline" method="POST" id="setupForm">
+ {{ disk_form.hidden_tag() }}
+ {{ disk_form.ips() }}
+
+ <table class="table">
+ <thead class="text-center">
+ <tr>
+ <th>{{ _('Disk') }}</th>
+ <th>{{ _('Partition Table Type') }}</th>
+ <th>{{ _('Total Disk Size') }} (MiB)</th>
+ </tr>
+ </thead>
+
+ <tbody data-target="partitons-fieldset" id="diskTable" class="text-center">
+ <tr>
+ <td>
+ {{ disk_form.disk(class_="form-control", onchange="handleDiskChange(this)") }}
+ </td>
+ {{ disk_form.hidden_tag() }}
+ <td>
+ {% if readonly_disk_inspector is defined %}
+ {{ disk_form.disk_type(class_="form-control", id="diskType", readonly="readonly") }}
+ {% else %}
+ {{ disk_form.disk_type(class_="form-control", id="diskType") }}
+ {% endif %}
+ </td>
+ <td id="diskSize">{{ disk_size }}</td>
+ </tr>
+</tbody>
+ </table>
+ <table class="table">
+ <thead class="text-center">
+ <tr>
+ <th>{{ _('Partition') }}</th>
+ <th>{{ _('Type') }}</th>
+ <th>{{ _('Filesystem') }}</th>
+ <th>{{ _('Size') }} (MiB)</th>
+ {% if show_part_images is defined %}
+ <th>{{ _('Image') }}</th>
+ {% endif %}
+ <th colspan="2"></th>
+ </tr>
+ </thead>
+
+ <tbody data-target="partitons-fieldset" id="partitionsTable" class="text-center">
+ {% for partition in disk_form.partitions %}
+ <tr data-toggle="fieldset-entry">
+ {{ partition.hidden_tag() }}
+ <td>{{ partition.partition.data }}</td>
+ <td>
+ {% if readonly_disk_inspector is defined %}
+ {{ partition.part_type(class_="form-control", readonly="readonly") }}
+ {% else %}
+ {{ partition.part_type(class_="form-control") }}
+ {% endif %}
+ </td>
+ <td>
+ {% if readonly_disk_inspector is defined %}
+ {{ partition.fs(class_="form-control", readonly="readonly") }}
+ {% else %}
+ {{ partition.fs(class_="form-control") }}
+ {% endif %}
+ </td>
+ <td>
+ {% if readonly_disk_inspector is defined %}
+ {{ partition.size(class_="form-control", oninput="handleEdit(this)", readonly="readonly") }}
+ {% else %}
+ {{ partition.size(class_="form-control", oninput="handleEdit(this)") }}
+ {% endif %}
+ </td>
+ {% if show_part_images is defined %}
+ <td></td>
+ {% endif %}
+ <td>
+ <button class="btn btn-danger" type="button" onclick="RemovePartition(this, true)"
+ {% if readonly_disk_inspector is defined %}style="display: none;"{% endif %}>
+ {{ _('Remove') }}
+ </button>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+</form>
+
+<button class="btn btn-primary" data-target="#partitionsTable" id="addPartButton" onclick="AddPartition(this, true)"
+{% if readonly_disk_inspector is defined %}style="display: none;"{% endif %}>
+ {{ _('Add a new partition') }}
+</button>
+
+{% if not readonly_disk_inspector is defined %}
+ <button class="btn btn-success" form="setupForm">
+ {{ _('Submit') }}
+ </button>
+{% endif %}
+
+<div class="card text-center">
+ <div class="card-header">
+ {{ _('Partition graph') }}
+ </div>
+ <div class="card-body mx-auto col-7">
+ <canvas id="partitionChart" class="mb-2"></canvas>
+ </div>
+</div>
+
+<!-- jQuery -->
+<script src="{{ url_for('static', filename='AdminLTE/plugins/jquery/jquery.min.js') }}"></script>
+<!-- ChartJS -->
+<script src="{{ url_for('static', filename='AdminLTE/plugins/chart.js/Chart.min.js') }}"></script>
+<script>
+ const usedColor = 'rgb(255, 99, 132)';
+ const freeColor = 'rgb(54, 162, 235)';
+
+ let selectedDisk = {{selected_disk}};
+ let setupData = {{setup_data|tojson|safe}}
+ let diskSize = 0;
+
+ let chartConfig = {
+ type: 'doughnut',
+ data: {
+ labels: [],
+ datasets: [
+ {
+ label: 'Partitions',
+ data: [],
+ backgroundColor: [],
+ },
+ ],
+ },
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Doughnut Chart'
+ },
+ },
+ },
+ };
+
+ let partitionChart = new Chart(
+ document.getElementById('partitionChart'),
+ chartConfig,
+ );
+
+ function addPartitionToChart(chart, label, value, bgColor) {
+ chart.data.labels.push(label)
+ chart.data.datasets[0].data.push(value);
+ chart.data.datasets[0].backgroundColor.push(bgColor);
+ }
+
+ function resetChart() {
+ partitionChart.data.labels = [];
+ partitionChart.data.datasets[0].data = [];
+ partitionChart.data.datasets[0].backgroundColor = [];
+ }
+
+ function updatePartitionChart() {
+ resetChart();
+
+ let freeSpace = diskSize;
+ let partNum = 1;
+ $('#partitionsTable tr').each(function() {
+ let partitionSize = parseInt($(this).find('td').eq(3).find('input').val().trim());
+ if (isNaN(partitionSize)) {
+ partitionSize = 0;
+ }
+ freeSpace -= partitionSize;
+ addPartitionToChart(partitionChart, 'Partition ' + partNum, partitionSize, usedColor);
+ partNum++;
+ });
+
+ addPartitionToChart(partitionChart, 'Free', Math.max(freeSpace, 0), freeColor);
+ partitionChart.update();
+ }
+
+ function handleEdit(element) {
+ const numericValue = parseInt(element.value);
+
+ if (isNaN(numericValue)) {
+ updatePartitionChart();
+ return;
+ }
+
+ let freeSpace = diskSize;
+ $('#partitionsTable tr').each(function() {
+ let partitionSize = parseInt($(this).find('td').eq(3).find('input').val().trim());
+ if (isNaN(partitionSize)) {
+ partitionSize = 0;
+ }
+ freeSpace -= partitionSize;
+ });
+
+ if (freeSpace < 0) {
+ element.value = numericValue + freeSpace;
+ }
+
+ updatePartitionChart();
+ }
+
+ function AddPartition(evt, updateChart) {
+ const target = $($(evt).data("target"));
+ const oldrow = target.find("[data-toggle=fieldset-entry]:last");
+ const row = oldrow.clone(true, true);
+ const elem_id = row.find(".form-control")[0].id;
+ const elem_num = parseInt(elem_id.replace(/(.*)-(\d{1,4})/m, '$2')) + 1;
+ // Increment WTForms unique identifiers
+ row.find('.form-control').each(function() {
+ const id = $(this).attr('id').replace(/(.*)-(\d{1,4})-(.*)/, `$1-${elem_num}-$3`);
+ $(this).attr('name', id).attr('id', id).val('').removeAttr("checked");
+ });
+ let part_field = row.find('td').filter(':first')[0];
+ part_field.innerText = elem_num + 1;
+ row.show();
+ oldrow.after(row);
+
+ if (updateChart) {
+ updatePartitionChart();
+ }
+ }
+
+ function RemovePartition(evt, updateChart) {
+ const target = $(evt).parent().parent();
+ const table = target.parent();
+
+ if (table[0].children.length > 1) {
+ target.remove();
+ // Reassign rows ids
+ table.find('tr').each(function(index) {
+ function update_references() {
+ const id = $(this).attr('id').replace(/(.*)-(\d{1,4})-(.*)/, `$1-${index}-$3`);
+ $(this).attr('name', id).attr('id', id);
+ }
+
+ let part_field = $(this).find('td').filter(':first')[0];
+ part_field.innerText = index + 1;
+ $(this).find('input').filter(':first').each(update_references);
+ $(this).find('.form-control').each(update_references);
+ });
+ } else {
+ table.find('tr').each(function(index) {
+ $(this).find('.form-control').each(function() {
+ $(this).val('').removeAttr("checked");
+ });
+ });
+ }
+ if (updateChart) {
+ updatePartitionChart();
+ }
+ }
+
+ function setDiskData(diskNumber) {
+ selectedDisk = diskNumber;
+ let partitions = setupData[selectedDisk];
+ diskSize = Math.floor(partitions[0].size / 1024);
+
+ $('#diskSize').text(diskSize);
+ $('#diskType').val(partitions[0].code);
+
+ const partitionsTable = $('#partitionsTable');
+ let partNumber = partitionsTable.find('tr').length;
+ const targetPartNumber = partitions.length - 1;
+
+ while (partNumber < targetPartNumber) {
+ AddPartition($('#addPartButton'), false);
+ partNumber++;
+ }
+
+ while (partNumber > targetPartNumber) {
+ RemovePartition(partitionsTable.find('tr:last').find('button'), false);
+ partNumber--;
+ }
+
+ for (let i = 1; i < partitions.length; i++) {
+ let p = partitions[i];
+
+ let row = partitionsTable.find('tr').eq(i - 1);
+
+ row.find('td').eq(0).text(p.partition);
+ row.find('td').eq(1).find('select').val(p.code);
+ row.find('td').eq(2).find('select').val(p.filesystem);
+ row.find('td').eq(3).find('input').val(Math.floor(p.size / 1024));
+ {% if show_part_images is defined %}
+ row.find('td').eq(4).text(p.image);
+ {% endif %}
+ }
+
+ updatePartitionChart();
+ }
+
+ function handleDiskChange(selectElement) {
+ setDiskData(selectElement.value);
+ }
+
+ $(document).ready(function() {
+ setDiskData(selectedDisk);
+ });
+
+</script>
+
+{% endif %}