accrete 0.0.150__py3-none-any.whl → 0.0.151__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- accrete/contrib/log/queries.py +3 -1
- accrete/contrib/ui/admin.py +9 -1
- accrete/contrib/ui/forms.py +57 -0
- accrete/contrib/ui/migrations/0001_initial.py +39 -0
- accrete/contrib/ui/migrations/0002_alter_theme_color_danger_alter_theme_color_link_and_more.py +38 -0
- accrete/contrib/ui/migrations/0003_alter_theme_check_user_or_tenant.py +21 -0
- accrete/contrib/ui/migrations/0004_theme_force_tenant_theme.py +18 -0
- accrete/contrib/ui/models.py +115 -1
- accrete/contrib/ui/response.py +11 -4
- accrete/contrib/ui/static/css/accrete.css +23 -57
- accrete/contrib/ui/static/css/accrete.css.map +1 -1
- accrete/contrib/ui/static/css/accrete.scss +76 -55
- accrete/contrib/ui/templates/django/forms/widgets/input.html +1 -1
- accrete/contrib/ui/templates/ui/custom_theme.html +19 -0
- accrete/contrib/ui/templates/ui/layout.html +9 -9
- accrete/contrib/ui/templates/ui/list.html +2 -2
- accrete/contrib/ui/templates/ui/message.html +2 -2
- accrete/contrib/ui/templates/ui/modal.html +3 -3
- accrete/contrib/ui/templates/ui/table.html +5 -5
- accrete/contrib/ui/templates/ui/templatetags/field.html +50 -11
- accrete/contrib/ui/templates/ui/widgets/date_weekday.html +1 -1
- accrete/contrib/ui/templates/ui/widgets/model_search_select.html +4 -3
- accrete/contrib/ui/templates/ui/widgets/model_search_select_multi.html +5 -4
- accrete/contrib/ui/templatetags/ui.py +34 -4
- accrete/contrib/ui/views.py +90 -2
- accrete/contrib/ui/widgets/search_select.py +2 -2
- accrete/contrib/user/forms.py +1 -1
- accrete/contrib/user/migrations/0009_alter_user_theme.py +18 -0
- accrete/contrib/user/migrations/0010_alter_user_theme.py +18 -0
- accrete/contrib/user/models.py +5 -3
- accrete/contrib/user/templates/user/login.html +3 -11
- accrete/contrib/user/templates/user/user_preferences.html +27 -15
- accrete/contrib/user/views.py +7 -2
- accrete/fields.py +4 -2
- accrete/managers.py +9 -0
- accrete/migrations/0009_alter_accessgroup_name.py +30 -0
- accrete/models.py +6 -4
- accrete/views.py +32 -20
- {accrete-0.0.150.dist-info → accrete-0.0.151.dist-info}/METADATA +1 -1
- {accrete-0.0.150.dist-info → accrete-0.0.151.dist-info}/RECORD +42 -33
- {accrete-0.0.150.dist-info → accrete-0.0.151.dist-info}/WHEEL +0 -0
- {accrete-0.0.150.dist-info → accrete-0.0.151.dist-info}/licenses/LICENSE +0 -0
@@ -1,34 +1,33 @@
|
|
1
|
-
@import "../bulma/css/bulma.css";
|
1
|
+
@import "../bulma/css/bulma.min.css";
|
2
2
|
|
3
3
|
:root {
|
4
4
|
--bulma-body-size: .9em;
|
5
5
|
--bulma-navbar-height: 40px;
|
6
|
-
--bulma-menu-item-selected-h: --bulma-
|
7
|
-
--accrete-detail-width:
|
6
|
+
--bulma-menu-item-selected-h: var(--bulma-primary-h);
|
7
|
+
--accrete-detail-width: 35em;
|
8
|
+
--bulma-primary-h: 153.28deg;
|
9
|
+
--bulma-primary-s: 52.89%;
|
10
|
+
--bulma-primary-l: 52.55%;
|
8
11
|
--accrete-action-panel-width: 320px;
|
9
|
-
--bulma-input-
|
10
|
-
--bulma-
|
11
|
-
--bulma-arrow-color: var(--bulma-success);
|
12
|
-
--bulma-menu-nested-list-margin: .5em 0 0.5em 0.75em;
|
13
|
-
--bulma-navbar-burger-color: var(--bulma-success);
|
12
|
+
--bulma-input-arrow: var(--bulma-primary);
|
13
|
+
--bulma-arrow-color: var(--bulma-primary);
|
14
14
|
--accrete-hover-color: #F0F2F4;
|
15
|
-
|
16
15
|
}
|
17
16
|
|
18
17
|
html[data-theme='light'] {
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
//--bulma-menu-item-h: var(--bulma-success-h);
|
19
|
+
//--bulma-menu-item-s: var(--bulma-success-s);
|
20
|
+
//--bulma-menu-item-l: var(--bulma-success-l);
|
21
|
+
//--bulma-menu-item-background-l: 50%;
|
22
|
+
//--bulma-menu-item-color-l: 10%;
|
23
|
+
//--bulma-navbar-burger-color: var(--bulma-success);
|
24
|
+
//--bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
|
25
|
+
//--accrete-hover-color: #F0F2F4;
|
27
26
|
}
|
28
27
|
|
29
28
|
html[data-theme='dark'] {
|
30
|
-
|
31
|
-
|
29
|
+
//--bulma-navbar-burger-color: var(--bulma-success);
|
30
|
+
//--bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
|
32
31
|
--accrete-hover-color: #1E2128;
|
33
32
|
|
34
33
|
.button.is-light {
|
@@ -78,21 +77,22 @@ a {
|
|
78
77
|
border-left-color: transparent;
|
79
78
|
}
|
80
79
|
|
81
|
-
|
82
|
-
border-top: none;
|
83
|
-
border-right: none;
|
84
|
-
border-left: none;
|
85
|
-
border-top-left-radius: 0;
|
86
|
-
border-top-right-radius: 0;
|
87
|
-
border-bottom-right-radius: 0;
|
88
|
-
border-bottom-left-radius: 0;
|
89
|
-
box-shadow: none;
|
90
|
-
|
91
|
-
|
80
|
+
//.input {
|
81
|
+
// border-top: none;
|
82
|
+
// border-right: none;
|
83
|
+
// border-left: none;
|
84
|
+
// border-top-left-radius: 0;
|
85
|
+
// border-top-right-radius: 0;
|
86
|
+
// border-bottom-right-radius: 0;
|
87
|
+
// border-bottom-left-radius: 0;
|
88
|
+
// box-shadow: none;
|
89
|
+
// //box-shadow: inset 0 -10px 10px -16px #000000;
|
90
|
+
// font-weight: bold;
|
91
|
+
//}
|
92
92
|
|
93
93
|
.input:focus, .input:focus-within {
|
94
94
|
box-shadow: none;
|
95
|
-
border
|
95
|
+
border: 1px solid var(--bulma-primary);
|
96
96
|
//border-color: var(--bulma-success);
|
97
97
|
}
|
98
98
|
|
@@ -110,7 +110,7 @@ textarea {
|
|
110
110
|
}
|
111
111
|
|
112
112
|
textarea:focus {
|
113
|
-
border-color: var(--bulma-
|
113
|
+
border-color: var(--bulma-primary) !important;
|
114
114
|
}
|
115
115
|
|
116
116
|
.is-small.textarea, .is-small.input {
|
@@ -118,29 +118,52 @@ textarea:focus {
|
|
118
118
|
font-size: var(--bulma-size-small);
|
119
119
|
}
|
120
120
|
|
121
|
+
td:first-child > .input {
|
122
|
+
//border-top-left-radius: var(--bulma-radius);
|
123
|
+
//border-bottom-left-radius: var(--bulma-radius);
|
124
|
+
|
125
|
+
//border-right: 0;
|
126
|
+
//border-top: none!important;
|
127
|
+
//border-right: none!important;
|
128
|
+
//border-bottom: none!important;
|
129
|
+
//border-left: none!important;
|
130
|
+
}
|
131
|
+
|
132
|
+
td:last-child > .input {
|
133
|
+
//border-top-right-radius: var(--bulma-radius);
|
134
|
+
//border-bottom-right-radius: var(--bulma-radius);
|
135
|
+
|
136
|
+
//border-right: 0;
|
137
|
+
//border-top: none!important;
|
138
|
+
//border-right: none!important;
|
139
|
+
//border-bottom: none!important;
|
140
|
+
//border-left: none!important;
|
141
|
+
}
|
142
|
+
|
121
143
|
td > .input, td * .input, td * select, td * .select {
|
122
|
-
border-top: none!important;
|
123
|
-
border-right: none!important;
|
124
|
-
border-bottom: none!important;
|
125
|
-
border-left: none!important;
|
144
|
+
//border-top: none!important;
|
145
|
+
//border-right: none!important;
|
146
|
+
//border-bottom: none!important;
|
147
|
+
//border-left: none!important;
|
148
|
+
border-radius: 0;
|
126
149
|
}
|
127
150
|
|
128
151
|
td:has(.input:focus) {
|
129
|
-
border-bottom: 1px solid var(--bulma-
|
152
|
+
//border-bottom: 1px solid var(--bulma-primary)!important;
|
130
153
|
}
|
131
154
|
|
132
155
|
select {
|
133
|
-
border-top: transparent !important;
|
134
|
-
border-right: transparent !important;
|
135
|
-
border-left: transparent !important;
|
136
|
-
border-radius: 0 !important;
|
156
|
+
//border-top: transparent !important;
|
157
|
+
//border-right: transparent !important;
|
158
|
+
//border-left: transparent !important;
|
159
|
+
//border-radius: 0 !important;
|
137
160
|
box-shadow: none !important;
|
138
|
-
font-weight: bold;
|
161
|
+
//font-weight: bold;
|
139
162
|
}
|
140
163
|
|
141
164
|
select:focus {
|
142
165
|
box-shadow: none;
|
143
|
-
border
|
166
|
+
border: 1px solid var(--bulma-primary)!important;
|
144
167
|
}
|
145
168
|
|
146
169
|
#detail-container {
|
@@ -195,7 +218,7 @@ select:focus {
|
|
195
218
|
}
|
196
219
|
|
197
220
|
.list-entry > .box:hover, .box.selected {
|
198
|
-
box-shadow: 0 0 5px 2px var(--bulma-
|
221
|
+
box-shadow: 0 0 5px 2px var(--bulma-primary);
|
199
222
|
}
|
200
223
|
|
201
224
|
.helptext {
|
@@ -234,12 +257,12 @@ select:focus {
|
|
234
257
|
border-top: 1px solid var(--bulma-grey-light);
|
235
258
|
}
|
236
259
|
|
237
|
-
table.can-compact * tr.is-
|
238
|
-
background-color: var(--bulma-
|
260
|
+
table.can-compact * tr.is-primary {
|
261
|
+
background-color: var(--bulma-primary);
|
239
262
|
}
|
240
263
|
|
241
|
-
table.can-compact * tr.is-
|
242
|
-
background-color: var(--bulma-
|
264
|
+
table.can-compact * tr.is-primary:hover {
|
265
|
+
background-color: var(--bulma-primary)!important;
|
243
266
|
}
|
244
267
|
|
245
268
|
table.can-compact > thead {
|
@@ -258,8 +281,6 @@ select:focus {
|
|
258
281
|
@media screen and (min-width: 769px) {
|
259
282
|
.modal-card {
|
260
283
|
max-width: 100%;
|
261
|
-
//min-width: var(--bulma-modal-content-width);
|
262
|
-
//width: unset;
|
263
284
|
}
|
264
285
|
}
|
265
286
|
|
@@ -305,11 +326,11 @@ select:focus {
|
|
305
326
|
}
|
306
327
|
|
307
328
|
.menu-list a.is-active, .menu-list a.is-selected, .menu-list button.is-active, .menu-list button.is-selected, .menu-list .menu-item.is-active, .menu-list .menu-item.is-selected {
|
308
|
-
--bulma-menu-item-h: var(--bulma-
|
309
|
-
--bulma-menu-item-s: var(--bulma-
|
310
|
-
--bulma-menu-item-l: var(--bulma-
|
311
|
-
--bulma-menu-item-background-l: var(--bulma-
|
312
|
-
--bulma-menu-item-color-l: var(--bulma-
|
329
|
+
--bulma-menu-item-h: var(--bulma-primary-h);
|
330
|
+
--bulma-menu-item-s: var(--bulma-primary-s);
|
331
|
+
--bulma-menu-item-l: var(--bulma-primary-l);
|
332
|
+
--bulma-menu-item-background-l: var(--bulma-primary-l);
|
333
|
+
--bulma-menu-item-color-l: var(--bulma-primary-invert-l);
|
313
334
|
}
|
314
335
|
|
315
336
|
.hoverable *:hover {
|
@@ -1 +1 @@
|
|
1
|
-
<input class="{% if widget.type != 'checkbox' %}input{% endif %}" type="{{ widget.type }}" name="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
|
1
|
+
<input class="{% if widget.type != 'checkbox' and widget.type != 'radio' %}input{% endif %}" type="{{ widget.type }}" name="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<style>
|
2
|
+
:root {
|
3
|
+
--bulma-primary-h: {{ primary.h }}deg;
|
4
|
+
--bulma-primary-s: {{ primary.s }}%;
|
5
|
+
--bulma-primary-l: {{ primary.l }}%;
|
6
|
+
--bulma-success-h: {{ success.h }}deg;
|
7
|
+
--bulma-success-s: {{ success.s }}%;
|
8
|
+
--bulma-success-l: {{ success.l }}%;
|
9
|
+
--bulma-link-h: {{ link.h }}deg;
|
10
|
+
--bulma-link-s: {{ link.s }}%;
|
11
|
+
--bulma-link-l: {{ link.l }}%;
|
12
|
+
--bulma-warning-h: {{ warning.h }}deg;
|
13
|
+
--bulma-warning-s: {{ warning.s }}%;
|
14
|
+
--bulma-warning-l: {{ warning.l }}%;
|
15
|
+
--bulma-danger-h: {{ danger.h }}deg;
|
16
|
+
--bulma-danger-s: {{ danger.s }}%;
|
17
|
+
--bulma-danger-l: {{ danger.l }}%;
|
18
|
+
}
|
19
|
+
</style>
|
@@ -4,17 +4,17 @@
|
|
4
4
|
{% load partials %}
|
5
5
|
{% load ui %}
|
6
6
|
|
7
|
-
<html lang="en" style="overflow: hidden" {% block theme %}{% if request.user.theme %}data-theme="{{ request.user.theme }}"{% endif %}{% endblock %}>
|
7
|
+
<html lang="en" style="overflow: hidden;" {% block theme %}{% if request.user.theme %}data-theme="{{ request.user.theme }}"{% endif %}{% endblock %}>
|
8
8
|
|
9
9
|
<head>
|
10
10
|
{% block head %}
|
11
11
|
<meta charset="utf-8">
|
12
12
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
13
13
|
{% include 'ui/favicon.html' %}
|
14
|
-
<link rel="stylesheet" type="text/css" href="{% static "css/accrete.css" %}?v=0.0.
|
14
|
+
<link rel="stylesheet" type="text/css" href="{% static "css/accrete.css" %}?v=0.0.151">
|
15
15
|
<link rel="stylesheet" type="text/css" href="{% static "css/icons.css" %}">
|
16
16
|
<link rel="stylesheet" type="text/css" href="{% static "css/fa.css" %}">
|
17
|
-
|
17
|
+
{% custom_theme request.user %}
|
18
18
|
<script src="{% static "js/filter.js" %}" type="text/javascript"></script>
|
19
19
|
<script src="{% static "js/htmx.min.js" %}" defer type="text/javascript"></script>
|
20
20
|
<script src="{% static "js/alpine-focus-3.14.9.js" %}" defer type="text/javascript"></script>
|
@@ -51,7 +51,7 @@
|
|
51
51
|
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' data-tenant-id="{{ tenant.id }}" hx-boost="true" hx-history="false"
|
52
52
|
x-data="{ showPanel: false, openPanel() { if(window.innerWidth >= 1216) {this.showPanel = true} } }"
|
53
53
|
>
|
54
|
-
<nav id="navbar" class="navbar is-
|
54
|
+
<nav id="navbar" class="navbar is-primary is-fixed-top" role="navigation" aria-label="main navigation">
|
55
55
|
<div class="navbar-brand">
|
56
56
|
{% if has_panel %}
|
57
57
|
<div class="navbar-item is-hidden-widescreen pr-2" x-on:click.stop="$dispatch('toggle-panel')">
|
@@ -131,7 +131,7 @@
|
|
131
131
|
<div id="message" class="" style="position: fixed; top: calc(var(--bulma-navbar-height) + 5px); left: 50%; transform: translateX(-50%); z-index: 999">
|
132
132
|
{% for message in messages %}
|
133
133
|
<div class="mb-2" style="min-width: 330px; max-width: 330px" x-data="{ show: false }" x-show="show" x-cloak="" x-init="show = true; setTimeout(() => show = false, 4000)" x-transition.duration.200ms>
|
134
|
-
<div class="notification is-light has-text-centered
|
134
|
+
<div class="notification is-light has-text-centered" style="box-shadow: 2px 2px 5px">
|
135
135
|
{{ message }}
|
136
136
|
</div>
|
137
137
|
</div>
|
@@ -148,9 +148,9 @@
|
|
148
148
|
<div id="overview-container" class="table-container is-flex is-flex-grow-1 is-flex-direction-column mb-0" x-bind:class="showContentRight ? 'is-hidden-mobile' : ''">
|
149
149
|
<div id="overview-header">
|
150
150
|
<div class="is-flex is-justify-content-space-between is-flex-wrap-wrap {% if is_centered %}container{% endif %}">
|
151
|
-
<div class="is-flex is-flex-wrap-wrap is-flex-grow-5 is-align-self-center py-2 header-items">
|
151
|
+
<div class="is-flex is-flex-wrap-wrap is-flex-grow-5 is-align-self-center py-2 mx-1 header-items">
|
152
152
|
{% block overview_header %}
|
153
|
-
<div class="
|
153
|
+
<div class="" style="align-self: center">
|
154
154
|
<p class="title is-5">{{ title }}</p>
|
155
155
|
</div>
|
156
156
|
{% if header_template %}{% include header_template %}{% endif %}
|
@@ -197,9 +197,9 @@
|
|
197
197
|
</section>
|
198
198
|
</div>
|
199
199
|
</div>
|
200
|
-
|
200
|
+
|
201
201
|
<div id="detail-container" x-show="showContentRight" {% if show_content_right != 'true' %}style="display: none;"{% endif %}
|
202
|
-
|
202
|
+
x-transition:enter.duration.200ms x-transition:leave.duration.50ms
|
203
203
|
>
|
204
204
|
<div id="detail-indicator" class="htmx-indicator">
|
205
205
|
<progress class="progress is-success" max="100"></progress>
|
@@ -8,8 +8,8 @@
|
|
8
8
|
{% partialdef entry inline=True %}
|
9
9
|
<div id="list-entry-{{ instance.pk }}" class="list-entry cell pb-0" style="height: {{ column_height }}">
|
10
10
|
<div class="box p-3"
|
11
|
-
style="word-break: break-word; height: 100%; overflow-y: auto; {% if instance.get_absolute_url %}cursor:pointer;{% endif %}"
|
12
|
-
{% if instance.get_absolute_url %}
|
11
|
+
style="word-break: break-word; height: 100%; overflow-y: auto; {% if instance.get_absolute_url and detail_enabled %}cursor:pointer;{% endif %}"
|
12
|
+
{% if instance.get_absolute_url and detail_enabled %}
|
13
13
|
hx-get="{{ instance.get_absolute_url }}{% querystring %}" hx-swap="none" hx-indicator="#detail-indicator" hx-replace-url="{% querystring detail=instance.pk %}"
|
14
14
|
x-on:click="$dispatch('unselect-list-entry'); selected = true; $nextTick(() => { $el.scrollIntoView({block: 'nearest'}) });" x-bind:class="selected ? 'selected' : ''"
|
15
15
|
{% endif %}
|
@@ -4,8 +4,8 @@
|
|
4
4
|
{% for message in messages %}
|
5
5
|
<div hx-swap-oob="{% if append %}beforeend:#message{% else %}innerHTML:#message{% endif %}">
|
6
6
|
<div class="mb-2" style="min-width: 340px; max-width: 340px" x-data="{ show: false }" x-show="show" x-cloak="" x-init="show = true; {% if not persistent %}setTimeout(() => show = false, 4000){% endif %}" x-transition.duration.200ms>
|
7
|
-
<div class="notification
|
8
|
-
|
7
|
+
<div class="notification has-text-centered " style="box-shadow: 2px 2px 5px">
|
8
|
+
<button class="delete" x-on:click="show = false;"></button>
|
9
9
|
{{ message }}
|
10
10
|
</div>
|
11
11
|
</div>
|
@@ -1,13 +1,13 @@
|
|
1
1
|
{% load i18n %}
|
2
2
|
{% load ui %}
|
3
3
|
|
4
|
-
<div hx-swap-oob="{% if is_update %}
|
5
|
-
<div id="{{ modal_id }}" x-data="{showModal: false, close() {$dispatch('close-modal-{{ modal_id }}')} }" x-ref="modal" class="modal is-active is-justify-content-flex-start"
|
4
|
+
<div hx-swap-oob="{% if is_update %}innerHTML:#{{ modal_id }}{% else %}beforeend:body{% endif %}">
|
5
|
+
<div id="{{ modal_id }}" x-data="{showModal: false, close() {$dispatch('close-modal-{{ modal_id }}')} }" x-ref="modal" x-trap="true" class="modal is-active is-justify-content-flex-start"
|
6
6
|
style="padding-top: calc(var(--bulma-navbar-height) + 20px); padding-bottom: 40px;"
|
7
7
|
@close-modal-{{ modal_id }}.window="showModal = false; setTimeout(() => $refs.modal.remove(), 200);"
|
8
8
|
@close-modals.window="showModal = false; setTimeout(() => $refs.modal.remove(), 200);"
|
9
9
|
{% if not is_blocking %}@keyup.escape.window="if (! $refs.{{ modal_id|xrefsave }}Indicator.classList.contains('htmx-request')) {$dispatch('close-modal-{{ modal_id }}')}"{% endif %}
|
10
|
-
|
10
|
+
hx-indicator="#{{ modal_id }}-indicator" hx-disabled-elt="#{{ modal_id }}-background"
|
11
11
|
>
|
12
12
|
<button id="{{ modal_id }}-background" class="modal-background" {% if not is_blocking %}@click="$dispatch('close-modal-{{ modal_id }}')"{% endif %} style="cursor: default"></button>
|
13
13
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<table id="content-table" class="table can-compact is-fullwidth is-hoverable is-narrow my-0" hx-indicator=".htmx-indicator" x-data="">
|
6
6
|
<thead style="position: sticky; top: 0; z-index: 10; background-color: var(--bulma-scheme-main)">
|
7
7
|
<tr>
|
8
|
-
<th>{{ instance_label }}</th>
|
8
|
+
{% if instance_label %}<th>{{ instance_label }}</th>{% endif %}
|
9
9
|
{% for field in fields %}
|
10
10
|
<th style="text-align: {{ page.object_list|table_alignment:field }}">{{ page.object_list|verbose_field_name:field }}</th>
|
11
11
|
{% endfor %}
|
@@ -20,14 +20,14 @@
|
|
20
20
|
hx-get="{{ instance.get_absolute_url }}{% querystring %}" hx-swap="none"
|
21
21
|
hx-replace-url="{% querystring detail=instance.pk %}"
|
22
22
|
x-data="{selected: false}" @unselect-tr.window="selected = false"
|
23
|
-
x-on:click="$dispatch('unselect-tr'); selected = true; $nextTick(() => { $el.scrollIntoView( {block: 'nearest'} ) });" x-bind:class="selected ? 'is-
|
23
|
+
x-on:click="$dispatch('unselect-tr'); selected = true; $nextTick(() => { $el.scrollIntoView( {block: 'nearest'} ) });" x-bind:class="selected ? 'is-primary' : ''"
|
24
24
|
{% endif %}
|
25
25
|
>
|
26
26
|
{% partialdef td inline=True %}
|
27
|
-
<td>{{ instance }}</td>
|
27
|
+
{% if instance_label %}<td>{{ instance }}</td>{% endif %}
|
28
28
|
{% for field in fields %}
|
29
29
|
<td style="text-align: {{ instance|table_alignment:field }}">
|
30
|
-
<span
|
30
|
+
<span>
|
31
31
|
<span class="responsive-heading has-text-weight-light" style="margin-right: .2rem">{{ instance|verbose_field_name:field }}:</span>
|
32
32
|
{{ instance|table_display:field|default_if_none:'' }}
|
33
33
|
</span>
|
@@ -72,4 +72,4 @@
|
|
72
72
|
{% endif %}
|
73
73
|
>
|
74
74
|
</div>
|
75
|
-
<progress id="endless-scroll-indicator" class="htmx-indicator progress is-small is-
|
75
|
+
<progress id="endless-scroll-indicator" class="htmx-indicator progress is-small is-primary" max="100">15%</progress>
|
@@ -1,27 +1,66 @@
|
|
1
1
|
{% load ui %}
|
2
2
|
{% load partials %}
|
3
3
|
|
4
|
+
{#{% partialdef form_field %}#}
|
5
|
+
{# <label class="label mt-2 mb-5">#}
|
6
|
+
{# {{ field.label }}#}
|
7
|
+
{# {{ field }}#}
|
8
|
+
{# <span class="has-text-danger is-size-6">{{ field.errors }}</span>#}
|
9
|
+
{# <span class="helptext is-size-7">{{ field.help_text }}</span>#}
|
10
|
+
{# <span class="helptext is-size-7">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>#}
|
11
|
+
{# </label>#}
|
12
|
+
{#{% endpartialdef %}#}
|
13
|
+
|
14
|
+
{#{% partialdef form_field %}#}
|
15
|
+
{# <label class="label mt-2 mb-5" style="border: 1px solid; border-radius: var(--bulma-radius);">#}
|
16
|
+
{# <span style="justify-content: left" class="is-fullwidth button is-static helptext is-size-7 {% if field.field.required %}has-text-weight-bold{% endif %}">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>#}
|
17
|
+
{# {{ field }}#}
|
18
|
+
{# <span class="has-text-danger is-size-6">{{ field.errors }}Testmessage</span>#}
|
19
|
+
{##}
|
20
|
+
{# </label>#}
|
21
|
+
{#{% endpartialdef %}#}
|
22
|
+
|
4
23
|
{% partialdef form_field %}
|
5
|
-
<
|
6
|
-
{{ field }}
|
24
|
+
<div class="mb-5">
|
25
|
+
<label class="label mb-0 {% if field.field.required %}has-text-weight-medium{% endif %}" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
26
|
+
<div class="field has-addons mb-0">
|
27
|
+
{% if icon %}
|
28
|
+
<p class="control">
|
29
|
+
<button tabindex="-1" type="button" class="button is-static"><span class="icon"><i class="{{ icon }}"></i></span></button>
|
30
|
+
</p>
|
31
|
+
{% endif %}
|
32
|
+
<div class="control is-expanded">{{ field }}</div>
|
33
|
+
</div>
|
7
34
|
<span class="has-text-danger is-size-6">{{ field.errors }}</span>
|
8
|
-
<span class="helptext
|
9
|
-
</
|
35
|
+
<span class="helptext is-size-7">{{ field.help_text|default_if_falsy:'' }}</span>
|
36
|
+
</div>
|
10
37
|
{% endpartialdef %}
|
11
38
|
|
12
39
|
{% partialdef textarea %}
|
13
40
|
<label class="label mt-2 mb-5">
|
14
|
-
<span class="
|
41
|
+
<span class="{% if field.field.required %}has-text-weight-normal{% endif %}">{{ field.label }}</span>
|
15
42
|
<span class="has-text-danger is-size-6">{{ field.errors }}</span>
|
16
43
|
{{ field }}
|
17
44
|
</label>
|
18
45
|
{% endpartialdef %}
|
19
46
|
|
20
47
|
{% partialdef model_field %}
|
21
|
-
<label class="label mt-2 mb-5"
|
22
|
-
<span class="field has-addons mb-0"
|
23
|
-
<span class="control input has-text-weight-
|
24
|
-
</span
|
25
|
-
<span class="helptext
|
26
|
-
</label
|
48
|
+
{# <label class="label mt-2 mb-5">#}
|
49
|
+
{# <span class="field has-addons mb-0">#}
|
50
|
+
{# <span class="control input has-text-weight-bold">{{ value|default_if_none:'' }}</span>#}
|
51
|
+
{# </span>#}
|
52
|
+
{# <span class="helptext">{{ label }}</span>#}
|
53
|
+
{# </label>#}
|
54
|
+
<div class="mb-5">
|
55
|
+
<label class="label mb-0 {% if field.field.required %}has-text-weight-bold{% endif %}" for="{{ field.id_for_label }}">{{ label }}</label>
|
56
|
+
<div class="field has-addons mb-0">
|
57
|
+
{% if icon %}
|
58
|
+
<p class="control">
|
59
|
+
<button tabindex="-1" type="button" class="button is-static"><span class="icon"><i class="{{ icon }}"></i></span></button>
|
60
|
+
</p>
|
61
|
+
{% endif %}
|
62
|
+
<div class="control input is-expanded">{{ value|default_if_none:'' }}</div>
|
63
|
+
</div>
|
64
|
+
<span class="helptext is-size-7">{{ field.help_text|default_if_falsy:'' }}</span>
|
65
|
+
</div>
|
27
66
|
{% endpartialdef %}
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
<div class="field has-addons mb-0">
|
4
4
|
<p class="control">
|
5
|
-
<p class="control"><a class="button is-
|
5
|
+
<p class="control"><a class="button is-static" style="height: 100%; border-top-left-radius: var(--bulma-radius-medium); border-bottom-left-radius: var(--bulma-radius-medium);">{{ widget.value|weekday:'' }}</a></p>
|
6
6
|
</p>
|
7
7
|
<p class="control is-expanded">
|
8
8
|
<input class="{% if widget.type != 'checkbox' %}input{% endif %} is-fullwidth" name="{{ widget.name }}" type="{{ widget.type }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %} {% include "django/forms/widgets/attrs.html" %}>
|
@@ -11,12 +11,13 @@
|
|
11
11
|
>
|
12
12
|
<input id="id_{{ widget.name }}_display" class="input" type="text" readonly x-ref="inputDisplay" value="{{ widget.value_display }}" aria-label="inputDisplay"
|
13
13
|
style="padding-right: 30px"
|
14
|
+
{% include "django/forms/widgets/attrs.html" %}
|
14
15
|
x-on:keydown="if (!open && [38, 40].includes($event.keyCode)) {}; if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
|
15
16
|
x-on:click.stop="if (open) {open = false; } else {open = true; $refs.searchInput.focus()}"
|
16
17
|
>
|
17
|
-
<div style="position: relative; top:
|
18
|
-
<div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" x-cloak="" class="box pt-
|
19
|
-
<input id="id_{{ widget.name }}_search" type="search" autocomplete="off" class="input
|
18
|
+
<div style="position: relative; top: .5rem; z-index: 90;">
|
19
|
+
<div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" x-cloak="" class="box pt-3 px-3 mb-2" x-ref="dropdownContent" tabindex="-1" x-transition style="position: absolute; width: 100%">
|
20
|
+
<input id="id_{{ widget.name }}_search" type="search" autocomplete="off" class="input my-2" x-ref="searchInput" aria-label="search"
|
20
21
|
name="{{ widget.search_parameter }}"
|
21
22
|
placeholder="{% translate 'Type to search' %}"
|
22
23
|
hx-get="{{ widget.search_url }}"
|
@@ -10,8 +10,8 @@
|
|
10
10
|
<option selected value="{{ obj.pk }}"></option>
|
11
11
|
{% endfor %}
|
12
12
|
</select>
|
13
|
-
<div id="{{ widget.attrs.id }}_display" class="input select py-1
|
14
|
-
style="padding-right: 30px;
|
13
|
+
<div id="{{ widget.attrs.id }}_display" class="input select py-1" tabindex="0" x-ref="inputDisplay" aria-label="inputDisplay"
|
14
|
+
style="padding-right: 30px; min-height: var(--bulma-control-height); height: fit-content; width: 100%"
|
15
15
|
x-on:keydown="if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
|
16
16
|
x-on:click.stop="if (!$event.target.classList.contains('delete')) {if (open) {open = false; } else {open = true; $refs.searchInput.focus();}}"
|
17
17
|
>
|
@@ -33,8 +33,8 @@
|
|
33
33
|
{% endfor %}
|
34
34
|
</div>
|
35
35
|
</div>
|
36
|
-
<div style="position: relative; top:
|
37
|
-
<div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" class="box pt-
|
36
|
+
<div style="position: relative; top: .5rem; z-index: 9">
|
37
|
+
<div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" class="box pt-3 px-3 mb-2" x-ref="dropdownContent" x-cloak="" tabindex="-1" x-transition style="position: absolute; width: 100%">
|
38
38
|
<input id="id_{{ widget.uuid }}_search" type="search" autocomplete="off" class="input mb-2" x-ref="searchInput" aria-label="search"
|
39
39
|
name="{{ widget.search_parameter }}"
|
40
40
|
placeholder="{% translate 'Type to search' %}"
|
@@ -42,6 +42,7 @@
|
|
42
42
|
hx-trigger="input changed delay:300ms, search"
|
43
43
|
hx-target="#id_{{ widget.uuid }}_dropdown_items"
|
44
44
|
hx-swap="innerHTML"
|
45
|
+
style="border-radius: var(--bulma-radius)"
|
45
46
|
x-on:keydown="if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
|
46
47
|
@change.stop=""
|
47
48
|
>
|
@@ -2,16 +2,22 @@ import logging
|
|
2
2
|
import re
|
3
3
|
from datetime import datetime, date, timedelta
|
4
4
|
|
5
|
+
from django.contrib.auth import get_user_model
|
5
6
|
from django.utils.translation import gettext_lazy as _
|
6
7
|
from django import template
|
7
|
-
from django.db.models import
|
8
|
+
from django.db.models import (
|
9
|
+
Manager, DecimalField, IntegerField, FloatField, Model, Q
|
10
|
+
)
|
8
11
|
from django.apps import apps
|
9
12
|
from django.template.loader import render_to_string
|
10
13
|
from django.utils.safestring import mark_safe
|
11
14
|
from django.forms import widgets
|
15
|
+
from accrete.contrib.ui.models import Theme
|
16
|
+
from accrete.tenant import get_tenant
|
12
17
|
|
13
18
|
_logger = logging.getLogger(__name__)
|
14
19
|
register = template.Library()
|
20
|
+
User = get_user_model()
|
15
21
|
|
16
22
|
|
17
23
|
@register.simple_tag(name='combine_templates')
|
@@ -153,11 +159,17 @@ def x_ref_save(param: str):
|
|
153
159
|
|
154
160
|
|
155
161
|
@register.filter(name='wrap_form_field')
|
156
|
-
def wrap_form_fields(field,
|
162
|
+
def wrap_form_fields(field, icon=None):
|
157
163
|
if isinstance(field.field.widget, widgets.Textarea):
|
158
|
-
html = render_to_string(
|
164
|
+
html = render_to_string(
|
165
|
+
'ui/templatetags/field.html#textarea',
|
166
|
+
{'field': field, 'icon': None}
|
167
|
+
)
|
159
168
|
return mark_safe(html)
|
160
|
-
html = render_to_string(
|
169
|
+
html = render_to_string(
|
170
|
+
'ui/templatetags/field.html#form_field',
|
171
|
+
{'field': field, 'icon': icon}
|
172
|
+
)
|
161
173
|
return mark_safe(html)
|
162
174
|
|
163
175
|
|
@@ -181,3 +193,21 @@ def default_if_falsy(value, default):
|
|
181
193
|
if bool(value):
|
182
194
|
return value
|
183
195
|
return default
|
196
|
+
|
197
|
+
|
198
|
+
@register.simple_tag(name='custom_theme')
|
199
|
+
def custom_theme(user: User) -> str:
|
200
|
+
if user.is_anonymous:
|
201
|
+
return ''
|
202
|
+
tenant = get_tenant()
|
203
|
+
tenant_theme = Theme.objects.filter(
|
204
|
+
tenant=tenant, tenant__isnull=False
|
205
|
+
).first()
|
206
|
+
if tenant_theme and tenant_theme.force_tenant_theme:
|
207
|
+
return mark_safe(tenant_theme.theme_markup)
|
208
|
+
if user.theme == 'custom':
|
209
|
+
theme = Theme.objects.filter(user=user).first()
|
210
|
+
return theme and mark_safe(theme.theme_markup) or ''
|
211
|
+
if user.theme == 'preset' and tenant_theme:
|
212
|
+
return mark_safe(tenant_theme.theme_markup)
|
213
|
+
return ''
|