feat: RBAC + SAML support

This commit is contained in:
Markos Gogoulos
2025-04-05 12:44:21 +03:00
committed by GitHub
parent 8fecccce1c
commit 05414f66c7
158 changed files with 6423 additions and 106 deletions

951
static/jazzmin/css/main.css Normal file
View File

@@ -0,0 +1,951 @@
/** Django-related improvements to AdminLTE UI **/
div.inline-related {
padding: 10px;
}
.form-row {
padding: 5px;
}
.help-block ul {
margin: 10px 0 0 15px;
padding: 0;
}
/** Fix bug of adminLTE, since django is using th headers in middle of table **/
.card-body.p-0 .table thead > tr > th:first-of-type,
.card-body.p-0 .table thead > tr > td:first-of-type,
.card-body.p-0 .table tfoot > tr > th:first-of-type,
.card-body.p-0 .table tfoot > tr > td:first-of-type,
.card-body.p-0 .table tbody > tr > th:first-of-type,
.card-body.p-0 .table tbody > tr > td:first-of-type {
padding-left: 0.75rem;
}
.card-body.p-0 .table thead > tr > th:last-of-type,
.card-body.p-0 .table thead > tr > td:last-of-type,
.card-body.p-0 .table tfoot > tr > th:last-of-type,
.card-body.p-0 .table tfoot > tr > td:last-of-type,
.card-body.p-0 .table tbody > tr > th:last-of-type,
.card-body.p-0 .table tbody > tr > td:last-of-type {
padding-right: 0.75rem;
}
.card-body.p-0 .table thead > tr > th:first-child,
.card-body.p-0 .table thead > tr > td:first-child,
.card-body.p-0 .table tfoot > tr > th:first-child,
.card-body.p-0 .table tfoot > tr > td:first-child,
.card-body.p-0 .table tbody > tr > th:first-child,
.card-body.p-0 .table tbody > tr > td:first-child {
padding-left: 1.5rem;
}
.card-body.p-0 .table thead > tr > th:last-child,
.card-body.p-0 .table thead > tr > td:last-child,
.card-body.p-0 .table tfoot > tr > th:last-child,
.card-body.p-0 .table tfoot > tr > td:last-child,
.card-body.p-0 .table tbody > tr > th:last-child,
.card-body.p-0 .table tbody > tr > td:last-child {
padding-right: 1.5rem;
}
[class*=sidebar-dark-] .nav-header {
margin-top: 1rem;
}
.nav-sidebar .nav-header {
font-size: 1.2rem !important
}
/* Table styles */
.table tr.form-row {
display: table-row;
}
.table td.action-checkbox {
width: 45px;
}
.table thead th {
color: #64748b;
border-bottom: 0;
}
.empty-form {
display: none !important;
}
.inline-related .tabular {
background-color: white;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
td.djn-td,
th.djn-th {
padding: 10px;
}
td.delete input {
margin: 10px;
}
tr.djn-tr>.original {
padding-left: 20px;
}
.hidden {
display: none;
}
/* Checkbox selection table header */
.djn-checkbox-select-all {
padding-right: 0 !important;
width: 0;
}
.object-tools {
padding: 0;
}
.object-tools li {
list-style: none;
margin: 0;
padding: 0;
}
.object-tools .historylink {
background-color: #3c8dbc;
width: 100%;
display: block;
padding: 5px;
text-align: center;
color: white;
}
.jazzmin-avatar {
font-size: 20px;
}
.related-widget-wrapper-link {
padding: 7px;
}
.related-widget-wrapper select {
width: initial;
/* Setting a width will make the *-related btns overflow */
height: auto;
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: .25rem;
box-shadow: inset 0 0 0 transparent;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
.tab-pane {
overflow-x: auto;
}
table.dataTable thead .sorting::after,
table.dataTable thead .sorting_asc::after,
table.dataTable thead .sorting_desc::after,
table.dataTable thead .sorting_asc_disabled::after,
table.dataTable thead .sorting_desc_disabled::after {
right: 0.5em;
content: "\2193";
}
.select2-container {
min-width: 200px;
}
.select2-container .select2-selection--single {
border: 1px solid #ced4da !important;
min-height: 38px;
/* Center text inside */
display: flex !important;
align-items: center;
}
.select2-container--default .select2-selection--single {
border: 1px solid #ced4da;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
right: 5px !important;
top: unset !important;
}
.select2-results__option {
color: black;
}
.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
background-color: #0074f0 !important;
color: white !important;
}
.select2-container--default .select2-results__option--selected {
background-color: #ddd !important;
}
#changelist-search .form-group {
margin-bottom: .5em;
margin-right: .5em;
}
.table tbody tr th {
padding-left: .75rem;
}
.user-profile {
font-size: 2.4em;
}
.date-hierarchy {
margin-right: 8px;
display: block;
}
/* APP.CSS */
.form-group div .vTextField,
.form-group div .vLargeTextField,
.form-group div .vURLField,
.form-group div .vBigIntegerField,
.form-group div input[type="text"]
{
display: block;
width: 100%;
}
.vTextField,
.vLargeTextField,
.vURLField,
.vIntegerField,
.vBigIntegerField,
.vForeignKeyRawIdAdminField,
.vDateField,
.vTimeField,
input[type="number"],
input[type="text"]
{
height: calc(2.25rem + 2px);
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: .25rem;
box-shadow: inset 0 0 0 transparent;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
.vDateField,
.vTimeField {
margin-bottom: 5px;
display: inline-block;
}
.vLargeTextField {
height: auto;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
}
.date-icon:before,
.clock-icon:before {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome !important;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: "\f073";
}
.clock-icon:before {
content: "\f017";
}
/* CALENDARS & CLOCKS */
.calendarbox,
.clockbox {
margin: 5px auto;
font-size: 12px;
width: 19em;
text-align: center;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
overflow: hidden;
position: relative;
}
.clockbox {
width: auto;
}
.calendar {
margin: 0;
padding: 0;
}
.calendar table {
margin: 0;
padding: 0;
border-collapse: collapse;
background: white;
width: 100%;
}
.calendar caption,
.calendarbox h2,
.clockbox h2 {
margin: 0;
text-align: center;
border-top: none;
background: #f5dd5d;
font-weight: 700;
font-size: 12px;
color: #333;
}
.clockbox h2 {
font-size: 16px;
padding: 5px;
}
.calendar th {
padding: 8px 5px;
background: #f8f8f8;
border-bottom: 1px solid #ddd;
font-weight: 400;
font-size: 12px;
text-align: center;
color: #666;
}
.calendar td {
font-weight: 400;
font-size: 12px;
text-align: center;
padding: 0;
border-top: 1px solid #eee;
border-bottom: none;
}
.calendar td.selected a {
background: #3C8DBC;
color: #fff !important;
}
.calendar td.nonday {
background: #f8f8f8;
}
.calendar td.today a {
font-weight: 700;
}
.calendar td a,
.timelist a {
display: block;
font-weight: 400;
padding: 6px;
text-decoration: none;
color: #444;
}
.calendar td a:focus,
.timelist a:focus,
.calendar td a:hover,
.timelist a:hover {
background: #3C8DBC;
color: white;
}
.calendar td a:active,
.timelist a:active {
background: #3C8DBC;
color: white;
}
.calendarnav {
font-size: 10px;
text-align: center;
color: #ccc;
margin: 0;
padding: 1px 3px;
}
.calendarnav a:link,
#calendarnav a:visited,
#calendarnav a:focus,
#calendarnav a:hover {
color: #999;
}
.calendar-shortcuts {
background: white;
font-size: 11px;
line-height: 11px;
border-top: 1px solid #eee;
padding: 8px 0;
color: #ccc;
}
.calendarbox .calendarnav-previous,
.calendarbox .calendarnav-next {
display: block;
position: absolute;
top: 8px;
width: 15px;
height: 15px;
text-indent: -9999px;
padding: 0;
}
.calendarnav-previous {
left: 10px;
background: url(../img/calendar-icons.svg) 0 0 no-repeat;
}
.calendarbox .calendarnav-previous:focus,
.calendarbox .calendarnav-previous:hover {
background-position: 0 -15px;
}
.calendarnav-next {
right: 10px;
background: url(../img/calendar-icons.svg) 0 -30px no-repeat;
}
.calendarbox .calendarnav-next:focus,
.calendarbox .calendarnav-next:hover {
background-position: 0 -45px;
}
.calendar-cancel {
margin: 0;
padding: 4px 0;
font-size: 12px;
background: #eee;
border-top: 1px solid #ddd;
color: #333;
}
.calendar-cancel:focus,
.calendar-cancel:hover {
background: #ddd;
}
.calendar-cancel a {
color: black;
display: block;
}
/* Selectors - This needs some work TODO */
.selector {
width: 100%;
float: left;
}
.selector select {
width: 100%;
height: 15em;
}
.selector-available,
.selector-chosen {
float: left;
width: 48%;
text-align: center;
margin-bottom: 5px;
}
.selector-available h2,
.selector-chosen h2 {
border: 1px solid #ccc;
font-size: 16px;
padding: 5px;
}
.selector-chosen h2 {
background: #007bff;
color: #fff;
}
.selector .selector-available h2 {
background: #f8f8f8;
color: #666;
}
.selector .selector-filter {
background: white;
border: 1px solid #ccc;
padding: 8px;
color: #999;
font-size: 10px;
margin: 0;
text-align: left;
}
.selector-filter input {
height: 24px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
margin-left: 0 !important;
}
.selector .selector-filter label,
.inline-group .aligned .selector .selector-filter label {
float: left;
margin: 0;
width: 18px;
height: 18px;
padding: 0;
overflow: hidden;
line-height: 1;
}
select#id_rbac_groups_from,
select#id_rbac_groups_to,
select#id_contributors_field_to,
select#id_contributors_field_from,
select#id_members_field_to,
select#id_members_field_from,
select#id_managers_field_to,
select#id_managers_field_from,
select#id_categories_to,
select#id_categories_from {
height: 285px !important;
}
/* Might need to import more rules from:
* https://github.com/django/django/blob/master/django/contrib/admin/static/admin/css/responsive.css
*/
.inline-group {
overflow: auto;
}
.selector .selector-available input {
width: 100%;
margin-left: 8px;
}
.selector ul.selector-chooser {
float: left;
width: 4%;
background-color: #eee;
border-radius: 10px;
margin: 10em 0 0;
padding: 0;
}
.selector-chooser li {
margin: 0;
padding: 3px;
list-style-type: none;
}
.selector select {
padding: 0 10px;
margin: 0 0 10px;
/*border-radius: 0 0 4px 4px;*/
;
}
.selector-add,
.selector-remove {
height: 16px;
display: block;
text-indent: -3000px;
overflow: hidden;
cursor: default;
opacity: 0.3;
}
.active.selector-add,
.active.selector-remove {
opacity: 1;
}
.active.selector-add:hover,
.active.selector-remove:hover {
cursor: pointer;
}
.selector-add {
background: url(../img/selector-icons.svg) 0 -96px no-repeat;
}
.active.selector-add:focus,
.active.selector-add:hover {
background-position: 0 -112px;
}
.selector-remove {
background: url(../img/selector-icons.svg) 0 -64px no-repeat;
}
.active.selector-remove:focus,
.active.selector-remove:hover {
background-position: 0 -80px;
}
a.selector-chooseall,
a.selector-clearall {
display: inline-block;
height: 16px;
text-align: left;
margin: 1px auto 3px;
overflow: hidden;
font-weight: bold;
line-height: 16px;
color: #666;
text-decoration: none;
opacity: 0.3;
}
a.active.selector-chooseall:focus,
a.active.selector-clearall:focus,
a.active.selector-chooseall:hover,
a.active.selector-clearall:hover {
color: #447e9b;
}
a.active.selector-chooseall,
a.active.selector-clearall {
opacity: 1;
}
a.active.selector-chooseall:hover,
a.active.selector-clearall:hover {
cursor: pointer;
}
a.selector-chooseall {
padding: 0 18px 0 0;
background: url(../img/selector-icons.svg) right -160px no-repeat;
cursor: default;
}
a.active.selector-chooseall:focus,
a.active.selector-chooseall:hover {
background-position: 100% -176px;
}
a.selector-clearall {
padding: 0 0 0 18px;
background: url(../img/selector-icons.svg) 0 -128px no-repeat;
cursor: default;
}
a.active.selector-clearall:focus,
a.active.selector-clearall:hover {
background-position: 0 -144px;
}
.selector .search-label-icon {
height: 0;
}
#user_form input[type="password"] {
width: 100%;
}
.control-label {
margin-top: 7px;
}
.help-block,
.timezonewarning {
font-size: .8em;
color: #859099;
font-style: italic;
}
.dashboard tbody tr:first-child td {
border-top: none;
}
.vTimeField {
margin-top: 10px;
}
.vTimeField,
.vDateField {
min-width: 200px;
}
.date-icon::before,
.clock-icon::before {
font-family: "Font Awesome 5 Free" !important;
}
.timelist li {
list-style-type: none;
}
.timelist {
margin: 0;
padding: 0;
}
body.no-sidebar .content-wrapper,
body.no-sidebar .main-footer,
body.no-sidebar .main-header {
margin-left: 0;
}
.vCheckboxLabel.inline {
vertical-align: top;
color: red;
margin-bottom: 0;
}
.inline-related .card-header>span {
float: right;
}
.ui-customiser .menu-items div {
width: 40px;
height: 20px;
border-radius: 25px;
margin-right: 10px;
margin-bottom: 10px;
opacity: 0.8;
cursor: pointer;
}
.ui-customiser select {
width: 100%;
height: auto;
padding: 6px 2px;
}
.control-sidebar-content label {
vertical-align: top;
}
.ui-customiser .menu-items div.inactive {
opacity: 0.3;
}
.ui-customiser .menu-items div.active {
opacity: 1;
border: 1px solid white;
}
.timeline-item {
word-break: break-word;
}
.navbar-nav .brand-link {
padding-top: 3px;
}
.breadcrumb {
background: transparent;
margin: 0;
}
.breadcrumb-item+.breadcrumb-item::before {
content: "\203A";
}
.login-box,
.register-box {
width: 500px;
max-width: 100%;
}
#jazzy-collapsible .collapsible-header:hover {
background: #007bff;
color: white;
}
#jazzy-collapsible .collapsible-header {
cursor: pointer;
}
#jazzy-carousel .carousel-indicators li {
background-color: #007bfe;
}
#jazzy-carousel .carousel-indicators {
position: initial;
}
form ul.radiolist li {
list-style-type: none;
}
form ul.radiolist label {
float: none;
display: inline;
}
form ul.radiolist input[type="radio"] {
margin: -2px 4px 0 0;
padding: 0;
}
form ul.inline {
margin-left: 0;
padding: 0;
}
form ul.inline li {
float: left;
padding-right: 7px;
}
.content-wrapper>.content {
padding: 1rem 2rem;
}
.navbar {
padding: .5rem 2rem;
}
.main-footer {
color: #869099;
padding: 1rem 2rem;
font-size: 14px;
}
.page-actions > a {
margin-right:0.25rem;
margin-left: 0.25rem;
}
#jazzy-actions.sticky-top {
top: 10px;
}
body.layout-navbar-fixed #jazzy-actions.sticky-top {
top: 67px;
}
/* stacked inlines */
a.inline-deletelink:hover {
background-color: #c82333;
border-color: #bd2130;
}
a.inline-deletelink {
float: right;
padding: 3px 5px;
margin: 10px;
background-color: #dc3545;
border-radius: .25rem;
color: white !important;
border: 1px solid #dc3545;
transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
/* end stacked inlines */
/* Support for django-mptt */
#result_list .field-tree_actions {
width: calc(40px + 2.25rem);
}
#result_list .field-tree_actions>div {
margin-top: 0;
}
/* End support for django-mptt */
/* modal tweaks */
.modal.modal-wide .modal-dialog {
width: 50%;
max-width: inherit;
}
.modal-wide .modal-body {
overflow-y: auto;
}
iframe.related-iframe {
width: 100%;
height: 450px;
}
/* Blur background when using modal */
.modal-open .wrapper {
-webkit-filter: blur(1px);
-moz-filter: blur(1px);
-o-filter: blur(1px);
-ms-filter: blur(1px);
filter: blur(1px);
}
/* end modal tweaks */
.control-sidebar {
overflow: hidden scroll;
}
/* tweaks to allow bootstrap styling */
body.jazzmin-login-page {
-ms-flex-align: center;
align-items: center;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: column;
flex-direction: column;
height: 100vh;
-ms-flex-pack: center;
justify-content: center;
}
.callout {
color: black;
}
/* sidebar scrolling */
.layout-fixed #jazzy-sidebar {
top: 0;
bottom: 0;
/* Enable y scroll */
overflow-y: scroll;
/* May inherit scroll, so we need to explicitly hide */
overflow-x: hidden;
}
/* calculate height to fit content, we don't to enable scrolling if the content fits */
.layout-fixed #jazzy-sidebar .sidebar {
height: auto !important;
}
/* Hide scrollbar */
.layout-fixed #jazzy-sidebar {
scrollbar-width: none;
}
.layout-fixed #jazzy-sidebar::-webkit-scrollbar {
width: 0;
}
/* nav-item will overflow container in width if scrollbar is visible */
#jazzy-sidebar .nav-sidebar > .nav-item {
width: 100%;
}
/* tweeks for django-filer*/
.navigator-top-nav + #content-main {
float: left;
width: 100%;
}

