{% extends "hq/base.html" %} {% load static humanize i18n hq %} {% block title %}{% translate "Website status" %}{% endblock %} {% block heading %}{% translate "Website status" %}{% endblock %} {% block module_css %}{% endblock %} {% block actions %} {% comment %} A format switch rather than a disclosure: the same facts are either laid out as cards or printed as the JSON an API reader would get, never both at once. The two panels are siblings so the button can simply swap which is on. {% endcomment %}
{% translate "Open endpoint" %}{% hq_icon "external-link" %}
{% endblock %} {% block content %}
{% comment %} The environment's warning colour rides on the tile's stripe, which is what a .tile is already built to be told. {% endcomment %} {% if environment %}
{% translate "Environment" %}
{{ environment }}
{% endif %} {% if repo_url %} {% endif %}
{% translate "Branch" %}
{{ branch|default:"—" }}
{% translate "Version" %}
{{ version|default:"—" }}
{% comment %} The number is the CI run, so it is worth a click: it opens the log of the build that produced this image. A local build has no run behind it and the tile says so rather than borrowing a number. {% endcomment %}
{% translate "Build" %}
{% if build_url %} #{{ build_number }}{% hq_icon "external-link" %} {% else %} {{ build_number|default:"—" }} {% endif %}
{% comment %} The string Sentry files events under, so a stack trace and this page can be matched to each other. Empty exactly when Sentry is not reporting at all. {% endcomment %}
{% translate "Release" %}
{{ sentry_release|default:"—" }}

{% hq_icon "git-commit-horizontal" %} {% translate "Deployment" %}

{% translate "What the image now running in this container was built from" %}

{% translate "Commit" %}
{% if commit_url %} {{ commit_short }}{% hq_icon "external-link" %} {% elif commit_short %} {{ commit_short }} {% else %} {% endif %}
{% comment %} The half `git describe --abbrev=0` throws away. It belongs next to the commit rather than beside the version: it qualifies which commit is deployed, not what the release is called. {% endcomment %}
{% translate "Ahead of tag" %}
{% if commits_since_tag is None %} {% elif commits_since_tag %} +{{ commits_since_tag }} {% blocktranslate with tag=version %}past {{ tag }}{% endblocktranslate %} {% else %} {% translate "on the tag" %} {% endif %}
{% translate "Subject" %}
{{ subject|default:"—" }}
{% translate "Committed" %}
{% if committed_at %} {{ committed_at|date:"j M Y H:i" }} {{ committed_at|naturaltime }} {% else %} {% endif %}
{% translate "Built" %}
{% if built_at %} {{ built_at|date:"j M Y H:i" }} {{ built_at|naturaltime }} {% else %} {% endif %}
{% translate "Deployed" %}
{% if deployed_at %} {{ deployed_at|date:"j M Y H:i" }} {{ deployed_at|naturaltime }} {% else %} {% endif %}
{% if pipeline %} {% comment %} The commit → build → deploy span, drawn to scale. The segments are sized by JS from data-seconds rather than a style attribute; the CSS min-width keeps a near-instant stage from vanishing, and a segment too thin to read still has its figure in the legend below. {% endcomment %}
{% translate "Path to production" %} {% blocktranslate with total=pipeline.total %}{{ total }} in total{% endblocktranslate %}
{% for stage in pipeline.stages %}
{% endfor %}
{% for stage in pipeline.stages %} {{ stage.label }} {{ stage.text }} {% endfor %}
{% endif %} {% comment %} Said plainly, because the number is only as honest as its source: the container start time is stamped by the entrypoint, so a restart or a reboot moves it without anything having been released. {% endcomment %}

{% hq_icon "info" %} {% translate "“Deployed” is the container start time — a restart or a reboot moves it with nothing having been released." %}

{% comment %} Side by side: the runtime rows are a narrow label-and-value list, and "everything applied" is a single line — each was claiming a full-width strip for content that fills a third of it. They stack again below 900px. {% endcomment %}
{% comment %} Everything above describes the image. This describes the process running out of it — which container answered, how long it has been up, and what versions it really has as opposed to what the lock file asks for. {% endcomment %}

{% hq_icon "server" %} {% translate "Runtime" %}

{% translate "The container that served this request, and the versions it runs on" %}

{% include "hq/status/_brand_mark.html" with brand=docker_icon only %} {% translate "Container" %}
{% if container_id %} {{ container_id }} {% else %} {% translate "outside Docker" %} {% endif %}
{% hq_icon "timer" %}{% translate "Uptime" %}
{% if uptime %} {{ uptime }} {% else %} {% endif %}
{% comment %} DEBUG on a deployed box leaks tracebacks and settings to anyone who can provoke an error, so it is stated rather than assumed — and coloured when it is on. {% endcomment %}
{% hq_icon "bug" %}{% translate "Debug" %}
{% if debug %} {% translate "on" %} {% else %} {% translate "off" %} {% endif %}
{% for entry in runtime %}
{% include "hq/status/_brand_mark.html" with brand=entry.brand only %} {{ entry.label }}
{{ entry.value }}
{% endfor %}
{% comment %} The whole plan, not a count: a number says something is wrong without saying what, and this is the page you would open to find out. {% endcomment %}

{% hq_icon "layers" %} {% translate "Migrations" %}

{% translate "What this database still owes the code running against it" %}

{% if migrations is None %}

{% hq_icon "info" %} {% translate "The migration plan could not be read." %}

{% elif migrations %}
    {% for migration in migrations %}
  1. {{ migration.app }} {{ migration.name }}
  2. {% endfor %}

{% hq_icon "triangle-alert" %} {% blocktranslate count counter=migrations|length %} One migration is waiting — the code is running against a schema it does not expect. {% plural %} {{ counter }} migrations are waiting — the code is running against a schema it does not expect. {% endblocktranslate %}

{% else %}

{% hq_icon "check" %} {% translate "Everything applied." %}

{% endif %}
{% comment %} Two donuts and not one, because the disk is measured in hundreds of gigabytes and this application in tens of megabytes — a single chart would give the database an arc thinner than a pixel and call it a reading. {% endcomment %}

{% hq_icon "hard-drive" %} {% translate "Storage" %}

{% translate "How full the box is, and what this application accounts for" %}

{% if storage.disk_chart %} {% include "hq/status/_donut.html" with chart=storage.disk_chart chart_title=_("Disk") only %} {% endif %} {% if storage.application_chart %} {% include "hq/status/_donut.html" with chart=storage.application_chart chart_title=_("This application") only %} {% endif %}
{% if not storage.media_measured %}

{% hq_icon "info" %} {% translate "The media directory was not measured." %}

{% elif storage.media is None and storage.media_path %}

{% hq_icon "info" %} {% blocktranslate with path=storage.media_path %}{{ path }} could not be measured — it is missing, or larger than the file budget.{% endblocktranslate %}

{% endif %}
{% if show_environment_variables %} {% include "hq/status/_secret_list.html" with entries=environment_variables list_title=_("Environment variables") list_icon="sliders-horizontal" only %} {% endif %} {% if show_django_settings %} {% include "hq/status/_secret_list.html" with entries=django_settings list_title=_("Django settings") list_icon="settings" only %} {% endif %}
{% comment %} The same facts, in the shape a script would get them. Fetched rather than rendered inline so what you read is genuinely the endpoint's answer — if the JSON ever disagreed with the cards, this is where it would show. {% endcomment %} {% endblock %} {% block scripts %}{% endblock %}