125 lines
4.6 KiB
HTML
125 lines
4.6 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Welcome Prompt — Admin{% endblock %}
|
|
{% block content %}
|
|
<div class="admin-page">
|
|
<h1>Analyst Welcome Prompt</h1>
|
|
<p class="muted">
|
|
This is the CLAUDE.md generated for analysts when they run
|
|
<code>da analyst setup</code>. Edit it to customize the onboarding
|
|
instructions for this instance. Leave empty (or click <em>Reset to default</em>)
|
|
to use the OSS-shipped default.
|
|
</p>
|
|
|
|
<p class="status" id="status-line">
|
|
{% if is_override %}
|
|
Overridden by <strong>{{ updated_by }}</strong> on
|
|
{{ updated_at.strftime("%Y-%m-%d %H:%M UTC") if updated_at else "—" }}.
|
|
{% else %}
|
|
Using shipped default.
|
|
{% endif %}
|
|
</p>
|
|
|
|
<h2>Available placeholders</h2>
|
|
<pre class="placeholder-cheatsheet">
|
|
{{ "{{ instance.name }}" }} — instance display name
|
|
{{ "{{ instance.subtitle }}" }} — operator name
|
|
{{ "{{ server.url }}" }} — full server URL
|
|
{{ "{{ server.hostname }}" }} — host part
|
|
{{ "{{ sync_interval }}" }} — refresh cadence (instance.yaml)
|
|
{{ "{{ data_source.type }}" }} — keboola | bigquery | local
|
|
{{ "{{ tables }}" }} — list of {name, description, query_mode}
|
|
{{ "{{ metrics.count }}" }}, {{ "{{ metrics.categories }}" }}
|
|
{{ "{{ marketplaces }}" }} — RBAC-filtered list of {slug, name, plugins[]}
|
|
{{ "{{ user.email }}" }}, {{ "{{ user.name }}" }}, {{ "{{ user.is_admin }}" }}, {{ "{{ user.groups }}" }}
|
|
{{ "{{ now }}" }}, {{ "{{ today }}" }}
|
|
</pre>
|
|
|
|
<form id="welcome-form" onsubmit="return false">
|
|
<textarea id="content" rows="30" cols="100">{{ current or default_template }}</textarea>
|
|
<div class="actions">
|
|
<button type="button" id="save-btn">Save override</button>
|
|
<button type="button" id="reset-btn" class="secondary">Reset to default</button>
|
|
<button type="button" id="preview-btn" class="secondary">Preview</button>
|
|
</div>
|
|
<div id="result" class="result"></div>
|
|
<pre id="preview" class="preview" hidden></pre>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
const $ = (id) => document.getElementById(id);
|
|
const result = $("result");
|
|
|
|
async function refreshStatus() {
|
|
const r = await fetch("/api/admin/welcome-template", {credentials: "include"});
|
|
if (!r.ok) return;
|
|
const data = await r.json();
|
|
const status = $("status-line");
|
|
if (data.content !== null) {
|
|
const when = data.updated_at
|
|
? new Date(data.updated_at).toISOString().slice(0, 16).replace("T", " ") + " UTC"
|
|
: "—";
|
|
status.innerHTML = "Overridden by <strong>" + (data.updated_by || "—") + "</strong> on " + when + ".";
|
|
$("content").value = data.content;
|
|
} else {
|
|
status.textContent = "Using shipped default.";
|
|
$("content").value = data.default;
|
|
}
|
|
}
|
|
|
|
$("save-btn").addEventListener("click", async () => {
|
|
result.textContent = "Saving…";
|
|
const r = await fetch("/api/admin/welcome-template", {
|
|
method: "PUT",
|
|
credentials: "include",
|
|
headers: {"Content-Type": "application/json"},
|
|
body: JSON.stringify({content: $("content").value}),
|
|
});
|
|
if (r.ok) {
|
|
result.textContent = "Saved.";
|
|
await refreshStatus();
|
|
} else {
|
|
let detail = r.statusText;
|
|
try { detail = (await r.json()).detail || detail; } catch {}
|
|
result.textContent = "Error: " + detail;
|
|
}
|
|
});
|
|
|
|
$("reset-btn").addEventListener("click", async () => {
|
|
if (!confirm("Reset to OSS default? Your override will be lost.")) return;
|
|
const r = await fetch("/api/admin/welcome-template", {
|
|
method: "DELETE",
|
|
credentials: "include",
|
|
});
|
|
if (r.ok) {
|
|
result.textContent = "Reset to default.";
|
|
await refreshStatus();
|
|
} else {
|
|
let detail = r.statusText;
|
|
try { detail = (await r.json()).detail || detail; } catch {}
|
|
result.textContent = "Error: " + detail;
|
|
}
|
|
});
|
|
|
|
$("preview-btn").addEventListener("click", async () => {
|
|
result.textContent = "Rendering preview…";
|
|
const r = await fetch("/api/admin/welcome-template/preview", {
|
|
method: "POST",
|
|
credentials: "include",
|
|
headers: {"Content-Type": "application/json"},
|
|
body: JSON.stringify({content: $("content").value}),
|
|
});
|
|
if (r.ok) {
|
|
const j = await r.json();
|
|
$("preview").textContent = j.content;
|
|
$("preview").hidden = false;
|
|
result.textContent = "Preview rendered.";
|
|
} else {
|
|
let detail = r.statusText;
|
|
try { detail = (await r.json()).detail || detail; } catch {}
|
|
result.textContent = "Render error: " + detail;
|
|
$("preview").hidden = true;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|