admin-redesign #26

Merged
eising merged 9 commits from admin-redesign into main 2025-06-19 05:24:06 +00:00
21 changed files with 641 additions and 267 deletions
Showing only changes of commit b4c395f0da - Show all commits

View File

@ -14,7 +14,7 @@
</sl-breadcrumb-item> </sl-breadcrumb-item>
{% if breadcrumbs %} {% if breadcrumbs %}
{% for label, url in breadcrumbs %} {% for label, url in breadcrumbs %}
<sl-breadcrumb-item> <sl-breadcrumb-item class="page-breadcrumb">
{% if url %} {% if url %}
<a href="{{url}}">{{label}}</a> <a href="{{url}}">{{label}}</a>
{% else %} {% else %}

View File

@ -11,9 +11,8 @@
<div id="clientdetails" class="w-full"> <div id="clientdetails" class="w-full">
<h3 class="mb-4 text-sm italic text-gray-400 dark:text-white">Click an item to view details</h3> <h3 class="mb-4 text-sm italic text-gray-400 dark:text-white">Click an item to view details</h3>
</div> </div>
{% endblock %}
{% include '/clients/partials/drawer_create.html.j2' %} {% include '/clients/partials/drawer_create.html.j2' %}
{% endblock %}
{% block local_scripts %} {% block local_scripts %}
<script> <script>

View File

@ -47,36 +47,18 @@
{% endmacro %} {% endmacro %}
{% extends "/dashboard/_base.html" %} {% block content %} {% extends 'base/master-detail-email.html.j2' %}
<div class="p-4 bg-white block sm:flex items-center justify-between border-b border-gray-200 lg:mt-1.5 dark:bg-gray-800 dark:border-gray-700"> {% block title %}Secrets{% endblock %}
<div class="w-full mb-1">
<div class="mb-4">
<nav class="flex mb-5" aria-label="Breadcrumb"> {% block master %}
<ol class="inline-flex items-center space-x-1 text-sm font-medium md:space-x-2">
<li class="inline-flex items-center"> <div class="flowbite-init-target">
<a href="/" class="inline-flex items-center text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-white"> <div class="tree-header grid grid-cols-2 place-content-between mb-6">
<svg class="w-5 h-5 mr-2.5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"></path></svg>
Home
</a>
</li>
<li>
<div class="flex items-center">
<svg class="w-6 h-6 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path></svg>
<span class="ml-1 text-gray-400 md:ml-2 dark:text-gray-500" aria-current="page">Secrets</span>
</div>
</li>
</ol>
</nav>
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">Secrets</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">Secrets</h1>
</div> </div>
<div id="secret-tree">
<div class="grid w-full grid-cols-1 gap-4 mt-4 xl:grid-cols-3">
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm sm:flex dark:border-gray-700 sm:p-6 dark:bg-gray-800" id="secret-tree">
<div class="flex flex-1 flex-col">
<div class="h-full w-full">
<sl-tree class="tree-with-icons"> <sl-tree class="tree-with-icons">
<sl-tree-item <sl-tree-item
id="secret-group-root-item" id="secret-group-root-item"
@ -103,8 +85,9 @@
</div> </div>
</div> </div>
</div> {% endblock %}
<div class="2xl:col-span-2 xl:col-span-2 p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
{% block detail %}
{% if group_page | default(false) %} {% if group_page | default(false) %}
<div class="w-full" id="secretdetails"> <div class="w-full" id="secretdetails">
{% include '/secrets/partials/group_detail.html.j2' %} {% include '/secrets/partials/group_detail.html.j2' %}
@ -121,11 +104,13 @@
{% include '/secrets/partials/default_detail.html.j2' %} {% include '/secrets/partials/default_detail.html.j2' %}
{% endif %} {% endif %}
</div> {% endblock %}
</div>
</div>
</div> {% block local_scripts %}
<script> <script>
{% include '/secrets/partials/tree_event.js' %} {% include '/secrets/partials/tree_event.js' %}
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,61 @@
document.addEventListener("DOMContentLoaded", () => { function createCrumb(name, url = null) {
// Create a breadcrumb
const crumb = document.createElement("sl-breadcrumb-item");
crumb.classList.add("page-breadcrumb");
if (url) {
var crumbChild = document.createElement("a");
crumbChild.setAttribute("href", url);
const crumbChildText = document.createTextNode(name);
crumbChild.appendChild(crumbChildText);
} else {
var crumbChild = document.createTextNode(name);
}
crumb.appendChild(crumbChild);
return crumb;
}
function setGroupBreadcrumbs(name, path, secret = null) {
// Set breadcrumbs for a whole group.
const breadcrumbs = document.getElementById("breadcrumbs");
// First, remove all existing page breadcrumbs
console.log(`setGroupBreadcrumbs: ${name} ${path}`);
let pageCrumbs = document.getElementsByClassName("page-breadcrumb");
for (let i = 0; i < pageCrumbs.length; i++) {
breadcrumbs.removeChild(pageCrumbs[i]);
}
// Re-create the breadcrumbs
const newcrumbs = [
["Secrets", "/secrets/"],
["Groups", "/secrets/groups/"],
];
if (path) {
const pathnodes = path.split("/");
for (let i = 0; i < pathnodes.length; i++) {
let pathnode = pathnodes[i];
let nextnode = i + 1;
let groupPathNodes = pathnodes.slice(0, nextnode);
let groupPath = groupPathNodes.join("/");
newcrumbs.push([pathnode, `/secrets/groups/${groupPath}`]);
}
} else {
newcrumbs.push(["Ungrouped", "/secrets/groups/"]);
}
if (secret) {
newcrumbs.push([secret, `/secrets/secret/${secret}`]);
}
for (let i = 0; i < newcrumbs.length; i++) {
let crumbParam = newcrumbs[i];
let newcrumb = createCrumb(crumbParam[0], crumbParam[1]);
breadcrumbs.appendChild(newcrumb);
}
}
function addTreeListener() {
const tree = document.querySelector("sl-tree"); const tree = document.querySelector("sl-tree");
if (!tree) return; if (!tree) return;
@ -33,4 +90,12 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
} }
}); });
}
document.addEventListener("DOMContentLoaded", () => {
addTreeListener();
});
document.addEventListener("htmx:afterSwap", () => {
addTreeListener();
}); });

View File

@ -63,12 +63,14 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)], admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
current_user: Annotated[LocalUserInfo, Depends(dependencies.get_user_info)], current_user: Annotated[LocalUserInfo, Depends(dependencies.get_user_info)],
): ):
breadcrumbs = [("secrets", "/secrets/")]
groups = await admin.get_secret_groups() groups = await admin.get_secret_groups()
return templates.TemplateResponse( return templates.TemplateResponse(
request, request,
"secrets/index.html.j2", "secrets/index.html.j2",
{ {
"groups": groups, "groups": groups,
"breadcrumbs": breadcrumbs,
"user": current_user, "user": current_user,
"selected_group": None, "selected_group": None,
"group_path_nodes": ["/"], "group_path_nodes": ["/"],
@ -83,8 +85,15 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
): ):
"""Show the root path.""" """Show the root path."""
clients = await admin.get_clients() clients = await admin.get_clients()
breadcrumbs = [
("secrets", "/secrets/"),
("groups", "/secrets/groups/"),
("Ungrouped", "/secrets/groups/"),
]
context: dict[str, Any] = { context: dict[str, Any] = {
"clients": clients, "clients": clients,
"breadcrumbs": breadcrumbs,
"root_group_page": True, "root_group_page": True,
} }
headers: dict[str, str] = {} headers: dict[str, str] = {}
@ -119,11 +128,20 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
) )
clients = await admin.get_clients() clients = await admin.get_clients()
breadcrumbs = [("secrets", "/secrets/"), ("groups", "/secrets/groups/")]
path_nodes = group.path.split("/")
for x in range(len(path_nodes)):
next_node = x + 1
group_path = "/".join(path_nodes[:next_node])
crumb_path = os.path.join("/secrets", group_path)
breadcrumbs.append((path_nodes[x], crumb_path))
headers: dict[str, str] = {} headers: dict[str, str] = {}
context: dict[str, Any] = { context: dict[str, Any] = {
"group_page": True, "group_page": True,
"group": group, "group": group,
"clients": clients, "clients": clients,
"breadcrumbs": breadcrumbs,
} }
if request.headers.get("HX-Request"): if request.headers.get("HX-Request"):
# This is a HTMX request. # This is a HTMX request.