View File

@@ -0,0 +1,14 @@
<svg width="15" height="60" viewBox="0 0 1792 7168" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="previous">
<path d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="next">
<path d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
</defs>
<use xlink:href="#previous" x="0" y="0" fill="#333333" />
<use xlink:href="#previous" x="0" y="1792" fill="#000000" />
<use xlink:href="#next" x="0" y="3584" fill="#333333" />
<use xlink:href="#next" x="0" y="5376" fill="#000000" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -0,0 +1,9 @@
<svg width="16" height="32" viewBox="0 0 1792 3584" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="icon">
<path d="M192 1664h288v-288h-288v288zm352 0h320v-288h-320v288zm-352-352h288v-320h-288v320zm352 0h320v-320h-320v320zm-352-384h288v-288h-288v288zm736 736h320v-288h-320v288zm-384-736h320v-288h-320v288zm768 736h288v-288h-288v288zm-384-352h320v-320h-320v320zm-352-864v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm736 864h288v-320h-288v320zm-384-384h320v-288h-320v288zm384 0h288v-288h-288v288zm32-480v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm384-64v1280q0 52-38 90t-90 38h-1408q-52 0-90-38t-38-90v-1280q0-52 38-90t90-38h128v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h384v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h128q52 0 90 38t38 90z"/>
</g>
</defs>
<use xlink:href="#icon" x="0" y="0" fill="#447e9b" />
<use xlink:href="#icon" x="0" y="1792" fill="#003366" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#efb80b" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View File

