diff --git a/supervisor/shared/web_workflow/static/directory.html b/supervisor/shared/web_workflow/static/directory.html
index b88e74684b..6e2b833d6f 100644
--- a/supervisor/shared/web_workflow/static/directory.html
+++ b/supervisor/shared/web_workflow/static/directory.html
@@ -11,8 +11,8 @@
| | | | | Edit |
-
- Type | Size | Path | Modified | |
+
diff --git a/supervisor/shared/web_workflow/static/directory.js b/supervisor/shared/web_workflow/static/directory.js
index 91389343d6..657a8169d4 100644
--- a/supervisor/shared/web_workflow/static/directory.js
+++ b/supervisor/shared/web_workflow/static/directory.js
@@ -1,3 +1,172 @@
+/*
+ * This content is licensed according to the W3C Software License at
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * File: sortable-table.js
+ *
+ * Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices
+ */
+
+'use strict';
+
+class SortableTable {
+ constructor(tableNode) {
+ this.tableNode = tableNode;
+
+ this.columnHeaders = tableNode.querySelectorAll('thead th');
+
+ this.sortColumns = [];
+
+ for (var i = 0; i < this.columnHeaders.length; i++) {
+ var ch = this.columnHeaders[i];
+ var buttonNode = ch.querySelector('button');
+ if (buttonNode) {
+ this.sortColumns.push(i);
+ buttonNode.setAttribute('data-column-index', i);
+ buttonNode.addEventListener('click', this.handleClick.bind(this));
+ }
+ }
+
+ this.optionCheckbox = document.querySelector(
+ 'input[type="checkbox"][value="show-unsorted-icon"]'
+ );
+
+ if (this.optionCheckbox) {
+ this.optionCheckbox.addEventListener(
+ 'change',
+ this.handleOptionChange.bind(this)
+ );
+ if (this.optionCheckbox.checked) {
+ this.tableNode.classList.add('show-unsorted-icon');
+ }
+ }
+ }
+
+ setColumnHeaderSort(columnIndex) {
+ if (typeof columnIndex === 'string') {
+ columnIndex = parseInt(columnIndex);
+ }
+
+ for (var i = 0; i < this.columnHeaders.length; i++) {
+ var ch = this.columnHeaders[i];
+ var buttonNode = ch.querySelector('button');
+ if (i === columnIndex) {
+ var value = ch.getAttribute('aria-sort');
+ if (value === 'descending') {
+ ch.setAttribute('aria-sort', 'ascending');
+ this.sortColumn(
+ columnIndex,
+ 'ascending',
+ ch.classList.contains('num')
+ );
+ } else {
+ ch.setAttribute('aria-sort', 'descending');
+ this.sortColumn(
+ columnIndex,
+ 'descending',
+ ch.classList.contains('num')
+ );
+ }
+ } else {
+ if (ch.hasAttribute('aria-sort') && buttonNode) {
+ ch.removeAttribute('aria-sort');
+ }
+ }
+ }
+ }
+
+ sortColumn(columnIndex, sortValue, isNumber) {
+ function compareValues(a, b) {
+ if (sortValue === 'ascending') {
+ if (a.value === b.value) {
+ return 0;
+ } else {
+ if (isNumber) {
+ return a.value - b.value;
+ } else {
+ return a.value < b.value ? -1 : 1;
+ }
+ }
+ } else {
+ if (a.value === b.value) {
+ return 0;
+ } else {
+ if (isNumber) {
+ return b.value - a.value;
+ } else {
+ return a.value > b.value ? -1 : 1;
+ }
+ }
+ }
+ }
+
+ if (typeof isNumber !== 'boolean') {
+ isNumber = false;
+ }
+
+ var tbodyNode = this.tableNode.querySelector('tbody');
+ var rowNodes = [];
+ var dataCells = [];
+
+ var rowNode = tbodyNode.firstElementChild;
+
+ var index = 0;
+ while (rowNode) {
+ rowNodes.push(rowNode);
+ var rowCells = rowNode.querySelectorAll('th, td');
+ var dataCell = rowCells[columnIndex];
+
+ var data = {};
+ data.index = index;
+ data.value = dataCell.textContent.toLowerCase().trim();
+ if (isNumber) {
+ data.value = parseFloat(data.value);
+ }
+ dataCells.push(data);
+ rowNode = rowNode.nextElementSibling;
+ index += 1;
+ }
+
+ dataCells.sort(compareValues);
+
+ // remove rows
+ while (tbodyNode.firstChild) {
+ tbodyNode.removeChild(tbodyNode.lastChild);
+ }
+
+ // add sorted rows
+ for (var i = 0; i < dataCells.length; i += 1) {
+ tbodyNode.appendChild(rowNodes[dataCells[i].index]);
+ }
+ }
+
+ /* EVENT HANDLERS */
+
+ handleClick(event) {
+ var tgt = event.currentTarget;
+ this.setColumnHeaderSort(tgt.getAttribute('data-column-index'));
+ }
+
+ handleOptionChange(event) {
+ var tgt = event.currentTarget;
+
+ if (tgt.checked) {
+ this.tableNode.classList.add('show-unsorted-icon');
+ } else {
+ this.tableNode.classList.remove('show-unsorted-icon');
+ }
+ }
+}
+
+// Initialize sortable table buttons
+window.addEventListener('load', function () {
+ var sortableTables = document.querySelectorAll('table.sortable');
+ for (var i = 0; i < sortableTables.length; i++) {
+ new SortableTable(sortableTables[i]);
+ }
+});
+
+
let new_directory_name = document.getElementById("name");
let files = document.getElementById("files");