Skip to content

Commit 473c6fe

Browse files
authored
Track the current browsing path in the browser URL (#1853)
Signed-off-by: Aayush Kumar <aayush214.kumar@gmail.com>
1 parent 2af8198 commit 473c6fe

File tree

4 files changed

+67
-74
lines changed

4 files changed

+67
-74
lines changed

scanpipe/templates/scanpipe/panels/codebase_tree_panel.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<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>
77
<i class="fas fa-chevron-right"></i>
88
</span>
9-
<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">
9+
<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 }}">
1010
<span class="icon is-small mr-2">
1111
<i class="fas fa-folder"></i>
1212
</span>
@@ -17,7 +17,7 @@
1717
<div id="dir-{{ node.path|slugify }}" class="ml-4 is-hidden" data-loaded="false"></div>
1818
{% endif %}
1919
{% else %}
20-
<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">
20+
<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 }}">
2121
<span class="icon is-small mr-2">
2222
<i class="far fa-file"></i>
2323
</span>

scanpipe/templates/scanpipe/panels/resource_table_panel.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{% load humanize %}
22
<div class="mb-4">
3-
<div class="has-text-weight-semibold is-flex is-align-items-center is-family-monospace">
3+
<div class="has-text-weight-semibold is-flex is-align-items-center">
44
{% if path_segments %}
55
<span id="resource-path" class="has-text-weight-medium">
66
{% spaceless %}
77
{% for subpath, segment in path_segments %}
88
{% if not forloop.first %}<span class="mx-1">/</span>{% endif %}
99
{% if not forloop.last %}
10-
<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>
10+
<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>
1111
{% else %}
1212
<span>{{ segment }}</span>
1313
{% endif %}
@@ -45,7 +45,7 @@
4545
{% endif %}
4646
</span>
4747
{% if resource.is_dir %}
48-
<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>
48+
<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>
4949
{% else %}
5050
<a href="{% url 'resource_detail' project.slug resource.path %}">{{ resource.name }}</a>
5151
{% endif %}
@@ -73,10 +73,10 @@
7373
{% if is_paginated %}
7474
<nav class="pagination is-centered mt-4" role="navigation">
7575
{% if page_obj.has_previous %}
76-
<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>
76+
<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>
7777
{% endif %}
7878
{% if page_obj.has_next %}
79-
<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>
79+
<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>
8080
{% endif %}
8181
<ul class="pagination-list">
8282
<li>

scanpipe/templates/scanpipe/resource_tree.html

Lines changed: 58 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -104,91 +104,83 @@
104104
</div>
105105
<div id="resizer" class="resizer"></div>
106106
<div id="right-pane" class="right-pane px-2">
107-
{% include "scanpipe/panels/resource_table_panel.html" %}
107+
{% if path %}
108+
<div hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}" hx-trigger="load" hx-target="this"></div>
109+
{% else %}
110+
{% include "scanpipe/panels/resource_table_panel.html" %}
111+
{% endif %}
108112
</div>
109113
</div>
110114
{% endblock %}
111115