@@ -0,0 +1,34 @@
<svg width="16" height="192" viewBox="0 0 1792 21504" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="up">
<path d="M1412 895q0-27-18-45l-362-362-91-91q-18-18-45-18t-45 18l-91 91-362 362q-18 18-18 45t18 45l91 91q18 18 45 18t45-18l189-189v502q0 26 19 45t45 19h128q26 0 45-19t19-45v-502l189 189q19 19 45 19t45-19l91-91q18-18 18-45zm252 1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="down">
<path d="M1412 897q0-27-18-45l-91-91q-18-18-45-18t-45 18l-189 189v-502q0-26-19-45t-45-19h-128q-26 0-45 19t-19 45v502l-189-189q-19-19-45-19t-45 19l-91 91q-18 18-18 45t18 45l362 362 91 91q18 18 45 18t45-18l91-91 362-362q18-18 18-45zm252-1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="left">
<path d="M1408 960v-128q0-26-19-45t-45-19h-502l189-189q19-19 19-45t-19-45l-91-91q-18-18-45-18t-45 18l-362 362-91 91q-18 18-18 45t18 45l91 91 362 362q18 18 45 18t45-18l91-91q18-18 18-45t-18-45l-189-189h502q26 0 45-19t19-45zm256-64q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="right">
<path d="M1413 896q0-27-18-45l-91-91-362-362q-18-18-45-18t-45 18l-91 91q-18 18-18 45t18 45l189 189h-502q-26 0-45 19t-19 45v128q0 26 19 45t45 19h502l-189 189q-19 19-19 45t19 45l91 91q18 18 45 18t45-18l362-362 91-91q18-18 18-45zm251 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="clearall">
<path transform="translate(336, 336) scale(0.75)" d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="chooseall">
<path transform="translate(336, 336) scale(0.75)" d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
</defs>
<use xlink:href="#up" x="0" y="0" fill="#666666" />
<use xlink:href="#up" x="0" y="1792" fill="#447e9b" />
<use xlink:href="#down" x="0" y="3584" fill="#666666" />
<use xlink:href="#down" x="0" y="5376" fill="#447e9b" />
<use xlink:href="#left" x="0" y="7168" fill="#666666" />
<use xlink:href="#left" x="0" y="8960" fill="#447e9b" />
<use xlink:href="#right" x="0" y="10752" fill="#666666" />
<use xlink:href="#right" x="0" y="12544" fill="#447e9b" />
<use xlink:href="#clearall" x="0" y="14336" fill="#666666" />
<use xlink:href="#clearall" x="0" y="16128" fill="#447e9b" />
<use xlink:href="#chooseall" x="0" y="17920" fill="#666666" />
<use xlink:href="#chooseall" x="0" y="19712" fill="#447e9b" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,151 @@
(function($) {
'use strict';
function FixSelectorHeight() {
$('.selector .selector-chosen').each(function () {
let selector_chosen = $(this);
let selector_available = selector_chosen.siblings('.selector-available');
let selector_chosen_select = selector_chosen.find('select').first();
let selector_available_select = selector_available.find('select').first();
let selector_available_filter = selector_available.find('p.selector-filter').first();
selector_chosen_select.height(selector_available_select.height() + selector_available_filter.outerHeight());
selector_chosen_select.css('border-top', selector_chosen_select.css('border-bottom'));
});
}
function handleCarousel($carousel) {
const errors = $('.errorlist li', $carousel);
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
const errorCarousel = errors.eq(0).closest('.carousel-item');
$carousel.carousel(errorCarousel.data('carouselid'));
$('.carousel-fieldset-label', $carousel).text(errorCarousel.data()["label"]);
} else if (hash) {
// If we have a tab hash, open that
const activeCarousel = $('.carousel-item[data-target="' + hash + '"]', $carousel);
$carousel.carousel(activeCarousel.data()["carouselid"]);
$('.carousel-fieldset-label', $carousel).text(activeCarousel.data()["label"]);
}
// Update page hash/history on slide
$carousel.on('slide.bs.carousel', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
if (e.relatedTarget.dataset.hasOwnProperty("label")) {
$('.carousel-fieldset-label', $carousel).text(e.relatedTarget.dataset.label);
}
const hash = e.relatedTarget.dataset.target;
if (history.pushState) {
history.pushState(null, null, hash);
} else {
location.hash = hash;
}
});
}
function handleTabs($tabs) {
const errors = $('.change-form .errorlist li');
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
const tabId = errors.eq(0).closest('.tab-pane').attr('id');
$('a[href="#' + tabId + '"]').tab('show');
} else if (hash) {
// If we have a tab hash, open that
$('a[href="' + hash + '"]', $tabs).tab('show');
}
// Change hash for page-reload
$('a', $tabs).on('shown.bs.tab', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
e.preventDefault();
if (history.pushState) {
history.pushState(null, null, e.target.hash);
} else {
location.hash = e.target.hash;
}
});
}
function handleCollapsible($collapsible) {
const errors = $('.errorlist li', $collapsible);
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
$('.panel-collapse', $collapsible).collapse('hide');
errors.eq(0).closest('.panel-collapse').collapse('show');
} else if (hash) {
// If we have a tab hash, open that
$('.panel-collapse', $collapsible).collapse('hide');
$(hash, $collapsible).collapse('show');
}
// Change hash for page-reload
$collapsible.on('shown.bs.collapse', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
if (history.pushState) {
history.pushState(null, null, '#' + e.target.id);
} else {
location.hash = '#' + e.target.id;
}
});
}
function applySelect2() {
// Apply select2 to any select boxes that don't yet have it
// and are not part of the django's empty-form inline
const noSelect2 = '.empty-form select, .select2-hidden-accessible, .selectfilter, .selector-available select, .selector-chosen select, select[data-autocomplete-light-function=select2]';
$('select').not(noSelect2).select2({ width: 'element' });
}
$(document).ready(function () {
const $carousel = $('#content-main form #jazzy-carousel');
const $tabs = $('#content-main form #jazzy-tabs');
const $collapsible = $('#content-main form #jazzy-collapsible');
// Ensure all raw_id_fields have the search icon in them
$('.related-lookup').append('<i class="fa fa-search"></i>');
// Style the inline fieldset button
$('.inline-related fieldset.module .add-row a').addClass('btn btn-sm btn-default float-right');
$('div.add-row>a').addClass('btn btn-sm btn-default float-right');
// Ensure we preserve the tab the user was on using the url hash, even on page reload
if ($tabs.length) { handleTabs($tabs); }
else if ($carousel.length) { handleCarousel($carousel); }
else if ($collapsible.length) { handleCollapsible($collapsible); }
applySelect2();
$('body').on('change', '.related-widget-wrapper select', function(e) {
const event = $.Event('django:update-related');
$(this).trigger(event);
if (!event.isDefaultPrevented() && typeof(window.updateRelatedObjectLinks) !== 'undefined') {
updateRelatedObjectLinks(this);
}
});
});
// Apply select2 to all select boxes when new inline row is created
django.jQuery(document).on('formset:added', applySelect2);
})(jQuery);

