144 lines
5.6 KiB
HTML
144 lines
5.6 KiB
HTML
|
|
{% extends "base.html" %}
|
||
|
|
|
||
|
|
{% block title %}{{ panel.title | default(value="Panel") }} — Ontoref{% endblock title %}
|
||
|
|
{% block nav_group_knowledge %}active{% endblock nav_group_knowledge %}
|
||
|
|
{% block main_class %}container mx-auto px-4 py-6{% endblock main_class %}
|
||
|
|
|
||
|
|
{% block head %}
|
||
|
|
{% if panel.kind == "Timeline" or panel.kind == "Gantt" %}
|
||
|
|
<link rel="stylesheet" href="{{ base_url }}/assets/vendor/vis-timeline.min.css" />
|
||
|
|
<style>
|
||
|
|
#panel-root {
|
||
|
|
width: 100%; height: calc(100vh - 220px); min-height: 380px;
|
||
|
|
border-radius: 0.5rem; overflow: hidden;
|
||
|
|
border: 1px solid oklch(var(--bc) / 0.12);
|
||
|
|
}
|
||
|
|
.vis-timeline { background: oklch(var(--b1)); color: oklch(var(--bc)); }
|
||
|
|
.vis-time-axis .vis-text { color: oklch(var(--bc) / 0.6); }
|
||
|
|
.vis-panel.vis-center, .vis-panel.vis-left { border-color: oklch(var(--bc) / 0.12); }
|
||
|
|
</style>
|
||
|
|
{% elif panel.kind == "Graph" %}
|
||
|
|
<style>
|
||
|
|
#panel-root { width: 100%; height: calc(100vh - 220px); min-height: 380px;
|
||
|
|
border-radius: 0.5rem; overflow: hidden; border: 1px solid oklch(var(--bc) / 0.12); }
|
||
|
|
#cy { width: 100%; height: 100%; }
|
||
|
|
</style>
|
||
|
|
{% endif %}
|
||
|
|
{% endblock head %}
|
||
|
|
|
||
|
|
{% block content %}
|
||
|
|
<div class="flex items-center justify-between mb-4 gap-4">
|
||
|
|
<div>
|
||
|
|
<h1 class="text-xl font-semibold">{{ panel.title | default(value="Panel") }}</h1>
|
||
|
|
<p class="text-xs opacity-60 mt-0.5">
|
||
|
|
kind={{ panel.kind | default(value="?") }}
|
||
|
|
· op={{ panel.data_source_op | default(value="—") }}
|
||
|
|
· id={{ panel.id | default(value="—") }}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
{% if panel.kind == "Timeline" or panel.kind == "Gantt" %}
|
||
|
|
<button class="btn btn-ghost btn-sm" onclick="pTimeline && pTimeline.fit()">Fit</button>
|
||
|
|
{% endif %}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{% if panel.kind == "Timeline" or panel.kind == "Gantt" %}
|
||
|
|
<div id="panel-root"></div>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Graph" %}
|
||
|
|
<div id="panel-root"><div id="cy"></div></div>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Table" %}
|
||
|
|
<div class="overflow-x-auto">
|
||
|
|
<table class="table table-zebra text-sm w-full">
|
||
|
|
<thead>
|
||
|
|
<tr id="tbl-head"></tr>
|
||
|
|
</thead>
|
||
|
|
<tbody id="tbl-body"></tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Board" %}
|
||
|
|
<div id="board-root" class="grid grid-cols-1 md:grid-cols-3 gap-4"></div>
|
||
|
|
|
||
|
|
{% else %}
|
||
|
|
<div class="alert alert-info">
|
||
|
|
Panel kind <strong>{{ panel.kind | default(value="unknown") }}</strong> has no renderer.
|
||
|
|
Raw data: <code>{{ panel.data_source_op | default(value="—") }}</code>
|
||
|
|
</div>
|
||
|
|
{% endif %}
|
||
|
|
{% endblock content %}
|
||
|
|
|
||
|
|
{% block scripts %}
|
||
|
|
{% if panel.kind == "Timeline" or panel.kind == "Gantt" %}
|
||
|
|
<script src="{{ base_url }}/assets/vendor/vis-timeline.min.js"></script>
|
||
|
|
<script>
|
||
|
|
const PANEL_DATA = {{ panel_data_json | safe }};
|
||
|
|
const items = (PANEL_DATA.items || PANEL_DATA.entries || []).map((e, i) => ({
|
||
|
|
id: e.id || String(i),
|
||
|
|
start: e.date || e.start || e.target_date || "1970-01-01",
|
||
|
|
end: e.end || undefined,
|
||
|
|
content: `<span style="max-width:220px;overflow:hidden;text-overflow:ellipsis;display:inline-block;white-space:nowrap">${e.title || e.content || JSON.stringify(e)}</span>`,
|
||
|
|
group: e.kind || e.group || e.status || "item",
|
||
|
|
title: e.title || "",
|
||
|
|
}));
|
||
|
|
const groups = [...new Set(items.map(i => i.group))].map(g => ({ id: g, content: g }));
|
||
|
|
const pTimeline = new vis.Timeline(
|
||
|
|
document.getElementById('panel-root'),
|
||
|
|
new vis.DataSet(items),
|
||
|
|
new vis.DataSet(groups),
|
||
|
|
{ stack: true, orientation: { axis: "top" }, selectable: false }
|
||
|
|
);
|
||
|
|
pTimeline.fit();
|
||
|
|
</script>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Graph" %}
|
||
|
|
<script src="https://cdn.jsdelivr.net/npm/cytoscape@3.30.2/dist/cytoscape.min.js"></script>
|
||
|
|
<script>
|
||
|
|
const PANEL_DATA = {{ panel_data_json | safe }};
|
||
|
|
const cy = cytoscape({
|
||
|
|
container: document.getElementById('cy'),
|
||
|
|
elements: [
|
||
|
|
...(PANEL_DATA.nodes || []).map(n => ({ data: { id: n.id, label: n.name || n.id } })),
|
||
|
|
...(PANEL_DATA.edges || []).map(e => ({ data: { id: e.id || `${e.from}-${e.to}`, source: e.from || e.source, target: e.to || e.target, label: e.kind || "" } })),
|
||
|
|
],
|
||
|
|
style: [
|
||
|
|
{ selector: 'node', style: { 'label': 'data(label)', 'background-color': '#3b82f6', 'color': '#fff', 'font-size': '11px', 'text-halign': 'center', 'text-valign': 'center' } },
|
||
|
|
{ selector: 'edge', style: { 'line-color': '#6b7280', 'target-arrow-color': '#6b7280', 'target-arrow-shape': 'triangle', 'curve-style': 'bezier', 'font-size': '10px' } },
|
||
|
|
],
|
||
|
|
layout: { name: 'cose', animate: false },
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Table" %}
|
||
|
|
<script>
|
||
|
|
const PANEL_DATA = {{ panel_data_json | safe }};
|
||
|
|
const rows = PANEL_DATA.items || PANEL_DATA.entries || [];
|
||
|
|
if (rows.length > 0) {
|
||
|
|
const cols = Object.keys(rows[0]);
|
||
|
|
document.getElementById('tbl-head').innerHTML = cols.map(c => `<th>${c}</th>`).join('');
|
||
|
|
document.getElementById('tbl-body').innerHTML = rows.map(r =>
|
||
|
|
`<tr>${cols.map(c => `<td class="max-w-xs overflow-hidden text-ellipsis">${String(r[c] ?? '')}</td>`).join('')}</tr>`
|
||
|
|
).join('');
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
{% elif panel.kind == "Board" %}
|
||
|
|
<script>
|
||
|
|
const PANEL_DATA = {{ panel_data_json | safe }};
|
||
|
|
const cols = PANEL_DATA.columns || [{ id: "items", label: "Items", items: PANEL_DATA.items || [] }];
|
||
|
|
const board = document.getElementById('board-root');
|
||
|
|
board.innerHTML = cols.map(col => `
|
||
|
|
<div class="bg-base-200 rounded-lg p-3">
|
||
|
|
<h3 class="font-semibold text-sm mb-3">${col.label || col.id}</h3>
|
||
|
|
<div class="space-y-2">
|
||
|
|
${(col.items || []).map(it => `
|
||
|
|
<div class="bg-base-100 rounded p-2 text-xs">
|
||
|
|
<p class="font-medium">${it.title || it.id || JSON.stringify(it)}</p>
|
||
|
|
${it.description ? `<p class="opacity-60 mt-1">${it.description}</p>` : ''}
|
||
|
|
</div>`).join('')}
|
||
|
|
</div>
|
||
|
|
</div>`).join('');
|
||
|
|
</script>
|
||
|
|
{% endif %}
|
||
|
|
{% endblock scripts %}
|