Playwright Tests / test (push) Canceled after 0s
serializeObject() returns null for an invalid form, but most callers sent
the result anyway. Add $.fn.rejectInvalid (stop the spinner, let the
browser report the offending field) and use it at every call site.
Bugs fixed:
- Password change: on a mismatch the spinner kept running, and the custom
validity on "npw" was never cleared, so the browser blocked every later
submit even after the passwords matched. It is now cleared as soon as
either password field is edited.
- sendForm: options.complete referenced an undefined jqXHR (ReferenceError)
and an invalid form was posted with partial data.
- login.send: an invalid form threw a TypeError on qs.loginaccount.
- postXT({ form }): an invalid form was posted with empty data.
- Form dialogs without required fields had no "Bitte überprüfen Sie Ihre
Eingaben" note, so a rejected submit showed nothing.
Hardening: null guards for the user, user-group, re-login, SMS password,
admin specialties and report-parameter submits.
Add e2e_tests/form-validation.cjs covering each path against the real
scripts; it fails on the previous code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
130 lines
5.3 KiB
JavaScript
130 lines
5.3 KiB
JavaScript
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 });
|
|
if (qs === null) { c.rejectInvalid(); return; }
|
|
$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 });
|
|
if (qs === null) { c.rejectInvalid(); return; }
|
|
$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;
|