View File

@@ -0,0 +1,64 @@
(function($) {
'use strict';
$.fn.search_filters = function () {
$(this).change(function () {
const $field = $(this);
const $option = $field.find('option:selected');
const select_name = $option.data('name');
if (select_name) {
$field.attr('name', select_name);
} else {
$field.removeAttr('name');
}
});
$(this).trigger('change');
};
function getMinimuInputLength(element) {
return window.filterInputLength[element.data('name')] ?? window.filterInputLengthDefault;
}
function searchFilters() {
// Make search filters select2 and ensure they work for filtering
const $ele = $('.search-filter');
$ele.search_filters();
$ele.each(function () {
const $this = $(this);
$this.select2({ width: '100%', minimumInputLength: getMinimuInputLength($this) });
});
// Use select2 for mptt dropdowns
const $mptt = $('.search-filter-mptt');
if ($mptt.length) {
$mptt.search_filters();
$mptt.select2({
width: '100%',
minimumInputLength: getMinimuInputLength($mptt),
templateResult: function (data) {
// https://stackoverflow.com/questions/30820215/selectable-optgroups-in-select2#30948247
// rewrite templateresult for build tree hierarchy
if (!data.element) {
return data.text;
}
const $element = $(data.element);
let $wrapper = $('<span></span>');
$wrapper.attr('style', $($element[0]).attr('style'));
$wrapper.text(data.text);
return $wrapper;
},
});
}
}
$(document).ready(function () {
// Ensure all raw_id_fields have the search icon in them
$('.related-lookup').append('<i class="fa fa-search"></i>')
// Allow for styling of selects
$('.actions select').addClass('form-control').select2({ width: 'element' });
searchFilters();
});
})(jQuery);

