django-smartbase-admin 1.0.5__py3-none-any.whl → 1.0.6b1__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.
- django_smartbase_admin/admin/admin_base.py +142 -35
- django_smartbase_admin/admin/widgets.py +81 -23
- django_smartbase_admin/engine/admin_base_view.py +30 -21
- django_smartbase_admin/engine/configuration.py +30 -21
- django_smartbase_admin/static/sb_admin/dist/main.js +1 -1
- django_smartbase_admin/static/sb_admin/dist/main_style.css +1 -1
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Caution.svg +3 -0
- django_smartbase_admin/static/sb_admin/src/css/components/_input.css +19 -15
- django_smartbase_admin/static/sb_admin/src/js/autocomplete.js +18 -0
- django_smartbase_admin/static/sb_admin/src/js/choices.js +8 -0
- django_smartbase_admin/static/sb_admin/src/js/datepicker.js +7 -5
- django_smartbase_admin/static/sb_admin/src/js/main.js +64 -26
- django_smartbase_admin/static/sb_admin/src/js/range.js +3 -2
- django_smartbase_admin/templates/sb_admin/actions/change_form.html +75 -36
- django_smartbase_admin/templates/sb_admin/inlines/table_inline.html +49 -33
- django_smartbase_admin/templates/sb_admin/sprites/sb_admin.svg +1 -1
- django_smartbase_admin/templates/sb_admin/widgets/autocomplete.html +13 -2
- django_smartbase_admin/templates/sb_admin/widgets/date.html +1 -1
- django_smartbase_admin/templates/sb_admin/widgets/includes/related_item_buttons.html +31 -0
- django_smartbase_admin/templates/sb_admin/widgets/time.html +1 -1
- django_smartbase_admin/utils.py +5 -0
- {django_smartbase_admin-1.0.5.dist-info → django_smartbase_admin-1.0.6b1.dist-info}/METADATA +2 -2
- {django_smartbase_admin-1.0.5.dist-info → django_smartbase_admin-1.0.6b1.dist-info}/RECORD +25 -23
- {django_smartbase_admin-1.0.5.dist-info → django_smartbase_admin-1.0.6b1.dist-info}/LICENSE.md +0 -0
- {django_smartbase_admin-1.0.5.dist-info → django_smartbase_admin-1.0.6b1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
|
2
|
+
<path d="M7.99999 1C8.23789 1 8.45795 1.12713 8.57714 1.33301L15.9102 13.999C16.0295 14.2052 16.03 14.4596 15.9111 14.666C15.7921 14.8725 15.5713 15 15.333 15H0.666987C0.428667 15 0.207898 14.8725 0.0888618 14.666C-0.0299797 14.4596 -0.0295034 14.2052 0.0898383 13.999L7.42285 1.33301C7.54204 1.12713 7.7621 1 7.99999 1ZM7.99999 11C7.63202 11 7.33335 11.2981 7.333 11.666V12C7.33313 12.3681 7.63189 12.666 7.99999 12.666C8.3681 12.666 8.66685 12.3681 8.66699 12V11.666C8.66663 11.2981 8.36797 11 7.99999 11ZM7.99902 5.66699C7.6311 5.66753 7.33283 5.96605 7.333 6.33398L7.33593 9.66699C7.33625 10.035 7.63492 10.3331 8.00292 10.333C8.37106 10.3327 8.66916 10.0341 8.66894 9.66602L8.66699 6.33301C8.66655 5.96493 8.36713 5.66669 7.99902 5.66699Z"/>
|
|
3
|
+
</svg>
|
|
@@ -235,22 +235,26 @@
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
input.checkbox-delete {
|
|
241
|
+
+ label {
|
|
242
|
+
@apply text-dark-300 transition-colors;
|
|
243
|
+
@apply p-8 h-full w-full flex-center;
|
|
244
|
+
|
|
245
|
+
&:before,
|
|
246
|
+
&:after {
|
|
247
|
+
@apply hidden;
|
|
249
248
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
|
|
250
|
+
&:hover {
|
|
251
|
+
@apply text-dark-400;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
&:checked {
|
|
256
|
+
+ label {
|
|
257
|
+
@apply text-negative;
|
|
254
258
|
}
|
|
255
259
|
}
|
|
256
260
|
}
|
|
@@ -25,6 +25,10 @@ export default class Autocomplete {
|
|
|
25
25
|
this.handleDynamiclyAddedAutocomplete(document.getElementById('sb-admin-modal'))
|
|
26
26
|
})
|
|
27
27
|
this.handleDynamiclyAddedAutocomplete(document)
|
|
28
|
+
document.body.addEventListener('sbadmin:modal-change-form-response', (event) => {
|
|
29
|
+
const {field, id, label} = event.detail
|
|
30
|
+
this.selectAutocompleteItem(field, id, label)
|
|
31
|
+
})
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
handleDynamiclyAddedAutocomplete(el) {
|
|
@@ -88,6 +92,10 @@ export default class Autocomplete {
|
|
|
88
92
|
choicesJS.SBhasNextPage = true
|
|
89
93
|
this.search(choicesJS.SBcurrentSearchTerm, choicesJS, inputEl, autocompleteData, choicesJS.SBcurrentPage)
|
|
90
94
|
}, 200))
|
|
95
|
+
|
|
96
|
+
choiceInput.addEventListener('selectItem', (event) => {
|
|
97
|
+
choicesJSListeners.selectItem(event.detail, inputEl)
|
|
98
|
+
})
|
|
91
99
|
choiceInput.addEventListener('addItem', () => {
|
|
92
100
|
choicesJSListeners.addItem(choicesJS, inputEl)
|
|
93
101
|
})
|
|
@@ -277,4 +285,14 @@ export default class Autocomplete {
|
|
|
277
285
|
choicesJS.SBcurrentPage = requestedPage
|
|
278
286
|
})
|
|
279
287
|
}
|
|
288
|
+
|
|
289
|
+
selectAutocompleteItem(field, id, label) {
|
|
290
|
+
const selectEl = document.querySelector(`select.js-autocomplete[data-autocomplete-data-id="${field}_data"]`)
|
|
291
|
+
if (selectEl) {
|
|
292
|
+
selectEl.dispatchEvent(new CustomEvent('selectItem', {
|
|
293
|
+
detail: {value: id, label: label},
|
|
294
|
+
}))
|
|
295
|
+
document.getElementById(`${field}-value`).textContent = label
|
|
296
|
+
}
|
|
297
|
+
}
|
|
280
298
|
}
|
|
@@ -50,6 +50,14 @@ export const choicesJSOptions = (choiceInput) => ({
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
export const choicesJSListeners = {
|
|
53
|
+
'selectItem': (item, inputEl) => {
|
|
54
|
+
if (!item) return
|
|
55
|
+
const choiceValue = [{
|
|
56
|
+
value: item.value,
|
|
57
|
+
label: item.label
|
|
58
|
+
}]
|
|
59
|
+
inputEl.value = JSON.stringify(choiceValue)
|
|
60
|
+
},
|
|
53
61
|
'addItem': (choicesJS, inputEl) => {
|
|
54
62
|
const choiceValue = []
|
|
55
63
|
let choicesJSValue = choicesJS.getValue()
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
export default class Datepicker {
|
|
11
|
-
constructor() {
|
|
11
|
+
constructor(target) {
|
|
12
|
+
target = target || document
|
|
12
13
|
let documentLocale = document.documentElement.lang || 'default'
|
|
13
14
|
documentLocale = documentLocale.split('-')[0]
|
|
14
15
|
if (documentLocale === 'en') {
|
|
@@ -16,10 +17,11 @@ export default class Datepicker {
|
|
|
16
17
|
}
|
|
17
18
|
flatpickr.localize(this.getLocale(documentLocale))
|
|
18
19
|
this.initWidgets()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
if(target === document) {
|
|
21
|
+
document.addEventListener('formset:added', (e) => {
|
|
22
|
+
this.initWidgets(e.target)
|
|
23
|
+
})
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
getLocale(locale) {
|
|
@@ -5,7 +5,13 @@ import Modal from 'bootstrap/js/dist/modal'
|
|
|
5
5
|
import Tooltip from 'bootstrap/js/dist/tooltip'
|
|
6
6
|
|
|
7
7
|
// remove Modal focus trap to fix interaction with fields in modals inside another modal
|
|
8
|
-
Modal.prototype._initializeFocusTrap = function () {
|
|
8
|
+
Modal.prototype._initializeFocusTrap = function () {
|
|
9
|
+
return {
|
|
10
|
+
activate: function () {
|
|
11
|
+
}, deactivate: function () {
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
9
15
|
|
|
10
16
|
window.bootstrap5 = {
|
|
11
17
|
Modal: Modal,
|
|
@@ -31,7 +37,7 @@ class Main {
|
|
|
31
37
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
|
32
38
|
tooltipTriggerList.map((tooltipTriggerEl) => {
|
|
33
39
|
const tooltipEl = tooltipTriggerEl.closest('.js-tooltip')
|
|
34
|
-
if(tooltipEl) {
|
|
40
|
+
if (tooltipEl) {
|
|
35
41
|
return new Tooltip(tooltipTriggerEl, {container: tooltipEl})
|
|
36
42
|
}
|
|
37
43
|
return null
|
|
@@ -49,10 +55,10 @@ class Main {
|
|
|
49
55
|
window.open(e.detail.url, e.detail?.target || '_blank')
|
|
50
56
|
})
|
|
51
57
|
|
|
52
|
-
if(window.htmx){
|
|
58
|
+
if (window.htmx) {
|
|
53
59
|
window.htmx.on("htmx:afterSwap", (detail) => {
|
|
54
60
|
const requestEl = detail.detail.requestConfig.elt.closest('[hx-swap]')
|
|
55
|
-
if(requestEl && requestEl.getAttribute('hx-swap') === "none") {
|
|
61
|
+
if (requestEl && requestEl.getAttribute('hx-swap') === "none") {
|
|
56
62
|
// do not process afterSwap if none swap is performed
|
|
57
63
|
// this should prevent double processing of afterSwap for first oob-swapped element
|
|
58
64
|
// which in case of hx-swap=none is returned here in the detail.target
|
|
@@ -60,16 +66,18 @@ class Main {
|
|
|
60
66
|
}
|
|
61
67
|
this.initFileInputs(detail.target)
|
|
62
68
|
this.initDropdowns(detail.target)
|
|
69
|
+
this.initInputs(detail.target)
|
|
70
|
+
this.autocomplete.handleDynamiclyAddedAutocomplete(detail.target)
|
|
71
|
+
this.initInlines(detail.target)
|
|
72
|
+
this.initCKEditor(detail.target)
|
|
63
73
|
})
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
new Sidebar()
|
|
67
|
-
this.
|
|
68
|
-
this.range = new Range()
|
|
77
|
+
this.initInputs()
|
|
69
78
|
new Sorting()
|
|
70
79
|
this.autocomplete = new Autocomplete()
|
|
71
80
|
new ChoicesJS()
|
|
72
|
-
this.multiselect = new Multiselect()
|
|
73
81
|
document.addEventListener('click', (e) => {
|
|
74
82
|
this.closeAlert(e)
|
|
75
83
|
this.selectAll(e)
|
|
@@ -82,8 +90,22 @@ class Main {
|
|
|
82
90
|
this.handleLocationHashFromTabs()
|
|
83
91
|
}
|
|
84
92
|
|
|
93
|
+
initInlines(target) {
|
|
94
|
+
target = target || document
|
|
95
|
+
const inlineGroups = target.querySelectorAll('.inline-group')
|
|
96
|
+
inlineGroups.forEach(group => {
|
|
97
|
+
window.django.jQuery(group).djangoFormset()
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
initInputs(target) {
|
|
102
|
+
this.datepicker = new Datepicker(target)
|
|
103
|
+
this.range = new Range(null, null, target)
|
|
104
|
+
this.multiselect = new Multiselect()
|
|
105
|
+
}
|
|
106
|
+
|
|
85
107
|
handleLocationHashFromTabs() {
|
|
86
|
-
if(window.location.hash) {
|
|
108
|
+
if (window.location.hash) {
|
|
87
109
|
document.querySelector(`#tab_${window.location.hash.slice(1)}`)?.click()
|
|
88
110
|
}
|
|
89
111
|
const tabEls = document.querySelectorAll('button[data-bs-toggle="tab"]:not([data-bs-disable-history])')
|
|
@@ -116,7 +138,7 @@ class Main {
|
|
|
116
138
|
|
|
117
139
|
fileDownload(event) {
|
|
118
140
|
const button = event.target.closest('.js-file-button')
|
|
119
|
-
if(button) {
|
|
141
|
+
if (button) {
|
|
120
142
|
event.preventDefault()
|
|
121
143
|
event.stopPropagation()
|
|
122
144
|
const download_window = window.open(button.getAttribute("href"))
|
|
@@ -132,21 +154,20 @@ class Main {
|
|
|
132
154
|
const dropdowns = [].slice.call(target.querySelectorAll('[data-bs-toggle="dropdown"]'))
|
|
133
155
|
dropdowns.map((dropdownToggleEl) => {
|
|
134
156
|
let offset = dropdownToggleEl.dataset['bsOffset']
|
|
135
|
-
if(offset) {
|
|
157
|
+
if (offset) {
|
|
136
158
|
offset = JSON.parse(dropdownToggleEl.dataset['bsOffset'])
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
offset = [0,8]
|
|
159
|
+
} else {
|
|
160
|
+
offset = [0, 8]
|
|
140
161
|
}
|
|
141
162
|
return new Dropdown(dropdownToggleEl, {
|
|
142
163
|
autoClose: 'outside',
|
|
143
164
|
offset: offset,
|
|
144
165
|
popperConfig(defaultBsPopperConfig) {
|
|
145
166
|
const elementConf = {}
|
|
146
|
-
if(dropdownToggleEl.dataset['bsPopperPlacement']) {
|
|
167
|
+
if (dropdownToggleEl.dataset['bsPopperPlacement']) {
|
|
147
168
|
elementConf['placement'] = dropdownToggleEl.dataset['bsPopperPlacement']
|
|
148
169
|
}
|
|
149
|
-
return {
|
|
170
|
+
return {...defaultBsPopperConfig, ...elementConf, strategy: 'fixed'}
|
|
150
171
|
}
|
|
151
172
|
})
|
|
152
173
|
})
|
|
@@ -154,7 +175,7 @@ class Main {
|
|
|
154
175
|
|
|
155
176
|
initAliasName() {
|
|
156
177
|
const aliasGroup = document.getElementById(window.sb_admin_const.GLOBAL_FILTER_ALIAS_WIDGET_ID)
|
|
157
|
-
if(!aliasGroup) {
|
|
178
|
+
if (!aliasGroup) {
|
|
158
179
|
return
|
|
159
180
|
}
|
|
160
181
|
|
|
@@ -180,9 +201,9 @@ class Main {
|
|
|
180
201
|
const saveStateEl = event.target.closest('.js-save-state')
|
|
181
202
|
if (saveStateEl) {
|
|
182
203
|
const isBsToggle = saveStateEl.dataset['bsToggle']
|
|
183
|
-
if(isBsToggle === 'collapse') {
|
|
204
|
+
if (isBsToggle === 'collapse') {
|
|
184
205
|
const expanded = saveStateEl.getAttribute('aria-expanded') === 'true'
|
|
185
|
-
setCookie(saveStateEl.id, expanded, expanded?1:0)
|
|
206
|
+
setCookie(saveStateEl.id, expanded, expanded ? 1 : 0)
|
|
186
207
|
}
|
|
187
208
|
}
|
|
188
209
|
}
|
|
@@ -196,7 +217,7 @@ class Main {
|
|
|
196
217
|
selectAll(event) {
|
|
197
218
|
const wrapper = event.target.closest('.js-select-all-wrapper')
|
|
198
219
|
|
|
199
|
-
if(wrapper) {
|
|
220
|
+
if (wrapper) {
|
|
200
221
|
const selectAll = event.target.closest('.js-select-all')
|
|
201
222
|
const clearAll = event.target.closest('.js-clear-all')
|
|
202
223
|
if (selectAll) {
|
|
@@ -231,17 +252,16 @@ class Main {
|
|
|
231
252
|
const input = fileInput.querySelector('input[type="file"]')
|
|
232
253
|
const delete_checkbox = fileInput.querySelector('input[type="checkbox"]')
|
|
233
254
|
input?.addEventListener('change', e => {
|
|
234
|
-
if(delete_checkbox) {
|
|
255
|
+
if (delete_checkbox) {
|
|
235
256
|
delete_checkbox.checked = false
|
|
236
257
|
}
|
|
237
|
-
if(e.target.files[0]) {
|
|
258
|
+
if (e.target.files[0]) {
|
|
238
259
|
fileInput.classList.add('filled')
|
|
239
260
|
fileInput.querySelectorAll('.js-input-file-image').forEach(el => {
|
|
240
261
|
el.src = URL.createObjectURL(e.target.files[0])
|
|
241
262
|
})
|
|
242
263
|
fileInput.querySelector('.js-input-file-filename').innerHTML = e.target.files[0].name
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
264
|
+
} else {
|
|
245
265
|
fileInput.classList.remove('filled')
|
|
246
266
|
fileInput.querySelector('.js-input-file-filename').innerHTML = ""
|
|
247
267
|
}
|
|
@@ -251,13 +271,25 @@ class Main {
|
|
|
251
271
|
deleteButton?.addEventListener('click', () => {
|
|
252
272
|
input.value = ""
|
|
253
273
|
input.dispatchEvent(new Event('change'))
|
|
254
|
-
if(delete_checkbox) {
|
|
274
|
+
if (delete_checkbox) {
|
|
255
275
|
delete_checkbox.checked = true
|
|
256
276
|
}
|
|
257
277
|
})
|
|
258
278
|
})
|
|
259
279
|
}
|
|
260
280
|
|
|
281
|
+
initCKEditor(target) {
|
|
282
|
+
target = target || document
|
|
283
|
+
target.querySelectorAll('textarea[data-type="ckeditortype"]').forEach((textarea) => {
|
|
284
|
+
const id = textarea.id
|
|
285
|
+
if (!id) return
|
|
286
|
+
if (window.CKEDITOR.instances[id]) {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
window.CKEDITOR.replace(id)
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
|
|
261
293
|
clearFilter(inputId) {
|
|
262
294
|
const fieldElem = document.querySelector(`#${inputId}`)
|
|
263
295
|
fieldElem.value = ''
|
|
@@ -266,9 +298,9 @@ class Main {
|
|
|
266
298
|
}
|
|
267
299
|
|
|
268
300
|
executeListAction(table_id, action_url, no_params) {
|
|
269
|
-
if(window.SBAdminTable && window.SBAdminTable[table_id]){
|
|
301
|
+
if (window.SBAdminTable && window.SBAdminTable[table_id]) {
|
|
270
302
|
window.SBAdminTable[table_id].executeListAction(action_url, no_params)
|
|
271
|
-
} else{
|
|
303
|
+
} else {
|
|
272
304
|
window.location.href = action_url
|
|
273
305
|
}
|
|
274
306
|
}
|
|
@@ -277,3 +309,9 @@ class Main {
|
|
|
277
309
|
window.addEventListener('DOMContentLoaded', () => {
|
|
278
310
|
window.SBAdmin = new Main()
|
|
279
311
|
})
|
|
312
|
+
|
|
313
|
+
document.body.addEventListener('sbadmin:modal-change-form-response', function (event) {
|
|
314
|
+
if (event.detail.reload) {
|
|
315
|
+
window.location.reload()
|
|
316
|
+
}
|
|
317
|
+
})
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
export default class Range {
|
|
3
|
-
constructor(selector_override, options_override) {
|
|
3
|
+
constructor(selector_override, options_override, target) {
|
|
4
|
+
target = target || document
|
|
4
5
|
const selector = selector_override || '.js-range'
|
|
5
6
|
this.separator = ' - '
|
|
6
|
-
|
|
7
|
+
target.querySelectorAll(selector).forEach(el => {
|
|
7
8
|
this.initRange(el, options_override)
|
|
8
9
|
})
|
|
9
10
|
}
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
{% block view_class %}change-form{% endblock %}
|
|
11
11
|
|
|
12
12
|
{% block js %}
|
|
13
|
-
{
|
|
13
|
+
{% if not sbadmin_is_modal %}
|
|
14
|
+
{{ block.super }}
|
|
15
|
+
{% endif %}
|
|
14
16
|
<script type="text/javascript"
|
|
15
17
|
id="django-admin-form-add-constants"
|
|
16
18
|
src="{% static 'admin/js/change_form.js' %}"
|
|
@@ -109,7 +111,8 @@
|
|
|
109
111
|
|
|
110
112
|
{% block form %}
|
|
111
113
|
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post"
|
|
112
|
-
id="{{ opts.model_name }}_form" class="detail-view-form flex-grow flex flex-col w-full max-w-1180 mx-auto" novalidate>
|
|
114
|
+
id="{% if sbadmin_is_modal %}modal__{% endif %}{{ opts.model_name }}_form" class="detail-view-form flex-grow flex flex-col w-full max-w-1180 mx-auto" novalidate>
|
|
115
|
+
<div class=" {% if sbadmin_is_modal %}max-h-[70vh] overflow-y-auto sbadmin_is_modal realative flex-grow{% endif %}">
|
|
113
116
|
{% csrf_token %}
|
|
114
117
|
{% if errors %}
|
|
115
118
|
<div class="alert bg-negative-50 border border-negative-100 text-negative-900 mb-24">
|
|
@@ -133,8 +136,8 @@
|
|
|
133
136
|
{% for tab, tab_content_object in tabular_context.context.items %}
|
|
134
137
|
<li role="presentation">
|
|
135
138
|
<button class="relative{% for class in tab_content_object.classes %} {{ class }}{% endfor %}" id="tab_{{ tab|slugify }}" data-bs-toggle="tab"
|
|
136
|
-
data-bs-target="#
|
|
137
|
-
aria-controls="
|
|
139
|
+
data-bs-target="#{% if sbadmin_is_modal %}modal__{% endif %}{{ opts.model_name }}_tabcontent_{{ tab|slugify }}" type="button" role="tab"
|
|
140
|
+
aria-controls="{% if sbadmin_is_modal %}modal__{% endif %}{{ opts.model_name }}_tabcontent_{{ tab|slugify }}" aria-selected="true">
|
|
138
141
|
{{ tab }}
|
|
139
142
|
</button>
|
|
140
143
|
</li>
|
|
@@ -142,7 +145,7 @@
|
|
|
142
145
|
</ul>
|
|
143
146
|
{% endif %}
|
|
144
147
|
{% for tab, tab_content_object in tabular_context.context.items %}
|
|
145
|
-
<div class="detail-view-tab tab-pane fade{% for class in tab_content_object.classes %} {{ class }}{% endfor %} pt-20" id="
|
|
148
|
+
<div class="detail-view-tab tab-pane fade{% for class in tab_content_object.classes %} {{ class }}{% endfor %} pt-20" id="{% if sbadmin_is_modal %}modal__{% endif %}{{ opts.model_name }}_tabcontent_{{ tab|slugify }}" role="tabpanel"
|
|
146
149
|
aria-labelledby="tab_{{ tab|slugify }}">
|
|
147
150
|
<div class="flex max-md:flex-wrap w-full lg:gap-24">
|
|
148
151
|
<div class="min-w-0 w-full">
|
|
@@ -150,7 +153,7 @@
|
|
|
150
153
|
{% if tab_content.type == 'fieldset' %}
|
|
151
154
|
{% block tab_content_fieldset %}
|
|
152
155
|
{% with tab_content.value as fieldset %}
|
|
153
|
-
{% if DETAIL_STRUCTURE_RIGHT_CLASS not in fieldset.classes %}
|
|
156
|
+
{% if DETAIL_STRUCTURE_RIGHT_CLASS not in fieldset.classes or sbadmin_is_modal %}
|
|
154
157
|
{% include "sb_admin/includes/fieldset.html" %}
|
|
155
158
|
{% endif %}
|
|
156
159
|
{% endwith %}
|
|
@@ -170,7 +173,7 @@
|
|
|
170
173
|
{% for tab_content in tab_content_object.content %}
|
|
171
174
|
{% if tab_content.type == 'fieldset' %}
|
|
172
175
|
{% with tab_content.value as fieldset %}
|
|
173
|
-
{% if DETAIL_STRUCTURE_RIGHT_CLASS in fieldset.classes %}
|
|
176
|
+
{% if DETAIL_STRUCTURE_RIGHT_CLASS in fieldset.classes and not sbadmin_is_modal %}
|
|
174
177
|
{% include "sb_admin/includes/fieldset.html" %}
|
|
175
178
|
{% endif %}
|
|
176
179
|
{% endwith %}
|
|
@@ -191,41 +194,77 @@
|
|
|
191
194
|
{% endif %}>
|
|
192
195
|
</script>
|
|
193
196
|
{% endblock %}
|
|
197
|
+
</div>
|
|
194
198
|
{% if is_popup %}
|
|
195
199
|
{# TODO: check sticky bar in popups #}
|
|
196
|
-
|
|
197
|
-
{%
|
|
198
|
-
<div class="
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
200
|
+
{% endif %}
|
|
201
|
+
{% if sbadmin_is_modal %}
|
|
202
|
+
<div class="bg-light bottom-0 left-0 w-full px-24 py-24 flex justify-between gap-8">
|
|
203
|
+
{% if original %}
|
|
204
|
+
{% url opts|admin_urlname:'change' original.pk|admin_urlquote as post_url %}
|
|
205
|
+
{% else %}
|
|
206
|
+
{% url opts|admin_urlname:'add' as post_url %}
|
|
207
|
+
{% endif %}
|
|
208
|
+
<button
|
|
209
|
+
form="{% if sbadmin_is_modal %}modal__{% endif %}{{ opts.model_name }}_form"
|
|
210
|
+
hx-post="{{ post_url }}"
|
|
211
|
+
hx-target="#sb-admin-modal .modal-content"
|
|
212
|
+
hx-swap="innerHTML"
|
|
213
|
+
hx-encoding="multipart/form-data"
|
|
214
|
+
hx-vals='{
|
|
215
|
+
"sbadmin_is_modal": 1,
|
|
216
|
+
"sb_admin_source_field": "{{ request.GET.sb_admin_source_field }}",
|
|
217
|
+
"sbadmin_reload_on_save": {% if sbadmin_reload_on_save %}1{% else %}0{% endif %},
|
|
218
|
+
"sbadmin_parent_instance_field": "{{ request.GET.sbadmin_parent_instance_field }}",
|
|
219
|
+
"sbadmin_parent_instance_pk": "{{ request.GET.sbadmin_parent_instance_pk | default:"" }}",
|
|
220
|
+
"sbadmin_parent_instance_label": "{{ request.GET.sbadmin_parent_instance_label }}"
|
|
221
|
+
}'
|
|
222
|
+
class="btn btn-primary flex-grow flex items-center justify-center">
|
|
223
|
+
<svg class="w-20 h-20 mr-8">
|
|
224
|
+
<use xlink:href="#Save"></use>
|
|
225
|
+
</svg>
|
|
226
|
+
{% trans 'Save' %}
|
|
227
|
+
</button>
|
|
228
|
+
<button type="button"
|
|
229
|
+
class="btn flex-grow"
|
|
230
|
+
data-bs-dismiss="modal" aria-label="Close">
|
|
231
|
+
{% trans 'Close' %}
|
|
232
|
+
</button>
|
|
233
|
+
</div>
|
|
234
|
+
{% else %}
|
|
235
|
+
{% block action_bar %}
|
|
236
|
+
<div class="detail-view-action-bar">
|
|
237
|
+
<div>
|
|
238
|
+
<h2 class="text-dark-900 font-semibold text-18 mr-16 line-clamp-1">
|
|
239
|
+
{% include 'sb_admin/includes/change_form_title.html' %}
|
|
240
|
+
</h2>
|
|
241
|
+
{% if previous_url or next_url %}
|
|
242
|
+
<div class="flex items-center gap-8 mr-8">
|
|
243
|
+
<{% if previous_url %}a href="{{ previous_url }}"{% else %}button type="button" disabled{% endif %} class="btn btn-small" title="{% trans 'Prev' %}">
|
|
244
|
+
<svg class="w-20 h-20">
|
|
245
|
+
<use xlink:href="#Left"></use>
|
|
246
|
+
</svg>
|
|
247
|
+
</{% if previous_url %}a{% else %}button{% endif %}>
|
|
248
|
+
<div class="text-12">{% blocktrans %}<strong>{{ current_index }}</strong> / {{ all_objects_count }}{% endblocktrans %}</div>
|
|
249
|
+
<{% if next_url %}a href="{{ next_url }}"{% else %}button type="button" disabled{% endif %} class="btn btn-small" title="{% trans 'Next' %}">
|
|
250
|
+
<svg class="w-20 h-20">
|
|
251
|
+
<use xlink:href="#Right"></use>
|
|
252
|
+
</svg>
|
|
253
|
+
</{% if next_url %}a{% else %}button{% endif %}>
|
|
254
|
+
</div>
|
|
222
255
|
{% endif %}
|
|
256
|
+
<div class="flex ml-auto gap-8">
|
|
257
|
+
{% if not is_popup and has_view_permission %}
|
|
258
|
+
{% url opts|admin_urlname:'changelist' as changelist_url %}
|
|
259
|
+
<a href="{% add_preserved_filters changelist_url %}" class="btn btn-empty">{% trans 'Back' %}</a>
|
|
260
|
+
{% endif %}
|
|
223
261
|
|
|
224
|
-
|
|
262
|
+
{% submit_row %}
|
|
263
|
+
</div>
|
|
225
264
|
</div>
|
|
226
265
|
</div>
|
|
227
|
-
|
|
228
|
-
{%
|
|
266
|
+
{% endblock %}
|
|
267
|
+
{% endif %}
|
|
229
268
|
</form>
|
|
230
269
|
{% endblock %}
|
|
231
270
|
{% endblock %}
|
|
@@ -24,12 +24,28 @@
|
|
|
24
24
|
class="btn {{ list_action.css_class|default_if_none:'' }}">{{ list_action.title }}</a>
|
|
25
25
|
{% endfor %}
|
|
26
26
|
{% if inline_admin_formset.has_add_permission %}
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
{% if context_data.add_url and not sbadmin_is_modal %}
|
|
28
|
+
<a
|
|
29
|
+
class="btn btn-icon ml-auto {{ inline_admin_formset.handler_classes|join:" " }}"
|
|
30
|
+
data-bs-toggle="modal"
|
|
31
|
+
data-bs-target="#sb-admin-modal"
|
|
32
|
+
hx-get="{{ context_data.add_url }}?_popup=1&sbadmin_is_modal=1&sbadmin_reload_on_save=1&sbadmin_parent_instance_field={{ context_data.parent_data.sbadmin_parent_instance_field }}&sbadmin_parent_instance_pk={{ context_data.parent_data.sbadmin_parent_instance_pk }}&sbadmin_parent_instance_label={{ context_data.parent_data.sbadmin_parent_instance_label }}"
|
|
33
|
+
hx-target="#sb-admin-modal .modal-content"
|
|
34
|
+
hx-swap="innerHTML"
|
|
35
|
+
>
|
|
36
|
+
<svg class="w-20 h-20 md:mr-8">
|
|
37
|
+
<use xlink:href="#Plus"></use>
|
|
38
|
+
</svg>
|
|
39
|
+
<span>{% trans 'Add' %}</span>
|
|
40
|
+
</a>
|
|
41
|
+
{% else %}
|
|
42
|
+
<a href="javascript://" class="add-handler djn-add-handler btn btn-icon ml-auto {{ inline_admin_formset.handler_classes|join:" " }}">
|
|
43
|
+
<svg class="w-20 h-20 md:mr-8">
|
|
44
|
+
<use xlink:href="#Plus"></use>
|
|
45
|
+
</svg>
|
|
46
|
+
<span>{% trans 'Add' %}</span>
|
|
47
|
+
</a>
|
|
48
|
+
{% endif %}
|
|
33
49
|
{% endif %}
|
|
34
50
|
</div>
|
|
35
51
|
</header>
|
|
@@ -47,35 +63,35 @@
|
|
|
47
63
|
<table class="djn-items inline-related djn-table">
|
|
48
64
|
{% with inline_admin_formset.opts.sortable_field_name|default:"" as sortable_field_name %}
|
|
49
65
|
<thead class="djn-module djn-thead">
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
<tr>
|
|
67
|
+
{% if context_data.is_sortable_active %}
|
|
68
|
+
<th class="original{% if sortable_field_name %} is-sortable{% endif %}"></th>
|
|
69
|
+
{% endif %}
|
|
70
|
+
{% for field in inline_admin_formset.fields %}
|
|
71
|
+
{% if not field.widget.is_hidden and not field|is_row_class_field %}
|
|
72
|
+
<th class="djn-th
|
|
57
73
|
{{ field.label|lower|slugify }}{% if field.required %} required{% endif %}">
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
</div>
|
|
74
|
+
<div class="flex items-center">
|
|
75
|
+
<span class="mr-auto">{{ field.label|capfirst }}{% if field.required %}<span class="ml-4 text-negative">*</span>{% endif %}</span>
|
|
76
|
+
{% if field.help_text %}
|
|
77
|
+
<div class="ml-4">
|
|
78
|
+
<div class="js-tooltip flex" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ field.help_text|striptags }}">
|
|
79
|
+
<svg class="w-12 h-12">
|
|
80
|
+
<use xlink:href="#Help"></use>
|
|
81
|
+
</svg>
|
|
67
82
|
</div>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
</
|
|
71
|
-
|
|
72
|
-
{%
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{%
|
|
78
|
-
|
|
83
|
+
</div>
|
|
84
|
+
{% endif %}
|
|
85
|
+
</div>
|
|
86
|
+
</th>
|
|
87
|
+
{% endif %}
|
|
88
|
+
{% endfor %}
|
|
89
|
+
{% block table_inline_delete_table_head %}
|
|
90
|
+
{% if inline_admin_formset.formset.can_delete %}
|
|
91
|
+
<th class="djn-th sticky-table-head" style="min-width: 54px; width: 54px;"></th>
|
|
92
|
+
{% endif %}
|
|
93
|
+
{% endblock %}
|
|
94
|
+
</tr>
|
|
79
95
|
</thead>
|
|
80
96
|
|
|
81
97
|
|