Merge pull request #118 from theta42/feat/directory-tree-only-and-click-detail

Directory: tree view is now the only view; click a name for detail
This commit is contained in:
2026-07-28 13:29:45 -04:00
committed by GitHub
+34 -40
View File
@@ -15,12 +15,6 @@
<option value="kind">Kind</option> <option value="kind">Kind</option>
<option value="env">Environment</option> <option value="env">Environment</option>
</select> </select>
<div class="btn-group btn-group-sm shadow-sm" role="group">
<input type="radio" class="btn-check" name="viewMode" id="view-list" value="list" autocomplete="off" checked onchange="renderTable()">
<label class="btn btn-outline-secondary" for="view-list"><i class="fa-solid fa-list"></i></label>
<input type="radio" class="btn-check" name="viewMode" id="view-tree" value="tree" autocomplete="off" onchange="renderTable()">
<label class="btn btn-outline-secondary" for="view-tree"><i class="fa-solid fa-folder-tree"></i></label>
</div>
<button class="btn btn-sm btn-primary ms-1 shadow-sm" onclick="openAddModal()"> <button class="btn btn-sm btn-primary ms-1 shadow-sm" onclick="openAddModal()">
<i class="fas fa-plus"></i> Add Resource <i class="fas fa-plus"></i> Add Resource
</button> </button>
@@ -49,7 +43,12 @@
{{{indentHtml}}} {{{indentHtml}}}
<span class="badge bg-secondary">{{kind}}{{#metadata.subType}} ({{metadata.subType}}){{/metadata.subType}}</span> <span class="badge bg-secondary">{{kind}}{{#metadata.subType}} ({{metadata.subType}}){{/metadata.subType}}</span>
</td> </td>
<td><strong>{{name}}</strong><br><small class="text-muted">{{slug}}</small></td> <td>
<a href="#" class="text-reset text-decoration-none" onclick="openEditModal('{{id}}'); return false;" title="View details">
<strong>{{name}}</strong>
</a>
<br><small class="text-muted">{{slug}}</small>
</td>
<td> <td>
{{#metadata.isProduction}}<span class="badge bg-danger">Prod</span>{{/metadata.isProduction}} {{#metadata.isProduction}}<span class="badge bg-danger">Prod</span>{{/metadata.isProduction}}
{{^metadata.isProduction}}<span class="badge bg-info">Dev</span>{{/metadata.isProduction}} {{^metadata.isProduction}}<span class="badge bg-info">Dev</span>{{/metadata.isProduction}}
@@ -376,7 +375,6 @@
function renderTable() { function renderTable() {
const filter = $('#search-filter').val().toLowerCase(); const filter = $('#search-filter').val().toLowerCase();
const sort = $('#sort-by').val(); const sort = $('#sort-by').val();
const viewMode = $('input[name="viewMode"]:checked').val();
let filtered = rawResources.filter(r => { let filtered = rawResources.filter(r => {
if (!filter) return true; if (!filter) return true;
@@ -402,41 +400,37 @@
let finalRenderList = []; let finalRenderList = [];
if (viewMode === 'tree') { const map = {};
const map = {}; const roots = [];
const roots = []; filtered.forEach(r => { map[r.id] = { ...r, children: [] }; });
filtered.forEach(r => { map[r.id] = { ...r, children: [] }; });
filtered.forEach(r => { filtered.forEach(r => {
const node = map[r.id]; const node = map[r.id];
if (node.parentId && map[node.parentId]) { if (node.parentId && map[node.parentId]) {
map[node.parentId].children.push(node); map[node.parentId].children.push(node);
} else { } else {
roots.push(node); roots.push(node);
} }
}); });
const flatten = (nodes, depth) => { const flatten = (nodes, depth) => {
nodes.forEach(n => { nodes.forEach(n => {
let indentHtml = ''; let indentHtml = '';
for(let i = 0; i < depth; i++) { for(let i = 0; i < depth; i++) {
indentHtml += '<span style="display:inline-block; width: 1.5rem;"></span>'; indentHtml += '<span style="display:inline-block; width: 1.5rem;"></span>';
} }
if (depth > 0) { if (depth > 0) {
indentHtml += '<i class="fa-solid fa-turn-up fa-rotate-90 text-muted me-2"></i>'; indentHtml += '<i class="fa-solid fa-turn-up fa-rotate-90 text-muted me-2"></i>';
} }
n.indentHtml = indentHtml; n.indentHtml = indentHtml;
finalRenderList.push(n); finalRenderList.push(n);
if (n.children.length > 0) { if (n.children.length > 0) {
flatten(n.children, depth + 1); flatten(n.children, depth + 1);
} }
}); });
}; };
flatten(roots, 0); flatten(roots, 0);
} else {
finalRenderList = filtered.map(r => ({ ...r, indentHtml: '' }));
}
$.scope.resources.empty(); $.scope.resources.empty();
for (const r of finalRenderList) { for (const r of finalRenderList) {