67
static/jazzmin/js/main.js Normal file
View File

@@ -0,0 +1,67 @@
(function($) {
'use strict';
function setCookie(key, value) {
const expires = new Date();
expires.setTime(expires.getTime() + (value * 24 * 60 * 60 * 1000));
document.cookie = key + '=' + value + ';expires=' + expires.toUTCString() + '; SameSite=Strict;path=/';
}
function getCookie(key) {
const keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
return keyValue ? keyValue[2] : null;
}
function handleMenu() {
$('[data-widget=pushmenu]').bind('click', function () {
const menuClosed = getCookie('jazzy_menu') === 'closed';
if (!menuClosed) {
setCookie('jazzy_menu', 'closed');
} else {
setCookie('jazzy_menu', 'open');
}
});
}
function setActiveLinks() {
/*
Set the currently active menu item based on the current url, or failing that, find the parent
item from the breadcrumbs
*/
const url = window.location.pathname;
const $breadcrumb = $('.breadcrumb a').last();
const $link = $('a[href="' + url + '"]');
const $parent_link = $('a[href="' + $breadcrumb.attr('href') + '"]');
if ($link.length) {
$link.addClass('active');
} else if ($parent_link.length) {
$parent_link.addClass('active');
};
const $a_active = $('a.nav-link.active');
const $main_li_parent = $a_active.closest('li.nav-item.has-treeview');
const $ul_child = $main_li_parent.children('ul');
$ul_child.show();
$main_li_parent.addClass('menu-is-opening menu-open');
};
$(document).ready(function () {
// Set active status on links
setActiveLinks()
// When we use the menu, store its state in a cookie to preserve it
handleMenu();
// Add minimal changelist styling to templates that we have been unable to override (e.g MPTT)
// Needs to be here and not in change_list.js because this is the only JS we are guaranteed to run
// (as its included in base.html)
const $changeListTable = $('#changelist .results table');
if ($changeListTable.length && !$changeListTable.hasClass('table table-striped')) {
$changeListTable.addClass('table table-striped');
};
});
})(jQuery);

View File

