mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-06 03:14:12 +08:00
💋 Sync 2026-10-04 04:16:09
This commit is contained in:
1 parent
f6b2df73ec
commit
f62992fd80
745 files changed
+212416
-1173
No files matched your search
@@ -0,0 +1,326 @@
|
||||
'use strict';
|
||||
|
||||
'require baseclass';
|
||||
'require dom';
|
||||
'require form';
|
||||
'require ui';
|
||||
'require podman.form as podmanForm';
|
||||
'require podman.ui as podmanUI';
|
||||
'require podman.utils as podmanUtil';
|
||||
|
||||
const FormTableSelectSection = form.TableSection.extend({
|
||||
__name__: 'Podman.Form.TableSelectSection',
|
||||
|
||||
checkboxColumn: null,
|
||||
view: null,
|
||||
toolbarExtraButtons: [],
|
||||
modalCreateBtnText: null,
|
||||
modalCreateTitle: null,
|
||||
handleRefreshCb: null,
|
||||
|
||||
render() {
|
||||
if (!this.checkboxColumn) {
|
||||
this.checkboxColumn = this.option(
|
||||
podmanForm.field.SelectDummyValue,
|
||||
this.selectKey,
|
||||
new ui.Checkbox(0, { hiddenname: 'all' }).render()
|
||||
);
|
||||
this.checkboxColumn.width = 30;
|
||||
|
||||
podmanUtil.moveArrayItem(this.children, this.children.length - 1, 0);
|
||||
}
|
||||
|
||||
return this.super('render', []);
|
||||
},
|
||||
|
||||
renderContents(cfgsections, nodes) {
|
||||
const config_name = this.uciconfig ?? this.map.config;
|
||||
const max_cols = this.children.length;
|
||||
|
||||
if (this.footer === true) {
|
||||
this.footer = [
|
||||
`${_('Total')} ${nodes.length}`,
|
||||
];
|
||||
}
|
||||
|
||||
const sectionEl = E('div', {
|
||||
id: 'cbi-%s-%s'.format(config_name, this.sectiontype),
|
||||
class: 'cbi-section cbi-tblsection',
|
||||
});
|
||||
|
||||
const tableEl = E('table', { class: 'table cbi-section-table cbi-section-table-select' });
|
||||
const theadEl = E('thead', { class: 'thead cbi-section-thead' });
|
||||
const tbodyEl = E('tbody', { class: 'tbody cbi-section-tbody' });
|
||||
const tfootEl = E('tfoot', { class: 'tfoot cbi-section-tfoot' });
|
||||
|
||||
if (this.description != null && this.description !== '') {
|
||||
sectionEl.appendChild(E('div', { class: 'cbi-section-descr' }, this.description));
|
||||
}
|
||||
|
||||
sectionEl.appendChild(E('div', { class: 'cbi-section-actions' }, this.renderToolbar()));
|
||||
|
||||
theadEl.appendChild(this.renderHeaderRows(false));
|
||||
|
||||
if (theadEl.hasChildNodes())
|
||||
tableEl.appendChild(theadEl);
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const trEl = E('tr', {
|
||||
id: 'cbi-%s-%s'.format(config_name, cfgsections[i]),
|
||||
class: 'tr cbi-section-table-row',
|
||||
'data-sid': cfgsections[i],
|
||||
'data-section-id': cfgsections[i]
|
||||
});
|
||||
|
||||
for (let j = 0; j < max_cols && nodes[i].firstChild; j++) {
|
||||
trEl.appendChild(nodes[i].firstChild);
|
||||
}
|
||||
|
||||
tbodyEl.appendChild(trEl);
|
||||
}
|
||||
|
||||
if (nodes.length === 0)
|
||||
tbodyEl.appendChild(E('tr', { class: 'tr cbi-section-table-row' },
|
||||
E('td', { class: 'td text-center', colspan: max_cols }, this.renderSectionPlaceholder())));
|
||||
|
||||
tableEl.appendChild(tbodyEl);
|
||||
|
||||
tfootEl.appendChild(this.renderFooterRows(false));
|
||||
|
||||
if (tfootEl.hasChildNodes()) {
|
||||
tableEl.appendChild(tfootEl);
|
||||
}
|
||||
|
||||
this.registerCheckboxEvents(theadEl, tableEl);
|
||||
|
||||
sectionEl.appendChild(tableEl);
|
||||
|
||||
dom.bindClassInstance(sectionEl, this);
|
||||
|
||||
return sectionEl;
|
||||
},
|
||||
|
||||
renderToolbar() {
|
||||
return E('div', { class: 'list-toolbar mb-sm d-flex justify-center gap-xs' }, this.getToolbarButtons());
|
||||
},
|
||||
|
||||
getToolbarButtons() {
|
||||
const buttons = [];
|
||||
|
||||
if (this.handleCreate) {
|
||||
buttons.push(this.getCreateButton());
|
||||
}
|
||||
if (this.handleRemove) {
|
||||
buttons.push(this.getRemoveButton());
|
||||
}
|
||||
|
||||
if (this.handleRefresh) {
|
||||
buttons.push(this.getReloadButton());
|
||||
}
|
||||
|
||||
if (this.toolbarExtraButtons.length > 0) {
|
||||
buttons.push(...this.toolbarExtraButtons);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
},
|
||||
|
||||
getCreateButton() {
|
||||
return new podmanUI.ButtonNew(_('Create'), {
|
||||
click: ui.createHandlerFn(this, 'handleCreate'),
|
||||
type: 'add',
|
||||
}).render();
|
||||
},
|
||||
|
||||
getRemoveButton() {
|
||||
return new podmanUI.ButtonNew(_('Delete'), {
|
||||
click: ui.createHandlerFn(this, 'handleRemove'),
|
||||
type: 'remove',
|
||||
}).render();
|
||||
},
|
||||
|
||||
getReloadButton() {
|
||||
return new podmanUI.ButtonNew(_('Reload'), {
|
||||
click: ui.createHandlerFn(this, 'handleRefresh'),
|
||||
type: 'apply',
|
||||
}).render();
|
||||
},
|
||||
|
||||
async handleCreate() {
|
||||
const createForm = new this.createForm.init();
|
||||
const formElement = await createForm.render();
|
||||
const title = this.modalCreateTitle || _('Create %s').format(this.view.titleSingle || '').trim();
|
||||
|
||||
const modal = new podmanUI.Modal(title, [ formElement ]);
|
||||
modal.getButtons = () => [
|
||||
modal.getCloseButton(),
|
||||
new podmanUI.ButtonNew(this.modalCreateBtnText || _('Create'), {
|
||||
click: () => {
|
||||
createForm.handleCreate().then(() => this.handleRefresh());
|
||||
},
|
||||
type: 'positive',
|
||||
}).render(),
|
||||
];
|
||||
modal.render();
|
||||
},
|
||||
|
||||
async handleRemove() {
|
||||
const selected = this.getSelectedData();
|
||||
|
||||
if (selected.length === 0) {
|
||||
return this.showNoneSelectedWarning();
|
||||
}
|
||||
|
||||
this.view.confirm([
|
||||
E('p', {}, _('Are you sure to delete the records?')),
|
||||
], async () => {
|
||||
let i = 1;
|
||||
for (const item of selected) {
|
||||
this.view.loading(_('Deleting records: %d/%d').format(i, selected.length));
|
||||
|
||||
await item.remove();
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
ui.hideModal();
|
||||
this.handleRefresh();
|
||||
});
|
||||
},
|
||||
|
||||
async handleRefresh() {
|
||||
const indicatorId = 'podman-refresh-' + this.sectiontype;
|
||||
ui.showIndicator(indicatorId, _('Refreshing %s...').format(this.sectiontype));
|
||||
|
||||
const data = await this.view.load();
|
||||
|
||||
if (this.footer) {
|
||||
const count = Array.isArray(data) ? data.length : 0;
|
||||
this.footer = [`${_('Total')} ${count}`];
|
||||
}
|
||||
|
||||
const obj = {};
|
||||
obj[this.sectiontype] = data;
|
||||
|
||||
this.map.data.__init__(obj);
|
||||
|
||||
this.map.root
|
||||
.querySelector('input[type="hidden"][name="all"] ~ input[type=checkbox]').checked = false;
|
||||
|
||||
await this.map.save(null, false);
|
||||
await this.map.load();
|
||||
await this.map.reset();
|
||||
|
||||
if (this.handleRefreshCb) await this.handleRefreshCb();
|
||||
|
||||
ui.hideIndicator(indicatorId);
|
||||
},
|
||||
|
||||
handleInspect(item, hiddenFields) {
|
||||
this.view.loading(_('Fetching information...'));
|
||||
|
||||
item.inspect().then((data) => {
|
||||
ui.hideModal();
|
||||
this.showInspectModal(data, hiddenFields);
|
||||
});
|
||||
},
|
||||
|
||||
showInspectModal(data, hiddenFields) {
|
||||
const displayData = JSON.parse(JSON.stringify(data));
|
||||
|
||||
if (hiddenFields && hiddenFields.length > 0) {
|
||||
hiddenFields.forEach((field) => {
|
||||
if (displayData[field]) {
|
||||
displayData[field] = '***HIDDEN***';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const content = [
|
||||
new podmanUI.JsonArea(displayData).render(),
|
||||
];
|
||||
|
||||
if (hiddenFields && hiddenFields.length > 0) {
|
||||
content.unshift(E('p', { class: 'mb-sm text-error' }, [
|
||||
E('strong', {}, _('Security Notice:')), ' ', _('Sensitive data is hidden for security reasons.')
|
||||
]));
|
||||
}
|
||||
|
||||
const modal = new podmanUI.Modal('', content);
|
||||
modal.handleSubmit = undefined;
|
||||
modal.render();
|
||||
},
|
||||
|
||||
showNoneSelectedWarning() {
|
||||
this.view.warning(_('No %s selected').format(this.sectiontype));
|
||||
},
|
||||
|
||||
registerCheckboxEvents(theadEl, tableEl) {
|
||||
const checkboxSelectAll = theadEl.querySelector('input[name="all"] + input[type="checkbox"]');
|
||||
const rows = tableEl.querySelectorAll('tbody tr');
|
||||
let lastClickedIndex = -1;
|
||||
|
||||
if (!checkboxSelectAll) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkboxSelectAll.addEventListener('click', (event) => {
|
||||
const checked = event.target.checked;
|
||||
tableEl.querySelectorAll('tbody tr input[type="checkbox"]').forEach((checkbox) => {
|
||||
checkbox.checked = checked;
|
||||
});
|
||||
});
|
||||
|
||||
rows.forEach((row, index) => {
|
||||
const checkbox = row.querySelector('input[type=checkbox]');
|
||||
|
||||
if (!checkbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
row.addEventListener('click', (ev) => {
|
||||
const clickedInteractiveElement = ev.target.closest('button, a, input, .cbi-tooltip-container');
|
||||
|
||||
// If the click was inside an interactive element, ignore it and exit.
|
||||
if (clickedInteractiveElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkbox.click();
|
||||
});
|
||||
|
||||
checkbox.addEventListener('click', (ev) => {
|
||||
// Handle shift+click for range selection
|
||||
if (ev.shiftKey && lastClickedIndex !== -1 &&
|
||||
lastClickedIndex !== index) {
|
||||
const start = Math.min(lastClickedIndex, index);
|
||||
const end = Math.max(lastClickedIndex, index);
|
||||
const targetState = checkbox.checked;
|
||||
|
||||
// Select/deselect all checkboxes in range
|
||||
for (let i = start; i <= end; i++) {
|
||||
rows[i].querySelector('input[type=checkbox]').checked = targetState;
|
||||
}
|
||||
}
|
||||
|
||||
// Update last clicked index
|
||||
lastClickedIndex = index;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getSelectedCheckboxes() {
|
||||
return this.map.root.querySelectorAll('tbody tr input[type=checkbox]:checked');
|
||||
},
|
||||
|
||||
getSelectedData() {
|
||||
return [...this.getSelectedCheckboxes()].map((checkbox) => {
|
||||
const sectionId = checkbox.previousSibling.name;
|
||||
return this.map.data.data[sectionId];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return baseclass.extend({
|
||||
TableSelectSection: FormTableSelectSection
|
||||
});
|
||||
Reference in new issue
Block a user