mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 21:13:00 +08:00
242 lines
7.8 KiB
JavaScript
242 lines
7.8 KiB
JavaScript
// SPDX-License-Identifier: MIT
|
|
'use strict';
|
|
/* global feedback */
|
|
'require device-manager.feedback as feedback';
|
|
'require baseclass';
|
|
'require ui';
|
|
'require device-manager.model as model';
|
|
|
|
return baseclass.extend({
|
|
showGroupModal: function() {
|
|
if (this.readonly) return;
|
|
const self = this;
|
|
|
|
// Calculate count of devices per group
|
|
const groupCounts = new Map();
|
|
for (let i = 0; i < this.devices.length; i++) {
|
|
const g = this.devices[i].group;
|
|
if (g && g !== 'ungrouped') {
|
|
groupCounts.set(g, (groupCounts.get(g) || 0) + 1);
|
|
}
|
|
}
|
|
|
|
const groupRows = this.groups.map(function(g) {
|
|
const count = groupCounts.get(g.id) || 0;
|
|
|
|
const btnRename = E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button cbi-button-neutral',
|
|
'style': 'margin-right:6px;',
|
|
'click': function() { self.promptRenameGroup(g); }
|
|
}, [ _('Rename') ]);
|
|
|
|
const btnDelete = E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button cbi-button-remove',
|
|
'click': function() { self.confirmDeleteGroup(g, count); }
|
|
}, [ _('Delete') ]);
|
|
|
|
return E('tr', { 'class': 'tr' }, [
|
|
E('td', { 'class': 'td', 'style': 'font-weight:bold;' }, [ g.name ]),
|
|
E('td', { 'class': 'td' }, E('code', {}, [ g.id ])),
|
|
E('td', { 'class': 'td' }, [ _('%d devices').format(count) ]),
|
|
E('td', { 'class': 'td', 'style': 'text-align:right;' }, [ btnRename, btnDelete ])
|
|
]);
|
|
});
|
|
|
|
const newGroupInput = E('input', {
|
|
'type': 'text',
|
|
'class': 'cbi-input-text',
|
|
'placeholder': _('e.g. Media devices, office devices'),
|
|
'maxlength': 32,
|
|
'style': 'width:240px; margin-right:8px;'
|
|
});
|
|
|
|
const errorDiv = E('div', {
|
|
'class': 'alert-message danger',
|
|
'style': 'display:none; margin-bottom:12px;'
|
|
});
|
|
|
|
const btnAddGroup = E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button cbi-button-positive',
|
|
'click': function(ev) {
|
|
const button = ev.currentTarget;
|
|
const name = model.sanitizeInput(newGroupInput.value);
|
|
if (!name) {
|
|
errorDiv.textContent = _('Enter a valid group name');
|
|
errorDiv.style.display = 'block';
|
|
newGroupInput.focus();
|
|
return;
|
|
}
|
|
|
|
// Check duplicate name
|
|
if (self.groups.some(g => g.name === name)) {
|
|
errorDiv.textContent = _('A group with this name already exists');
|
|
errorDiv.style.display = 'block';
|
|
newGroupInput.focus();
|
|
return;
|
|
}
|
|
|
|
button.classList.add('spinning');
|
|
button.disabled = true;
|
|
|
|
return self.handleAddGroup(name)
|
|
.then(function() {
|
|
ui.hideModal();
|
|
ui.addNotification(null, E('p', [ _('Group "%s" created.').format(name) ]), 'info');
|
|
return self.refresh().then(function() {
|
|
self.showGroupModal();
|
|
});
|
|
})
|
|
.catch(function(err) {
|
|
errorDiv.textContent = _('Could not create group: %s').format(err.message || err);
|
|
errorDiv.style.display = 'block';
|
|
})
|
|
.finally(function() {
|
|
button.classList.remove('spinning');
|
|
button.disabled = false;
|
|
});
|
|
}
|
|
}, [ _('Add group') ]);
|
|
|
|
ui.showModal(_('Device groups'), [
|
|
E('div', { 'class': 'cbi-section' }, [
|
|
errorDiv,
|
|
E('table', { 'class': 'table', 'style': 'width:100%; margin-bottom:20px;' }, [
|
|
E('tr', { 'class': 'tr table-titles' }, [
|
|
E('th', { 'class': 'th' }, [ _('Group name') ]),
|
|
E('th', { 'class': 'th' }, [ _('Group ID') ]),
|
|
E('th', { 'class': 'th' }, [ _('Device count') ]),
|
|
E('th', { 'class': 'th', 'style': 'text-align:right;' }, [ _('Actions') ])
|
|
]),
|
|
E('tbody', {}, groupRows)
|
|
]),
|
|
E('div', { 'class': 'cbi-value', 'style': 'padding-top:10px; border-top:1px solid #eee;' }, [
|
|
E('label', { 'class': 'cbi-value-title' }, [ _('New group') ]),
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
newGroupInput,
|
|
btnAddGroup,
|
|
E('div', { 'class': 'cbi-value-description' }, [ _('Group names support Unicode text and common symbols') ])
|
|
])
|
|
])
|
|
]),
|
|
E('div', { 'class': 'button-row', 'style': 'margin-top:20px; text-align:right;' }, [
|
|
E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button',
|
|
'click': ui.hideModal
|
|
}, [ _('Close') ])
|
|
])
|
|
]);
|
|
},
|
|
|
|
promptRenameGroup: function(group) {
|
|
if (this.readonly) return;
|
|
const self = this;
|
|
const nameInput = E('input', {
|
|
'type': 'text',
|
|
'class': 'cbi-input-text',
|
|
'value': group.name,
|
|
'maxlength': 32,
|
|
'style': 'width:100%;'
|
|
});
|
|
|
|
const errorDiv = E('div', {
|
|
'class': 'alert-message danger',
|
|
'style': 'display:none; margin-bottom:12px;'
|
|
});
|
|
|
|
ui.showModal(_('Rename group'), [
|
|
E('div', { 'class': 'cbi-section' }, [
|
|
errorDiv,
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
E('label', { 'class': 'cbi-value-title' }, [ _('Current group name') ]),
|
|
E('div', { 'class': 'cbi-value-field', 'style': 'padding-top:6px;' }, [ group.name ])
|
|
]),
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
E('label', { 'class': 'cbi-value-title' }, [ _('New group name') ]),
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
nameInput,
|
|
E('div', { 'class': 'cbi-value-description' }, [ _('Renaming preserves the group ID and all device assignments') ])
|
|
])
|
|
])
|
|
]),
|
|
E('div', { 'class': 'button-row', 'style': 'margin-top:20px; text-align:right;' }, [
|
|
E('button', { 'type': 'button', 'class': 'btn cbi-button', 'click': function() { self.showGroupModal(); } }, [ _('Cancel') ]),
|
|
' ',
|
|
E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button cbi-button-positive',
|
|
'click': function(ev) {
|
|
const button = ev.currentTarget;
|
|
const newName = model.sanitizeInput(nameInput.value);
|
|
if (!newName) {
|
|
errorDiv.textContent = _('Enter a valid group name');
|
|
errorDiv.style.display = 'block';
|
|
nameInput.focus();
|
|
return;
|
|
}
|
|
|
|
if (newName === group.name) {
|
|
self.showGroupModal();
|
|
return;
|
|
}
|
|
|
|
button.classList.add('spinning');
|
|
button.disabled = true;
|
|
|
|
return self.handleRenameGroup(group.id, newName)
|
|
.then(function() {
|
|
ui.addNotification(null, E('p', [ _('Group renamed to "%s".').format(newName) ]), 'info');
|
|
return self.refresh().then(function() {
|
|
self.showGroupModal();
|
|
});
|
|
})
|
|
.catch(function(err) {
|
|
errorDiv.textContent = _('Rename failed: %s').format(err.message || err);
|
|
errorDiv.style.display = 'block';
|
|
})
|
|
.finally(function() {
|
|
button.classList.remove('spinning');
|
|
button.disabled = false;
|
|
});
|
|
}
|
|
}, [ _('Save changes') ])
|
|
])
|
|
]);
|
|
},
|
|
|
|
confirmDeleteGroup: function(group, deviceCount) {
|
|
if (this.readonly) return;
|
|
const self = this;
|
|
|
|
ui.showModal(_('Delete group'), [
|
|
E('p', {}, [ _('Delete group "%s"?').format(group.name) ]),
|
|
E('p', { 'class': 'cbi-value-description' }, [ _('The %d devices in this group will become ungrouped. Their names, MAC addresses and remarks will be preserved.').format(deviceCount) ]),
|
|
E('div', { 'class': 'button-row', 'style': 'margin-top:20px; text-align:right;' }, [
|
|
E('button', { 'type': 'button', 'class': 'btn cbi-button', 'click': function() { self.showGroupModal(); } }, [ _('Cancel') ]),
|
|
' ',
|
|
E('button', { 'type': 'button',
|
|
'class': 'btn cbi-button cbi-button-remove',
|
|
'click': function(ev) {
|
|
const button = ev.currentTarget;
|
|
button.classList.add('spinning');
|
|
button.disabled = true;
|
|
|
|
return self.handleDeleteGroup(group.id)
|
|
.then(function() {
|
|
ui.addNotification(null, E('p', [ _('Group "%s" deleted. Its devices are now ungrouped.').format(group.name) ]), 'info');
|
|
return self.refresh().then(function() {
|
|
self.showGroupModal();
|
|
});
|
|
})
|
|
.catch(function(err) {
|
|
ui.hideModal();
|
|
feedback.notify(_('Could not delete group: %s').format(err.message || err), 'danger');
|
|
}).finally(function() {
|
|
button.classList.remove('spinning');
|
|
button.disabled = false;
|
|
});
|
|
}
|
|
}, [ _('Confirm delete') ])
|
|
])
|
|
]);
|
|
}
|
|
});
|