@@ -0,0 +1,188 @@
(function($) {
'use strict';
let relatedModalCounter = 0;
function checkIfInIframe() {
return window.top !== window.self;
}
// create the function that will close the modal
function dismissModal() {
if (checkIfInIframe()) {
const parentWindow = window.parent;
parentWindow.dismissModal();
return;
}
$('.related-modal-' + relatedModalCounter).modal('hide');
relatedModalCounter-=1;
}
// create the function that will show the modal
function showModal(title, body, e) {
if (checkIfInIframe()) {
const parentWindow = window.parent;
parentWindow.showModal(title, body, e);
return;
}
relatedModalCounter+=1;
$.showModal({
title: title,
body: body,
backdrop: false,
modalDialogClass: "modal-dialog-centered modal-lg",
modalClass: "fade modal-wide related-modal-" + relatedModalCounter,
onDispose: function() {
// add focus to the previous modal (if exists) when the current one is closed
var lastModal = $("div[class*='related-modal-']").last();
if (lastModal) {
lastModal.focus();
}
}
});
const modalEl = $("div[class*='related-modal-']");
const iframeEl = modalEl.find('#related-modal-iframe');
if (e.data.lookup === true) {
// set current window as iframe opener because
// the callback is called on the opener window
iframeEl.on('load', function() {
const iframeObj = $(this).get(0);
const iframeWindow = iframeObj.contentWindow;
iframeWindow.opener = window;
});
}
}
function dismissRelatedLookupModal(win, chosenId) {
const windowName = win.name;
const widgetName = windowName.replace(/^(change|add|delete|lookup)_/, '');
let widgetEl;
if (checkIfInIframe) {
// select second to last iframe in the main parent document
const secondLastIframe = $('iframe.related-iframe', win.parent.document).eq(-2);
let documentContext;
// if second to last iframe exists get its contents
if (secondLastIframe.length) {
documentContext = secondLastIframe.contents();
// else get main parent document
} else {
documentContext = $(win.parent.document);
}
// find and select widget from the specified document context
widgetEl = documentContext.find('#' + widgetName);
// else select widget from the main document
} else {
widgetEl = $('#' + widgetName);
}
const widgetVal = widgetEl.val();
if (widgetEl.hasClass('vManyToManyRawIdAdminField') && Boolean(widgetVal)) {
widgetEl.val(widgetVal + ', ' + chosenId);
} else {
widgetEl.val(chosenId);
}
dismissModal();
}
// assign functions to global variables
window.dismissRelatedObjectModal = dismissModal;
window.dismissRelatedLookupPopup = dismissRelatedLookupModal;
window.showModal = showModal;
function presentRelatedObjectModal(e) {
let linkEl = $(this);
let href = (linkEl.attr('href') || '');
if (href === '') {
return;
}
// open the popup as modal
e.preventDefault();
e.stopImmediatePropagation();
// remove focus from clicked link
linkEl.blur();
// use the clicked link id as iframe name
// it will be available as window.name in the loaded iframe
let iframeName = linkEl.attr('id');
let iframeSrc = href;
const modalTitle = linkEl.attr('title');
if (e.data.lookup !== true) {
// browsers stop loading nested iframes having the same src url
// create a random parameter and append it to the src url to prevent it
// this workaround doesn't work with related lookup url
let iframeSrcRandom = String(Math.round(Math.random() * 999999));
if (iframeSrc.indexOf('?') === -1) {
iframeSrc += '?_modal=' + iframeSrcRandom;
} else {
iframeSrc += '&_modal=' + iframeSrcRandom;
}
}
if (iframeSrc.indexOf('_popup=1') === -1) {
if (iframeSrc.indexOf('?') === -1) {
iframeSrc += '?_popup=1';
} else {
iframeSrc += '&_popup=1';
}
}
// build the iframe html
let iframeHTML = '<iframe id="related-modal-iframe" name="' + iframeName + '" src="' + iframeSrc + '" frameBorder="0" class="related-iframe"></iframe>';
// the modal css class
let iframeInternalModalClass = 'related-modal';
// if the current window is inside an iframe, it means that it is already in a modal,
// append an additional css class to the modal to offer more customization
if (window.top !== window.self) {
iframeInternalModalClass += ' related-modal__nested';
}
// open the modal using dynamic bootstrap modal
showModal(modalTitle, iframeHTML, e);
return false;
}
// listen click events on related links
function presentRelatedObjectModalOnClickOn(selector, lookup) {
let el = $(selector);
el.removeAttr('onclick');
el.unbind('click');
el.click({lookup: lookup}, presentRelatedObjectModal);
}
function init() {
presentRelatedObjectModalOnClickOn('a.related-widget-wrapper-link', false);
// raw_id_fields support
presentRelatedObjectModalOnClickOn('a.related-lookup', true);
// django-dynamic-raw-id support - #61
// https://github.com/lincolnloop/django-dynamic-raw-id
presentRelatedObjectModalOnClickOn('a.dynamic_raw_id-related-lookup', true);
}
$(document).ready(function(){
init()
});
django.jQuery(document).on('formset:added', init);
})(jQuery);

View File

