mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
388 lines
8.2 KiB
JavaScript
388 lines
8.2 KiB
JavaScript
'use strict';
|
|
|
|
'require baseclass';
|
|
'require view';
|
|
'require form';
|
|
'require dom';
|
|
'require ui';
|
|
|
|
'require podman.ui as podmanUI';
|
|
'require podman.constants as constant';
|
|
|
|
const ViewDefault = {
|
|
scrollToTop() {
|
|
document.body.scrollTop = 0;
|
|
document.documentElement.scrollTop = 0;
|
|
},
|
|
|
|
loading(text) {
|
|
this.scrollToTop();
|
|
podmanUI.showSpinningModal(null, text || _('Loading...'));
|
|
},
|
|
|
|
confirm(content, onConfirm) {
|
|
const modal = new podmanUI.Modal(_('Confirm'), content, [ 'confirm-modal' ]);
|
|
modal.getCloseButton = () => new podmanUI.ButtonNew(_('Cancel'), {
|
|
click: () => ui.hideModal(),
|
|
type: 'negative',
|
|
}).render();
|
|
modal.handleSubmit = onConfirm;
|
|
modal.render();
|
|
},
|
|
|
|
error(message) {
|
|
this.scrollToTop();
|
|
ui.hideModal();
|
|
podmanUI.alert(message, 'error');
|
|
},
|
|
|
|
warning(message) {
|
|
this.scrollToTop();
|
|
ui.hideModal();
|
|
podmanUI.alert(message, 'warning', true);
|
|
},
|
|
|
|
success(message) {
|
|
this.scrollToTop();
|
|
ui.hideModal();
|
|
podmanUI.alert(message, 'success', true);
|
|
},
|
|
};
|
|
|
|
const ViewBase = view.extend({
|
|
...ViewDefault,
|
|
__name__: 'PodmanView.Base',
|
|
|
|
handleSaveApply: null,
|
|
handleSave: null,
|
|
handleReset: null,
|
|
|
|
__init__() {
|
|
document.querySelector('head').appendChild(E('link', {
|
|
rel: 'stylesheet',
|
|
type: 'text/css',
|
|
href: L.resource('view/podman/podman.css'),
|
|
}));
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Escape') ui.hideModal();
|
|
});
|
|
|
|
this.super('__init__', []);
|
|
},
|
|
});
|
|
|
|
const ViewList = ViewBase.extend({
|
|
__name__: 'Podman.View.List',
|
|
|
|
map: null,
|
|
section: null,
|
|
title: '',
|
|
sectionName: '',
|
|
sectionHeadline: '',
|
|
TableSelectSection: null,
|
|
|
|
async render(data) {
|
|
const listData = {};
|
|
listData[this.sectionName] = data;
|
|
|
|
await this.initSection(listData);
|
|
await this.updateSection();
|
|
|
|
return this.transformMap(await this.map.render());
|
|
},
|
|
|
|
transformMap(map) {
|
|
return map;
|
|
},
|
|
|
|
initTableSelectSection(data) {
|
|
this.map = new form.JSONMap(data, this.title);
|
|
|
|
this.section = this.map.section(
|
|
this.TableSelectSection,
|
|
this.sectionName,
|
|
'',
|
|
this.sectionHeadline || _('Manage podman %s').format(this.title.toLowerCase())
|
|
);
|
|
this.section.view = this;
|
|
this.section.anonymous = true;
|
|
this.section.footer = true;
|
|
|
|
return this.section;
|
|
},
|
|
|
|
async initSection(data) {
|
|
if (!this.TableSelectSection) {
|
|
// Require on-the-fly to avoid circular dependency
|
|
const mod = await L.require('podman.TableSelectSection');
|
|
this.TableSelectSection = mod.TableSelectSection;
|
|
}
|
|
return this.initTableSelectSection(data);
|
|
},
|
|
|
|
getSection() {
|
|
return this.section;
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Form View
|
|
*/
|
|
const ViewForm = baseclass.extend({
|
|
...ViewDefault,
|
|
__name__: 'Podman.View.Form',
|
|
|
|
map: null,
|
|
section: null,
|
|
|
|
__init__() {
|
|
|
|
},
|
|
|
|
makeData() {
|
|
return {};
|
|
},
|
|
|
|
async render() {
|
|
const data = this.makeData();
|
|
const sectionName = Object.keys(data)[0];
|
|
this.map = new form.JSONMap(data, '', '');
|
|
this.section = this.map.section(form.TypedSection, sectionName, '');
|
|
this.section.anonymous = true;
|
|
|
|
await this.createForm();
|
|
|
|
return this.map.render();
|
|
},
|
|
|
|
createForm() {},
|
|
|
|
getField(name) {
|
|
return this.section?.getOption(name);
|
|
},
|
|
|
|
getFields() {
|
|
return this.section?.getOption() || {};
|
|
},
|
|
|
|
getFieldValue(name) {
|
|
return this.getField(name)?.formvalue(this.section?.sectiontype);
|
|
},
|
|
|
|
getFieldValues() {
|
|
const values = {};
|
|
const fields = this.getFields();
|
|
|
|
Object.keys(fields).forEach((name) => {
|
|
values[name] = fields[name].formvalue(this.section?.sectiontype);
|
|
});
|
|
|
|
return values;
|
|
},
|
|
|
|
isValid() {
|
|
const fields = this.getFields();
|
|
const sectionId = this.section.sectiontype;
|
|
|
|
for (const [_key, field] of Object.entries(fields)) {
|
|
if (field.isValid(sectionId) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
scrollToInvalid() {
|
|
const invalidElement = this.map.root.querySelector('.cbi-input-invalid');
|
|
invalidElement.scrollIntoView();
|
|
},
|
|
|
|
async save() {
|
|
try {
|
|
await this.map.save(() => {}, true);
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
async handleCreate(createFn, title, textLoading, textSuccess) {
|
|
ui.hideModal();
|
|
|
|
const loadingText = textLoading || _('Creating %s').format(title);
|
|
const successText = textSuccess || _('%s created successfully').format(title);
|
|
|
|
this.loading(loadingText);
|
|
|
|
await createFn();
|
|
ui.hideModal();
|
|
if (successText !== false) {
|
|
this.success(successText);
|
|
}
|
|
},
|
|
});
|
|
|
|
const ViewTabs = ViewBase.extend({
|
|
__name__: 'Podman.View.Tabs',
|
|
tabs: null,
|
|
|
|
__init__() {
|
|
this.tabs = new podmanUI.Tabs('info');
|
|
this.super('__init__', []);
|
|
},
|
|
|
|
renderTab(tab, content, description) {
|
|
const tabContainer = document.querySelector(`.tab-pane[data-tab="${tab}"]`);
|
|
const tabContainerNode = tabContainer?.querySelector('.cbi-section-node');
|
|
|
|
if (!tabContainerNode) return;
|
|
|
|
if (description) {
|
|
tabContainer.insertBefore(E('div', {
|
|
class: 'cbi-section-descr'
|
|
}, description), tabContainer.firstChild);
|
|
}
|
|
|
|
dom.content(tabContainerNode, content);
|
|
},
|
|
|
|
getTabInstance(name) {
|
|
const tabNode = document.querySelector(`.tab-pane[data-tab="${name}"]`);
|
|
return tabNode ? dom.findClassInstance(tabNode) : null;
|
|
},
|
|
});
|
|
|
|
const ViewContainer = ViewTabs.extend({
|
|
__name__: 'Podman.View.Container',
|
|
listUrl: '#',
|
|
|
|
async render() {
|
|
window.addEventListener('pagehide', () => this.stopStreams(), { once: true });
|
|
|
|
return E('div', {}, [ this.createHeader(), this.tabs.render() ]);
|
|
},
|
|
|
|
createHeader(name, isRunning, isStopped, isPaused) {
|
|
return E('div', { class: 'mb-sm container-toolbar' }, [
|
|
E('div', { class: 'd-flex align-start' }, [
|
|
E('h2', { class: 'mb-sm' }, [ name ]),
|
|
new podmanUI.ButtonNew(constant.ICON.BACK, {
|
|
click: () => this.redirectToList(),
|
|
type: 'none',
|
|
}).render(),
|
|
]),
|
|
E('div', { class: 'd-flex align-center' }, [
|
|
new podmanUI.ButtonNew(constant.ICON.START, {
|
|
click: ui.createHandlerFn(this, 'handleStart'),
|
|
type: isRunning ? 'active' : '',
|
|
}).render(),
|
|
new podmanUI.ButtonNew(constant.ICON.STOP, {
|
|
click: ui.createHandlerFn(this, 'handleStop'),
|
|
type: isStopped ? 'active' : '',
|
|
}).render(),
|
|
new podmanUI.ButtonNew(constant.ICON.RESTART, {
|
|
click: ui.createHandlerFn(this, 'handleRestart'),
|
|
}).render(),
|
|
new podmanUI.ButtonNew(constant.ICON.PAUSE, {
|
|
click: ui.createHandlerFn(this, 'handlePause'),
|
|
type: isPaused ? 'active' : '',
|
|
}).render(),
|
|
new podmanUI.ButtonNew(_('Delete'), {
|
|
click: ui.createHandlerFn(this, 'handleRemove'),
|
|
type: 'negative',
|
|
}).render(),
|
|
]),
|
|
]);
|
|
},
|
|
|
|
redirectToList() {
|
|
this.stopStreams();
|
|
window.location.href = this.listUrl;
|
|
},
|
|
|
|
stopStreams() {
|
|
},
|
|
});
|
|
|
|
const ViewTabContent = baseclass.extend({
|
|
...ViewDefault,
|
|
__name__: 'PodmanView.TabContent',
|
|
tab: null,
|
|
active: false,
|
|
|
|
__init__(tab) {
|
|
this.tab = tab || this.tab;
|
|
this.super('__init__', []);
|
|
|
|
if (!this.tab) {
|
|
return;
|
|
}
|
|
|
|
let attempts = 0;
|
|
new Promise((resolve, reject) => {
|
|
const check = () => {
|
|
if (attempts++ > 100) { reject(); return; }
|
|
const element = document.querySelector(`[data-tab="${this.tab}"]`);
|
|
if (element) resolve(element);
|
|
else setTimeout(check, 100);
|
|
};
|
|
check();
|
|
}).then(() => {
|
|
const mainNode = document.querySelector(`.tab-pane[data-tab="${this.tab}"]`);
|
|
|
|
dom.bindClassInstance(mainNode, this);
|
|
|
|
const mutationObserver = new MutationObserver((mutationsList) => {
|
|
let handled = false;
|
|
mutationsList.forEach((mutation) => {
|
|
const setActive = mutation.target.dataset.tabActive === 'true';
|
|
|
|
if (handled || mutation.attributeName !== 'data-tab-active') return;
|
|
handled = true;
|
|
|
|
if (this.active === setActive) {
|
|
return;
|
|
}
|
|
|
|
if (setActive) {
|
|
this.active = true;
|
|
this.onTabActive();
|
|
return;
|
|
}
|
|
|
|
this.active = false;
|
|
this.onTabInactive();
|
|
});
|
|
});
|
|
|
|
mutationObserver.observe(mainNode, { attributes: true });
|
|
}).catch(() => {});
|
|
},
|
|
|
|
async onTabActive() { },
|
|
|
|
async onTabInactive() { },
|
|
|
|
renderTabContent(headline, content) {
|
|
return E('div', {}, [
|
|
E('h4', {}, headline),
|
|
...(content || []),
|
|
]);
|
|
},
|
|
|
|
warningContent(message) {
|
|
return E('div', { class: 'alert-message d-flex justify-center p-sm' }, message);
|
|
},
|
|
});
|
|
|
|
return baseclass.extend({
|
|
base: ViewBase,
|
|
list: ViewList,
|
|
form: ViewForm,
|
|
container: ViewContainer,
|
|
tabContent: ViewTabContent,
|
|
});
|