Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scanpipe/templates/scanpipe/panels/codebase_tree_panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<span class="icon is-small chevron mr-1{% if not node.has_children %} is-invisible{% endif %} is-clickable is-flex is-align-items-center" data-chevron>
<i class="fas fa-chevron-right"></i>
</span>
<span class="is-flex is-align-items-center folder-meta is-clickable" data-folder-click hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ node.path }}" hx-target="#right-pane">
<span class="is-flex is-align-items-center folder-meta is-clickable" data-folder-click data-path="{{ node.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ node.path }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ node.path }}">
<span class="icon is-small mr-2">
<i class="fas fa-folder"></i>
</span>
Expand All @@ -17,7 +17,7 @@
<div id="dir-{{ node.path|slugify }}" class="ml-4 is-hidden" data-loaded="false"></div>
{% endif %}
{% else %}
<div class="tree-node-file is-flex is-align-items-center pl-5 is-clickable is-file" data-file data-path="{{ node.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ node.path }}" hx-target="#right-pane">
<div class="tree-node-file is-flex is-align-items-center pl-5 is-clickable is-file" data-file data-path="{{ node.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ node.path }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ node.path }}">
<span class="icon is-small mr-2">
<i class="far fa-file"></i>
</span>
Expand Down
10 changes: 5 additions & 5 deletions scanpipe/templates/scanpipe/panels/resource_table_panel.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{% load humanize %}
<div class="mb-4">
<div class="has-text-weight-semibold is-flex is-align-items-center is-family-monospace">
<div class="has-text-weight-semibold is-flex is-align-items-center">
{% if path_segments %}
<span id="resource-path" class="has-text-weight-medium">
{% spaceless %}
{% for subpath, segment in path_segments %}
{% if not forloop.first %}<span class="mx-1">/</span>{% endif %}
{% if not forloop.last %}
<a href="#" class="expand-in-tree has-text-link" data-path="{{ subpath }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ subpath }}" hx-target="#right-pane">{{ segment }}</a>
<a href="{% url 'codebase_resource_tree' project.slug %}?path={{ subpath }}" class="expand-in-tree has-text-link" data-path="{{ subpath }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ subpath }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ subpath }}">{{ segment }}</a>
{% else %}
<span>{{ segment }}</span>
{% endif %}
Expand Down Expand Up @@ -45,7 +45,7 @@
{% endif %}
</span>
{% if resource.is_dir %}
<a href="#" class="expand-in-tree" data-path="{{ resource.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ resource.path }}" hx-target="#right-pane">{{ resource.name }}</a>
<a href="{% url 'codebase_resource_tree' project.slug %}?path={{ resource.path }}" class="expand-in-tree" data-path="{{ resource.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ resource.path }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ resource.path }}">{{ resource.name }}</a>
{% else %}
<a href="{% url 'resource_detail' project.slug resource.path %}">{{ resource.name }}</a>
{% endif %}
Expand Down Expand Up @@ -73,10 +73,10 @@
{% if is_paginated %}
<nav class="pagination is-centered mt-4" role="navigation">
{% if page_obj.has_previous %}
<a class="pagination-previous" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}" hx-target="#right-pane">Previous</a>
<a class="pagination-previous" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% if page_obj.has_next %}
<a class="pagination-next" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}" hx-target="#right-pane">Next page</a>
<a class="pagination-next" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}">Next page</a>
{% endif %}
<ul class="pagination-list">
<li>
Expand Down
124 changes: 58 additions & 66 deletions scanpipe/templates/scanpipe/resource_tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,91 +104,83 @@
</div>
<div id="resizer" class="resizer"></div>
<div id="right-pane" class="right-pane px-2">
{% include "scanpipe/panels/resource_table_panel.html" %}
{% if path %}
<div hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}" hx-trigger="load" hx-target="this"></div>
{% else %}
{% include "scanpipe/panels/resource_table_panel.html" %}
{% endif %}
</div>
</div>
{% endblock %}