112116
{% block scripts %}
113117
<script>
114-
document.body.addEventListener('htmx:afterSwap', function(evt) {
115-
if (evt.target && evt.target.id === 'right-pane') {
116-
if (typeof enableCopyToClipboard === 'function') {
117-
enableCopyToClipboard('.copy-to-clipboard');
118-
}
118+
document.body.addEventListener('htmx:afterSettle', function(evt) {
119+
if (typeof enableCopyToClipboard === 'function') {
120+
enableCopyToClipboard('.copy-to-clipboard');
119121
}
120122
});
121-
122-
// Tree functionality
123-
document.addEventListener("click", async function (e) {
124-
const chevron = e.target.closest("[data-chevron]");
125-
if (chevron) {
126-
const folderNode = chevron.closest("[data-folder]");
127-
const targetId = folderNode.dataset.target;
128-
const url = folderNode.dataset.url;
129-
const target = document.getElementById("dir-" + targetId);
130-
131-
if (target.dataset.loaded === "true") {
132-
target.classList.toggle("is-hidden");
133-
} else {
134-
target.classList.remove("is-hidden");
135-
const response = await fetch(url + "&tree_panel=true");
136-
target.innerHTML = await response.text();
137-
target.dataset.loaded = "true";
138-
htmx.process(target);
139-
}
140123

141-
chevron.classList.toggle("rotated");
142-
e.stopPropagation();
143-
return;
144-
}
124+
async function toggleFolderNode(folderNode, forceExpand = false) {
125+
const targetId = folderNode.dataset.target;
126+
const url = folderNode.dataset.url;
127+
const target = document.getElementById("dir-" + targetId);
128+
const chevron = folderNode.querySelector("[data-chevron]");
129+
130+
if (!target || !chevron) return;
145131

146-
const folderMeta = e.target.closest(".folder-meta");
147-
if (folderMeta) {
148-
const folderNode = folderMeta.closest("[data-folder]");
149-
if (folderNode && folderNode.dataset.target) {
150-
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
151-
folderNode.classList.add('is-current');
152-
const chevron = folderNode.querySelector("[data-chevron]");
153-
const target = document.getElementById("dir-" + folderNode.dataset.target);
154-
155-
if (target.classList.contains("is-hidden")) {
156-
target.classList.remove("is-hidden");
157-
chevron.classList.add("rotated");
158-
if (target.dataset.loaded !== "true") {
159-
const response = await fetch(folderNode.dataset.url + "&tree_panel=true");
160-
target.innerHTML = await response.text();
161-
target.dataset.loaded = "true";
162-
htmx.process(target);
163-
}
164-
}
132+
if (target.dataset.loaded === "true") {
133+
if (forceExpand) {
134+
target.classList.remove("is-hidden");
135+
chevron.classList.add("rotated");
136+
} else {
137+
target.classList.toggle("is-hidden");
138+
chevron.classList.toggle("rotated");
165139
}
140+
} else {
141+
target.classList.remove("is-hidden");
142+
const response = await fetch(url + "&tree_panel=true");
143+
target.innerHTML = await response.text();
144+
target.dataset.loaded = "true";
145+
htmx.process(target);
146+
chevron.classList.add("rotated");
166147
}
148+
}
167149

168-
const fileNode = e.target.closest(".is-file[data-file]");
169-
if (fileNode) {
170-
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
171-
fileNode.classList.add('is-current');
150+
async function expandToPath(path) {
151+
const parts = path.split('/').filter(Boolean);
152+
let current = "";
153+
for (const part of parts) {
154+
current = current ? current + "/" + part : part;
155+
const folderNode = document.querySelector(`[data-folder][data-path="${current}"]`);
156+
if (folderNode) await toggleFolderNode(folderNode, true);
157+
}
158+
const finalNode = document.querySelector(`[data-folder][data-path="${path}"], .is-file[data-file][data-path="${path}"]`);
159+
if (finalNode) {
160+
document.querySelectorAll('.is-current').forEach(el => el.classList.remove('is-current'));
161+
finalNode.classList.add('is-current');
162+
finalNode.scrollIntoView({ behavior: "smooth", block: "center" });
172163
}
164+
}
173165

174-
const expandLink = e.target.closest(".expand-in-tree");
175-
if (expandLink) {
176-
e.preventDefault();
177-
const path = expandLink.getAttribute("data-path");
178-
const leftPane = document.getElementById("left-pane");
179-
if (!leftPane) return;
180-
let node = leftPane.querySelector(`[data-folder][data-path="${path}"], .is-file[data-file][data-path="${path}"]`);
181-
if (node) {
182-
document.querySelectorAll('.tree-node.is-current, .is-file.is-current').forEach(el => el.classList.remove('is-current'));
183-
node.classList.add('is-current');
184-
const chevron = node.querySelector("[data-chevron]");
185-
if (chevron && !chevron.classList.contains("rotated")) chevron.click();
186-
node.scrollIntoView({behavior: "smooth", block: "center"});
187-
}
166+
document.addEventListener("click", async e => {
167+
const node = e.target.closest("[data-folder], .is-file[data-file], .expand-in-tree, [data-chevron]");
168+
if (!node) return;
169+
170+
e.preventDefault();
171+
if (node.matches("[data-chevron]")) {
172+
await toggleFolderNode(node.closest("[data-folder]"));
173+
} else if (node.matches("[data-folder], .is-file[data-file], .expand-in-tree")) {
174+
await expandToPath(node.dataset.path);
188175
}
189176
});
190177

191178
document.addEventListener("DOMContentLoaded", function() {
179+
const currentPath = "{{ path }}";
180+
if (currentPath) {
181+
expandToPath(currentPath);
182+
}
183+
192184
const resizer = document.getElementById('resizer');
193185
const leftPane = document.getElementById('left-pane');
194186
const rightPane = document.getElementById('right-pane');

scanpipe/views.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2767,9 +2767,10 @@ def get(self, request, *args, **kwargs):
27672767
slug = self.kwargs.get("slug")
27682768
project = get_object_or_404(Project, slug=slug)
27692769
path = request.GET.get("path", "")
2770+
parent_path = path if request.GET.get("tree_panel") == "true" else ""
27702771

27712772
children = (
2772-
project.codebaseresources.filter(parent_path=path)
2773+
project.codebaseresources.filter(parent_path=parent_path)
27732774
.with_has_children()
27742775
.only("id", "project_id", "path", "name", "type")
27752776
.order_by("type", "path")

0 commit comments

Comments
 (0)