@@ -0,0 +1,343 @@
(function ($) {
'use strict';
const $body = $('body');
const $footer = $('footer');
const $sidebar_ul = $('aside#jazzy-sidebar nav ul:first-child');
const $sidebar = $('aside#jazzy-sidebar');
const $navbar = $('nav#jazzy-navbar');
const $logo = $('#jazzy-logo');
const $actions = $('#jazzy-actions');
const buttons = [
"primary",
"secondary",
"info",
"warning",
"danger",
"success",
]
const darkThemes = ["darkly", "cyborg", "slate", "solar", "superhero"]
window.ui_changes = window.ui_changes || {'button_classes': {}};
function miscListeners() {
$('#footer-fixed').on('click', function () {
$body.toggleClass('layout-footer-fixed');
if (this.checked) {
$('#layout-boxed:checked').click();
}
window.ui_changes['footer_fixed'] = this.checked;
});
$('#layout-boxed').on('click', function () {
$body.toggleClass('layout-boxed');
// We cannot combine these options with layout boxed
if (this.checked) {
$('#navbar-fixed:checked').click();
$('#footer-fixed:checked').click();
}
window.ui_changes['layout_boxed'] = this.checked;
});
$('#actions-fixed').on('click', function () {
$actions.toggleClass('sticky-top');
window.ui_changes['actions_sticky_top'] = this.checked;
});
// Colour pickers
$('#accent-colours div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$body.removeClass(function (index, className) {
return (className.match(/(^|\s)accent-\S+/g) || []).join(' ');
}).addClass(newClasses);
window.ui_changes['accent'] = newClasses;
});
$('#brand-logo-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
let newClasses = $(this).data('classes');
$logo.removeClass(function (index, className) {
return (className.match(/(^|\s)navbar-\S+/g) || []).join(' ');
}).addClass(newClasses);
if (newClasses === "") {
newClasses = false;
$(this).parent().find('div').removeClass('active inactive');
}
window.ui_changes['brand_colour'] = newClasses;
});
// show code
$("#codeBox").on('show.bs.modal', function () {
$('.modal-body code', this).html(
'JAZZMIN_UI_TWEAKS = ' + JSON.stringify(
window.ui_changes, null, 4
).replace(
/true/g, 'True'
).replace(
/false/g, 'False'
).replace(
/null/g, 'None'
)
);
});
}
function themeSpecificTweaks(theme) {
if (darkThemes.indexOf(theme) > -1) {
$('#navbar-variants .bg-dark').click();
$("#jazzmin-btn-style-primary").val('btn-primary').change();
$("#jazzmin-btn-style-secondary").val('btn-secondary').change();
$body.addClass('dark-mode');
} else {
$('#navbar-variants .bg-white').click();
$("#jazzmin-btn-style-primary").val('btn-outline-primary').change();
$("#jazzmin-btn-style-secondary").val('btn-outline-secondary').change();
$body.removeClass('dark-mode');
}
}
function themeChooserListeners() {
// Theme chooser (standard)
$("#jazzmin-theme-chooser").on('change', function () {
let $themeCSS = $('#jazzmin-theme');
// If we are using the default theme, there will be no theme css, just the bundled one in adminlte
if (!$themeCSS.length) {
const staticSrc = $('#adminlte-css').attr('href').split('vendor')[0]
$themeCSS = $('<link>').attr({
'href': staticSrc + 'vendor/bootswatch/default/bootstrap.min.css',
'rel': 'stylesheet',
'id': 'jazzmin-theme'
}).appendTo('head');
}
const currentSrc = $themeCSS.attr('href');
const currentTheme = currentSrc.split('/')[4];
let newTheme = $(this).val();
$themeCSS.attr('href', currentSrc.replace(currentTheme, newTheme));
$body.removeClass (function (index, className) {
return (className.match (/(^|\s)theme-\S+/g) || []).join(' ');
});
$body.addClass('theme-' + newTheme);
themeSpecificTweaks(newTheme);
window.ui_changes['theme'] = newTheme;
});
// Theme chooser (dark mode)
$("#jazzmin-dark-mode-theme-chooser").on('change', function () {
let $themeCSS = $('#jazzmin-dark-mode-theme');
// If we are using the default theme, there will be no theme css, just the bundled one in adminlte
if (this.value === "") {
$themeCSS.remove();
window.ui_changes['dark_mode_theme'] = null;
return
}
if (!$themeCSS.length) {
const staticSrc = $('#adminlte-css').attr('href').split('vendor')[0]
$themeCSS = $('<link>').attr({
'href': staticSrc + 'vendor/bootswatch/darkly/bootstrap.min.css',
'rel': 'stylesheet',
'id': 'jazzmin-dark-mode-theme',
'media': '(prefers-color-scheme: dark)'
}).appendTo('head');
}
const currentSrc = $themeCSS.attr('href');
const currentTheme = currentSrc.split('/')[4];
const newTheme = $(this).val();
$themeCSS.attr('href', currentSrc.replace(currentTheme, newTheme));
themeSpecificTweaks(newTheme);
window.ui_changes['dark_mode_theme'] = newTheme;
});
}
function navBarTweaksListeners() {
$('#navbar-fixed').on('click', function () {
$body.toggleClass('layout-navbar-fixed');
if (this.checked) {$('#layout-boxed:checked').click();}
window.ui_changes['navbar_fixed'] = this.checked;
});
$('#no-navbar-border').on('click', function () {
$navbar.toggleClass('border-bottom-0');
window.ui_changes['no_navbar_border'] = $navbar.hasClass('border-bottom-0');
});
// Colour picker
$('#navbar-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$navbar.removeClass(function (index, className) {
return (className.match(/(^|\s)navbar-\S+/g) || []).join(' ');
}).addClass('navbar-expand ' + newClasses);
window.ui_changes['navbar'] = newClasses;
});
}
function sideBarTweaksListeners() {
$('#sidebar-nav-flat-style').on('click', function () {
$sidebar_ul.toggleClass('nav-flat');
window.ui_changes['sidebar_nav_flat_style'] = this.checked;
});
$('#sidebar-nav-legacy-style').on('click', function () {
$sidebar_ul.toggleClass('nav-legacy');
window.ui_changes['sidebar_nav_legacy_style'] = this.checked;
});
$('#sidebar-nav-compact').on('click', function () {
$sidebar_ul.toggleClass('nav-compact');
window.ui_changes['sidebar_nav_compact_style'] = this.checked;
});
$('#sidebar-nav-child-indent').on('click', function () {
$sidebar_ul.toggleClass('nav-child-indent');
window.ui_changes['sidebar_nav_child_indent'] = this.checked;
});
$('#main-sidebar-disable-hover-focus-auto-expand').on('click', function () {
$sidebar.toggleClass('sidebar-no-expand');
window.ui_changes['sidebar_disable_expand'] = this.checked;
});
$('#sidebar-fixed').on('click', function () {
$body.toggleClass('layout-fixed');
window.ui_changes['sidebar_fixed'] = this.checked;
});
// Colour pickers
$('#dark-sidebar-variants div, #light-sidebar-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$sidebar.removeClass(function (index, className) {
return (className.match(/(^|\s)sidebar-[\S|-]+/g) || []).join(' ');
}).addClass(newClasses);
window.ui_changes['sidebar'] = newClasses.trim();
});
}
function smallTextListeners() {
$('#navbar-small-text').on('click', function () {
$navbar.toggleClass('text-sm');
window.ui_changes['navbar_small_text'] = this.checked;
});
$('#brand-small-text').on('click', function () {
$logo.toggleClass('text-sm');
window.ui_changes['brand_small_text'] = this.checked;
});
$('#body-small-text').on('click', function () {
$body.toggleClass('text-sm');
window.ui_changes['body_small_text'] = this.checked;
const $smallTextControls = $('#navbar-small-text, #brand-small-text, #footer-small-text, #sidebar-nav-small-text');
if (this.checked) {
window.ui_changes['navbar_small_text'] = false;
window.ui_changes['brand_small_text'] = false;
window.ui_changes['footer_small_text'] = false;
window.ui_changes['sidebar_nav_small_text'] = false;
$smallTextControls.prop({'checked': false, 'disabled': 'disabled'});
} else {
$smallTextControls.prop({'checked': false, 'disabled': ''});
}
});
$('#footer-small-text').on('click', function () {
$footer.toggleClass('text-sm');
window.ui_changes['footer_small_text'] = this.checked;
});
$('#sidebar-nav-small-text').on('click', function () {
$sidebar_ul.toggleClass('text-sm');
window.ui_changes['sidebar_nav_small_text'] = this.checked;
});
}
function buttonStyleListeners() {
buttons.forEach(function(btn) {
$("#jazzmin-btn-style-" + btn).on('change', function () {
const btnClasses = ['btn-' + btn, 'btn-outline-' + btn];
const selectorClasses = '.btn-' + btn + ', .btn-outline-' + btn;
$(selectorClasses).removeClass(btnClasses).addClass(this.value);
window.ui_changes['button_classes'][btn] = this.value;
});
});
}
function setFromExisting() {
$('#jazzmin-theme-chooser').val(window.ui_changes['theme']);
$('#jazzmin-dark-mode-theme-chooser').val(window.ui_changes['dark_mode_theme']);
$('#theme-condition').val(window.ui_changes['theme_condition']);
$('#body-small-text').get(0).checked = window.ui_changes['body_small_text'];
$('#footer-small-text').get(0).checked = window.ui_changes['footer_small_text'];
$('#sidebar-nav-small-text').get(0).checked = window.ui_changes['sidebar_nav_small_text'];
$('#sidebar-nav-legacy-style').get(0).checked = window.ui_changes['sidebar_nav_legacy_style'];
$('#sidebar-nav-compact').get(0).checked = window.ui_changes['sidebar_nav_compact_style'];
$('#sidebar-nav-child-indent').get(0).checked = window.ui_changes['sidebar_nav_child_indent'];
$('#main-sidebar-disable-hover-focus-auto-expand').get(0).checked = window.ui_changes['sidebar_disable_expand'];
$('#no-navbar-border').get(0).checked = window.ui_changes['no_navbar_border'];
$('#navbar-small-text').get(0).checked = window.ui_changes['navbar_small_text'];
$('#brand-small-text').get(0).checked = window.ui_changes['brand_small_text'];
// deactivate colours
$('#navbar-variants div, #accent-colours div, #dark-sidebar-variants div, #light-sidebar-variants div, #brand-logo-variants div').addClass('inactive');
// set button styles
buttons.forEach(function(btn) {
$("#jazzmin-btn-style-" + btn).val(window.ui_changes['button_classes'][btn]);
});
// set colours
$('#navbar-variants div[data-classes="' + window.ui_changes['navbar'] + '"]').addClass('active');
$('#accent-colours div[data-classes="' + window.ui_changes['accent'] + '"]').addClass('active');
$('#dark-sidebar-variants div[data-classes="' + window.ui_changes['sidebar'] + '"]').addClass('active');
$('#light-sidebar-variants div[data-classes="' + window.ui_changes['sidebar'] + '"]').addClass('active');
$('#brand-logo-variants div[data-classes="' + window.ui_changes['brand_colour'] + '"]').addClass('active');
}
/*
Don't call if it is inside an iframe
*/
if (!$body.hasClass("popup")) {
setFromExisting();
themeChooserListeners();
miscListeners();
navBarTweaksListeners();
sideBarTweaksListeners();
smallTextListeners();
buttonStyleListeners();
}
})(jQuery);

