mirror of
https://github.com/techgarage-ir/MTWireGuard.git
synced 2025-08-30 14:49:31 +02:00
Use new front-end based on Dashmin template
This commit is contained in:
parent
c118242c5b
commit
dbd7fafb34
4391 changed files with 228401 additions and 73494 deletions
628
UI/wwwroot/js/page-users.js
Normal file
628
UI/wwwroot/js/page-users.js
Normal file
|
@ -0,0 +1,628 @@
|
|||
const assetsPath = "../assets/";
|
||||
const api = new APIClient();
|
||||
const toastContainer = $('.toast-container');
|
||||
const onlineUsers = new Set();
|
||||
|
||||
let renderTableCell = (function () {
|
||||
function renderTitle(title) {
|
||||
return title
|
||||
.replace('_', ' ')
|
||||
.split(" ")
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
function renderSwitch(data, disable=false) {
|
||||
let enabled = data == true;
|
||||
let active = enabled ? ' active' : '';
|
||||
let disabled = disable ? 'disabled' : '';
|
||||
return ' <button type="button" class="btn btn-sm btn-toggle item-activation' + active + '" data-bs-toggle="button" aria-pressed="' + enabled + '" autocomplete="off"' + disabled + '>' +
|
||||
' <div class="handle"></div>' +
|
||||
' </button>';
|
||||
}
|
||||
|
||||
function renderName(full) {
|
||||
var $name = full['name'],
|
||||
$lastSeen = full['lastHandshake'].replace('T', ' ')
|
||||
$userId = full['id'];
|
||||
|
||||
// Avatar badge
|
||||
var stateNum = Math.floor(Math.random() * 6);
|
||||
var states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary'];
|
||||
var $state = states[stateNum],
|
||||
$name = full['name'],
|
||||
$initials = ($name || '').match(/\b\w/g)?.join('').toUpperCase() || '';
|
||||
let online = 'offline';
|
||||
// online check
|
||||
if ($lastSeen.length == 8) {
|
||||
const time = new Date(`2000-01-01T${$lastSeen}`);
|
||||
const comparison = new Date(`2000-01-01T00:03:00`);
|
||||
if (time < comparison) {
|
||||
online = 'online';
|
||||
onlineUsers.add($userId);
|
||||
};
|
||||
}
|
||||
// end online check
|
||||
let $output = '<div class="position-relative badge rounded-circle h-100 w-100 d-flex justify-content-center align-items-center bg-' + $state + '">' + $initials + '</div>';
|
||||
|
||||
// Creates full output for row
|
||||
var $row_output =
|
||||
'<div class="d-flex justify-content-start align-items-center">' +
|
||||
'<div class="avatar-wrapper">' +
|
||||
'<div class="avatar avatar-' + online + ' me-2">' +
|
||||
$output +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="d-flex flex-column">' +
|
||||
'<span class="emp_name text-truncate">' +
|
||||
$name +
|
||||
'</span>' +
|
||||
'<small class="emp_post text-truncate text-muted ms-1">' +
|
||||
$lastSeen +
|
||||
'</small>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
return $row_output;
|
||||
}
|
||||
|
||||
function renderTraffic(full) {
|
||||
let used = convertByteSize(full['trafficUsed']);
|
||||
let total = full['traffic'] == 0 ? '∞' : `${full['traffic']}GB`;
|
||||
let output = `${used} / ${total}`;
|
||||
return '<span class="badge text-bg-success">' + output + '</span>';
|
||||
}
|
||||
|
||||
function renderExpire(data) {
|
||||
return '<span class="badge text-bg-warning text-uppercase">' + (data.toLowerCase() != 'unlimited' ? data.replace('T', ' ').slice(0, -3) : data) + '</span>';
|
||||
}
|
||||
|
||||
return {
|
||||
renderTitle,
|
||||
renderName,
|
||||
renderSwitch,
|
||||
renderTraffic,
|
||||
renderExpire
|
||||
}
|
||||
})();
|
||||
|
||||
$(function() {
|
||||
'use strict';
|
||||
|
||||
var dt_basic_table = $('.datatables-basic');
|
||||
|
||||
// DataTable with buttons
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
if (dt_basic_table.length) {
|
||||
try {
|
||||
var dt_basic = dt_basic_table.DataTable({
|
||||
ajax: function(data, callback, settings) {
|
||||
settings.sAjaxDataProp = '';
|
||||
api.users.getAll()
|
||||
.then(function(response) {
|
||||
callback(response);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error(error);
|
||||
callback([]);
|
||||
});
|
||||
},
|
||||
columns: [
|
||||
{ data: '' },
|
||||
{ data: 'isEnabled' },
|
||||
{ data: 'name' },
|
||||
{ data: 'interface' },
|
||||
{ data: 'address'},
|
||||
{ data: 'traffic' },
|
||||
{ data: 'expire' },
|
||||
{ data: 'isDifferent' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
targets: 0,
|
||||
className: 'dtr-control',
|
||||
orderable: false,
|
||||
responsivePriority: 2,
|
||||
searchable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
// Enablity Switch
|
||||
targets: 1,
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
return renderTableCell.renderSwitch(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Name and Online status
|
||||
targets: 2,
|
||||
responsivePriority: 1,
|
||||
render: function(data, type, full, meta) {
|
||||
return renderTableCell.renderName(full);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Interface
|
||||
responsivePriority: 4,
|
||||
targets: 3
|
||||
},
|
||||
{
|
||||
// Allowed Address
|
||||
responsivePriority: 3,
|
||||
targets: 4
|
||||
},
|
||||
{
|
||||
// Traffic
|
||||
targets: 5,
|
||||
render: function(data, type, full, meta) {
|
||||
return renderTableCell.renderTraffic(full);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Expire
|
||||
targets: 6,
|
||||
render: function(data, type, full, meta) {
|
||||
return renderTableCell.renderExpire(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1, // Last
|
||||
title: 'Actions',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
className: 'action-buttons',
|
||||
render: function(data, type, full, meta) {
|
||||
let dlBtns = data ? '<a href="javascript:;" class="btn text-primary btn-icon item-sync" data-bs-toggle="offcanvas" data-bs-target="#offcanvasSyncUser"><i class="bx bx-sync"></i></a>' :
|
||||
'<a href="javascript:;" class="btn text-primary btn-icon item-qr" data-bs-toggle="modal" data-bs-target="#QRModal"><i class="bx bx-qr"></i></a>' +
|
||||
'<a href="javascript:;" class="btn text-primary btn-icon item-download"><i class="bx bxs-download"></i></a>';
|
||||
return (
|
||||
'<a href="javascript:;" class="btn text-primary btn-icon item-edit" data-bs-toggle="offcanvas" data-bs-target="#offcanvasEditUser"><i class="bx bxs-edit"></i></a>' +
|
||||
dlBtns +
|
||||
'<div class="d-inline-block">' +
|
||||
'<a href="javascript:;" class="btn text-primary btn-icon dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="bx bx-dots-vertical-rounded"></i></a>' +
|
||||
'<ul class="dropdown-menu dropdown-menu-end">' +
|
||||
'<li><a href="javascript:;" class="dropdown-item item-details">Details</a></li>' +
|
||||
'<div class="dropdown-divider"></div>' +
|
||||
'<li><a href="javascript:;" class="dropdown-item text-danger item-delete" data-bs-toggle="modal" data-bs-target="#RemoveModal">Delete</a></li>' +
|
||||
'</ul>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[2, 'desc']],
|
||||
dom: '<"card-header"<"dt-action-buttons text-end"B>><"d-flex justify-content-between align-items-center row"<"col-sm-12 col-md-6"l><"col-sm-12 col-md-6"f>>t<"d-flex justify-content-between row"<"col-sm-12 col-md-6"i><"col-sm-12 col-md-6"p>>',
|
||||
displayLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50, 75, 100],
|
||||
buttons: {
|
||||
dom: {
|
||||
button: {
|
||||
tag: 'button',
|
||||
className: 'btn'
|
||||
}
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
extend: 'collection',
|
||||
className: 'btn-primary dropdown-toggle me-2',
|
||||
text: '<i class="bx bx-show me-1"></i>Export',
|
||||
buttons: [
|
||||
{
|
||||
extend: 'copy',
|
||||
text: '<i class="bx bx-copy me-1"></i>Copy',
|
||||
className: 'dropdown-item'
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
text: '<i class="bx bx-file me-1"></i>CSV',
|
||||
className: 'dropdown-item'
|
||||
},
|
||||
{
|
||||
text: '<i class="bx bxs-file-json me-1"></i>JSON',
|
||||
className: 'dropdown-item',
|
||||
action: function ( e, dt, button, config ) {
|
||||
//let data = dt.buttons.exportData();
|
||||
let array = [];
|
||||
let data = dt.rows().data();
|
||||
$.each(data, function(i) {
|
||||
array.push(data[i]);
|
||||
});
|
||||
|
||||
$.fn.dataTable.fileSave(
|
||||
new Blob([JSON.stringify(array, null, 2)]),
|
||||
'wg-peers.json'
|
||||
);
|
||||
}
|
||||
}/*,
|
||||
{
|
||||
text: '<i class="bx bx-hdd me-1"></i>Backup',
|
||||
className: 'dropdown-item'
|
||||
}*/
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '<i class="bx bx-plus me-1"></i> <span class="d-none d-lg-inline-block">Add New User</span>',
|
||||
className: 'btn-success create-new',
|
||||
attr: {
|
||||
"data-bs-toggle": "offcanvas",
|
||||
"data-bs-target": "#offcanvasAddUser"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function(row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function(api, rowIdx, columns) {
|
||||
var data = $.map(columns, function(col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
let output = data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
},
|
||||
language: {
|
||||
"emptyTable": "No users found"
|
||||
},
|
||||
initComplete: function(settings, json) {
|
||||
const result = Object.values(json).reduce(
|
||||
(acc, currentItem) => {
|
||||
acc.totalItems++;
|
||||
if (currentItem.isEnabled) {
|
||||
acc.enabledItems++;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ totalItems: 0, enabledItems: 0 }
|
||||
);
|
||||
const totalItems = result.totalItems;
|
||||
const enabledItems = result.enabledItems;
|
||||
$('#users-total').text(totalItems);
|
||||
$('#users-active').text(enabledItems);
|
||||
$('#users-online').text(onlineUsers.size);
|
||||
|
||||
dt_basic.on('click', 'a.item-details', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr)
|
||||
let rowData = row.data();
|
||||
var data = $.map(rowData, function(value, key) {
|
||||
if (key !== '') // ? Do not show row in modal popup if title is blank (for check box)
|
||||
{
|
||||
let tdValue = '';
|
||||
switch (key) {
|
||||
case 'enabled':
|
||||
tdValue = renderTableCell.renderSwitch(value, true);
|
||||
break;
|
||||
case 'name':
|
||||
tdValue = renderTableCell.renderName(rowData);
|
||||
break;
|
||||
case 'traffic':
|
||||
tdValue = renderTableCell.renderTraffic(rowData);
|
||||
break;
|
||||
case 'expire':
|
||||
tdValue = renderTableCell.renderExpire(value);
|
||||
break;
|
||||
default:
|
||||
tdValue = value;
|
||||
break;
|
||||
}
|
||||
return '<tr>' +
|
||||
'<th>' +
|
||||
renderTableCell.renderTitle(key) +
|
||||
'</th> ' +
|
||||
'<td><div class="text-truncate" style="width: 35ch;">' +
|
||||
tdValue +
|
||||
'</div></td>' +
|
||||
'</tr>'
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}).join('');
|
||||
|
||||
|
||||
let body = data ? $('<table class="table m-0"/><tbody />').append(data) : false;
|
||||
$('#DetailsModal .modal-body').html(body);
|
||||
$('#DetailsModal .modal-title').html('Details of ' + row.data()["name"].toUpperCase());
|
||||
const detailsModal = new bootstrap.Modal('#DetailsModal');
|
||||
detailsModal.show();
|
||||
});
|
||||
dt_basic.on('click', 'a.item-qr', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr);
|
||||
let rowData = row.data();
|
||||
let id = rowData['id'];
|
||||
let username = rowData['name'];
|
||||
$('#QRModalLabel').text(username + "'s QR");
|
||||
api.users.qr(id).then((qrData) => {
|
||||
console.log(qrData);
|
||||
$('#qr-src').attr('src', `data:image/png;base64,${qrData}`);
|
||||
});
|
||||
});
|
||||
dt_basic.on('click', 'a.item-download', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr);
|
||||
let rowData = row.data();
|
||||
let id = rowData['id'];
|
||||
console.log(`DL: ${id}`);
|
||||
api.users.download(id).then((dlLink) => {
|
||||
console.log(dlLink);
|
||||
window.location = dlLink;
|
||||
});
|
||||
});
|
||||
dt_basic.on('click', 'a.item-edit', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr)
|
||||
let rowData = row.data();
|
||||
|
||||
$.map(rowData, function(value, key) {
|
||||
key = key.replace('_', '-');
|
||||
let field = $('#offcanvasEditUser #edit-' + key);
|
||||
if (field) {
|
||||
switch (key) {
|
||||
case 'name':
|
||||
$('#edit-username').val(value);
|
||||
break;
|
||||
case 'address':
|
||||
$('#edit-allowed-address').val(value.replace('/32', ''));
|
||||
break;
|
||||
case 'publicKey':
|
||||
case 'privateKey':
|
||||
case 'presharedKey':
|
||||
field.val('');
|
||||
break;
|
||||
case 'expire':
|
||||
if (value != 'Unlimited')
|
||||
$("#edit-expire").flatpickr({
|
||||
enableTime: true,
|
||||
altInput: true,
|
||||
altFormat: "Y-m-d H:i",
|
||||
dateFormat: "Z",
|
||||
defaultDate: value.replace('T', ' ').slice(0, -3)
|
||||
});
|
||||
else {
|
||||
$("#edit-expire").flatpickr({
|
||||
enableTime: true,
|
||||
altInput: true,
|
||||
altFormat: "Y-m-d H:i",
|
||||
dateFormat: "Z"
|
||||
}).clear();
|
||||
}
|
||||
break;
|
||||
case 'traffic':
|
||||
if (value == 0)
|
||||
field.val(value);
|
||||
else
|
||||
field.val(value);
|
||||
break;
|
||||
default:
|
||||
field.val(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
dt_basic.on('click', 'a.item-sync', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr)
|
||||
let rowData = row.data();
|
||||
|
||||
$.map(rowData, function(value, key) {
|
||||
key = key.replace('_', '-');
|
||||
let field = $('#offcanvasSyncUser #sync-' + key);
|
||||
if (field) {
|
||||
switch (key) {
|
||||
case 'name':
|
||||
$('#sync-username').val(value);
|
||||
break;
|
||||
case 'publicKey':
|
||||
$('#sync-private-key').val(value);
|
||||
break;
|
||||
case 'privateKey':
|
||||
$('#sync-public-key').val(value);
|
||||
break;
|
||||
default:
|
||||
console.log(`${key} => ${value}`);
|
||||
field.val(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
dt_basic.on('click', 'a.item-delete', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr)
|
||||
let rowData = row.data();
|
||||
let userId = rowData['id'];
|
||||
$('#removeForm input[name="ID"]').val(userId);
|
||||
});
|
||||
dt_basic.on('click', 'button.item-activation', function (e) {
|
||||
let tr = e.target.closest('tr');
|
||||
let row = dt_basic.row(tr)
|
||||
let rowData = row.data();
|
||||
let userId = rowData['id'];
|
||||
let enabled = rowData['isEnabled'];
|
||||
console.log(`${userId}: ${enabled}`);
|
||||
api.users.activate(userId, {enabled: enabled}).then(data => {
|
||||
const toastMSG = new toastMessage("Activate User", data.body, data.title, data.background);
|
||||
const toastElement = toastMSG.getElement();
|
||||
toastContainer.append(toastElement);
|
||||
bootstrap.Toast.getOrCreateInstance(toastElement).show();
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
}).finally(() => {
|
||||
dt_basic.ajax.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
alert(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Load interface options
|
||||
api.servers.getAll().then((servers) => {
|
||||
$.each(servers, function(index) {
|
||||
let server = servers[index];
|
||||
$('#add-interface').append('<option value="' + server.name + '">' + server.name + '</option>');
|
||||
$('#edit-interface').append('<option value="' + server.name + '">' + server.name + '</option>');
|
||||
});
|
||||
});
|
||||
|
||||
// Toggle dynamic inputs
|
||||
toggleDynamicInput($('#add-dns-dynamic'), $('#add-dns-server'));
|
||||
toggleDynamicInput($('#edit-dns-dynamic'), $('#edit-dns-address'));
|
||||
toggleDynamicInput($('#add-ip-dynamic'), $('#add-allowed-address'));
|
||||
toggleDynamicInput($('#edit-ip-dynamic'), $('#edit-allowed-address'));
|
||||
|
||||
// FormValidation
|
||||
|
||||
// Add user form field types
|
||||
$('#add-expire').flatpickr({
|
||||
enableTime: true,
|
||||
altInput: true,
|
||||
altFormat: "Y-m-d H:i",
|
||||
dateFormat: "Z"
|
||||
});
|
||||
|
||||
// Add user form
|
||||
$('#addUserForm').on('submit', e => {
|
||||
let form = $(e.target);
|
||||
let data = new FormData(e.target);
|
||||
api.users.create({
|
||||
name: data.get('Username'),
|
||||
password: data.get('Password'),
|
||||
interface: data.get('Interface'),
|
||||
privateKey: data.get('PrivateKey'),
|
||||
publicKey: data.get('PublicKey'),
|
||||
presharedKey: data.get('PresharedKey'),
|
||||
inheritIP: data.get('InheritIP') == 'on',
|
||||
allowedAddress: data.get('AllowedAddress'),
|
||||
endpointAddress: data.get('Endpoint'),
|
||||
endpointPort: data.get('EndpointPort') || null,
|
||||
keepalive: data.get('KeepAlive') || null,
|
||||
inheritDNS: data.get('InheritDNS') == 'on',
|
||||
dnsAddress: data.get('DNSAddress'),
|
||||
expire: data.get('Expire'),
|
||||
traffic: data.get('Traffic'),
|
||||
enabled: form.find('button.btn-toggle').attr('aria-pressed') == 'true'
|
||||
}).then(data => {
|
||||
const toastMSG = new toastMessage("Create User", data.body, data.title, data.background);
|
||||
const toastElement = toastMSG.getElement();
|
||||
toastContainer.append(toastElement);
|
||||
bootstrap.Toast.getOrCreateInstance(toastElement).show();
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
}).finally(() => {
|
||||
dt_basic.ajax.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// Edit user form
|
||||
$('#editUserForm').on('submit', e => {
|
||||
let form = $(e.target);
|
||||
let data = new FormData(e.target);
|
||||
api.users.update(data.get('ID'), {
|
||||
name: data.get('Username') || null,
|
||||
password: data.get('Password') || null,
|
||||
interface: data.get('Interface'),
|
||||
privateKey: data.get('PrivateKey') || null,
|
||||
publicKey: data.get('PublicKey') || null,
|
||||
presharedKey: data.get('PresharedKey') || null,
|
||||
inheritIP: data.get('InheritIP') == 'on',
|
||||
allowedAddress: data.get('AllowedAddress') || null,
|
||||
endpointAddress: data.get('Endpoint') || null,
|
||||
endpointPort: data.get('EndpointPort') || null,
|
||||
keepalive: data.get('KeepAlive') || null,
|
||||
inheritDNS: data.get('InheritDNS') == 'on',
|
||||
dnsAddress: data.get('DNSAddress') || null,
|
||||
expire: data.get('Expire') || null,
|
||||
traffic: data.get('Traffic') || null,
|
||||
enabled: form.find('button.btn-toggle').attr('aria-pressed') == 'true'
|
||||
}).then(data => {
|
||||
const toastMSG = new toastMessage("Update User", data.body, data.title, data.background);
|
||||
const toastElement = toastMSG.getElement();
|
||||
toastContainer.append(toastElement);
|
||||
bootstrap.Toast.getOrCreateInstance(toastElement).show();
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
}).finally(() => {
|
||||
dt_basic.ajax.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// Sync user form
|
||||
$('#syncUserForm').on('submit', e => {
|
||||
let data = new FormData(e.target);
|
||||
api.users.sync(data.get('ID'), {
|
||||
name: data.get('Username') || null,
|
||||
password: data.get('Password') || null,
|
||||
privateKey: data.get('PrivateKey') || null,
|
||||
publicKey: data.get('PublicKey') || null
|
||||
}).then(data => {
|
||||
const toastMSG = new toastMessage("Sync User", data.body, data.title, data.background);
|
||||
const toastElement = toastMSG.getElement();
|
||||
toastContainer.append(toastElement);
|
||||
bootstrap.Toast.getOrCreateInstance(toastElement).show();
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
}).finally(() => {
|
||||
dt_basic.ajax.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// Delete user form
|
||||
$('#removeForm').on('submit', e => {
|
||||
let data = new FormData(e.target);
|
||||
api.users.delete(data.get('ID')).then(data => {
|
||||
const toastMSG = new toastMessage("Delete User", data.body, data.title, data.background);
|
||||
const toastElement = toastMSG.getElement();
|
||||
toastContainer.append(toastElement);
|
||||
bootstrap.Toast.getOrCreateInstance(toastElement).show();
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
return;
|
||||
}).finally(() => {
|
||||
dt_basic.ajax.reload();
|
||||
new bootstrap.Modal('#RemoveModal').hide();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function toggleDynamicInput(checkbox, element) {
|
||||
checkbox.on('change', function() {
|
||||
element.prop('disabled', checkbox.is(':checked'));
|
||||
});
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue