Improve settings hierarchy conciseness
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{% load static %}
|
||||
{% load cache %}
|
||||
{% load page_title %}
|
||||
{% load accessibility %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
@@ -290,10 +291,26 @@
|
||||
.osint-search-form .button.is-fullwidth {
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-dropdown .navbar-item.is-current-route {
|
||||
background-color: rgba(50, 115, 220, 0.14) !important;
|
||||
color: #1f4f99 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.security-page-tabs a {
|
||||
transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;
|
||||
}
|
||||
.reduced-motion,
|
||||
.reduced-motion * {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% get_accessibility_settings request.user as a11y_settings %}
|
||||
<body{% if a11y_settings and a11y_settings.disable_animations %} class="reduced-motion"{% endif %}>
|
||||
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
@@ -343,6 +360,31 @@
|
||||
<a class="navbar-item" href="{% url 'ai_workspace' %}">
|
||||
AI
|
||||
</a>
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link">
|
||||
Security
|
||||
</a>
|
||||
<div class="navbar-dropdown">
|
||||
<a
|
||||
class="navbar-item{% if request.resolver_match.url_name == 'encryption_settings' or request.resolver_match.url_name == 'security_settings' %} is-current-route{% endif %}"
|
||||
href="{% url 'encryption_settings' %}"
|
||||
>
|
||||
Encryption
|
||||
</a>
|
||||
<a
|
||||
class="navbar-item{% if request.resolver_match.url_name == 'permission_settings' %} is-current-route{% endif %}"
|
||||
href="{% url 'permission_settings' %}"
|
||||
>
|
||||
Permission
|
||||
</a>
|
||||
<a
|
||||
class="navbar-item{% if request.resolver_match.url_name == 'security_2fa' or request.resolver_match.namespace == 'two_factor' %} is-current-route{% endif %}"
|
||||
href="{% url 'security_2fa' %}"
|
||||
>
|
||||
2FA
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="navbar-item" href="{% url 'osint_search' type='page' %}">
|
||||
Search
|
||||
</a>
|
||||
@@ -400,38 +442,47 @@
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown">
|
||||
<a class="navbar-item" href="{% url 'security_settings' %}">
|
||||
Security
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'two_factor:profile' %}">
|
||||
2FA
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'notifications_update' type='page' %}">
|
||||
<div class="navbar-item has-text-weight-semibold is-size-7 has-text-grey">
|
||||
General
|
||||
</div>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'notifications_settings' or request.resolver_match.url_name == 'notifications_update' %} is-current-route{% endif %}" href="{% url 'notifications_settings' %}">
|
||||
Notifications
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'ais' type='page' %}">
|
||||
Models
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'command_routing' %}">
|
||||
Command Routing
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'tasks_settings' %}">
|
||||
Task Settings
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'availability_settings' %}">
|
||||
Availability
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'translation_settings' %}">
|
||||
Translation
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'ai_execution_log' %}">
|
||||
AI Execution Log
|
||||
</a>
|
||||
{% if user.is_superuser %}
|
||||
<a class="navbar-item" href="{% url 'system_settings' %}">
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'system_settings' %} is-current-route{% endif %}" href="{% url 'system_settings' %}">
|
||||
System
|
||||
</a>
|
||||
{% endif %}
|
||||
<hr class="navbar-divider">
|
||||
<div class="navbar-item has-text-weight-semibold is-size-7 has-text-grey">
|
||||
AI
|
||||
</div>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'ai_models' or request.resolver_match.url_name == 'ais' %} is-current-route{% endif %}" href="{% url 'ai_models' %}">
|
||||
Models
|
||||
</a>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'ai_execution_log' %} is-current-route{% endif %}" href="{% url 'ai_execution_log' %}">
|
||||
Traces
|
||||
</a>
|
||||
<hr class="navbar-divider">
|
||||
<div class="navbar-item has-text-weight-semibold is-size-7 has-text-grey">
|
||||
Modules
|
||||
</div>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'command_routing' %} is-current-route{% endif %}" href="{% url 'command_routing' %}">
|
||||
Commands
|
||||
</a>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'tasks_settings' %} is-current-route{% endif %}" href="{% url 'tasks_settings' %}">
|
||||
Tasks
|
||||
</a>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'translation_settings' %} is-current-route{% endif %}" href="{% url 'translation_settings' %}">
|
||||
Translation
|
||||
</a>
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'availability_settings' %} is-current-route{% endif %}" href="{% url 'availability_settings' %}">
|
||||
Availability
|
||||
</a>
|
||||
<hr class="navbar-divider">
|
||||
<a class="navbar-item{% if request.resolver_match.url_name == 'accessibility_settings' %} is-current-route{% endif %}" href="{% url 'accessibility_settings' %}">
|
||||
Accessibility
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -682,8 +733,9 @@
|
||||
</script>
|
||||
{% block outer_content %}
|
||||
{% endblock %}
|
||||
<section class="section">
|
||||
<div>
|
||||
<div class="container">
|
||||
{% include "partials/settings-hierarchy-nav.html" %}
|
||||
{% block content_wrapper %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
@@ -695,6 +747,6 @@
|
||||
<div id="widgets-here" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
61
core/templates/mixins/window-content/objects.html
Normal file
61
core/templates/mixins/window-content/objects.html
Normal file
@@ -0,0 +1,61 @@
|
||||
{% include 'mixins/partials/notify.html' %}
|
||||
{% if page_title is not None %}
|
||||
<h1 class="title is-4">{{ page_title }}</h1>
|
||||
{% endif %}
|
||||
{% if page_subtitle is not None %}
|
||||
<h1 class="subtitle">{{ page_subtitle }}</h1>
|
||||
{% endif %}
|
||||
<div class="buttons">
|
||||
|
||||
{% if submit_url is not None %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{{ submit_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</span>
|
||||
<span>{{ title_singular }}</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if delete_all_url is not None %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-delete="{{ delete_all_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
hx-swap="innerHTML"
|
||||
hx-confirm="Are you sure you wish to delete all {{ context_object_name }}?"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</span>
|
||||
<span>Delete all {{ context_object_name }} </span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% for button in extra_buttons %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-{{ button.method }}="{{ button.url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
hx-swap="innerHTML"
|
||||
{% if button.confirm %}hx-confirm="Are you sure you wish to {{ button.action }}?"{% endif %}
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ button.icon }}"></i>
|
||||
</span>
|
||||
<span>{{ button.label }}</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% include list_template %}
|
||||
25
core/templates/pages/accessibility-settings.html
Normal file
25
core/templates/pages/accessibility-settings.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title is-4">Accessibility</h1>
|
||||
<div class="box">
|
||||
<h2 class="title is-6">Motion</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="field">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="disable_animations"{% if accessibility_settings.disable_animations %} checked{% endif %}>
|
||||
Disable animations
|
||||
</label>
|
||||
<p class="help is-size-7 has-text-grey mt-1">
|
||||
Reduces motion by disabling most transitions and animations across the interface.
|
||||
</p>
|
||||
</div>
|
||||
<button class="button is-link is-small" type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,13 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<div>
|
||||
<h1 class="title is-4">AI Execution Log</h1>
|
||||
<h1 class="title is-4">Traces</h1>
|
||||
<p class="subtitle is-6">Tracked model calls and usage metrics for this account.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,6 +157,7 @@
|
||||
<table class="table is-fullwidth is-size-7 is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Started</th>
|
||||
<th>Status</th>
|
||||
<th>Operation</th>
|
||||
@@ -173,6 +172,22 @@
|
||||
<tbody>
|
||||
{% for run in runs %}
|
||||
<tr>
|
||||
<td>
|
||||
<button
|
||||
class="button is-small is-light trace-run-expand"
|
||||
type="button"
|
||||
data-detail-row="trace-run-detail-{{ run.id }}"
|
||||
data-detail-content="trace-run-detail-content-{{ run.id }}"
|
||||
data-expanded-label="Hide"
|
||||
data-collapsed-label="Show"
|
||||
hx-get="{% url 'ai_execution_run_detail' run_id=run.id %}"
|
||||
hx-target="#trace-run-detail-content-{{ run.id }}"
|
||||
hx-swap="innerHTML"
|
||||
hx-trigger="click once"
|
||||
>
|
||||
Show
|
||||
</button>
|
||||
</td>
|
||||
<td>{{ run.started_at }}</td>
|
||||
<td>
|
||||
{% if run.status == "ok" %}
|
||||
@@ -197,14 +212,90 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="trace-run-detail-{{ run.id }}" class="is-hidden">
|
||||
<td colspan="10">
|
||||
<div id="trace-run-detail-content-{{ run.id }}" class="trace-run-detail-shell is-size-7 has-text-grey">
|
||||
Click Show to load run details.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="9">No runs yet.</td></tr>
|
||||
<tr><td colspan="10">No runs yet.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
(function () {
|
||||
document.querySelectorAll(".trace-run-expand").forEach(function (button) {
|
||||
button.addEventListener("click", function () {
|
||||
const rowId = String(button.getAttribute("data-detail-row") || "");
|
||||
const row = rowId ? document.getElementById(rowId) : null;
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
const isHidden = row.classList.contains("is-hidden");
|
||||
row.classList.toggle("is-hidden", !isHidden);
|
||||
button.textContent = isHidden
|
||||
? String(button.getAttribute("data-expanded-label") || "Hide")
|
||||
: String(button.getAttribute("data-collapsed-label") || "Show");
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
const trigger = event.target.closest(".trace-run-tab-trigger");
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
const shell = trigger.closest(".trace-run-detail-tabs");
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
const targetName = String(trigger.getAttribute("data-tab-target") || "");
|
||||
if (!targetName) {
|
||||
return;
|
||||
}
|
||||
shell.querySelectorAll(".trace-run-tab-trigger").forEach(function (item) {
|
||||
item.parentElement.classList.toggle("is-active", item === trigger);
|
||||
});
|
||||
shell.querySelectorAll(".trace-run-tab-panel").forEach(function (panel) {
|
||||
const isActive = panel.getAttribute("data-tab-panel") === targetName;
|
||||
panel.classList.toggle("is-hidden", !isActive);
|
||||
});
|
||||
|
||||
const lazyUrl = String(trigger.getAttribute("data-lazy-url") || "");
|
||||
if (!lazyUrl) {
|
||||
return;
|
||||
}
|
||||
const panel = shell.querySelector(
|
||||
'.trace-run-tab-panel[data-tab-panel="' + targetName + '"]'
|
||||
);
|
||||
if (!panel || panel.getAttribute("data-loaded") === "1") {
|
||||
return;
|
||||
}
|
||||
panel.setAttribute("data-loaded", "1");
|
||||
panel.classList.add("is-loading");
|
||||
fetch(lazyUrl, { credentials: "same-origin" })
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error("tab load failed");
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(function (html) {
|
||||
panel.innerHTML = html;
|
||||
})
|
||||
.catch(function () {
|
||||
panel.innerHTML =
|
||||
'<p class="has-text-danger">Unable to load this tab.</p>';
|
||||
})
|
||||
.finally(function () {
|
||||
panel.classList.remove("is-loading");
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title is-4">Security</h1>
|
||||
|
||||
{% if show_encryption %}
|
||||
<div class="columns is-desktop is-variable is-8">
|
||||
<div class="column">
|
||||
<div class="box">
|
||||
@@ -102,7 +101,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_permission %}
|
||||
<div class="box">
|
||||
<h2 class="title is-6">Global Scope Override</h2>
|
||||
<p class="is-size-7 has-text-grey mb-3">
|
||||
@@ -194,14 +195,24 @@
|
||||
<label class="label is-size-7 mb-1">Require OMEMO</label>
|
||||
<div class="is-flex is-align-items-center" style="gap:0.5rem;">
|
||||
<span class="tag is-size-7" data-global-mode-label="require_omemo"></span>
|
||||
<button type="button" class="button is-small is-light" data-global-change-toggle="require_omemo">Change Global</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-small is-light"
|
||||
data-global-change-toggle="require_omemo"
|
||||
{% if security_settings.require_omemo %}disabled title="Disable 'Require OMEMO encryption' in Encryption settings to edit this override."{% endif %}
|
||||
>
|
||||
Change Global
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons has-addons is-hidden" data-global-mode-picker="require_omemo">
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="per_scope">Per Scope</button>
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="on">Force On</button>
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="off">Force Off</button>
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="per_scope"{% if security_settings.require_omemo %} disabled{% endif %}>Per Scope</button>
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="on"{% if security_settings.require_omemo %} disabled{% endif %}>Force On</button>
|
||||
<button class="button is-small" type="button" data-global-mode-set="require_omemo" data-mode="off"{% if security_settings.require_omemo %} disabled{% endif %}>Force Off</button>
|
||||
</div>
|
||||
{% if security_settings.require_omemo %}
|
||||
<p class="help is-size-7 has-text-grey">Locked by Encryption setting: disable "Require OMEMO encryption" to edit this override.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="field mb-3">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center">
|
||||
@@ -263,7 +274,7 @@
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h2 class="title is-6">Command Security Scopes</h2>
|
||||
<h2 class="title is-6">Fine-Grained Security Scopes</h2>
|
||||
<p class="is-size-7 has-text-grey mb-3">
|
||||
Choose a top-level category, expand a scope, then click <strong>Change</strong> to edit that scope.
|
||||
</p>
|
||||
@@ -319,7 +330,7 @@
|
||||
<input class="scope-editable" data-lock-state="{% if row.enabled_locked %}locked{% else %}free{% endif %}" type="checkbox" name="policy_enabled"{% if row.enabled %} checked{% endif %}{% if row.enabled_locked %} disabled{% endif %}>
|
||||
Scope Enabled
|
||||
</label>
|
||||
<label class="checkbox mr-4" title="{% if row.require_omemo_locked %}{{ row.lock_help }}{% endif %}">
|
||||
<label class="checkbox mr-4" title="{% if row.require_omemo_locked %}{{ row.require_omemo_lock_help }}{% endif %}">
|
||||
<input class="scope-editable" data-lock-state="{% if row.require_omemo_locked %}locked{% else %}free{% endif %}" type="checkbox" name="policy_require_omemo"{% if row.require_omemo %} checked{% endif %}{% if row.require_omemo_locked %} disabled{% endif %}>
|
||||
Require OMEMO
|
||||
</label>
|
||||
@@ -380,7 +391,9 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_encryption %}
|
||||
<div class="box">
|
||||
<h2 class="title is-6">OMEMO Enablement Plan</h2>
|
||||
<p class="is-size-7 has-text-grey mb-3">Complete each step to achieve end-to-end encrypted messaging with the gateway.</p>
|
||||
@@ -402,6 +415,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
22
core/templates/pages/settings-category.html
Normal file
22
core/templates/pages/settings-category.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title is-4">{{ category_title }}</h1>
|
||||
<p class="subtitle is-6">{{ category_description }}</p>
|
||||
<div class="tabs is-boxed is-small mb-4 security-page-tabs">
|
||||
<ul>
|
||||
{% for tab in category_tabs %}
|
||||
<li class="{% if tab.active %}is-active{% endif %}">
|
||||
<a href="{{ tab.href }}">{{ tab.label }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<p class="is-size-7 has-text-grey">Choose a tab above to open settings in this category.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
7
core/templates/partials/ai-execution-run-detail-tab.html
Normal file
7
core/templates/partials/ai-execution-run-detail-tab.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% if tab_slug == "error" %}
|
||||
{% if run.error %}
|
||||
<pre style="white-space: pre-wrap; margin: 0;">{{ run.error }}</pre>
|
||||
{% else %}
|
||||
<p class="has-text-grey">No error recorded for this run.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
56
core/templates/partials/ai-execution-run-detail.html
Normal file
56
core/templates/partials/ai-execution-run-detail.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="trace-run-detail-tabs">
|
||||
<div class="tabs is-small is-toggle is-toggle-rounded mb-2">
|
||||
<ul>
|
||||
<li class="is-active">
|
||||
<a href="#" class="trace-run-tab-trigger" data-tab-target="summary">Summary</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="trace-run-tab-trigger" data-tab-target="identifiers">Identifiers</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="trace-run-tab-trigger" data-tab-target="usage">Usage</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="trace-run-tab-trigger"
|
||||
data-tab-target="error"
|
||||
data-lazy-url="{% url 'ai_execution_run_detail_tab' run_id=run.id tab_slug='error' %}"
|
||||
>Error</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="trace-run-tab-panel" data-tab-panel="summary">
|
||||
<table class="table is-fullwidth is-narrow is-size-7">
|
||||
<tbody>
|
||||
<tr><th>Status</th><td>{{ run.status|default:"-" }}</td></tr>
|
||||
<tr><th>Operation</th><td>{{ run.operation|default:"-" }}</td></tr>
|
||||
<tr><th>Model</th><td>{{ run.model|default:"-" }}</td></tr>
|
||||
<tr><th>Started</th><td>{{ run.started_at|default:"-" }}</td></tr>
|
||||
<tr><th>Finished</th><td>{{ run.finished_at|default:"-" }}</td></tr>
|
||||
<tr><th>Duration (ms)</th><td>{{ run.duration_ms|default:"-" }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="trace-run-tab-panel is-hidden" data-tab-panel="identifiers">
|
||||
<table class="table is-fullwidth is-narrow is-size-7">
|
||||
<tbody>
|
||||
<tr><th>Run ID</th><td>{{ run.id }}</td></tr>
|
||||
<tr><th>AI ID</th><td>{% if run.ai_id %}{{ run.ai_id }}{% else %}-{% endif %}</td></tr>
|
||||
<tr><th>Base URL</th><td><code>{{ run.base_url|default:"-" }}</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="trace-run-tab-panel is-hidden" data-tab-panel="usage">
|
||||
<table class="table is-fullwidth is-narrow is-size-7">
|
||||
<tbody>
|
||||
<tr><th>Message Count</th><td>{{ run.message_count }}</td></tr>
|
||||
<tr><th>Prompt Chars</th><td>{{ run.prompt_chars }}</td></tr>
|
||||
<tr><th>Response Chars</th><td>{{ run.response_chars }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="trace-run-tab-panel is-hidden" data-tab-panel="error" data-loaded="0">
|
||||
<p class="has-text-grey">Click the Error tab to load details.</p>
|
||||
</div>
|
||||
</div>
|
||||
12
core/templates/partials/settings-hierarchy-nav.html
Normal file
12
core/templates/partials/settings-hierarchy-nav.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{% if settings_nav %}
|
||||
<h1 class="title is-4">{{ settings_nav.title }}</h1>
|
||||
<div class="tabs is-boxed is-small mb-4 security-page-tabs">
|
||||
<ul>
|
||||
{% for tab in settings_nav.tabs %}
|
||||
<li class="{% if tab.active %}is-active{% endif %}">
|
||||
<a href="{{ tab.href }}">{{ tab.label }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -21,7 +21,7 @@
|
||||
{% endif %}
|
||||
|
||||
<form method="post">{% csrf_token %}{{ form }}
|
||||
<a href="{% url 'two_factor:profile'%}"
|
||||
<a href="{% url 'security_2fa' %}"
|
||||
class="float-right button">{% trans "Back to Account Security" %}</a>
|
||||
<button class="button" type="submit">{% trans "Generate Tokens" %}</button>
|
||||
</form>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
authentication.{% endblocktrans %}</p>
|
||||
|
||||
{% if not phone_methods %}
|
||||
<p class="subtitle"><a href="{% url 'two_factor:profile' %}"
|
||||
<p class="subtitle"><a href="{% url 'security_2fa' %}"
|
||||
class="button">{% trans "Back to Account Security" %}</a></p>
|
||||
{% else %}
|
||||
<p class="subtitle">{% blocktrans trimmed %}However, it might happen that you don't have access to
|
||||
your primary token device. To enable account recovery, add a phone
|
||||
number.{% endblocktrans %}</p>
|
||||
|
||||
<a href="{% url 'two_factor:profile' %}"
|
||||
<a href="{% url 'security_2fa' %}"
|
||||
class="float-right button">{% trans "Back to Account Security" %}</a>
|
||||
<p class="subtitle"><a href="{% url 'two_factor:phone_create' %}"
|
||||
class="button">{% trans "Add Phone Number" %}</a></p>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="title">{% block title %}{% trans "Account Security" %}{% endblock %}</h1>
|
||||
<h2 class="title is-5">{% block title %}{% trans "Account Security" %}{% endblock %}</h2>
|
||||
|
||||
{% if default_device %}
|
||||
{% if default_device_type == 'TOTPDevice' %}
|
||||
|
||||
Reference in New Issue
Block a user