feat: Add Admin Groups Management Module

- Introduced a new module for managing user groups (`usrgrp`) in the administration interface.
- Implemented CRUD operations for user groups: list, create, rename, and delete.
- Added authorization checks to ensure only users with appropriate permissions can manage groups.
- Created corresponding frontend JavaScript and SCSS files for the new module.
- Updated documentation to reflect the new group management functionality and its authorization model.
- Added SQL stored procedures for group management operations.
- Established a new login script for database access, ensuring proper security practices.
This commit is contained in:
Stefan
2026-09-16 09:35:31 +02:00
parent 1a5ac73f3c
commit 8bcec409c5
59 changed files with 1283 additions and 88 deletions
+6 -4
View File
@@ -2845,6 +2845,7 @@ $.extend($t, {
, m_admin: 'Administration'
, m_admin_status: 'Systemüberwachung'
, m_usr: 'Benutzerverwaltung'
, m_usrgrp: 'Gruppenverwaltung'
, rsp: 'Passwort ändern'
, pnm: 'Die Passwörter stimmen nicht überein'
, cps: 'Das neue Passwort wurde gespeichert.'
@@ -3241,10 +3242,10 @@ $fis.draft = {
})();
/* "Administration" is a single sidemenu dropdown (ocmsmenu supports nested items via `itm`)
containing two buttons — Benutzerverwaltung (fn=usr) and Systemüberwachung (fn=admin) — both
restricted to users whose fds_sys authorization exceeds 4. One auth check gates the whole
dropdown; it (and therefore both module scripts) is only added after that check resolves, so
lower-privileged users never see it or fetch either module's code.
containing three buttons — Benutzerverwaltung (fn=usr), Gruppenverwaltung (fn=usrgrp) and
Systemüberwachung (fn=admin) — all restricted to users whose fds_sys authorization exceeds 4.
One auth check gates the whole dropdown; it (and therefore all module scripts) is only added
after that check resolves, so lower-privileged users never see it or fetch any module's code.
Called from fis_main_go.js once the DOM (and the initial main menu) is ready. */
$fis.addAdminMenuButtonsIfAuthorized = function () {
if ($('#m_admin_grp').length > 0) { return; } // idempotent
@@ -3254,6 +3255,7 @@ $fis.addAdminMenuButtonsIfAuthorized = function () {
lbl: $t.m_admin, id: 'm_admin_grp', ico: 'glyphicon glyphicon-cog',
itm: [
{ lbl: $t.m_usr, id: 'm_usr', fnc: 'init:usr', ico: 'glyphicon glyphicon-user' },
{ lbl: $t.m_usrgrp, id: 'm_usrgrp', fnc: 'init:usrgrp', ico: 'glyphicon glyphicon-list' },
{ lbl: $t.m_admin_status, id: 'm_admin', fnc: 'init:admin', ico: 'glyphicon glyphicon-dashboard' }
]
});
+1 -1
View File
File diff suppressed because one or more lines are too long
+17 -2
View File
@@ -28,7 +28,7 @@
}
.usrfrm .usr_row {
display: grid;
grid-template-columns: 2.75rem 1.6fr 1.8fr 8rem;
grid-template-columns: 2.75rem 1.4fr 1.6fr 1.6fr 8rem;
align-items: center;
gap: 0.75rem;
padding: 0.55rem 1rem;
@@ -77,6 +77,16 @@
color: #555;
overflow-wrap: anywhere;
}
.usrfrm .usr_col_groups {
color: #555;
font-size: 0.9rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.usrfrm .usr_row_hd .usr_col_groups {
font-size: inherit;
}
.usrfrm .usr_pill {
display: inline-block;
padding: 0.1rem 0.6rem;
@@ -110,7 +120,7 @@
}
.usrfrm .usr_row {
grid-template-columns: 2.25rem 1fr;
grid-template-areas: "avatar name" "avatar email" "avatar status";
grid-template-areas: "avatar name" "avatar email" "avatar groups" "avatar status";
}
.usrfrm .usr_row_hd {
display: none;
@@ -125,6 +135,11 @@
grid-area: email;
font-size: 0.85rem;
}
.usrfrm .usr_col_groups {
grid-area: groups;
font-size: 0.85rem;
white-space: normal;
}
.usrfrm .usr_col_status {
grid-area: status;
}
+39 -15
View File
@@ -3,6 +3,7 @@ let $uct = {
, rel: 'Neu Laden'
, col_name: 'Name'
, col_email: 'E-Mail'
, col_groups: 'Gruppen'
, col_status: 'Status'
, active: 'Aktiv'
, disabled: 'Deaktiviert'
@@ -75,6 +76,40 @@ let $usr = {
let f = (firstname || '').trim().charAt(0), n = (name || '').trim().charAt(0);
return (f + n).toUpperCase() || '?';
},
/* Builds one (detached) grid row for a user record; shared by renderLst and refreshRow. */
buildRow: function (rw) {
let disabled = bool(rw.disabled, false) === true;
let row = $$.dc('usr_row', { id: 'usr' + rw.useraccount_id });
$$.dc('usr_avatar', row).text($usr.initials(rw.firstname, rw.name));
$$.dc('usr_col_name', row).text(`${rw.firstname || ''} ${rw.name || ''}`.trim());
$$.dc('usr_col_email', row).text(rw.email || '');
$$.dc('usr_col_groups', row).text(rw.groups || '').attr('title', rw.groups || '');
$$.dc('usr_col_status', row).append(
$$.dc(disabled ? 'usr_pill usr_pill_off' : 'usr_pill usr_pill_on').text(disabled ? $uct.disabled : $uct.active)
);
row.click(function () {
row.toggleClass('selected').siblings().rC('selected');
if (row.is('.selected') === true) { $usr.iMn(rw); } else { $usr.eM(true); }
});
return row;
},
/* Re-fetches a single user and swaps its grid row in place, keeping selection + ribbon
(used after changes that only affect that one row: email, group membership). Falls back
to a full reload when the row is no longer in the grid. */
refreshRow: function (rw) {
let old = $('#usr' + rw.useraccount_id);
if (old.length === 0) { $usr.renderLst(); return; }
$ocms.postXT({
url: $ocms.url('usr/list'), data: { useraccount_id: rw.useraccount_id }, success: function (r) {
let fresh = (r.users || [])[0];
if (!fresh) { $usr.renderLst(); return; }
let selected = old.is('.selected');
let row = $usr.buildRow(fresh).toggleClass('selected', selected);
old.replaceWith(row);
if (selected) { $usr.iMn(fresh); }
}, error: function () { $usr.renderLst(); }
});
},
renderLst: function () {
let usrlst = $fis.frm_list(true, true).ldng(1), usrfrm = $$.dc('usrfrm', usrlst);
$usr.eM(true);
@@ -86,25 +121,13 @@ let $usr = {
$$.dc('usr_col_avatar', hdr);
$$.dc('usr_col_name', hdr).text($uct.col_name);
$$.dc('usr_col_email', hdr).text($uct.col_email);
$$.dc('usr_col_groups', hdr).text($uct.col_groups);
$$.dc('usr_col_status', hdr).text($uct.col_status);
if ((r.users || []).length === 0) {
$$.dc('usr_empty', grid).text($uct.empty);
return;
}
$.each(r.users || [], function (ri, rw) {
let disabled = bool(rw.disabled, false) === true;
let row = $$.dc('usr_row', grid, { id: 'usr' + rw.useraccount_id });
$$.dc('usr_avatar', row).text($usr.initials(rw.firstname, rw.name));
$$.dc('usr_col_name', row).text(`${rw.firstname || ''} ${rw.name || ''}`.trim());
$$.dc('usr_col_email', row).text(rw.email || '');
$$.dc('usr_col_status', row).append(
$$.dc(disabled ? 'usr_pill usr_pill_off' : 'usr_pill usr_pill_on').text(disabled ? $uct.disabled : $uct.active)
);
row.click(function () {
row.toggleClass('selected').siblings().rC('selected');
if (row.is('.selected') === true) { $usr.iMn(rw); } else { $usr.eM(true); }
});
});
$.each(r.users || [], function (ri, rw) { grid.append($usr.buildRow(rw)); });
}, error: function () {
usrfrm.empty();
$$.dc('usr_err', usrfrm).text($uct.loadfail);
@@ -187,7 +210,7 @@ let $usr = {
}, error: function (jqXHR) {
let code = ((jqXHR || {}).responseJSON || {}).error;
alert($uct.err[code] || $uct.err_generic);
}, complete: function () { c.ldng(0); $usr.renderLst(); }
}, complete: function () { c.ldng(0); $usr.refreshRow(rw); }
});
}
});
@@ -206,6 +229,7 @@ let $usr = {
$ocms.postXT({
url: $ocms.url('usr/groupset'),
data: { useraccount_id: rw.useraccount_id, usergroup_id: g.usergroup_id, member: checked },
success: function () { $usr.refreshRow(rw); }, /* keep the groups csv in the grid current per toggle */
error: function () {
cb.prop('checked', !checked);
alert($uct.err_generic);
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
.usrfrm{padding:1.5rem 2rem}.usrfrm .usr_grid{border:1px solid #e2e2e2;border-radius:.5rem;background:#fff;box-shadow:0 1px 3px rgba(50,50,50,.1);overflow:hidden}.usrfrm .usr_row{display:grid;grid-template-columns:2.75rem 1.6fr 1.8fr 8rem;align-items:center;gap:.75rem;padding:.55rem 1rem;border-bottom:1px solid #eee}.usrfrm .usr_row:last-child{border-bottom:none}.usrfrm .usr_row_hd{background:#1b4379;color:#fff;font-weight:700;font-size:.85rem;text-transform:uppercase;letter-spacing:.02em;padding:.5rem 1rem}.usrfrm .usr_row:not(.usr_row_hd){cursor:pointer;transition:background-color .12s ease-in-out}.usrfrm .usr_row:not(.usr_row_hd):hover{background-color:#f3f6fb}.usrfrm .usr_row:not(.usr_row_hd).selected{background-color:rgba(86,165,50,.12);box-shadow:inset 3px 0 0 #56a532}.usrfrm .usr_avatar{width:2.1rem;height:2.1rem;border-radius:50%;background:#1b4379;color:#fff;font-size:.78rem;font-weight:700;display:flex;align-items:center;justify-content:center}.usrfrm .usr_col_name{font-weight:600;color:#222}.usrfrm .usr_col_email{color:#555;overflow-wrap:anywhere}.usrfrm .usr_pill{display:inline-block;padding:.1rem .6rem;border-radius:1rem;font-size:.78rem;font-weight:700;white-space:nowrap}.usrfrm .usr_pill_on{background:#e2f3da;color:#2f6d18}.usrfrm .usr_pill_off{background:#ececec;color:#777}.usrfrm .usr_empty{padding:1.5rem 1rem;text-align:center;color:#777}.usrfrm .usr_err{padding:1rem 2rem;color:#b00020;font-weight:700}@media (max-width:640px){.usrfrm{padding:.75rem}.usrfrm .usr_row{grid-template-columns:2.25rem 1fr;grid-template-areas:"avatar name" "avatar email" "avatar status"}.usrfrm .usr_row_hd{display:none}.usrfrm .usr_avatar{grid-area:avatar}.usrfrm .usr_col_name{grid-area:name}.usrfrm .usr_col_email{grid-area:email;font-size:.85rem}.usrfrm .usr_col_status{grid-area:status}}.usr_groups_dlg{padding:.25rem 0}.usr_groups_dlg .usr_group_row{display:flex;align-items:center;gap:.5rem;padding:.35rem 0;border-bottom:1px solid #eee}.usr_groups_dlg .usr_group_row:last-child{border-bottom:none}.usr_groups_dlg .usr_group_row input[type=checkbox]{margin:0}.usr_groups_dlg .usr_group_row label{margin:0;font-weight:400}
.usrfrm{padding:1.5rem 2rem}.usrfrm .usr_grid{border:1px solid #e2e2e2;border-radius:.5rem;background:#fff;box-shadow:0 1px 3px rgba(50,50,50,.1);overflow:hidden}.usrfrm .usr_row{display:grid;grid-template-columns:2.75rem 1.4fr 1.6fr 1.6fr 8rem;align-items:center;gap:.75rem;padding:.55rem 1rem;border-bottom:1px solid #eee}.usrfrm .usr_row:last-child{border-bottom:none}.usrfrm .usr_row_hd{background:#1b4379;color:#fff;font-weight:700;font-size:.85rem;text-transform:uppercase;letter-spacing:.02em;padding:.5rem 1rem}.usrfrm .usr_row:not(.usr_row_hd){cursor:pointer;transition:background-color .12s ease-in-out}.usrfrm .usr_row:not(.usr_row_hd):hover{background-color:#f3f6fb}.usrfrm .usr_row:not(.usr_row_hd).selected{background-color:rgba(86,165,50,.12);box-shadow:inset 3px 0 0 #56a532}.usrfrm .usr_avatar{width:2.1rem;height:2.1rem;border-radius:50%;background:#1b4379;color:#fff;font-size:.78rem;font-weight:700;display:flex;align-items:center;justify-content:center}.usrfrm .usr_col_name{font-weight:600;color:#222}.usrfrm .usr_col_email{color:#555;overflow-wrap:anywhere}.usrfrm .usr_col_groups{color:#555;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.usrfrm .usr_row_hd .usr_col_groups{font-size:inherit}.usrfrm .usr_pill{display:inline-block;padding:.1rem .6rem;border-radius:1rem;font-size:.78rem;font-weight:700;white-space:nowrap}.usrfrm .usr_pill_on{background:#e2f3da;color:#2f6d18}.usrfrm .usr_pill_off{background:#ececec;color:#777}.usrfrm .usr_empty{padding:1.5rem 1rem;text-align:center;color:#777}.usrfrm .usr_err{padding:1rem 2rem;color:#b00020;font-weight:700}@media (max-width:640px){.usrfrm{padding:.75rem}.usrfrm .usr_row{grid-template-columns:2.25rem 1fr;grid-template-areas:"avatar name" "avatar email" "avatar groups" "avatar status"}.usrfrm .usr_row_hd{display:none}.usrfrm .usr_avatar{grid-area:avatar}.usrfrm .usr_col_name{grid-area:name}.usrfrm .usr_col_email{grid-area:email;font-size:.85rem}.usrfrm .usr_col_groups{grid-area:groups;font-size:.85rem;white-space:normal}.usrfrm .usr_col_status{grid-area:status}}.usr_groups_dlg{padding:.25rem 0}.usr_groups_dlg .usr_group_row{display:flex;align-items:center;gap:.5rem;padding:.35rem 0;border-bottom:1px solid #eee}.usr_groups_dlg .usr_group_row:last-child{border-bottom:none}.usr_groups_dlg .usr_group_row input[type=checkbox]{margin:0}.usr_groups_dlg .usr_group_row label{margin:0;font-weight:400}
+73
View File
@@ -0,0 +1,73 @@
/* basics */
/* Color SCHEME */
/* #8396bd */
/* #e3e6e6 */
/* #ffffff */
/* #262626 */
/* #262626 */
/* #e3e6e6 */
/* #FFC801 */
/* #ffff4a */
/* media breaks */
/* other */
/* mixin */
/* basics */
/* Color SCHEME */
/* #1b4379 #0033b3 */
/*neu: #56a532 ; alt: rgb(32,144,119);*/
/* 10% sw */
.ugpfrm {
padding: 1.5rem 2rem;
}
.ugpfrm .ugp_grid {
border: 1px solid #e2e2e2;
border-radius: 0.5rem;
background: #fff;
box-shadow: 0 1px 3px rgba(50, 50, 50, 0.1);
overflow: hidden;
max-width: 32rem;
}
.ugpfrm .ugp_row {
display: grid;
grid-template-columns: 1fr;
align-items: center;
padding: 0.55rem 1rem;
border-bottom: 1px solid #eee;
}
.ugpfrm .ugp_row:last-child {
border-bottom: none;
}
.ugpfrm .ugp_row_hd {
background: rgb(27, 67, 121);
color: #fff;
font-weight: bold;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.02em;
padding: 0.5rem 1rem;
}
.ugpfrm .ugp_row:not(.ugp_row_hd) {
cursor: pointer;
transition: background-color 0.12s ease-in-out;
}
.ugpfrm .ugp_row:not(.ugp_row_hd):hover {
background-color: #f3f6fb;
}
.ugpfrm .ugp_row:not(.ugp_row_hd).selected {
background-color: rgba(86, 165, 50, 0.12);
box-shadow: inset 3px 0 0 rgb(86, 165, 50);
}
.ugpfrm .ugp_col_name {
font-weight: 600;
color: #222;
}
.ugpfrm .ugp_empty {
padding: 1.5rem 1rem;
text-align: center;
color: #777;
}
.ugpfrm .ugp_err {
padding: 1rem 2rem;
color: #b00020;
font-weight: bold;
}
+127
View File
@@ -0,0 +1,127 @@
let $ugt = {
mdl: 'Gruppenverwaltung'
, rel: 'Neu Laden'
, col_name: 'Name'
, loadfail: 'Die Gruppenliste konnte nicht geladen werden.'
, empty: 'Es sind keine Benutzergruppen vorhanden.'
, newgroup: 'Neue Gruppe'
, newgroup_btn: 'Anlegen'
, name_field: 'Gruppenname'
, rename: 'Gruppe umbenennen'
, rename_btn: 'Speichern'
, delete: 'Gruppe löschen'
, delete_confirm: 'Soll die Gruppe "{0}" wirklich gelöscht werden? Die Mitgliedschaft aller Benutzer in dieser Gruppe geht dabei verloren.'
, err: {
save_failed: 'Die Gruppe konnte nicht gespeichert werden.',
delete_failed: 'Die Gruppe konnte nicht gelöscht werden.'
}
, err_generic: 'Die Änderung konnte nicht gespeichert werden.'
};
let $ugp = {
init2: function () {
$ocms.getScript([], function () { $ugp.init3(); });
},
init3: function () {
$fis.cf(true);
$fis.lf(true);
$('#activemodule').text($ugt.mdl);
$ugp.eM();
$ugp.renderLst();
},
/* Default ribbon (nothing selected). */
eM: function (r) {
let m = [{ lbl: $ugt.newgroup_btn, fnc: $ugp.createDlg }];
if (bool(r, false) === true) { m.push({ lbl: $ugt.rel, fnc: $ugp.renderLst }); }
return $('#topbar').ocmsmenu(m);
},
/* Per-row ribbon shown while a group row is selected. */
iMn: function (rw) {
return $('#topbar').ocmsmenu([
{ lbl: $ugt.rename, fnc: function () { $ugp.renameDlg(rw); } },
{ lbl: $ugt.delete, fnc: function () { $ugp.deleteGroup(rw); } }
]);
},
renderLst: function () {
let ugplst = $fis.frm_list(true, true).ldng(1), ugpfrm = $$.dc('ugpfrm', ugplst);
$ugp.eM(true);
$ocms.postXT({
url: $ocms.url('usrgrp/list'), success: function (r) {
ugpfrm.empty();
let grid = $$.dc('ugp_grid', ugpfrm);
let hdr = $$.dc('ugp_row ugp_row_hd', grid);
$$.dc('ugp_col_name', hdr).text($ugt.col_name);
if ((r.groups || []).length === 0) {
$$.dc('ugp_empty', grid).text($ugt.empty);
return;
}
$.each(r.groups || [], function (gi, rw) {
let row = $$.dc('ugp_row', grid, { id: 'ugp' + rw.usergroup_id });
$$.dc('ugp_col_name', row).text(rw.name || '');
row.click(function () {
row.toggleClass('selected').siblings().rC('selected');
if (row.is('.selected') === true) { $ugp.iMn(rw); } else { $ugp.eM(true); }
});
});
}, error: function () {
ugpfrm.empty();
$$.dc('ugp_err', ugpfrm).text($ugt.loadfail);
}, complete: function () { ugplst.ldng(0); }
});
},
createDlg: function () {
$ocms.dlgform([
{ name: 'name', label: $ugt.name_field, type: 'string', required: true }
], {
title: $ugt.newgroup,
button: $ugt.newgroup_btn,
submit: function (e) {
let c = $(this).ldng(1);
let qs = c.serializeObject(true, { typedvalues: true });
$ocms.postXT({
url: $ocms.url('usrgrp/create'), data: qs, success: function () {
c.trigger('modal_close');
}, error: function (jqXHR) {
let code = ((jqXHR || {}).responseJSON || {}).error;
alert($ugt.err[code] || $ugt.err_generic);
}, complete: function () { c.ldng(0); $ugp.renderLst(); }
});
}
});
},
renameDlg: function (rw) {
$ocms.dlgform([
{ name: 'usergroup_id', type: 'hidden', value: rw.usergroup_id },
{ name: 'name', label: $ugt.name_field, type: 'string', required: true, value: rw.name }
], {
title: $ugt.rename,
button: $ugt.rename_btn,
submit: function (e) {
let c = $(this).ldng(1);
let qs = c.serializeObject(true, { typedvalues: true });
$ocms.postXT({
url: $ocms.url('usrgrp/rename'), data: qs, success: function () {
c.trigger('modal_close');
}, error: function (jqXHR) {
let code = ((jqXHR || {}).responseJSON || {}).error;
alert($ugt.err[code] || $ugt.err_generic);
}, complete: function () { c.ldng(0); $ugp.renderLst(); }
});
}
});
},
deleteGroup: function (rw) {
if (confirm(string($ugt.delete_confirm, [rw.name || '']))) {
$ocms.postXT({
url: $ocms.url('usrgrp/delete'), data: { usergroup_id: rw.usergroup_id }, success: function () {
$ugp.eM(true);
}, error: function (jqXHR) {
let code = ((jqXHR || {}).responseJSON || {}).error;
alert($ugt.err[code] || $ugt.err_generic);
}, complete: function () { $ugp.renderLst(); }
});
}
}
};
let $$ugp = { init2: $ugp.init2, auth: {} };
export default $$ugp;
+1
View File
@@ -0,0 +1 @@
let $ugt={mdl:"Gruppenverwaltung",rel:"Neu Laden",col_name:"Name",loadfail:"Die Gruppenliste konnte nicht geladen werden.",empty:"Es sind keine Benutzergruppen vorhanden.",newgroup:"Neue Gruppe",newgroup_btn:"Anlegen",name_field:"Gruppenname",rename:"Gruppe umbenennen",rename_btn:"Speichern",delete:"Gruppe löschen",delete_confirm:'Soll die Gruppe "{0}" wirklich gelöscht werden? Die Mitgliedschaft aller Benutzer in dieser Gruppe geht dabei verloren.',err:{save_failed:"Die Gruppe konnte nicht gespeichert werden.",delete_failed:"Die Gruppe konnte nicht gelöscht werden."},err_generic:"Die Änderung konnte nicht gespeichert werden."},$ugp={init2:function(){$ocms.getScript([],(function(){$ugp.init3()}))},init3:function(){$fis.cf(!0),$fis.lf(!0),$("#activemodule").text($ugt.mdl),$ugp.eM(),$ugp.renderLst()},eM:function(e){let n=[{lbl:$ugt.newgroup_btn,fnc:$ugp.createDlg}];return!0===bool(e,!1)&&n.push({lbl:$ugt.rel,fnc:$ugp.renderLst}),$("#topbar").ocmsmenu(n)},iMn:function(e){return $("#topbar").ocmsmenu([{lbl:$ugt.rename,fnc:function(){$ugp.renameDlg(e)}},{lbl:$ugt.delete,fnc:function(){$ugp.deleteGroup(e)}}])},renderLst:function(){let e=$fis.frm_list(!0,!0).ldng(1),n=$$.dc("ugpfrm",e);$ugp.eM(!0),$ocms.postXT({url:$ocms.url("usrgrp/list"),success:function(e){n.empty();let t=$$.dc("ugp_grid",n),r=$$.dc("ugp_row ugp_row_hd",t);$$.dc("ugp_col_name",r).text($ugt.col_name),0!==(e.groups||[]).length?$.each(e.groups||[],(function(e,n){let r=$$.dc("ugp_row",t,{id:"ugp"+n.usergroup_id});$$.dc("ugp_col_name",r).text(n.name||""),r.click((function(){r.toggleClass("selected").siblings().rC("selected"),!0===r.is(".selected")?$ugp.iMn(n):$ugp.eM(!0)}))})):$$.dc("ugp_empty",t).text($ugt.empty)},error:function(){n.empty(),$$.dc("ugp_err",n).text($ugt.loadfail)},complete:function(){e.ldng(0)}})},createDlg:function(){$ocms.dlgform([{name:"name",label:$ugt.name_field,type:"string",required:!0}],{title:$ugt.newgroup,button:$ugt.newgroup_btn,submit:function(e){let n=$(this).ldng(1),t=n.serializeObject(!0,{typedvalues:!0});$ocms.postXT({url:$ocms.url("usrgrp/create"),data:t,success:function(){n.trigger("modal_close")},error:function(e){let n=((e||{}).responseJSON||{}).error;alert($ugt.err[n]||$ugt.err_generic)},complete:function(){n.ldng(0),$ugp.renderLst()}})}})},renameDlg:function(e){$ocms.dlgform([{name:"usergroup_id",type:"hidden",value:e.usergroup_id},{name:"name",label:$ugt.name_field,type:"string",required:!0,value:e.name}],{title:$ugt.rename,button:$ugt.rename_btn,submit:function(e){let n=$(this).ldng(1),t=n.serializeObject(!0,{typedvalues:!0});$ocms.postXT({url:$ocms.url("usrgrp/rename"),data:t,success:function(){n.trigger("modal_close")},error:function(e){let n=((e||{}).responseJSON||{}).error;alert($ugt.err[n]||$ugt.err_generic)},complete:function(){n.ldng(0),$ugp.renderLst()}})}})},deleteGroup:function(e){confirm(string($ugt.delete_confirm,[e.name||""]))&&$ocms.postXT({url:$ocms.url("usrgrp/delete"),data:{usergroup_id:e.usergroup_id},success:function(){$ugp.eM(!0)},error:function(e){let n=((e||{}).responseJSON||{}).error;alert($ugt.err[n]||$ugt.err_generic)},complete:function(){$ugp.renderLst()}})}},$$ugp={init2:$ugp.init2,auth:{}};export default $$ugp;
+1
View File
@@ -0,0 +1 @@
.ugpfrm{padding:1.5rem 2rem}.ugpfrm .ugp_grid{border:1px solid #e2e2e2;border-radius:.5rem;background:#fff;box-shadow:0 1px 3px rgba(50,50,50,.1);overflow:hidden;max-width:32rem}.ugpfrm .ugp_row{display:grid;grid-template-columns:1fr;align-items:center;padding:.55rem 1rem;border-bottom:1px solid #eee}.ugpfrm .ugp_row:last-child{border-bottom:none}.ugpfrm .ugp_row_hd{background:#1b4379;color:#fff;font-weight:700;font-size:.85rem;text-transform:uppercase;letter-spacing:.02em;padding:.5rem 1rem}.ugpfrm .ugp_row:not(.ugp_row_hd){cursor:pointer;transition:background-color .12s ease-in-out}.ugpfrm .ugp_row:not(.ugp_row_hd):hover{background-color:#f3f6fb}.ugpfrm .ugp_row:not(.ugp_row_hd).selected{background-color:rgba(86,165,50,.12);box-shadow:inset 3px 0 0 #56a532}.ugpfrm .ugp_col_name{font-weight:600;color:#222}.ugpfrm .ugp_empty{padding:1.5rem 1rem;text-align:center;color:#777}.ugpfrm .ugp_err{padding:1rem 2rem;color:#b00020;font-weight:700}