{% block scripts %}
<script>
document.body.addEventListener('htmx:afterSwap', function(evt) {
if (evt.target && evt.target.id === 'right-pane') {
if (typeof enableCopyToClipboard === 'function') {
enableCopyToClipboard('.copy-to-clipboard');
}
document.body.addEventListener('htmx:afterSettle', function(evt) {
if (typeof enableCopyToClipboard === 'function') {
enableCopyToClipboard('.copy-to-clipboard');
}
});

// Tree functionality
document.addEventListener("click", async function (e) {
const chevron = e.target.closest("[data-chevron]");
if (chevron) {
const folderNode = chevron.closest("[data-folder]");
const targetId = folderNode.dataset.target;
const url = folderNode.dataset.url;
const target = document.getElementById("dir-" + targetId);

if (target.dataset.loaded === "true") {
target.classList.toggle("is-hidden");
} else {
target.classList.remove("is-hidden");
const response = await fetch(url + "&tree_panel=true");
target.innerHTML = await response.text();
target.dataset.loaded = "true";
htmx.process(target);
}

chevron.classList.toggle("rotated");
e.stopPropagation();
return;
}
async function toggleFolderNode(folderNode, forceExpand = false) {
const targetId = folderNode.dataset.target;
const url = folderNode.dataset.url;
const target = document.getElementById("dir-" + targetId);
const chevron = folderNode.querySelector("[data-chevron]");

if (!target || !chevron) return;

const folderMeta = e.target.closest(".folder-meta");
if (folderMeta) {
const folderNode = folderMeta.closest("[data-folder]");
if (folderNode && folderNode.dataset.target) {
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
folderNode.classList.add('is-current');
const chevron = folderNode.querySelector("[data-chevron]");
const target = document.getElementById("dir-" + folderNode.dataset.target);

if (target.classList.contains("is-hidden")) {
target.classList.remove("is-hidden");
chevron.classList.add("rotated");
if (target.dataset.loaded !== "true") {
const response = await fetch(folderNode.dataset.url + "&tree_panel=true");
target.innerHTML = await response.text();
target.dataset.loaded = "true";
htmx.process(target);
}
}
if (target.dataset.loaded === "true") {
if (forceExpand) {
target.classList.remove("is-hidden");
chevron.classList.add("rotated");
} else {
target.classList.toggle("is-hidden");
chevron.classList.toggle("rotated");
}
} else {
target.classList.remove("is-hidden");
const response = await fetch(url + "&tree_panel=true");
target.innerHTML = await response.text();
target.dataset.loaded = "true";
htmx.process(target);
chevron.classList.add("rotated");
}
}

const fileNode = e.target.closest(".is-file[data-file]");
if (fileNode) {
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
fileNode.classList.add('is-current');
async function expandToPath(path) {
const parts = path.split('/').filter(Boolean);
let current = "";
for (const part of parts) {
current = current ? current + "/" + part : part;
const folderNode = document.querySelector(`[data-folder][data-path="${current}"]`);
if (folderNode) await toggleFolderNode(folderNode, true);
}
const finalNode = document.querySelector(`[data-folder][data-path="${path}"], .is-file[data-file][data-path="${path}"]`);
if (finalNode) {
document.querySelectorAll('.is-current').forEach(el => el.classList.remove('is-current'));
finalNode.classList.add('is-current');
finalNode.scrollIntoView({ behavior: "smooth", block: "center" });
}
}

const expandLink = e.target.closest(".expand-in-tree");
if (expandLink) {
e.preventDefault();
const path = expandLink.getAttribute("data-path");
const leftPane = document.getElementById("left-pane");
if (!leftPane) return;
let node = leftPane.querySelector(`[data-folder][data-path="${path}"], .is-file[data-file][data-path="${path}"]`);
if (node) {
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
node.classList.add('is-current');
const chevron = node.querySelector("[data-chevron]");
if (chevron && !chevron.classList.contains("rotated")) chevron.click();
node.scrollIntoView({behavior: "smooth", block: "center"});
}
document.addEventListener("click", async e => {
const node = e.target.closest("[data-folder], .is-file[data-file], .expand-in-tree, [data-chevron]");
if (!node) return;

e.preventDefault();
if (node.matches("[data-chevron]")) {
await toggleFolderNode(node.closest("[data-folder]"));
} else if (node.matches("[data-folder], .is-file[data-file], .expand-in-tree")) {
await expandToPath(node.dataset.path);
}
});

document.addEventListener("DOMContentLoaded", function() {
const currentPath = "{{ path }}";
if (currentPath) {
expandToPath(currentPath);
}

const resizer = document.getElementById('resizer');
const leftPane = document.getElementById('left-pane');
const rightPane = document.getElementById('right-pane');
Expand Down
3 changes: 2 additions & 1 deletion scanpipe/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2767,9 +2767,10 @@ def get(self, request, *args, **kwargs):
slug = self.kwargs.get("slug")
project = get_object_or_404(Project, slug=slug)
path = request.GET.get("path", "")
parent_path = path if request.GET.get("tree_panel") == "true" else ""

children = (
project.codebaseresources.filter(parent_path=path)
project.codebaseresources.filter(parent_path=parent_path)
.with_has_children()
.only("id", "project_id", "path", "name", "type")
.order_by("type", "path")
Expand Down