mirror of
https://github.com/bugsink/bugsink.git
synced 2025-12-19 03:19:52 -06:00
Support hosting at subpath
"In principle" setting `SCRIPT_NAME` is enough. The way we do this is [1] using
`FORCE_SCRIPT_NAME` (which does not depend on messing with reverse proxy
settings and [2] by deducing the correct value from `BASE_URL` (which must be
set anyway) automatically.
By works I mean: `reverse` and `{% url` pick it up from there.
However, there are subtleties / extra work:
* `STATIC_URL` is needed too b/c https://code.djangoproject.com/ticket/34028
* in many pre-existing code I just created a path manually in the html. Such
hrefs are obviously not magically fixed for script_name. Rather than doing
the "full rewrite" (into `{% url`) this commit just prepends the
`script_name` in those cases. That's the way forward that will least likely
break and it gives us something to grep for if we ever want to 'do it
right'.
* `LOGIN_REDIRECT_URL` and `LOGIN_URL` needed to use a view-name for this to
work (using a view-name gets revolved using the thing that introduces
`script_name`)
Checked, no work needed:
* views (`redirect` and `HttpResponseRedirect`)
* html uses of action="..."
Fix #93
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood, deduce_script_name
|
||||
|
||||
from bugsink.settings.default import * # noqa
|
||||
from bugsink.settings.default import DATABASES
|
||||
@@ -195,3 +195,11 @@ if os.getenv("FILE_EVENT_STORAGE_PATH"):
|
||||
"USE_FOR_WRITE": os.getenv("FILE_EVENT_STORAGE_USE_FOR_WRITE", "false").lower() in ("true", "1", "yes"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
FORCE_SCRIPT_NAME = deduce_script_name(BUGSINK["BASE_URL"])
|
||||
if FORCE_SCRIPT_NAME:
|
||||
# "in theory" a "relative" (non-leading-slash) config for STATIC_URL should just prepend [FORCE_]SCRIPT_NAME
|
||||
# automatically, but I haven't been able to get that to work reliably, https://code.djangoproject.com/ticket/34028
|
||||
# so we'll just be explicit about it.
|
||||
STATIC_URL = f"{FORCE_SCRIPT_NAME}/static/"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# This is the configuration for the singleserver setup for Bugsink in production.
|
||||
|
||||
from bugsink.settings.default import * # noqa
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood, deduce_script_name
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "{{ secret_key }}"
|
||||
@@ -126,3 +126,10 @@ ALLOWED_HOSTS = deduce_allowed_hosts(BUGSINK["BASE_URL"])
|
||||
|
||||
# Alternatively, you can set the ALLOWED_HOSTS manually:
|
||||
# ALLOWED_HOSTS = ["{{ host }}"]
|
||||
|
||||
FORCE_SCRIPT_NAME = deduce_script_name(BUGSINK["BASE_URL"])
|
||||
if FORCE_SCRIPT_NAME:
|
||||
# "in theory" a "relative" (non-leading-slash) config for STATIC_URL should just prepend [FORCE_]SCRIPT_NAME
|
||||
# automatically, but I haven't been able to get that to work reliably, https://code.djangoproject.com/ticket/34028
|
||||
# so we'll just be explicit about it.
|
||||
STATIC_URL = f"{FORCE_SCRIPT_NAME}/static/"
|
||||
|
||||
@@ -9,6 +9,7 @@ from django.urls import reverse
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.db.utils import OperationalError
|
||||
from django.db.models import Sum
|
||||
from django.urls import get_script_prefix
|
||||
|
||||
from bugsink.app_settings import get_settings, CB_ANYBODY
|
||||
from bugsink.transaction import durable_atomic
|
||||
@@ -136,6 +137,7 @@ def useful_settings_processor(request):
|
||||
'registration_enabled': get_settings().USER_REGISTRATION == CB_ANYBODY,
|
||||
'app_settings': get_settings(),
|
||||
'system_warnings': get_system_warnings,
|
||||
'script_prefix': get_script_prefix().rstrip("/"), # TODO why
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.core.exceptions import SuspiciousOperation
|
||||
from django.utils.translation import get_supported_language_variant
|
||||
from django.utils.translation.trans_real import parse_accept_lang_header
|
||||
from django.utils import translation
|
||||
from django.urls import get_script_prefix
|
||||
|
||||
|
||||
performance_logger = logging.getLogger("bugsink.performance.views")
|
||||
@@ -48,7 +49,7 @@ class LoginRequiredMiddleware:
|
||||
|
||||
# we explicitly ignore the admin and accounts paths, and the api; we can always push this to a setting later
|
||||
for path in ["/admin", "/accounts", "/api"]:
|
||||
if request.path.startswith(path):
|
||||
if request.path.startswith(get_script_prefix().rstrip("/") + path):
|
||||
return None
|
||||
|
||||
if getattr(view_func, 'login_exempt', False):
|
||||
|
||||
@@ -221,7 +221,8 @@ DATABASE_ROUTERS = ("bugsink.dbrouters.SeparateSnappeaDBRouter",)
|
||||
CONN_MAX_AGE = 0
|
||||
|
||||
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
LOGIN_REDIRECT_URL = "home"
|
||||
LOGIN_URL = "login"
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
from django.utils._os import safe_join
|
||||
from sentry_sdk_extensions.transport import MoreLoudlyFailingTransport
|
||||
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood
|
||||
from bugsink.utils import deduce_allowed_hosts, eat_your_own_dogfood, deduce_script_name
|
||||
|
||||
|
||||
# no_bandit_expl: _development_ settings, we know that this is insecure; would fail to deploy in prod if (as configured)
|
||||
@@ -86,7 +86,7 @@ BUGSINK = {
|
||||
# "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE,
|
||||
# "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE,
|
||||
|
||||
"BASE_URL": "http://bugsink:8000", # no trailing slash
|
||||
"BASE_URL": "http://bugsink:8000/foobar", # no trailing slash
|
||||
"SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company"
|
||||
|
||||
# undocumented feature: this enables links to the admin interface in the header/footer. I'm not sure where the admin
|
||||
@@ -151,3 +151,11 @@ ALLOWED_HOSTS = deduce_allowed_hosts(BUGSINK["BASE_URL"])
|
||||
|
||||
# django-tailwind setting; the below allows for environment-variable overriding of the npm binary path.
|
||||
NPM_BIN_PATH = os.getenv("NPM_BIN_PATH", "npm")
|
||||
|
||||
|
||||
FORCE_SCRIPT_NAME = deduce_script_name(BUGSINK["BASE_URL"])
|
||||
if FORCE_SCRIPT_NAME:
|
||||
# "in theory" a "relative" (non-leading-slash) config for STATIC_URL should just prepend [FORCE_]SCRIPT_NAME
|
||||
# automatically, but I haven't been able to get that to work reliably, https://code.djangoproject.com/ticket/34028
|
||||
# so we'll just be explicit about it.
|
||||
STATIC_URL = f"{FORCE_SCRIPT_NAME}/static/"
|
||||
|
||||
@@ -77,6 +77,27 @@ def deduce_allowed_hosts(base_url):
|
||||
return [url.hostname] + ["localhost", "127.0.0.1"]
|
||||
|
||||
|
||||
def deduce_script_name(base_url):
|
||||
"""Extract the path prefix from BASE_URL for subpath hosting support."""
|
||||
|
||||
# On the matter of leading an trailing slashes:
|
||||
# https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.13 (the CGI spec) -> SCRIPT_NAME must start with a /
|
||||
# trailing slash: doesn't matter https://github.com/django/django/commit/a15a3e9148e9 (but normalized away)
|
||||
# So: leading-but-no-trailing slash is what we want.
|
||||
# Our usage in STATIC_URL is made consistent with that.
|
||||
# Because BASE_URL is documented to be "no trailing slash", the below produces exactly what we want.
|
||||
|
||||
try:
|
||||
parsed_url = urlparse(base_url)
|
||||
path = parsed_url.path
|
||||
except Exception:
|
||||
# maximize robustness here: one broken setting shouldn't break the deduction for others (the brokenness of
|
||||
# BASE_URL will be manifested elsewhere more explicitly anyway)
|
||||
return None
|
||||
|
||||
return path if path not in (None, "", "/") else None
|
||||
|
||||
|
||||
# Note: the excessive string-matching in the below is intentional:
|
||||
# I'd rather have our error-handling code as simple as possible
|
||||
# instead of relying on all kinds of imports of Exception classes.
|
||||
|
||||
@@ -109,13 +109,13 @@
|
||||
{# overflow-x-auto is needed at the level of the flex item such that it works at the level where we need it (the code listings)#}
|
||||
<div class="ml-4 mb-4 mr-4 border-2 overflow-x-auto flex-[2_1_96rem]"><!-- the whole of the big tabbed view--> {# 96rem is 1536px, which matches the 2xl class; this is no "must" but eyeballing revealed: good result #}
|
||||
<div class="flex bg-slate-50 dark:bg-slate-800 border-b-2"><!-- container for the actual tab buttons -->
|
||||
<a href="/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "stacktrace" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Stacktrace" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/details/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "event-details" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Event Details" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/breadcrumbs/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "breadcrumbs" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Breadcrumbs" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/events/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "event-list" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Event List" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/tags/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "tags" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Tags" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/grouping/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "grouping" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Grouping" %}</div></a>
|
||||
<a href="/issues/issue/{{ issue.id }}/history/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "history" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "History" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "stacktrace" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Stacktrace" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/details/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "event-details" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Event Details" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/{% if event %}{{ event.id }}{% else %}last{% endif %}/breadcrumbs/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "breadcrumbs" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Breadcrumbs" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/events/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "event-list" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Event List" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/tags/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "tags" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Tags" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/grouping/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "grouping" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "Grouping" %}</div></a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/history/{% current_qs %}"><div class="p-4 font-bold hover:bg-slate-200 dark:hover:bg-slate-800 {% if tab == "history" %}text-cyan-500 dark:text-cyan-300 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">{% translate "History" %}</div></a>
|
||||
</div>
|
||||
|
||||
<div class="m-4"><!-- div for tab_content -->
|
||||
@@ -127,16 +127,16 @@
|
||||
{% if is_event_page %}<div>{% blocktranslate with digest_order=event.digest_order|intcomma total_events=issue.digested_event_count|intcomma ingested_at=event.ingested_at|date:"j M G:i T" %}Event {{ digest_order }} of {{ total_events }} which occured at <span class="font-bold">{{ ingested_at }}</span>{% endblocktranslate %}</div>{% endif %}
|
||||
<div class="ml-auto pr-4 font-bold text-slate-500 dark:text-slate-300">
|
||||
{% if is_event_page %}
|
||||
<a href="/events/event/{{ event.id }}/download/">{% translate "Download" %}</a>
|
||||
| <a href="/events/event/{{ event.id }}/raw/" >{% translate "JSON" %}</a>
|
||||
| <a href="/events/event/{{ event.id }}/plain/" >{% translate "Plain" %}</a>
|
||||
<a href="{{ script_prefix }}/events/event/{{ event.id }}/download/">{% translate "Download" %}</a>
|
||||
| <a href="{{ script_prefix }}/events/event/{{ event.id }}/raw/" >{% translate "JSON" %}</a>
|
||||
| <a href="{{ script_prefix }}/events/event/{{ event.id }}/plain/" >{% translate "Plain" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if app_settings.USE_ADMIN and user.is_staff %}
|
||||
{% if is_event_page %}
|
||||
| <a href="/admin/events/event/{{ event.id }}/change/">{% translate "Event Admin" %}</a> |
|
||||
| <a href="{{ script_prefix }}/admin/events/event/{{ event.id }}/change/">{% translate "Event Admin" %}</a> |
|
||||
{% endif %}
|
||||
<a href="/admin/issues/issue/{{ issue.id }}/change/">{% translate "Issue Admin" %}</a>
|
||||
<a href="{{ script_prefix }}/admin/issues/issue/{{ issue.id }}/change/">{% translate "Issue Admin" %}</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -119,11 +119,11 @@ TODO
|
||||
<tr class="border-slate-200 dark:border-slate-700 border-2 ">
|
||||
|
||||
<td class="p-4 font-bold text-slate-500 dark:text-slate-300 align-top">
|
||||
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/{% current_qs %}">{{ event.digest_order }}</a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/{{ event.id }}/{% current_qs %}">{{ event.digest_order }}</a>
|
||||
</td>
|
||||
|
||||
<td class="p-4 font-bold text-slate-500 dark:text-slate-300 align-top"> {# how useful is this really? #}
|
||||
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/{% current_qs %}">{{ event.id|truncatechars:9 }}</a>
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/{{ event.id }}/{% current_qs %}">{{ event.id|truncatechars:9 }}</a>
|
||||
</td>
|
||||
|
||||
<td class="p-4 font-mono whitespace-nowrap align-top">
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
</td>
|
||||
<td class="w-full ml-0 pb-4 pt-4 pr-4">
|
||||
<div>
|
||||
<a href="/issues/issue/{{ issue.id }}/event/last/{% current_qs %}" class="text-cyan-500 dark:text-cyan-300 fill-cyan-500 font-bold {% if issue.is_resolved %}italic{% endif %}">{% if issue.is_resolved %}<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6 inline"><path fill-rule="evenodd" d="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z" clip-rule="evenodd" />
|
||||
<a href="{{ script_prefix }}/issues/issue/{{ issue.id }}/event/last/{% current_qs %}" class="text-cyan-500 dark:text-cyan-300 fill-cyan-500 font-bold {% if issue.is_resolved %}italic{% endif %}">{% if issue.is_resolved %}<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6 inline"><path fill-rule="evenodd" d="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z" clip-rule="evenodd" />
|
||||
</svg>{% endif %}{% if issue.is_muted %}<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 inline">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.25 9.75 19.5 12m0 0 2.25 2.25M19.5 12l2.25-2.25M19.5 12l-2.25 2.25m-10.5-6 4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z" />
|
||||
</svg> {% endif %}{{ issue.title|truncatechars:100 }}</a>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<td class="w-full p-4">
|
||||
<div>
|
||||
{% if project.member or request.user.is_superuser %}
|
||||
<a href="/issues/{{ project.id }}" class="text-xl text-cyan-500 dark:text-cyan-300 font-bold">{{ project.name }}</a>
|
||||
<a href="{{ script_prefix }}/issues/{{ project.id }}" class="text-xl text-cyan-500 dark:text-cyan-300 font-bold">{{ project.name }}</a>
|
||||
{% else %}
|
||||
<span class="text-xl text-slate-800 dark:text-slate-100 font-bold">{{ project.name }}</span>
|
||||
{% endif %}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<body class="dark:bg-slate-700 dark:text-slate-100">
|
||||
<div id="content">
|
||||
<div class="flex pl-4 bg-slate-200 dark:bg-slate-800">
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="p-2 h-12 w-12 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="p-2 h-12 w-12 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="/"><div class="pt-4 pb-4 pl-2 pr-2 font-bold">Bugsink</div></a>
|
||||
<a href="{# probably broken? no (guaranteed) context! #}{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="p-2 h-12 w-12 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="p-2 h-12 w-12 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{# probably broken? no (guaranteed) context #}{{ script_prefix }}/"><div class="pt-4 pb-4 pl-2 pr-2 font-bold">Bugsink</div></a>
|
||||
</div>
|
||||
<div>
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
<body class="dark:bg-slate-700 dark:text-slate-100">
|
||||
<div id="content">
|
||||
<div class="flex pl-4 bg-slate-200 dark:bg-slate-800">
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="p-2 h-12 w-12 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="p-2 h-12 w-12 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="/"><div class="px-2 py-2 my-2 font-bold hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{{ site_title }}</div></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="p-2 h-12 w-12 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="p-2 h-12 w-12 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><div class="px-2 py-2 my-2 font-bold hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{{ site_title }}</div></a>
|
||||
|
||||
{% if not app_settings.SINGLE_TEAM %}
|
||||
<a href="{% url "team_list" %}"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Teams" %}</div></a>
|
||||
@@ -42,18 +42,18 @@
|
||||
|
||||
<div class="ml-auto flex">
|
||||
{% if app_settings.USE_ADMIN and user.is_staff %}
|
||||
<a href="/admin/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Admin" %}</div></a>
|
||||
<a href="{{ script_prefix }}/admin/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Admin" %}</div></a>
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_superuser %}
|
||||
<a href="/users/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Users" %}</div></a>
|
||||
<a href="/bsmain/auth_tokens/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Tokens" %}</div></a>
|
||||
<a href="{{ script_prefix }}/users/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Users" %}</div></a>
|
||||
<a href="{{ script_prefix }}/bsmain/auth_tokens/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Tokens" %}</div></a>
|
||||
{% endif %}
|
||||
|
||||
{% if logged_in_user.is_anonymous %}
|
||||
<a href="/accounts/login/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Login" %}</div></a> {# I don't think this is actually ever shown in practice, because you must always be logged in #}
|
||||
<a href="{{ script_prefix }}/accounts/login/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Login" %}</div></a> {# I don't think this is actually ever shown in practice, because you must always be logged in #}
|
||||
{% else %}
|
||||
<a href="/accounts/preferences/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Preferences" %}</div></a>
|
||||
<a href="{{ script_prefix }}/accounts/preferences/"><div class="px-4 py-2 my-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl">{% translate "Preferences" %}</div></a>
|
||||
<div class="px-4 py-2 my-2 mr-2 hover:bg-slate-300 dark:hover:bg-slate-700 rounded-xl"><form id="logout-form" method="post" action="{% url 'logout' %}">{% csrf_token %}<button type="submit">{% translate "Log out" %}</button></form></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="bg-cyan-100 dark:bg-cyan-900 h-screen overflow-y-scroll flex items-center justify-center"> {# the cyan background #}
|
||||
<div class="bg-white dark:bg-slate-900 lg:w-5/12 md:6/12 w-10/12"> {# the centered box #}
|
||||
<div class="bg-slate-200 dark:bg-slate-800 absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-full p-4 md:p-8"> {# the logo #}
|
||||
<a href="/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
<a href="{{ script_prefix }}/"><img src="{% static 'images/bugsink-logo.png' %}" class="h-8 w-8 md:h-16 md:w-16 dark:hidden block" alt="Bugsink logo"><img src="{% static 'images/bugsink-logo-dark.png' %}" class="h-8 w-8 md:h-16 md:w-16 hidden dark:block" alt="Bugsink logo"></a>
|
||||
</div>
|
||||
|
||||
<div class="p-12 md:pt-24 md:pl-24 md:pr-24 md:pb-16">
|
||||
|
||||
Reference in New Issue
Block a user