Rebuild workspace widgets and behavioral graph views
This commit is contained in:
@@ -43,7 +43,7 @@
|
||||
<link rel="preload" href="{% static 'vendor/fontawesome/webfonts/fa-regular-400.woff2' %}" as="font" type="font/woff2" integrity="sha512-qioT43fXB5q4Bbpn8sPQE9OIZLjKD0c0lVmpm6KmT8k34LM6gkRcOOMi1BOl2lohFG/7p9tzKfTP5G563BQq1g==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{% static 'css/bulma.min.css' %}" integrity="sha512-yh2RE0wZCVZeysGiqTwDTO/dKelCbS9bP2L94UvOFtl/FKXcNAje3Y2oBg/ZMZ3LS1sicYk4dYVGtDex75fvvA==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{% static 'vendor/fontawesome/css/all.css' %}" integrity="sha512-UKBBxJ5N3/MYiSsYTlEsARsp4vELKVRIklED4Mb6wpuVFOgy5Blt+sXUdz1TDReqWsm64xxBA2QoBJRCxI0x5Q==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{% static 'css/gia-theme.css' %}" integrity="sha512-17wNDv0gA1saxAIzoySMcOef4/8dKEo2eZcWGhVHUjKolxhbfYVia9i/wExDqEw8MhfP4Kk8BrMajcOHngqJJg==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{% static 'css/gia-theme.css' %}" integrity="sha512-Lnmy74rBeyPt8DwWBqsRj9hFqTXuXZqkIgIeIm+inhoXpOfGjsvlealaDwRNVv/ou0Bta6h/RmOkjOJYOkALCw==" crossorigin="anonymous">
|
||||
{% block extra_head_assets %}{% endblock %}
|
||||
<script src="{% static 'js/htmx.min.js' %}" integrity="sha512-CGXFnDNv5q48ciFeIyWFcfZhqYW0sSBiPO+HZDO3XLM+p8xjhezz5CCxtkXVDKfCbvF+iUhel7xoeSp19o7x7g==" crossorigin="anonymous"></script>
|
||||
<script defer src="{% static 'js/remove-me.js' %}" integrity="sha512-uhE4kDw2+tXdJPDKSttOEYhVnwYq310+d5DMQnTjafJ58QLlYPyx0RTCNbjcrTiGfCjAhaQob4AumEUa2m3TaQ==" crossorigin="anonymous"></script>
|
||||
@@ -163,6 +163,49 @@
|
||||
});
|
||||
});
|
||||
|
||||
var closeGiaDropdowns = function (exceptNode) {
|
||||
document.querySelectorAll(".dropdown[data-gia-dropdown].is-active").forEach(function (node) {
|
||||
if (exceptNode && node === exceptNode) {
|
||||
return;
|
||||
}
|
||||
node.classList.remove("is-active");
|
||||
var trigger = node.querySelector(".js-gia-dropdown-toggle");
|
||||
if (trigger) {
|
||||
trigger.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
var toggle = event.target.closest(".js-gia-dropdown-toggle");
|
||||
if (toggle) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var dropdown = toggle.closest(".dropdown[data-gia-dropdown]");
|
||||
if (!dropdown) {
|
||||
return;
|
||||
}
|
||||
var nextState = !dropdown.classList.contains("is-active");
|
||||
closeGiaDropdowns(nextState ? dropdown : null);
|
||||
dropdown.classList.toggle("is-active", nextState);
|
||||
toggle.setAttribute("aria-expanded", nextState ? "true" : "false");
|
||||
return;
|
||||
}
|
||||
if (!event.target.closest(".dropdown[data-gia-dropdown]")) {
|
||||
closeGiaDropdowns(null);
|
||||
return;
|
||||
}
|
||||
if (event.target.closest(".dropdown[data-gia-dropdown] .dropdown-item") && !event.target.closest("summary")) {
|
||||
closeGiaDropdowns(null);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape") {
|
||||
closeGiaDropdowns(null);
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener("htmx:afterRequest", function (event) {
|
||||
const detail = (event && event.detail) || null;
|
||||
const source = detail && detail.elt ? detail.elt : null;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
aria-label="Snap assistant">
|
||||
<p class="panel-heading gia-snap-assistant-heading">
|
||||
<span class="icon is-small"><i class="fa-solid fa-table-columns"></i></span>
|
||||
<span>Snap Right</span>
|
||||
<span class="gia-snap-assistant-title">Snap Right</span>
|
||||
<button
|
||||
type="button"
|
||||
class="delete is-small js-gia-snap-assistant-close"
|
||||
@@ -32,7 +32,7 @@
|
||||
</p>
|
||||
<div class="panel-block">
|
||||
<div class="content is-small">
|
||||
<p>Choose a second window for the right side.</p>
|
||||
<p class="gia-snap-assistant-message">Choose a second window for the right side.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block is-active gia-snap-assistant-body">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
data-gia-widget-shell="1"
|
||||
{% if widget_style_hrefs %}data-gia-style-hrefs="{{ widget_style_hrefs|join:'|' }}"{% endif %}
|
||||
{% if widget_script_srcs %}data-gia-script-srcs="{{ widget_script_srcs|join:'|' }}"{% endif %}>
|
||||
<div id="widget-{{ unique }}" class="grid-stack-item" {% block widget_options %}{% if widget_options is None %}gs-w="6" gs-h="1" gs-y="20" gs-x="0"{% else %}{% autoescape off %}{{ widget_options }}{% endautoescape %}{% endif %}{% endblock %}>
|
||||
<div id="widget-{{ unique }}" class="grid-stack-item" gs-id="widget-{{ unique }}" {% block widget_options %}{% if widget_options is None %}gs-w="6" gs-h="1" gs-y="20" gs-x="0"{% else %}{% autoescape off %}{{ widget_options }}{% endautoescape %}{% endif %}{% endblock %}>
|
||||
<div class="grid-stack-item-content">
|
||||
<section class="gia-widget-panel">
|
||||
<header class="gia-widget-heading">
|
||||
@@ -34,6 +34,14 @@
|
||||
aria-label="Snap window left">
|
||||
<span class="icon is-small"><i class="fa-solid fa-arrow-left"></i></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-gia-widget-action"
|
||||
data-gia-action="snap-top"
|
||||
data-gia-widget-id="widget-{{ unique }}"
|
||||
aria-label="Snap window top">
|
||||
<span class="icon is-small"><i class="fa-solid fa-arrow-up"></i></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-gia-widget-action"
|
||||
@@ -42,6 +50,14 @@
|
||||
aria-label="Snap window right">
|
||||
<span class="icon is-small"><i class="fa-solid fa-arrow-right"></i></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-gia-widget-action"
|
||||
data-gia-action="snap-bottom"
|
||||
data-gia-widget-id="widget-{{ unique }}"
|
||||
aria-label="Snap window bottom">
|
||||
<span class="icon is-small"><i class="fa-solid fa-arrow-down"></i></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-gia-widget-action"
|
||||
|
||||
@@ -1,98 +1,22 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="{{ workspace_url }}">AI Workspace</a></li>
|
||||
<li class="is-active"><a aria-current="page">Information</a></li>
|
||||
<li class="is-active"><a aria-current="page">MS / PS Information</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4" style="margin-bottom: 0.35rem;">Information: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">Commitment directionality and underlying metric factors from deterministic message-history snapshots.</p>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="information" %}
|
||||
</div>
|
||||
|
||||
<div class="column is-5">
|
||||
<div class="box">
|
||||
<p class="heading">Conversation Overview</p>
|
||||
{% if overview_rows %}
|
||||
{% for row in overview_rows %}
|
||||
<article class="message is-light" style="margin-bottom: 0.45rem;">
|
||||
<div class="message-body" style="padding: 0.45rem 0.55rem;">
|
||||
<p class="is-size-7 has-text-grey" style="margin-bottom: 0.12rem;">
|
||||
{{ row.group_title }}
|
||||
</p>
|
||||
<p style="margin-bottom: 0.3rem;">
|
||||
<strong>{{ row.title }}:</strong> {{ row.value|default:"-" }}
|
||||
</p>
|
||||
<a
|
||||
class="tag is-light"
|
||||
href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=row.slug %}">
|
||||
View Detail
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="is-size-7 has-text-grey">No conversation metadata available yet.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<p class="heading">Commitment Directionality</p>
|
||||
<p class="title is-5" style="margin-bottom: 0.35rem;">{{ directionality.direction_label }}</p>
|
||||
<p><strong>Commit In:</strong> {{ directionality.commit_in|default:"-" }}</p>
|
||||
<p><strong>Commit Out:</strong> {{ directionality.commit_out|default:"-" }}</p>
|
||||
<p><strong>Delta:</strong> {{ directionality.delta|default:"-" }}</p>
|
||||
<p><strong>Magnitude:</strong> {{ directionality.magnitude|default:"-" }}</p>
|
||||
<p><strong>Confidence:</strong> {{ directionality.confidence|default:"-" }}</p>
|
||||
<article class="message is-light" style="margin-top: 0.65rem;">
|
||||
<div class="message-body">
|
||||
{{ directionality.conclusion }}
|
||||
</div>
|
||||
</article>
|
||||
<div class="mb-4">
|
||||
<h1 class="title is-4 mb-1">MS / PS Information: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Current message-state and presence-state signals derived from timing data.
|
||||
</p>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="information" %}
|
||||
</div>
|
||||
{% include "partials/ai-workspace-behavioral-information.html" %}
|
||||
</div>
|
||||
|
||||
<div class="column is-7">
|
||||
<div class="box">
|
||||
<p class="heading">Factor Inputs</p>
|
||||
<div class="columns is-multiline" style="margin: 0 -0.2rem;">
|
||||
{% for factor in directionality.factors %}
|
||||
<div class="column is-12-mobile is-6-tablet" style="padding: 0.2rem;">
|
||||
<article class="box" style="margin-bottom: 0; border: 1px solid rgba(0, 0, 0, 0.14); box-shadow: none;">
|
||||
<p class="is-size-7 has-text-weight-semibold" style="margin-bottom: 0.2rem;">
|
||||
<span class="icon is-small"><i class="{{ factor.icon }}"></i></span>
|
||||
<span>{{ factor.title }}</span>
|
||||
</p>
|
||||
<p class="is-size-7"><strong>Weight:</strong> {{ factor.weight }}</p>
|
||||
<p class="is-size-7"><strong>Value:</strong> {{ factor.value|default:"-" }}</p>
|
||||
<p style="margin-top: 0.35rem;">
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=factor.slug %}">
|
||||
View Metric
|
||||
</a>
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<p class="heading">Linked Graphs</p>
|
||||
<div class="tags">
|
||||
{% for ref in directionality.graph_refs %}
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=ref.slug %}">
|
||||
{{ ref.title }}: {{ ref.value|default:"-" }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,113 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="{{ workspace_url }}">AI Workspace</a></li>
|
||||
<li><a href="{{ graphs_url }}">Insight Graphs</a></li>
|
||||
<li><a href="{{ graphs_url }}">Behavioral Graphs</a></li>
|
||||
<li class="is-active"><a aria-current="page">{{ metric.title }}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4" style="margin-bottom: 0.35rem;">{{ metric.title }}: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">Conversation {{ workspace_conversation.id }}</p>
|
||||
{% include "partials/ai-insight-nav.html" %}
|
||||
</div>
|
||||
<div class="column is-5">
|
||||
<div class="box">
|
||||
<p class="heading">{{ metric_group.title }}</p>
|
||||
<p class="title is-5" style="margin-bottom: 0.5rem;">{{ metric.title }}</p>
|
||||
<p><strong>Current Value:</strong> {{ metric_value|default:"-" }}</p>
|
||||
<p style="margin-top: 0.65rem;"><strong>How It Is Calculated</strong></p>
|
||||
<p>{{ metric.calculation }}</p>
|
||||
<p style="margin-top: 0.65rem;"><strong>Psychological Interpretation</strong></p>
|
||||
<p>{{ metric.psychology }}</p>
|
||||
{% if metric_psychology_hint %}
|
||||
<article class="message is-info is-light" style="margin-top: 0.75rem;">
|
||||
<div class="message-body">
|
||||
{{ metric_psychology_hint }}
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
<div class="mb-4">
|
||||
<h1 class="title is-4 mb-1">{{ metric.title }}: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Detailed MS/PS graph for this contact.
|
||||
</p>
|
||||
{% include "partials/ai-insight-nav.html" %}
|
||||
</div>
|
||||
{% include "partials/ai-workspace-behavioral-graph-detail.html" %}
|
||||
</div>
|
||||
<div class="column is-7">
|
||||
<div class="box">
|
||||
<p class="heading">History</p>
|
||||
{% if graph_applicable %}
|
||||
<div style="height: 360px;">
|
||||
<canvas id="metric-detail-chart"></canvas>
|
||||
</div>
|
||||
{% if not graph_points %}
|
||||
<p class="is-size-7 has-text-grey" style="margin-top: 0.65rem;">
|
||||
No historical points yet for this metric.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<article class="message is-light">
|
||||
<div class="message-body">
|
||||
This is a point-in-time metric and is not charted.
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ graph_points|json_script:"metric-detail-points" }}
|
||||
<script src="{% static 'js/chart.js' %}"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var node = document.getElementById("metric-detail-points");
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
var points = JSON.parse(node.textContent || "[]");
|
||||
var shouldRender = {{ graph_applicable|yesno:"true,false" }};
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
var labels = points.map(function(row) {
|
||||
var dt = new Date(row.x);
|
||||
return dt.toLocaleString();
|
||||
});
|
||||
var values = points.map(function(row) {
|
||||
return row.y;
|
||||
});
|
||||
var ctx = document.getElementById("metric-detail-chart");
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
new Chart(ctx.getContext("2d"), {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "{{ metric.title|escapejs }}",
|
||||
data: values,
|
||||
borderColor: "#3273dc",
|
||||
backgroundColor: "rgba(50,115,220,0.12)",
|
||||
borderWidth: 2,
|
||||
pointRadius: 2,
|
||||
tension: 0.28,
|
||||
spanGaps: true
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,129 +1,22 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="{{ workspace_url }}">AI Workspace</a></li>
|
||||
<li class="is-active"><a aria-current="page">Insight Graphs</a></li>
|
||||
<li class="is-active"><a aria-current="page">Behavioral Graphs</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4" style="margin-bottom: 0.35rem;">Insight Graphs: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Historical metrics for workspace {{ workspace_conversation.id }}. Points are range-downsampled server-side with high-resolution recent data and progressively sparser older ranges.
|
||||
</p>
|
||||
<div class="buttons are-small" style="margin: 0.5rem 0 0.25rem;">
|
||||
<a
|
||||
class="button {% if graph_density == 'low' %}is-dark{% else %}is-light{% endif %}"
|
||||
href="?density=low">
|
||||
Density: Low (max {{ graph_density_caps.low }})
|
||||
</a>
|
||||
<a
|
||||
class="button {% if graph_density == 'medium' %}is-dark{% else %}is-light{% endif %}"
|
||||
href="?density=medium">
|
||||
Density: Medium (max {{ graph_density_caps.medium }})
|
||||
</a>
|
||||
<a
|
||||
class="button {% if graph_density == 'high' %}is-dark{% else %}is-light{% endif %}"
|
||||
href="?density=high">
|
||||
Density: High (max {{ graph_density_caps.high }})
|
||||
</a>
|
||||
<div class="mb-4">
|
||||
<h1 class="title is-4 mb-1">Behavioral Graphs: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Rebuilt from message and event timing data using the MS/PS model rather than workspace snapshots.
|
||||
</p>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="graphs" %}
|
||||
</div>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="graphs" %}
|
||||
{% include "partials/ai-workspace-behavioral-graphs.html" %}
|
||||
</div>
|
||||
|
||||
{% for graph in graph_cards %}
|
||||
<div class="column is-6">
|
||||
<div class="box">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center" style="margin-bottom: 0.45rem;">
|
||||
<div>
|
||||
<p class="heading">{{ graph.group_title }}</p>
|
||||
<p class="title is-6" style="margin-bottom: 0.2rem;">{{ graph.title }}</p>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
{{ graph.count }} displayed of {{ graph.raw_count }} source point{{ graph.raw_count|pluralize }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="buttons are-small" style="margin: 0;">
|
||||
<a class="button is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=graph.slug %}">
|
||||
Detail
|
||||
</a>
|
||||
<a class="button is-light" href="{{ help_url }}#group-{{ graph.group }}">
|
||||
How It Works
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 250px;">
|
||||
<canvas id="graph-{{ graph.slug }}"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ graph_cards|json_script:"insight-graph-cards" }}
|
||||
<script src="{% static 'js/chart.js' %}"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var node = document.getElementById("insight-graph-cards");
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
var graphs = JSON.parse(node.textContent || "[]");
|
||||
var palette = ["#3273dc", "#23d160", "#ffdd57", "#ff3860", "#7957d5", "#00d1b2"];
|
||||
|
||||
graphs.forEach(function(graph, idx) {
|
||||
var canvas = document.getElementById("graph-" + graph.slug);
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
var labels = (graph.points || []).map(function(row) {
|
||||
return new Date(row.x).toLocaleString();
|
||||
});
|
||||
var values = (graph.points || []).map(function(row) {
|
||||
return row.y;
|
||||
});
|
||||
var color = palette[idx % palette.length];
|
||||
var yScale = {};
|
||||
if (graph.y_min !== null && graph.y_min !== undefined) {
|
||||
yScale.min = graph.y_min;
|
||||
}
|
||||
if (graph.y_max !== null && graph.y_max !== undefined) {
|
||||
yScale.max = graph.y_max;
|
||||
}
|
||||
new Chart(canvas.getContext("2d"), {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: graph.title,
|
||||
data: values,
|
||||
borderColor: color,
|
||||
backgroundColor: color + "33",
|
||||
borderWidth: 2,
|
||||
pointRadius: 2,
|
||||
tension: 0.24,
|
||||
spanGaps: true
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: yScale
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,58 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="{{ workspace_url }}">AI Workspace</a></li>
|
||||
<li><a href="{{ graphs_url }}">Insight Graphs</a></li>
|
||||
<li class="is-active"><a aria-current="page">Scoring Help</a></li>
|
||||
<li><a href="{{ graphs_url }}">Behavioral Graphs</a></li>
|
||||
<li class="is-active"><a aria-current="page">MS / PS Help</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="column is-12">
|
||||
<h1 class="title is-4" style="margin-bottom: 0.35rem;">Scoring Help: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Combined explanation for each metric collection group and what it can
|
||||
imply in relationship dynamics. Scoring is deterministic from message
|
||||
history and can be backfilled via metric history reconciliation.
|
||||
</p>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="help" %}
|
||||
</div>
|
||||
|
||||
{% for group_key, group in groups.items %}
|
||||
<div class="column is-12" id="group-{{ group_key }}">
|
||||
<div class="box">
|
||||
<p class="heading">{{ group.title }}</p>
|
||||
<p style="margin-bottom: 0.75rem;">{{ group.summary }}</p>
|
||||
|
||||
{% for metric in metrics %}
|
||||
{% if metric.group == group_key %}
|
||||
<article class="message is-light" style="margin-bottom: 0.6rem;">
|
||||
<div class="message-body">
|
||||
<h3 class="is-size-6 has-text-weight-semibold" style="margin-bottom: 0.45rem;">{{ metric.title }}</h3>
|
||||
|
||||
<p class="is-size-7 has-text-grey has-text-weight-semibold" style="margin-bottom: 0.15rem;">
|
||||
Current Value
|
||||
</p>
|
||||
<p style="margin-bottom: 0.55rem;">{{ metric.value|default:"-" }}</p>
|
||||
|
||||
<p class="is-size-7 has-text-grey has-text-weight-semibold" style="margin-bottom: 0.15rem;">
|
||||
How It Is Calculated
|
||||
</p>
|
||||
<p style="margin-bottom: 0.55rem;">{{ metric.calculation }}</p>
|
||||
|
||||
<p class="is-size-7 has-text-grey has-text-weight-semibold" style="margin-bottom: 0.15rem;">
|
||||
Psychological Interpretation
|
||||
</p>
|
||||
<p>{{ metric.psychology }}</p>
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<h1 class="title is-4 mb-1">MS / PS Help: {{ person.name }}</h1>
|
||||
<p class="is-size-7 has-text-grey">
|
||||
Definitions and psychological interpretation for the timing signal system.
|
||||
</p>
|
||||
{% include "partials/ai-insight-nav.html" with active_tab="help" %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% include "partials/ai-workspace-behavioral-help.html" %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
class="tag {% if active_tab == 'graphs' %}is-dark{% else %}is-link is-light{% endif %}"
|
||||
href="{{ graphs_url }}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-chart-line"></i></span>
|
||||
<span>Insight Graphs</span>
|
||||
<span>Behavioral Graphs</span>
|
||||
</a>
|
||||
<a
|
||||
class="tag {% if active_tab == 'information' %}is-dark{% else %}is-link is-light{% endif %}"
|
||||
href="{{ information_url }}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-circle-info"></i></span>
|
||||
<span>Information View</span>
|
||||
<span>MS / PS Information</span>
|
||||
</a>
|
||||
<a
|
||||
class="tag {% if active_tab == 'help' %}is-dark{% else %}is-link is-light{% endif %}"
|
||||
href="{{ help_url }}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-circle-question"></i></span>
|
||||
<span>Scoring Guide</span>
|
||||
<span>MS / PS Help</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="gia-behavior-shell">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap mb-3">
|
||||
<div>
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">{{ metric.state_label }} · {{ metric.group|upper }}</p>
|
||||
<h3 class="title is-5 mb-1">{{ metric.title }}</h3>
|
||||
<p class="is-size-7">{{ metric.calculation }}</p>
|
||||
</div>
|
||||
{% include "partials/behavioral-range-tabs.html" %}
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-12">
|
||||
{% include "partials/behavioral-graph-card.html" with graph=metric person=person graphs_widget_url=graphs_widget_url %}
|
||||
</div>
|
||||
<div class="column is-12-tablet is-6-desktop">
|
||||
<article class="message is-light">
|
||||
<div class="message-body">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">Psychological Reading</p>
|
||||
<p>{{ metric.psychology }}</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="column is-12-tablet is-6-desktop">
|
||||
<article class="message is-light">
|
||||
<div class="message-body">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">Coverage</p>
|
||||
<p class="mb-2">{{ coverage.message_count }} messages · {{ coverage.event_count }} events</p>
|
||||
<p class="is-size-7">Latest value: {{ metric.current_value_label }}</p>
|
||||
{% if metric.delta_label %}
|
||||
<p class="is-size-7">Latest shift: {{ metric.delta_label }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
36
core/templates/partials/ai-workspace-behavioral-graphs.html
Normal file
36
core/templates/partials/ai-workspace-behavioral-graphs.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div class="gia-behavior-shell">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap mb-3">
|
||||
<div>
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">Behavioral Graphs</p>
|
||||
<p class="mb-0">{{ coverage.message_count }} messages · {{ coverage.event_count }} events · {{ coverage.session_count }} sessions</p>
|
||||
</div>
|
||||
{% include "partials/behavioral-range-tabs.html" %}
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
{% for card in summary_cards %}
|
||||
<div class="column is-12-mobile is-6-tablet is-4-desktop">
|
||||
{% include "partials/behavioral-summary-card.html" with card=card %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for group_key, group in behavioral_groups.items %}
|
||||
<section class="mb-4">
|
||||
<div class="mb-3">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">{{ group.eyebrow }}</p>
|
||||
<h3 class="title is-5 mb-1">{{ group.title }}</h3>
|
||||
<p class="is-size-7">{{ group.summary }}</p>
|
||||
</div>
|
||||
<div class="columns is-multiline">
|
||||
{% for graph in graph_cards %}
|
||||
{% if graph.group == group_key %}
|
||||
<div class="column is-12-mobile is-6-desktop">
|
||||
{% include "partials/behavioral-graph-card.html" with graph=graph person=person graphs_widget_url=graphs_widget_url %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
33
core/templates/partials/ai-workspace-behavioral-help.html
Normal file
33
core/templates/partials/ai-workspace-behavioral-help.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<div class="gia-behavior-shell">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap mb-3">
|
||||
<div>
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">MS / PS Help</p>
|
||||
<p class="mb-0">Signal definitions and psychological interpretation for the timing system.</p>
|
||||
</div>
|
||||
{% include "partials/behavioral-range-tabs.html" %}
|
||||
</div>
|
||||
|
||||
{% for group_key, group in groups.items %}
|
||||
<section class="box mb-4">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">{{ group.eyebrow }}</p>
|
||||
<h3 class="title is-5 mb-2">{{ group.title }}</h3>
|
||||
<p class="mb-3">{{ group.summary }}</p>
|
||||
{% for metric in metrics %}
|
||||
{% if metric.group == group_key %}
|
||||
<article class="message is-light mb-3">
|
||||
<div class="message-body">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">{{ metric.state_label }}</p>
|
||||
<p class="title is-6 mb-2">
|
||||
<span class="icon is-small mr-1"><i class="{{ metric.icon }}"></i></span>
|
||||
<span>{{ metric.title }}</span>
|
||||
</p>
|
||||
<p class="mb-2"><strong>Current:</strong> {{ metric.current_value_label }}</p>
|
||||
<p class="mb-2"><strong>How it is calculated:</strong> {{ metric.calculation }}</p>
|
||||
<p><strong>What it can mean:</strong> {{ metric.psychology }}</p>
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
<div class="gia-behavior-shell">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap mb-3">
|
||||
<div>
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">MS / PS Information</p>
|
||||
<p class="mb-0">Current timing signals for {{ person.name }} across message state and presence state.</p>
|
||||
</div>
|
||||
{% include "partials/behavioral-range-tabs.html" %}
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
{% for card in summary_cards %}
|
||||
<div class="column is-12-mobile is-6-tablet is-4-desktop">
|
||||
{% include "partials/behavioral-summary-card.html" with card=card %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for group_key, group in behavioral_groups.items %}
|
||||
<section class="box mb-4">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">{{ group.eyebrow }}</p>
|
||||
<h3 class="title is-5 mb-2">{{ group.title }}</h3>
|
||||
<p class="mb-3">{{ group.summary }}</p>
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Metric</th>
|
||||
<th>Current</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for graph in graph_cards %}
|
||||
{% if graph.group == group_key %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=graph.slug %}?range={{ range_key }}">
|
||||
{{ graph.title }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ graph.current_value_label }}</td>
|
||||
<td>{{ graph.psychology }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -9,35 +9,18 @@
|
||||
<div style="margin-bottom: 0.75rem; padding: 0.5rem 0.25rem; border-bottom: 1px solid rgba(0, 0, 0, 0.12);">
|
||||
<p class="is-size-7 has-text-weight-semibold">Selected Person</p>
|
||||
<h3 class="title is-5" style="margin-bottom: 0.25rem;">{{ person.name }}</h3>
|
||||
<div class="tags" style="margin-top: 0.35rem;">
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='platform' %}">Platform {{ workspace_conversation.platform_type|title }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='thread' %}">Thread {{ workspace_conversation.platform_thread_id|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='workspace_created' %}">Workspace Created {{ workspace_conversation.created_at|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='stability_state' %}">Stability {{ workspace_conversation.stability_state|title }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='stability_score' %}">Stability Score {{ workspace_conversation.stability_score|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='stability_confidence' %}">Confidence {{ workspace_conversation.stability_confidence }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='sample_messages' %}">Sample Msg {{ workspace_conversation.stability_sample_messages }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='sample_days' %}">Sample Days {{ workspace_conversation.stability_sample_days }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='stability_computed' %}">Stability Computed {{ workspace_conversation.stability_last_computed_at|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='commitment_inbound' %}">Commit In {{ workspace_conversation.commitment_inbound_score|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='commitment_outbound' %}">Commit Out {{ workspace_conversation.commitment_outbound_score|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='commitment_confidence' %}">Commit Confidence {{ workspace_conversation.commitment_confidence }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='commitment_computed' %}">Commitment Computed {{ workspace_conversation.commitment_last_computed_at|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='last_event' %}">Last Event {{ workspace_conversation.last_event_ts|default:"-" }}</a>
|
||||
<a class="tag is-light" href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric='last_ai_run' %}">Last AI Run {{ workspace_conversation.last_ai_run_at|default:"-" }}</a>
|
||||
</div>
|
||||
<p class="is-size-7 has-text-grey" style="margin-top: 0.35rem; margin-bottom: 0;">
|
||||
Open MS / PS graphs, information, and help from the controls below.
|
||||
</p>
|
||||
<div class="buttons are-small" style="margin-top: 0.35rem; margin-bottom: 0;">
|
||||
<a class="button is-light" href="{% url 'ai_workspace_insight_graphs' type='page' person_id=person.id %}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-chart-line"></i></span>
|
||||
<span>Insight Graphs</span>
|
||||
</a>
|
||||
{% include "partials/behavioral-graph-launcher.html" with button_label="Graphs" show_widget_actions=behavioral_show_widget_actions default_widget_url=behavioral_graphs_widget_url default_page_url=behavioral_graphs_page_url graph_groups=behavioral_graph_groups %}
|
||||
<a class="button is-light" href="{% url 'ai_workspace_information' type='page' person_id=person.id %}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-circle-info"></i></span>
|
||||
<span>Information</span>
|
||||
<span>MS / PS</span>
|
||||
</a>
|
||||
<a class="button is-light" href="{% url 'ai_workspace_insight_help' type='page' person_id=person.id %}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-circle-question"></i></span>
|
||||
<span>Scoring Help</span>
|
||||
<span>Help</span>
|
||||
</a>
|
||||
</div>
|
||||
{% with participants=workspace_conversation.participants.all %}
|
||||
@@ -81,6 +64,7 @@
|
||||
id="ai-manual-widget-btn-{{ person.id }}"
|
||||
type="button"
|
||||
class="button is-light is-small js-widget-spawn-trigger is-hidden"
|
||||
data-gia-widget-id="{{ compose_widget_id }}"
|
||||
data-widget-url="{{ compose_widget_url }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{{ compose_widget_url }}"
|
||||
|
||||
71
core/templates/partials/behavioral-graph-card.html
Normal file
71
core/templates/partials/behavioral-graph-card.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<article class="card gia-behavior-graph-card">
|
||||
<header class="card-header">
|
||||
<div class="card-header-title is-flex is-justify-content-space-between is-align-items-flex-start">
|
||||
<div>
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">
|
||||
{{ graph.state_label }} · {{ graph.group|upper }}
|
||||
</p>
|
||||
<p class="mb-0">
|
||||
<span class="icon is-small mr-1"><i class="{{ graph.icon }}"></i></span>
|
||||
<span>{{ graph.title }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag is-light gia-badge">{{ graph.current_value_label }}</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<p class="is-size-7 has-text-grey mb-2">
|
||||
{{ graph.raw_count }} sample{{ graph.raw_count|pluralize }} in this range{% if graph.delta_label %} · {{ graph.delta_label }}{% endif %}
|
||||
</p>
|
||||
{% if graph.has_data %}
|
||||
<div class="gia-behavior-chart-shell">
|
||||
<svg
|
||||
class="gia-behavior-chart"
|
||||
viewBox="0 0 100 48"
|
||||
preserveAspectRatio="none"
|
||||
role="img"
|
||||
aria-label="{{ graph.title }} graph">
|
||||
{% if graph.area_path %}
|
||||
<path class="gia-behavior-chart-area" d="{{ graph.area_path }}"></path>
|
||||
{% endif %}
|
||||
{% if graph.polyline %}
|
||||
<polyline class="gia-behavior-chart-line" points="{{ graph.polyline }}"></polyline>
|
||||
{% endif %}
|
||||
{% for marker in graph.markers|slice:"-1:" %}
|
||||
<circle class="gia-behavior-chart-point" cx="{{ marker.x }}" cy="{{ marker.y }}" r="1.8"></circle>
|
||||
{% endfor %}
|
||||
</svg>
|
||||
<div class="is-flex is-justify-content-space-between is-size-7 has-text-grey mt-1">
|
||||
<span>{{ graph.y_min_label }}</span>
|
||||
<span>{{ graph.latest_bucket_label }}</span>
|
||||
<span>{{ graph.y_max_label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<article class="message is-light">
|
||||
<div class="message-body is-size-7">
|
||||
No samples for this metric in the selected range.
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
<p class="is-size-7 mt-3">{{ graph.psychology }}</p>
|
||||
<div class="buttons are-small mt-3 mb-0">
|
||||
<a
|
||||
class="button is-light"
|
||||
href="{% url 'ai_workspace_insight_detail' type='page' person_id=person.id metric=graph.slug %}?range={{ range_key }}">
|
||||
Page
|
||||
</a>
|
||||
{% if behavioral_show_widget_actions %}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-widget-spawn-trigger"
|
||||
data-widget-url="{% url 'ai_workspace_insight_detail' type='widget' person_id=person.id metric=graph.slug %}?range={{ range_key }}"
|
||||
hx-get="{% url 'ai_workspace_insight_detail' type='widget' person_id=person.id metric=graph.slug %}?range={{ range_key }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">
|
||||
Widget
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
71
core/templates/partials/behavioral-graph-launcher.html
Normal file
71
core/templates/partials/behavioral-graph-launcher.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<div class="dropdown is-right gia-split-dropdown" data-gia-dropdown>
|
||||
<div class="dropdown-trigger">
|
||||
<div class="buttons has-addons are-small mb-0">
|
||||
{% if show_widget_actions %}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-widget-spawn-trigger"
|
||||
data-widget-url="{{ default_widget_url }}"
|
||||
hx-get="{{ default_widget_url }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">
|
||||
<span class="icon is-small"><i class="fa-solid fa-chart-line"></i></span>
|
||||
<span>{{ button_label|default:"Graphs" }}</span>
|
||||
</button>
|
||||
{% else %}
|
||||
<a class="button is-light" href="{{ default_page_url }}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-chart-line"></i></span>
|
||||
<span>{{ button_label|default:"Graphs" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-light js-gia-dropdown-toggle"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="icon is-small"><i class="fa-solid fa-angle-down"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a class="dropdown-item" href="{{ default_page_url }}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-up-right-from-square"></i></span>
|
||||
<span>Page</span>
|
||||
</a>
|
||||
<hr class="dropdown-divider">
|
||||
<details class="gia-dropdown-nest">
|
||||
<summary class="dropdown-item">
|
||||
<span class="icon is-small"><i class="fa-solid fa-sliders"></i></span>
|
||||
<span>Custom Graph</span>
|
||||
</summary>
|
||||
<div class="gia-dropdown-nest-body">
|
||||
{% for group in graph_groups %}
|
||||
<p class="dropdown-item has-text-weight-semibold is-size-7 has-text-grey">
|
||||
{{ group.title }}
|
||||
</p>
|
||||
{% for item in group.items %}
|
||||
{% if show_widget_actions %}
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item js-widget-spawn-trigger"
|
||||
data-widget-url="{{ item.widget_url }}"
|
||||
hx-get="{{ item.widget_url }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">
|
||||
<span class="icon is-small"><i class="{{ item.icon }}"></i></span>
|
||||
<span>{{ item.title }}</span>
|
||||
</button>
|
||||
{% else %}
|
||||
<a class="dropdown-item" href="{{ item.page_url }}">
|
||||
<span class="icon is-small"><i class="{{ item.icon }}"></i></span>
|
||||
<span>{{ item.title }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
56
core/templates/partials/behavioral-range-tabs.html
Normal file
56
core/templates/partials/behavioral-range-tabs.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="tabs is-toggle is-small gia-inline-tabs">
|
||||
<ul>
|
||||
<li{% if range_key == "30d" %} class="is-active"{% endif %}>
|
||||
{% if behavioral_show_widget_actions %}
|
||||
<a
|
||||
class="button is-white is-small js-widget-spawn-trigger"
|
||||
href="{{ behavioral_range_urls.30d }}"
|
||||
data-widget-url="{{ behavioral_range_urls.30d }}"
|
||||
hx-get="{{ behavioral_range_urls.30d }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">30d</a>
|
||||
{% else %}
|
||||
<a href="{{ behavioral_range_urls.30d }}">30d</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li{% if range_key == "90d" %} class="is-active"{% endif %}>
|
||||
{% if behavioral_show_widget_actions %}
|
||||
<a
|
||||
class="button is-white is-small js-widget-spawn-trigger"
|
||||
href="{{ behavioral_range_urls.90d }}"
|
||||
data-widget-url="{{ behavioral_range_urls.90d }}"
|
||||
hx-get="{{ behavioral_range_urls.90d }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">90d</a>
|
||||
{% else %}
|
||||
<a href="{{ behavioral_range_urls.90d }}">90d</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li{% if range_key == "365d" %} class="is-active"{% endif %}>
|
||||
{% if behavioral_show_widget_actions %}
|
||||
<a
|
||||
class="button is-white is-small js-widget-spawn-trigger"
|
||||
href="{{ behavioral_range_urls.365d }}"
|
||||
data-widget-url="{{ behavioral_range_urls.365d }}"
|
||||
hx-get="{{ behavioral_range_urls.365d }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">1y</a>
|
||||
{% else %}
|
||||
<a href="{{ behavioral_range_urls.365d }}">1y</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li{% if range_key == "all" %} class="is-active"{% endif %}>
|
||||
{% if behavioral_show_widget_actions %}
|
||||
<a
|
||||
class="button is-white is-small js-widget-spawn-trigger"
|
||||
href="{{ behavioral_range_urls.all }}"
|
||||
data-widget-url="{{ behavioral_range_urls.all }}"
|
||||
hx-get="{{ behavioral_range_urls.all }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">All</a>
|
||||
{% else %}
|
||||
<a href="{{ behavioral_range_urls.all }}">All</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
18
core/templates/partials/behavioral-summary-card.html
Normal file
18
core/templates/partials/behavioral-summary-card.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<article class="message is-light gia-behavior-summary-card">
|
||||
<div class="message-body">
|
||||
<p class="is-size-7 has-text-weight-semibold has-text-grey mb-1">
|
||||
{{ card.state_label }} · {{ card.group|upper }}
|
||||
</p>
|
||||
<div class="is-flex is-align-items-center is-justify-content-space-between mb-2">
|
||||
<p class="title is-6 mb-0">
|
||||
<span class="icon is-small mr-1"><i class="{{ card.icon }}"></i></span>
|
||||
<span>{{ card.title }}</span>
|
||||
</p>
|
||||
<span class="tag is-light gia-badge">{{ card.current_value_label }}</span>
|
||||
</div>
|
||||
<p class="is-size-7 mb-1">{{ card.calculation }}</p>
|
||||
{% if card.delta_label %}
|
||||
<p class="is-size-7 has-text-grey">Latest shift: {{ card.delta_label }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</article>
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="box is-shadowless gia-send-composer p-2 m-0{% if composer_class %} {{ composer_class }}{% endif %}">
|
||||
<div class="field has-addons gia-send-composer-row">
|
||||
<div class="gia-send-composer m-0{% if composer_class %} {{ composer_class }}{% endif %}">
|
||||
<div class="field has-addons gia-send-composer-row mb-0">
|
||||
<div class="control is-expanded gia-send-composer-input-wrap">
|
||||
<textarea
|
||||
id="{{ textarea_id }}"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<div class="compose-row {% if msg.outgoing %}is-out{% else %}is-in{% endif %}{% if msg.is_deleted %} is-deleted{% endif %}" data-ts="{{ msg.ts }}" data-message-id="{{ msg.id }}"{% if msg.reply_to_id %} data-reply-to-id="{{ msg.reply_to_id }}"{% endif %} data-reply-snippet="{{ msg.display_text|default:msg.text|default:''|truncatechars:120|escape }}">
|
||||
<article class="compose-bubble {% if msg.outgoing %}is-out{% else %}is-in{% endif %}">
|
||||
<article
|
||||
class="compose-bubble {% if msg.outgoing %}is-out{% else %}is-in{% endif %}"
|
||||
title="Source: {{ msg.source_label }}{% if msg.author %} · {{ msg.author }}{% endif %}">
|
||||
{% if msg.reply_to_id %}
|
||||
<div class="compose-reply-ref" data-reply-target-id="{{ msg.reply_to_id }}">
|
||||
<button type="button" class="compose-reply-link" title="Jump to referenced message">
|
||||
@@ -7,9 +9,6 @@
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="compose-source-badge-wrap">
|
||||
<span class="tag is-light gia-badge compose-source-badge source-{{ msg.source_service|default:'web'|lower }}">{{ msg.source_label }}</span>
|
||||
</div>
|
||||
{% if msg.image_urls %}
|
||||
{% for image_url in msg.image_urls %}
|
||||
<figure class="compose-media">
|
||||
@@ -34,9 +33,9 @@
|
||||
</figure>
|
||||
{% endif %}
|
||||
{% if not msg.hide_text %}
|
||||
<p class="compose-body">{{ msg.display_text|default:"(no text)" }}</p>
|
||||
<p class="compose-body is-size-7">{{ msg.display_text|default:"(no text)" }}</p>
|
||||
{% else %}
|
||||
<p class="compose-body compose-image-fallback is-hidden">(no text)</p>
|
||||
<p class="compose-body compose-image-fallback is-hidden is-size-7">(no text)</p>
|
||||
{% endif %}
|
||||
{% if msg.edit_count %}
|
||||
<details class="compose-edit-history">
|
||||
@@ -71,7 +70,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="compose-msg-meta">
|
||||
<p class="compose-msg-meta is-size-7" title="Source: {{ msg.source_label }}">
|
||||
{{ msg.display_ts }}{% if msg.author %} · {{ msg.author }}{% endif %}
|
||||
{% if msg.is_edited %}
|
||||
<span class="tag is-light gia-badge compose-msg-flag is-edited" title="Message edited{% if msg.last_edit_display %} at {{ msg.last_edit_display }}{% endif %}">edited</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/compose-panel.css' %}">
|
||||
<script defer src="{% static 'js/compose-panel-core.js' %}"></script>
|
||||
<script defer src="{% static 'js/compose-panel-thread.js' %}"></script>
|
||||
<script defer src="{% static 'js/compose-panel-send.js' %}"></script>
|
||||
<script defer src="{% static 'js/compose-panel.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/compose-panel.css' %}?v={{ compose_asset_version|default:'20260313b' }}">
|
||||
<script defer src="{% static 'js/compose-panel-core.js' %}?v={{ compose_asset_version|default:'20260313b' }}"></script>
|
||||
<script defer src="{% static 'js/compose-panel-thread.js' %}?v={{ compose_asset_version|default:'20260313b' }}"></script>
|
||||
<script defer src="{% static 'js/compose-panel-send.js' %}?v={{ compose_asset_version|default:'20260313b' }}"></script>
|
||||
<script defer src="{% static 'js/compose-panel.js' %}?v={{ compose_asset_version|default:'20260313b' }}"></script>
|
||||
|
||||
@@ -66,6 +66,9 @@
|
||||
{{ service|title }} · {{ identifier }}
|
||||
</p>
|
||||
</div>
|
||||
{% if behavioral_graphs_page_url %}
|
||||
{% include "partials/behavioral-graph-launcher.html" with button_label="Graphs" show_widget_actions=behavioral_show_widget_actions default_widget_url=behavioral_graphs_widget_url default_page_url=behavioral_graphs_page_url graph_groups=behavioral_graph_groups %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if signal_ingest_warning %}
|
||||
@@ -90,6 +93,9 @@
|
||||
data-limit="{{ limit }}"
|
||||
data-last-ts="{{ last_ts }}"
|
||||
data-ws-url="{{ compose_ws_url }}">
|
||||
<p id="{{ panel_id }}-history-loader" class="compose-history-loader is-size-7 has-text-grey mb-2">
|
||||
Scroll up to load older messages.
|
||||
</p>
|
||||
{% include "partials/compose-message-rows.html" with message_rows=serialized_messages show_empty_state=True empty_message="No stored messages for this contact yet." %}
|
||||
</div>
|
||||
<p id="{{ panel_id }}-typing" class="compose-typing is-hidden">
|
||||
@@ -128,7 +134,7 @@
|
||||
<p class="help is-size-7 has-text-grey">Send disabled: {{ capability_send_reason }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include "partials/bulma-send-composer.html" with composer_class="compose-composer-capsule" textarea_id=panel_id|add:"-textarea" textarea_class="compose-textarea" textarea_name="text" textarea_rows="1" textarea_placeholder="Type a message. Enter to send, Shift+Enter for newline." button_class="is-link is-light compose-send-btn" button_type="submit" button_disabled=True button_title=capability_send_reason|default_if_none:"" button_label="Send" button_icon_class=manual_icon_class %}
|
||||
{% include "partials/bulma-send-composer.html" with composer_class="compose-composer-capsule" textarea_id=panel_id|add:"-textarea" textarea_class="is-small compose-textarea" textarea_name="text" textarea_rows="1" textarea_placeholder="Type a message. Enter to send, Shift+Enter for newline." button_class="is-link is-light is-small compose-send-btn" button_type="submit" button_disabled=True button_title=capability_send_reason|default_if_none:"" button_label="Send" button_icon_class=manual_icon_class %}
|
||||
</div>
|
||||
<div id="{{ panel_id }}-reply-banner" class="compose-reply-banner is-hidden">
|
||||
<span class="compose-reply-banner-label">Replying to:</span>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
{% for row in contact_rows %}
|
||||
<a
|
||||
class="panel-block"
|
||||
data-gia-widget-id="{{ row.compose_widget_id }}"
|
||||
hx-get="{{ row.compose_widget_url }}"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="beforeend">
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<div class="buttons are-small m-0">
|
||||
<button
|
||||
class="button is-small is-link is-light"
|
||||
data-gia-widget-id="{{ row.compose_widget_id }}"
|
||||
hx-get="{{ row.compose_widget_url }}"
|
||||
hx-include="#{{ browser_form_id }}"
|
||||
hx-target="#widgets-here"
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{{ action.url }}"
|
||||
hx-target="{{ action.target }}"
|
||||
hx-swap="innerHTML"
|
||||
hx-swap="{{ action.swap|default:'innerHTML' }}"
|
||||
{% if action.target == "#windows-here" %}onclick="if (window.giaPrepareWindowAnchor) { window.giaPrepareWindowAnchor(this); }"{% endif %}
|
||||
title="{{ action.title }}">
|
||||
<span class="icon"><i class="{{ action.icon }}"></i></span>
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
{% if item.can_compose %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
data-gia-widget-id="{{ item.compose_widget_id }}"
|
||||
hx-get="{{ item.compose_widget_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#widgets-here"
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<button
|
||||
type="button"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
data-gia-widget-id="{{ item.compose_widget_id }}"
|
||||
hx-get="{{ item.compose_widget_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#widgets-here"
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<button
|
||||
type="button"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
data-gia-widget-id="{{ item.compose_widget_id }}"
|
||||
hx-get="{{ item.compose_widget_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#widgets-here"
|
||||
|
||||
Reference in New Issue
Block a user