Add version (0.1.0) and a Settings -> About page

Single source of truth: __version__ in daybook_project/__init__.py, starting
at 0.1.0. Surfaced in two places from that constant:
- Settings -> About page (logo, name, version, description), in the settings
  nav and linked from the gear menu.
- GET /api/capabilities now includes "version", so the deploy agent / tester
  can confirm which version is actually running.

Release flow: bump __version__, commit, `git tag vX.Y.Z`, push tag, deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
peter 2026-09-03 14:41:02 +01:00
parent ca8e364010
commit 03d311b888
7 changed files with 63 additions and 0 deletions

View file

@ -21,4 +21,5 @@ urlpatterns = [
path("settings/users/", views.settings_users, name="settings-users"), path("settings/users/", views.settings_users, name="settings-users"),
path("settings/demo-data/", views.settings_demo_data, name="settings-demo-data"), path("settings/demo-data/", views.settings_demo_data, name="settings-demo-data"),
path("settings/storage/", views.settings_storage, name="settings-storage"), path("settings/storage/", views.settings_storage, name="settings-storage"),
path("settings/about/", views.settings_about, name="settings-about"),
] ]

View file

@ -307,8 +307,11 @@ class CapabilitiesView(APIView):
def get(self, request): def get(self, request):
if not request.user.is_authenticated and resolve_token_user(request) is None: if not request.user.is_authenticated and resolve_token_user(request) is None:
return HttpResponseForbidden("Login or a valid API token is required") return HttpResponseForbidden("Login or a valid API token is required")
from daybook_project import __version__
return Response( return Response(
{ {
"version": __version__,
"artifact_kinds": [choice[0] for choice in Artifact.KIND_CHOICES], "artifact_kinds": [choice[0] for choice in Artifact.KIND_CHOICES],
"filters": ["source", "label", "day", "kind", "q"], "filters": ["source", "label", "day", "kind", "q"],
"views": ["rendered", "raw"], "views": ["rendered", "raw"],
@ -1249,6 +1252,17 @@ def settings_users(request):
) )
@login_required
def settings_about(request):
from daybook_project import __version__
return render(
request,
"artifacts/settings_about.html",
{"active_section": "about", "version": __version__},
)
@login_required @login_required
def settings_demo_data(request): def settings_demo_data(request):
if request.method == "POST": if request.method == "POST":

View file

@ -0,0 +1,4 @@
# Single source of truth for the app version. Bump this, commit, then tag the
# commit `vX.Y.Z` and deploy. Surfaced on Settings -> About and in
# GET /api/capabilities ("version").
__version__ = "0.1.0"

View file

@ -990,6 +990,28 @@ kbd {
word-break: break-all; word-break: break-all;
} }
.about-head {
align-items: center;
display: flex;
gap: 1rem;
margin-bottom: 1.2rem;
}
.about-head h2 {
margin: 0;
}
.about-logo {
height: 3rem;
width: auto;
}
.about-version {
color: var(--muted);
font-size: 0.9rem;
margin: 0.15rem 0 0;
}
.keep-button.kept { .keep-button.kept {
background: var(--success-bg); background: var(--success-bg);
border-color: var(--success-border); border-color: var(--success-border);

View file

@ -12,6 +12,7 @@
<div class="user-menu-dropdown" hidden data-user-menu> <div class="user-menu-dropdown" hidden data-user-menu>
<a href="{% url 'settings-account' %}">Settings</a> <a href="{% url 'settings-account' %}">Settings</a>
<a href="{% url 'settings-demo-data' %}">Demo Data</a> <a href="{% url 'settings-demo-data' %}">Demo Data</a>
<a href="{% url 'settings-about' %}">About</a>
<button type="button" data-theme-toggle>Dark mode</button> <button type="button" data-theme-toggle>Dark mode</button>
<form method="post" action="{% url 'logout' %}">{% csrf_token %}<button type="submit">Log out</button></form> <form method="post" action="{% url 'logout' %}">{% csrf_token %}<button type="submit">Log out</button></form>
</div> </div>

View file

@ -0,0 +1,20 @@
{% extends "artifacts/settings_base.html" %}
{% block settings_content %}
<div class="about-head">
<img class="about-logo" src="/static/logo.png" alt="">
<div>
<h2>Daybook</h2>
<p class="about-version">Version {{ version }}</p>
</div>
</div>
<p>A self-hosted, multi-user journal where AI agents, scripts, or people
publish artifacts — reports, HTML, decks, images, PDFs, JSON, CSV — and each
logged-in user browses their own time-ordered, label-filterable feed. The
server owns IDs, styling, and storage; agents publish content, not files.</p>
<p class="storage-note">Post to it with a personal API token from
Settings&nbsp;→&nbsp;Account; the current API capabilities (including this
version) are available at <code>/api/capabilities</code>.</p>
{% endblock %}

View file

@ -30,6 +30,7 @@
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<a class="{% if active_section == 'users' %}selected{% endif %}" href="{% url 'settings-users' %}">Users</a> <a class="{% if active_section == 'users' %}selected{% endif %}" href="{% url 'settings-users' %}">Users</a>
{% endif %} {% endif %}
<a class="{% if active_section == 'about' %}selected{% endif %}" href="{% url 'settings-about' %}">About</a>
</nav> </nav>
<section class="settings-panel"> <section class="settings-panel">
{% if messages %} {% if messages %}