View File

@@ -0,0 +1 @@
!function(o){"use strict";var s=0;function i(t){for(var e in this.props={title:"",body:"",footer:"",modalClass:"fade",modalDialogClass:"",options:null,onCreate:null,onDispose:null,onSubmit:null},t)this.props[e]=t[e];this.id="bootstrap-show-modal-"+s,s++,this.show()}i.prototype.createContainerElement=function(){var t=this;this.element=document.createElement("div"),this.element.id=this.id,this.element.setAttribute("class","modal "+this.props.modalClass),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.element.setAttribute("aria-labelledby",this.id),this.element.innerHTML='<div class="modal-dialog '+this.props.modalDialogClass+'" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title"></h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div class="modal-body"></div><div class="modal-footer"></div></div></div>',document.body.appendChild(this.element),this.titleElement=this.element.querySelector(".modal-title"),this.bodyElement=this.element.querySelector(".modal-body"),this.footerElement=this.element.querySelector(".modal-footer"),o(this.element).on("hidden.bs.modal",function(){t.dispose()}),this.props.onCreate&&this.props.onCreate(this)},i.prototype.show=function(){this.element?o(this.element).modal("show"):(this.createContainerElement(),this.props.options?o(this.element).modal(this.props.options):o(this.element).modal()),this.props.title?(o(this.titleElement).show(),this.titleElement.innerHTML=this.props.title):o(this.titleElement).hide(),this.props.body?(o(this.bodyElement).show(),this.bodyElement.innerHTML=this.props.body):o(this.bodyElement).hide(),this.props.footer?(o(this.footerElement).show(),this.footerElement.innerHTML=this.props.footer):o(this.footerElement).hide()},i.prototype.hide=function(){o(this.element).modal("hide")},i.prototype.dispose=function(){o(this.element).modal("dispose"),document.body.removeChild(this.element),this.props.onDispose&&this.props.onDispose(this)},o.extend({showModal:function(t){if(t.buttons){var e,o="";for(e in t.buttons){o+='<button type="button" class="btn btn-primary" data-value="'+e+'" data-dismiss="modal">'+t.buttons[e]+"</button>"}t.footer=o}return new i(t)},showAlert:function(t){return t.buttons={OK:"OK"},this.showModal(t)},showConfirm:function(t){return t.footer='<button class="btn btn-secondary btn-false btn-cancel">'+t.textFalse+'</button><button class="btn btn-primary btn-true">'+t.textTrue+"</button>",t.onCreate=function(e){o(e.element).on("click",".btn",function(t){t.preventDefault(),e.hide(),e.props.onSubmit(-1!==t.target.getAttribute("class").indexOf("btn-true"),e)})},this.showModal(t)}})}(jQuery);

View File

@@ -0,0 +1,2 @@
group_id,category_id
all_students_FIT,9b0c545a-0615-49ff-892a-d2401224a27c
1 group_id category_id
2 all_students_FIT 9b0c545a-0615-49ff-892a-d2401224a27c

View File

@@ -0,0 +1,2 @@
group_id,name
all_students_FIT,All Students FIT
1 group_id name
2 all_students_FIT All Students FIT

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
static/vendor/adminlte/img/icons.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long