From 896dfda240d44817cd173e1802d09c413702a6d0 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 31 Jul 2026 11:43:43 +0200 Subject: [PATCH] fix: Preserve HTTPS X-Forwarded-Proto in Nginx and configure SECURE_PROXY_SSL_HEADER in Django to fix 403 CSRF verification on Django Admin --- .../__pycache__/settings.cpython-314.pyc | Bin 4475 -> 5303 bytes backend/shiftplan_backend/settings.py | 33 ++++- backend/staticfiles/admin/css/base.css | 123 ++++++------------ backend/staticfiles/admin/css/changelists.css | 40 +----- backend/staticfiles/admin/css/dark_mode.css | 16 --- backend/staticfiles/admin/css/forms.css | 42 ++---- backend/staticfiles/admin/css/responsive.css | 55 +++++--- .../staticfiles/admin/css/responsive_rtl.css | 24 ++-- backend/staticfiles/admin/css/rtl.css | 25 ++-- backend/staticfiles/admin/css/widgets.css | 29 +++-- backend/staticfiles/admin/img/LICENSE | 20 +++ backend/staticfiles/admin/img/README.txt | 7 + .../staticfiles/admin/img/calendar-icons.svg | 89 ++++++++----- .../admin/img/gis/move_vertex_off.svg | 1 + .../admin/img/gis/move_vertex_on.svg | 1 + .../staticfiles/admin/img/icon-addlink.svg | 10 +- backend/staticfiles/admin/img/icon-alert.svg | 10 +- .../staticfiles/admin/img/icon-calendar.svg | 12 +- .../staticfiles/admin/img/icon-changelink.svg | 10 +- backend/staticfiles/admin/img/icon-clock.svg | 16 +-- .../staticfiles/admin/img/icon-deletelink.svg | 12 +- .../staticfiles/admin/img/icon-hidelink.svg | 10 +- backend/staticfiles/admin/img/icon-no.svg | 10 +- .../admin/img/icon-unknown-alt.svg | 10 +- .../staticfiles/admin/img/icon-unknown.svg | 10 +- .../staticfiles/admin/img/icon-viewlink.svg | 10 +- backend/staticfiles/admin/img/icon-yes.svg | 10 +- .../staticfiles/admin/img/inline-delete.svg | 10 +- backend/staticfiles/admin/img/search.svg | 10 +- .../staticfiles/admin/img/selector-icons.svg | 59 ++++----- .../staticfiles/admin/img/sorting-icons.svg | 34 ++--- backend/staticfiles/admin/img/tooltag-add.svg | 10 +- .../admin/img/tooltag-arrowright.svg | 10 +- backend/staticfiles/admin/js/SelectFilter2.js | 30 +---- backend/staticfiles/admin/js/actions.js | 2 +- .../admin/js/admin/DateTimeShortcuts.js | 17 +-- backend/staticfiles/admin/js/calendar.js | 2 +- .../admin/js/unusable_password_field.js | 29 +++++ frontend/nginx.conf | 17 ++- 39 files changed, 366 insertions(+), 499 deletions(-) create mode 100644 backend/staticfiles/admin/img/LICENSE create mode 100644 backend/staticfiles/admin/img/README.txt create mode 100644 backend/staticfiles/admin/img/gis/move_vertex_off.svg create mode 100644 backend/staticfiles/admin/img/gis/move_vertex_on.svg create mode 100644 backend/staticfiles/admin/js/unusable_password_field.js diff --git a/backend/shiftplan_backend/__pycache__/settings.cpython-314.pyc b/backend/shiftplan_backend/__pycache__/settings.cpython-314.pyc index 6ee52fbb7fdf43ae5f320f80f182b5c093e82992..78ce6aba57e731e0de0a51a90a9eba6fbabf11c3 100644 GIT binary patch delta 1394 zcmZ`&-A^J{6u&ckh%z$6hroi$77$l-2T|9rZrKvWFD%eI7`4ePWu;ZD0fgI_5EJaC zX*5l$mZodp*r#=0wl+SrFHM^ErA_+)(a2<8{1oc=Ib=$z0hL^UECnXVtFYbMoMGYK07H!}t!y?NE(u z7N~(*sKZnXR6;#8VDxs7a1kykOQ7q}h~B_QoBxrdBv#&f{0HeK2wVPNi3R(1sd>>3 z-KYchAqTz;o!D-`e$>S);6RV^WjB!%-a_4Q5cR+zI1EQv5{|+*S;9r4n>dHX=7NL` zUpfo66o`W^Z~jZ^{hqL>8{^t-sEOf-sz}v{h83qZ^T>O!`An zo=nG=;|Y;Sit=bG^+6&g5-Va;21U~-v(X+$E26Sea-W`STcWK zwW^%Mpz=RuIwkqPRQGar$D^5tGmiof14nm$8auI1mF?~(OHd235?E>Q{^(*t&&EojejnvQL`KxuYocV<5iY!l~7YRA2&E}GagH7iip z%T#BH>O3UQDCe^VpmqG&1ey$6-tz{2C;wUkcRshzx~W__NdCAC~?i*J1x3{j65w delta 600 zcmYk1O-~b16o&7ej-|A8W?K3&{h}1KiY;?Rsz5=}`cbNZ;%VKOG*xPV5~8&|#)L#L z{)1)~Kw@;`0yhfjLbiql3pO+*G3m;mVBEU#PBF%tocBICC-=SQ{W|n}K#ECrE8*ux zd37Zs*Ckb06!$L7Qvs#==UCVVJqf{>6M}LO@74se3eae*5=;N^5Z%bl61 zQS^X{UcQU$1Nv_lwV*a0iz9TyH!Fi50uX~x!2*ys$ zH4*(Vf&sXUL2zS;S09XGn7btYcfo$Rf)Tii126{TFrf*Mgh`Du0SCeD!L$6~IiQ0) zY`7D+OopcQsQK-1+jT1kcZ+#=n9JX}UCcrzotewE$(m&uv65u$;##*sH3Rh%^D~-n zq`G!ZjRo7XiAMD!sT8PMc#yWG`s7uyRI4tw&(yG5u2hYbjU#!Sn%eZaZgH&G?(q)g zReK@muN@2higVLiw{A*xX=`KG)KU`Pm1I*%?vJ*V={NSDW_`-(n_y#K)<3Q9mrhu! z6_{_b)K27Z>D$s_`CVq~=7;ol`hA8sn|vgyKZ4O6+i@UqEULf6Mpy4P_2x_@_<+`W Q__qgP?~EoMOuD%K0m^BSZvX%Q diff --git a/backend/shiftplan_backend/settings.py b/backend/shiftplan_backend/settings.py index dd0c1a1..c622bba 100644 --- a/backend/shiftplan_backend/settings.py +++ b/backend/shiftplan_backend/settings.py @@ -10,14 +10,37 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-key-shiftplan-change- DEBUG = os.environ.get('DEBUG', 'True') == 'True' -ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '*').split(',') +ALLOWED_HOSTS = [h.strip() for h in os.environ.get('ALLOWED_HOSTS', '*').split(',') if h.strip()] + +# Reverse Proxy & SSL Configuration for Coolify / Traefik +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +USE_X_FORWARDED_HOST = True +USE_X_FORWARDED_PORT = True + +# CSRF & Trusted Origins Configuration +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost', + 'http://127.0.0.1', + 'https://*.op3n.link', + 'http://*.op3n.link', +] -# CSRF & Origin configuration for reverse proxies (Coolify, Traefik, custom domains) raw_csrf = os.environ.get('CSRF_TRUSTED_ORIGINS', '') if raw_csrf: - CSRF_TRUSTED_ORIGINS = [o.strip() for o in raw_csrf.split(',') if o.strip()] -else: - CSRF_TRUSTED_ORIGINS = ['http://*', 'https://*'] + for origin in raw_csrf.split(','): + o = origin.strip() + if o and o not in CSRF_TRUSTED_ORIGINS: + CSRF_TRUSTED_ORIGINS.append(o) + +for h in ALLOWED_HOSTS: + if h and h != '*': + if not h.startswith('http://') and not h.startswith('https://'): + http_origin = f'http://{h}' + https_origin = f'https://{h}' + if http_origin not in CSRF_TRUSTED_ORIGINS: + CSRF_TRUSTED_ORIGINS.append(http_origin) + if https_origin not in CSRF_TRUSTED_ORIGINS: + CSRF_TRUSTED_ORIGINS.append(https_origin) INSTALLED_APPS = [ 'django.contrib.admin', diff --git a/backend/staticfiles/admin/css/base.css b/backend/staticfiles/admin/css/base.css index a3ddccd..3791043 100644 --- a/backend/staticfiles/admin/css/base.css +++ b/backend/staticfiles/admin/css/base.css @@ -34,16 +34,9 @@ html[data-theme="light"], --error-fg: #ba2121; - --message-debug-bg: #efefef; - --message-debug-icon: url(../img/icon-debug.svg); - --message-info-bg: #ccefff; - --message-info-icon: url(../img/icon-info.svg); --message-success-bg: #dfd; - --message-success-icon: url(../img/icon-yes.svg); --message-warning-bg: #ffc; - --message-warning-icon: url(../img/icon-alert.svg); --message-error-bg: #ffefef; - --message-error-icon: url(../img/icon-no.svg); --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */ --selected-bg: #e4e4e4; /* E.g. selected table cells */ @@ -125,16 +118,6 @@ a:focus { text-decoration: underline; } -a:not( - [role="button"], - #header a, - #nav-sidebar a, - #content-main.app-list a, - .object-tools a -) { - text-decoration: underline; -} - a img { border: none; } @@ -243,10 +226,10 @@ details summary { blockquote { font-size: 0.6875rem; - color: var(--body-quiet-color); + color: #777; margin-left: 2px; padding-left: 10px; - border-left: 5px solid currentColor; + border-left: 5px solid #ddd; } code, pre { @@ -645,44 +628,20 @@ ul.messagelist li { font-size: 0.8125rem; padding: 10px 10px 10px 65px; margin: 0 0 10px 0; + background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat; + background-size: 16px auto; color: var(--body-fg); word-break: break-word; - background-color: var(--message-info-bg); - background-image: var(--message-info-icon); - background-position: 40px 12px; - background-repeat: no-repeat; - background-size: 16px auto; -} - -ul.messagelist li.debug { - background-color: var(--message-debug-bg); - background-image: var(--message-debug-icon); -} - -ul.messagelist li.info { - background-color: var(--message-info-bg); - background-image: var(--message-info-icon); -} - -ul.messagelist li.success { - background-color: var(--message-success-bg); - background-image: var(--message-success-icon); } ul.messagelist li.warning { - background-color: var(--message-warning-bg); - background-image: var(--message-warning-icon); + background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat; + background-size: 14px auto; } ul.messagelist li.error { - background-color: var(--message-error-bg); - background-image: var(--message-error-icon); -} - -@media (forced-colors: active) { - ul.messagelist li { - border: 1px solid; - } + background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat; + background-size: 16px auto; } .errornote { @@ -809,19 +768,19 @@ a.deletelink:focus, a.deletelink:hover { /* OBJECT TOOLS */ .object-tools { - padding: 0; - overflow: hidden; - text-align: right; - margin: 0 0 15px; + font-size: 0.625rem; + font-weight: bold; + padding-left: 0; + float: right; + position: relative; + margin-top: -48px; } .object-tools li { - display: inline-block; - height: auto; -} - -.object-tools li + li { - margin-left: 15px; + display: block; + float: left; + margin-left: 5px; + height: 1rem; } .object-tools a { @@ -1161,40 +1120,40 @@ a.deletelink:focus, a.deletelink:hover { line-height: 22px; margin: 0; border-top: 1px solid var(--hairline-color); + width: 100%; box-sizing: border-box; } -.paginator ul { - margin: 0; - margin-right: 6px; -} - -.paginator ul li { - display: inline-block; - line-height: 22px; - padding: 0; -} - -.paginator a { - display: inline-block; +.paginator a:link, .paginator a:visited { padding: 2px 6px; -} - -.paginator a:not(.showall) { background: var(--button-bg); text-decoration: none; color: var(--button-fg); } -.paginator a[aria-current="page"] { - color: var(--body-quiet-color); - background: transparent; - font-weight: bold; - cursor: default; +.paginator a.showall { + border: none; + background: none; + color: var(--link-fg); } -.paginator a:not([aria-current="page"], .showall):focus, -.paginator a:not([aria-current="page"], .showall):hover { +.paginator a.showall:focus, .paginator a.showall:hover { + background: none; + color: var(--link-hover-color); +} + +.paginator .end { + margin-right: 6px; +} + +.paginator .this-page { + padding: 2px 6px; + font-weight: bold; + font-size: 0.8125rem; + vertical-align: top; +} + +.paginator a:focus, .paginator a:hover { color: white; background: var(--link-hover-color); } diff --git a/backend/staticfiles/admin/css/changelists.css b/backend/staticfiles/admin/css/changelists.css index 0f367f8..005b776 100644 --- a/backend/staticfiles/admin/css/changelists.css +++ b/backend/staticfiles/admin/css/changelists.css @@ -1,22 +1,14 @@ /* CHANGELISTS */ -#changelist .changelist-form-container { +#changelist { display: flex; align-items: flex-start; - width: 100%; + justify-content: space-between; } -#changelist .changelist-form-container > div { +#changelist .changelist-form-container { flex: 1 1 auto; -} - -#changelist .changelist-form-container:not(:has(#changelist-filter)) > div { - width: 100%; -} - -#changelist .changelist-form-container:has(#changelist-filter) > div { min-width: 0; - max-width: calc(100% - 270px); } #changelist table { @@ -33,8 +25,8 @@ min-height: 400px; } -.change-list .filtered .results, .filtered #toolbar, -.filtered div.xfull { +.change-list .filtered .results, .change-list .filtered .paginator, +.filtered #toolbar, .filtered div.xfull { width: auto; } @@ -51,31 +43,11 @@ border-bottom: 1px solid var(--hairline-color); } -#changelist .changelist-footer { - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px; - border-top: 1px solid var(--hairline-color); - border-bottom: 1px solid var(--hairline-color); -} - -#changelist .changelist-footer .paginator { - color: var(--body-quiet-color); - background: var(--body-bg); - border: none; - padding: 0; -} - #changelist .paginator { color: var(--body-quiet-color); border-bottom: 1px solid var(--hairline-color); background: var(--body-bg); -} - -#changelist .paginator ul { - padding: 0; - white-space: nowrap; + overflow: hidden; } /* CHANGELIST TABLES */ diff --git a/backend/staticfiles/admin/css/dark_mode.css b/backend/staticfiles/admin/css/dark_mode.css index 76cbf17..65b58d0 100644 --- a/backend/staticfiles/admin/css/dark_mode.css +++ b/backend/staticfiles/admin/css/dark_mode.css @@ -20,17 +20,9 @@ --border-color: #353535; --error-fg: #e35f5f; - - --message-debug-bg: #4e4e4e; - --message-debug-icon: url(../img/icon-debug-dark.svg); - --message-info-bg: #265895; - --message-info-icon: url(../img/icon-info-dark.svg); --message-success-bg: #006b1b; - --message-success-icon: url(../img/icon-yes-dark.svg); --message-warning-bg: #583305; - --message-warning-icon: url(../img/icon-alert-dark.svg); --message-error-bg: #570808; - --message-error-icon: url(../img/icon-no-dark.svg); --darkened-bg: #212121; --selected-bg: #1b1b1b; @@ -65,17 +57,9 @@ html[data-theme="dark"] { --border-color: #353535; --error-fg: #e35f5f; - - --message-debug-bg: #4e4e4e; - --message-debug-icon: url(../img/icon-debug-dark.svg); - --message-info-bg: #265895; - --message-info-icon: url(../img/icon-info-dark.svg); --message-success-bg: #006b1b; - --message-success-icon: url(../img/icon-yes-dark.svg); --message-warning-bg: #583305; - --message-warning-icon: url(../img/icon-alert-dark.svg); --message-error-bg: #570808; - --message-error-icon: url(../img/icon-no-dark.svg); --darkened-bg: #212121; --selected-bg: #1b1b1b; diff --git a/backend/staticfiles/admin/css/forms.css b/backend/staticfiles/admin/css/forms.css index 9621ac2..c6ce788 100644 --- a/backend/staticfiles/admin/css/forms.css +++ b/backend/staticfiles/admin/css/forms.css @@ -30,20 +30,18 @@ form .form-row p { flex-wrap: wrap; } -.form-multiline > div, -.form-multiline > fieldset { +.form-multiline > div { padding-bottom: 10px; } /* FORM LABELS */ -legend, label { +label { font-weight: normal; color: var(--body-quiet-color); font-size: 0.8125rem; } -.required legend, legend.required, .required label, label.required { font-weight: bold; } @@ -93,20 +91,6 @@ fieldset .inline-heading, /* ALIGNED FIELDSETS */ -.aligned fieldset { - flex-grow: 1; - border-top: none; -} - -.aligned fieldset > div { - width: 100%; -} - -.aligned legend { - float: inline-start; -} - -.aligned legend, .aligned label { display: block; padding: 4px 10px 0 0; @@ -149,7 +133,7 @@ form .aligned ul { } form .aligned div.radiolist { - display: block; + display: inline-block; margin: 0; padding: 0; } @@ -217,8 +201,7 @@ fieldset .fieldBox { /* WIDE FIELDSETS */ -.wide label, -.wide legend { +.wide label { width: 200px; } @@ -355,7 +338,7 @@ body.popup .submit-row { width: 48em; } -.app-flatpages.model-flatpage #id_content { +.flatpages-flatpage #id_content { height: 40.2em; } @@ -430,12 +413,9 @@ body.popup .submit-row { border: none; } -.inline-related.tabular div.wrapper { - overflow-x: auto; -} - .inline-related.tabular fieldset.module table { width: 100%; + overflow-x: scroll; } .last-related fieldset { @@ -449,6 +429,7 @@ body.popup .submit-row { .inline-group .tabular tr td.original { padding: 2px 0 0 0; width: 0; + _position: relative; } .inline-group .tabular th.original { @@ -456,19 +437,16 @@ body.popup .submit-row { padding: 0; } -.inline-group .tabular td { - font-size: 1rem; -} - .inline-group .tabular td.original p { position: absolute; left: 0; - height: 1.2em; + height: 1.1em; padding: 2px 9px; overflow: hidden; - font-size: 0.875rem; + font-size: 0.5625rem; font-weight: bold; color: var(--body-quiet-color); + _width: 700px; } .inline-group div.add-row, diff --git a/backend/staticfiles/admin/css/responsive.css b/backend/staticfiles/admin/css/responsive.css index 93abf79..f0fcade 100644 --- a/backend/staticfiles/admin/css/responsive.css +++ b/backend/staticfiles/admin/css/responsive.css @@ -170,7 +170,6 @@ input[type="submit"], button { /* Forms */ - legend, label { font-size: 1rem; } @@ -338,8 +337,16 @@ input[type="submit"], button { /* Messages */ ul.messagelist li { - padding: 10px 10px 10px 55px; - background-position-x: 30px; + padding-left: 55px; + background-position: 30px 12px; + } + + ul.messagelist li.error { + background-position: 30px 12px; + } + + ul.messagelist li.warning { + background-position: 30px 14px; } /* Login */ @@ -410,15 +417,11 @@ input[type="submit"], button { /* Changelist */ - #changelist .changelist-form-container { + #changelist { + align-items: stretch; flex-direction: column; } - #changelist .changelist-form-container:has(#changelist-filter) > div { - max-width: 100%; - width: 100%; - } - #toolbar { padding: 10px; } @@ -441,12 +444,25 @@ input[type="submit"], button { } #changelist-filter { - width: 100%; + position: static; + width: auto; margin-top: 30px; } .object-tools { - text-align: left; + float: none; + margin: 0 0 15px; + padding: 0; + overflow: hidden; + } + + .object-tools li { + height: auto; + margin-left: 0; + } + + .object-tools li + li { + margin-left: 15px; } /* Forms */ @@ -485,7 +501,6 @@ input[type="submit"], button { padding-top: 15px; } - .aligned legend, .aligned label { width: 100%; min-width: auto; @@ -560,10 +575,6 @@ input[type="submit"], button { margin-top: 5px; } - form .aligned fieldset div.flex-container { - display: unset; - } - /* Related widget */ .related-widget-wrapper { @@ -728,8 +739,16 @@ input[type="submit"], button { /* Messages */ ul.messagelist li { - padding: 10px 10px 10px 40px; - background-position-x: 15px; + padding-left: 40px; + background-position: 15px 12px; + } + + ul.messagelist li.error { + background-position: 15px 12px; + } + + ul.messagelist li.warning { + background-position: 15px 14px; } /* Paginator */ diff --git a/backend/staticfiles/admin/css/responsive_rtl.css b/backend/staticfiles/admin/css/responsive_rtl.css index b336bbf..5e8f5c5 100644 --- a/backend/staticfiles/admin/css/responsive_rtl.css +++ b/backend/staticfiles/admin/css/responsive_rtl.css @@ -34,15 +34,19 @@ background-position: calc(100% - 8px) 9px; } + [dir="rtl"] .object-tools li { + float: right; + } + + [dir="rtl"] .object-tools li + li { + margin-left: 0; + margin-right: 15px; + } + [dir="rtl"] .dashboard .module table td a { padding-left: 0; padding-right: 16px; } - - [dir="rtl"] ul.messagelist li { - padding: 10px 55px 10px 10px; - background-position-x: calc(100% - 30px); - } } /* MOBILE */ @@ -63,11 +67,6 @@ margin-left: 0; margin-right: 0; } - - [dir="rtl"] .object-tools { - text-align: right; - } - [dir="rtl"] .aligned .vCheckboxLabel { padding: 1px 5px 0 0; } @@ -87,9 +86,4 @@ [dir="rtl"] :enabled.selector-add:focus, :enabled.selector-add:hover { background-position: 0 -72px; } - - [dir="rtl"] ul.messagelist li { - padding: 10px 40px 10px 10px; - background-position-x: calc(100% - 15px); - } } diff --git a/backend/staticfiles/admin/css/rtl.css b/backend/staticfiles/admin/css/rtl.css index ba4d0bf..a2556d0 100644 --- a/backend/staticfiles/admin/css/rtl.css +++ b/backend/staticfiles/admin/css/rtl.css @@ -26,12 +26,7 @@ th { } .object-tools { - text-align: left; -} - -.object-tools li + li { - margin-right: 15px; - margin-left: 0; + float: left; } thead th:first-child, @@ -112,7 +107,7 @@ thead th.sorted .text { border-left: none; } -.paginator ul { +.paginator .end { margin-left: 6px; margin-right: 0; } @@ -124,8 +119,7 @@ thead th.sorted .text { /* FORMS */ -.aligned label, -.aligned legend { +.aligned label { padding: 0 0 3px 1em; } @@ -243,10 +237,18 @@ fieldset .fieldBox { background-position: 0 -168px; } +.selector-chooseall { + background: url(../img/selector-icons.svg) right -128px no-repeat; +} + :enabled.selector-chooseall:focus, :enabled.selector-chooseall:hover { background-position: 100% -144px; } +.selector-clearall { + background: url(../img/selector-icons.svg) 0 -160px no-repeat; +} + :enabled.selector-clearall:focus, :enabled.selector-clearall:hover { background-position: 0 -176px; } @@ -289,8 +291,3 @@ form .form-row p.datetime { .selector .selector-chooser { margin: 0; } - -ul.messagelist li { - padding: 10px 65px 10px 10px; - background-position-x: calc(100% - 40px); -} diff --git a/backend/staticfiles/admin/css/widgets.css b/backend/staticfiles/admin/css/widgets.css index 43271f8..a5f615a 100644 --- a/backend/staticfiles/admin/css/widgets.css +++ b/backend/staticfiles/admin/css/widgets.css @@ -162,21 +162,21 @@ .selector-chooseall, .selector-clearall { display: inline-block; + height: 16px; text-align: left; - padding: 4px 5px; margin: 0 auto; overflow: hidden; - color: var(--button-fg); - background-color: var(--button-bg); + font-weight: bold; + line-height: 16px; + color: var(--body-quiet-color); text-decoration: none; opacity: 0.55; border: none; - border-radius: 4px; } :enabled.selector-chooseall:focus, :enabled.selector-clearall:focus, :enabled.selector-chooseall:hover, :enabled.selector-clearall:hover { - background-color: var(--button-hover-bg); + color: var(--link-fg); } :enabled.selector-chooseall, :enabled.selector-clearall { @@ -187,10 +187,22 @@ cursor: pointer; } +.selector-chooseall { + padding: 0 18px 0 0; + background: url(../img/selector-icons.svg) right -160px no-repeat; + cursor: default; +} + :enabled.selector-chooseall:focus, :enabled.selector-chooseall:hover { background-position: 100% -176px; } +.selector-clearall { + padding: 0 0 0 18px; + background: url(../img/selector-icons.svg) 0 -128px no-repeat; + cursor: default; +} + :enabled.selector-clearall:focus, :enabled.selector-clearall:hover { background-position: 0 -144px; } @@ -301,10 +313,6 @@ p.datetime { font-weight: bold; } -p.datetime label { - display: inline; -} - .datetime span { white-space: nowrap; font-weight: normal; @@ -568,8 +576,7 @@ ul.timelist, .timelist li { .inline-deletelink { float: right; text-indent: -9999px; - background: url(../img/inline-delete.svg) center center no-repeat; - background-size: contain; + background: url(../img/inline-delete.svg) 0 0 no-repeat; width: 1.5rem; height: 1.5rem; border: 0px none; diff --git a/backend/staticfiles/admin/img/LICENSE b/backend/staticfiles/admin/img/LICENSE new file mode 100644 index 0000000..a4faaa1 --- /dev/null +++ b/backend/staticfiles/admin/img/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Code Charm Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/backend/staticfiles/admin/img/README.txt b/backend/staticfiles/admin/img/README.txt new file mode 100644 index 0000000..bf81f35 --- /dev/null +++ b/backend/staticfiles/admin/img/README.txt @@ -0,0 +1,7 @@ +All icons are taken from Font Awesome (https://fontawesome.com/) project. +The Font Awesome font is licensed under the SIL OFL 1.1: +- https://scripts.sil.org/OFL + +SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG +Font-Awesome-SVG-PNG is licensed under the MIT license (see file license +in current folder). diff --git a/backend/staticfiles/admin/img/calendar-icons.svg b/backend/staticfiles/admin/img/calendar-icons.svg index 7845abb..04c0274 100644 --- a/backend/staticfiles/admin/img/calendar-icons.svg +++ b/backend/staticfiles/admin/img/calendar-icons.svg @@ -1,44 +1,63 @@ + - - - - + width="15" + height="30" + viewBox="0 0 1792 3584" + version="1.1" + id="svg5" + sodipodi:docname="calendar-icons.svg" + inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + + + + d="m 1037,1395 102,-102 q 19,-19 19,-45 0,-26 -19,-45 L 832,896 1139,589 q 19,-19 19,-45 0,-26 -19,-45 L 1037,397 q -19,-19 -45,-19 -26,0 -45,19 L 493,851 q -19,19 -19,45 0,26 19,45 l 454,454 q 19,19 45,19 26,0 45,-19 z m 627,-499 q 0,209 -103,385.5 Q 1458,1458 1281.5,1561 1105,1664 896,1664 687,1664 510.5,1561 334,1458 231,1281.5 128,1105 128,896 128,687 231,510.5 334,334 510.5,231 687,128 896,128 1105,128 1281.5,231 1458,334 1561,510.5 1664,687 1664,896 Z" + id="path1" /> - - + + d="m 845,1395 454,-454 q 19,-19 19,-45 0,-26 -19,-45 L 845,397 q -19,-19 -45,-19 -26,0 -45,19 L 653,499 q -19,19 -19,45 0,26 19,45 l 307,307 -307,307 q -19,19 -19,45 0,26 19,45 l 102,102 q 19,19 45,19 26,0 45,-19 z m 819,-499 q 0,209 -103,385.5 Q 1458,1458 1281.5,1561 1105,1664 896,1664 687,1664 510.5,1561 334,1458 231,1281.5 128,1105 128,896 128,687 231,510.5 334,334 510.5,231 687,128 896,128 1105,128 1281.5,231 1458,334 1561,510.5 1664,687 1664,896 Z" + id="path2" /> + xlink:href="#next" + x="0" + y="5376" + fill="#000000" + id="use5" + transform="translate(0,-3584)" /> + xlink:href="#previous" + x="0" + y="0" + fill="#333333" + id="use2" + style="fill:#000000;fill-opacity:1" /> diff --git a/backend/staticfiles/admin/img/gis/move_vertex_off.svg b/backend/staticfiles/admin/img/gis/move_vertex_off.svg new file mode 100644 index 0000000..228854f --- /dev/null +++ b/backend/staticfiles/admin/img/gis/move_vertex_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/staticfiles/admin/img/gis/move_vertex_on.svg b/backend/staticfiles/admin/img/gis/move_vertex_on.svg new file mode 100644 index 0000000..96b87fd --- /dev/null +++ b/backend/staticfiles/admin/img/gis/move_vertex_on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/staticfiles/admin/img/icon-addlink.svg b/backend/staticfiles/admin/img/icon-addlink.svg index 20fb814..8d5c6a3 100644 --- a/backend/staticfiles/admin/img/icon-addlink.svg +++ b/backend/staticfiles/admin/img/icon-addlink.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-alert.svg b/backend/staticfiles/admin/img/icon-alert.svg index 9b4ee36..e51ea83 100644 --- a/backend/staticfiles/admin/img/icon-alert.svg +++ b/backend/staticfiles/admin/img/icon-alert.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-calendar.svg b/backend/staticfiles/admin/img/icon-calendar.svg index 827ca5d..97910a9 100644 --- a/backend/staticfiles/admin/img/icon-calendar.svg +++ b/backend/staticfiles/admin/img/icon-calendar.svg @@ -1,15 +1,9 @@ - - + - - + - + diff --git a/backend/staticfiles/admin/img/icon-changelink.svg b/backend/staticfiles/admin/img/icon-changelink.svg index 6316702..592b093 100644 --- a/backend/staticfiles/admin/img/icon-changelink.svg +++ b/backend/staticfiles/admin/img/icon-changelink.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-clock.svg b/backend/staticfiles/admin/img/icon-clock.svg index 51f4db4..bf9985d 100644 --- a/backend/staticfiles/admin/img/icon-clock.svg +++ b/backend/staticfiles/admin/img/icon-clock.svg @@ -1,15 +1,9 @@ - - - + + - - + - - + + diff --git a/backend/staticfiles/admin/img/icon-deletelink.svg b/backend/staticfiles/admin/img/icon-deletelink.svg index eac19d7..4059b15 100644 --- a/backend/staticfiles/admin/img/icon-deletelink.svg +++ b/backend/staticfiles/admin/img/icon-deletelink.svg @@ -1,11 +1,3 @@ - - - - - - + + diff --git a/backend/staticfiles/admin/img/icon-hidelink.svg b/backend/staticfiles/admin/img/icon-hidelink.svg index 9462691..2a8b404 100644 --- a/backend/staticfiles/admin/img/icon-hidelink.svg +++ b/backend/staticfiles/admin/img/icon-hidelink.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-no.svg b/backend/staticfiles/admin/img/icon-no.svg index 6c5b15d..2e0d383 100644 --- a/backend/staticfiles/admin/img/icon-no.svg +++ b/backend/staticfiles/admin/img/icon-no.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-unknown-alt.svg b/backend/staticfiles/admin/img/icon-unknown-alt.svg index a7a51e7..1c6b99f 100644 --- a/backend/staticfiles/admin/img/icon-unknown-alt.svg +++ b/backend/staticfiles/admin/img/icon-unknown-alt.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-unknown.svg b/backend/staticfiles/admin/img/icon-unknown.svg index 3acf303..50b4f97 100644 --- a/backend/staticfiles/admin/img/icon-unknown.svg +++ b/backend/staticfiles/admin/img/icon-unknown.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-viewlink.svg b/backend/staticfiles/admin/img/icon-viewlink.svg index 40c86be..a1ca1d3 100644 --- a/backend/staticfiles/admin/img/icon-viewlink.svg +++ b/backend/staticfiles/admin/img/icon-viewlink.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/icon-yes.svg b/backend/staticfiles/admin/img/icon-yes.svg index 71683dc..5883d87 100644 --- a/backend/staticfiles/admin/img/icon-yes.svg +++ b/backend/staticfiles/admin/img/icon-yes.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/inline-delete.svg b/backend/staticfiles/admin/img/inline-delete.svg index 93e7e9d..8751150 100644 --- a/backend/staticfiles/admin/img/inline-delete.svg +++ b/backend/staticfiles/admin/img/inline-delete.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/search.svg b/backend/staticfiles/admin/img/search.svg index 75c21a5..c8c69b2 100644 --- a/backend/staticfiles/admin/img/search.svg +++ b/backend/staticfiles/admin/img/search.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/selector-icons.svg b/backend/staticfiles/admin/img/selector-icons.svg index a953b29..926b8e2 100644 --- a/backend/staticfiles/admin/img/selector-icons.svg +++ b/backend/staticfiles/admin/img/selector-icons.svg @@ -1,45 +1,34 @@ - - + - - + - - - - - - + - - + + + + + + + + + + - - - - - - - + + + + + + + + + + + diff --git a/backend/staticfiles/admin/img/sorting-icons.svg b/backend/staticfiles/admin/img/sorting-icons.svg index c3baa4a..7c31ec9 100644 --- a/backend/staticfiles/admin/img/sorting-icons.svg +++ b/backend/staticfiles/admin/img/sorting-icons.svg @@ -1,35 +1,19 @@ - - + - - + - - + - - + - - - - - + + + + + diff --git a/backend/staticfiles/admin/img/tooltag-add.svg b/backend/staticfiles/admin/img/tooltag-add.svg index 49cce19..1ca64ae 100644 --- a/backend/staticfiles/admin/img/tooltag-add.svg +++ b/backend/staticfiles/admin/img/tooltag-add.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/img/tooltag-arrowright.svg b/backend/staticfiles/admin/img/tooltag-arrowright.svg index 55ed8e5..b664d61 100644 --- a/backend/staticfiles/admin/img/tooltag-arrowright.svg +++ b/backend/staticfiles/admin/img/tooltag-arrowright.svg @@ -1,9 +1,3 @@ - - - - + + diff --git a/backend/staticfiles/admin/js/SelectFilter2.js b/backend/staticfiles/admin/js/SelectFilter2.js index 2100280..970b511 100644 --- a/backend/staticfiles/admin/js/SelectFilter2.js +++ b/backend/staticfiles/admin/js/SelectFilter2.js @@ -15,8 +15,7 @@ Requires core.js and SelectBox.js. const from_box = document.getElementById(field_id); from_box.id += '_from'; // change its ID from_box.className = 'filtered'; - from_box.setAttribute('aria-labelledby', field_id + '_from_label'); - from_box.setAttribute('aria-describedby', `${field_id}_helptext ${field_id}_choose_helptext`); + from_box.setAttribute('aria-labelledby', field_id + '_from_title'); for (const p of from_box.parentNode.getElementsByTagName('p')) { if (p.classList.contains("info")) { @@ -43,20 +42,12 @@ Requires core.js and SelectBox.js. const selector_available_title = quickElement('div', selector_available); selector_available_title.id = field_id + '_from_title'; selector_available_title.className = 'selector-available-title'; - quickElement( - 'label', - selector_available_title, - interpolate(gettext('Available %s') + ' ', [field_name]), - 'id', - field_id + '_from_label', - 'for', - field_id + '_from' - ); + quickElement('label', selector_available_title, interpolate(gettext('Available %s') + ' ', [field_name]), 'for', field_id + '_from'); quickElement( 'p', selector_available_title, interpolate(gettext('Choose %s by selecting them and then select the "Choose" arrow button.'), [field_name]), - 'id', `${field_id}_choose_helptext`, 'class', 'helptext' + 'class', 'helptext' ); const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); @@ -111,20 +102,12 @@ Requires core.js and SelectBox.js. const selector_chosen_title = quickElement('div', selector_chosen); selector_chosen_title.className = 'selector-chosen-title'; selector_chosen_title.id = field_id + '_to_title'; - quickElement( - 'label', - selector_chosen_title, - interpolate(gettext('Chosen %s') + ' ', [field_name]), - 'id', - field_id + '_to_label', - 'for', - field_id + '_to' - ); + quickElement('label', selector_chosen_title, interpolate(gettext('Chosen %s') + ' ', [field_name]), 'for', field_id + '_to'); quickElement( 'p', selector_chosen_title, interpolate(gettext('Remove %s by selecting them and then select the "Remove" arrow button.'), [field_name]), - 'id', `${field_id}_remove_helptext`, 'class', 'helptext' + 'class', 'helptext' ); const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected'); @@ -151,8 +134,7 @@ Requires core.js and SelectBox.js. 'multiple', '', 'size', from_box.size, 'name', from_box.name, - 'aria-labelledby', field_id + '_to_label', - 'aria-describedby', `${field_id}_helptext ${field_id}_remove_helptext`, + 'aria-labelledby', field_id + '_to_title', 'class', 'filtered' ); const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display'); diff --git a/backend/staticfiles/admin/js/actions.js b/backend/staticfiles/admin/js/actions.js index 23295f5..04b25e9 100644 --- a/backend/staticfiles/admin/js/actions.js +++ b/backend/staticfiles/admin/js/actions.js @@ -172,7 +172,7 @@ if (document.querySelector('[name=action]').value) { const text = list_editable_changed ? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.") - : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Run button rather than the Save button."); + : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button."); if (!confirm(text)) { event.preventDefault(); } diff --git a/backend/staticfiles/admin/js/admin/DateTimeShortcuts.js b/backend/staticfiles/admin/js/admin/DateTimeShortcuts.js index 6251614..aa1cae9 100644 --- a/backend/staticfiles/admin/js/admin/DateTimeShortcuts.js +++ b/backend/staticfiles/admin/js/admin/DateTimeShortcuts.js @@ -91,10 +91,7 @@ message = interpolate(message, [timezoneOffset]); const warning = document.createElement('div'); - const id = inp.id; - const field_id = inp.closest('p.datetime') ? id.slice(0, id.lastIndexOf("_")) : id; warning.classList.add('help', warningClass); - warning.id = `${field_id}_timezone_warning_helptext`; warning.textContent = message; inp.parentNode.appendChild(warning); }, @@ -111,7 +108,6 @@ const now_link = document.createElement('a'); now_link.href = "#"; now_link.textContent = gettext('Now'); - now_link.role = 'button'; now_link.addEventListener('click', function(e) { e.preventDefault(); DateTimeShortcuts.handleClockQuicklink(num, -1); @@ -167,7 +163,7 @@ // where name is the name attribute of the