import $ from 'jquery';
import { JSONRPC } from '@/json-rpc.js';
const ROS_COMPONENT_NAME = 'ru.kirillius.pf.sdn.External.API.Components.ROS';
const FIELD_IDS = {
container: 'ros-config-container',
instancesList: 'ros-instances-list',
addInstanceButton: 'ros-add-instance-btn',
saveButton: 'save-ros-btn',
status: 'ros-status-message'
};
const CLASS_NAMES = {
instance: 'ros-instance-entry',
removeInstanceButton: 'ros-remove-instance-btn',
host: 'ros-host',
username: 'ros-username',
password: 'ros-password',
vrf: 'ros-vrf',
gateway: 'ros-gateway'
};
const SELECTORS = {
container: `#${FIELD_IDS.container}`,
instancesList: `#${FIELD_IDS.instancesList}`,
addInstanceButton: `#${FIELD_IDS.addInstanceButton}`,
saveButton: `#${FIELD_IDS.saveButton}`,
status: `#${FIELD_IDS.status}`
};
let currentConfig = { instances: [] };
let statusTimeoutId = null;
let instanceCounter = 0;
const getStatusElement = () => $(SELECTORS.status);
function normalizeConfig(config) {
if (!config || !Array.isArray(config.instances)) {
return { instances: [] };
}
return {
instances: config.instances.map(instance => ({
host: instance?.host || '',
username: instance?.username || '',
password: instance?.password || '',
VRF: instance?.VRF || 'main',
gateway: instance?.gateway || ''
}))
};
}
function clearStatus() {
const $status = getStatusElement();
if (!$status.length) {
return;
}
if (statusTimeoutId) {
clearTimeout(statusTimeoutId);
statusTimeoutId = null;
}
$status.stop(true, true).hide().text('').removeClass('success-message error-message');
}
function updateStatus(message, type) {
const $status = getStatusElement();
if (!$status.length) {
return;
}
if (statusTimeoutId) {
clearTimeout(statusTimeoutId);
}
$status
.removeClass('success-message error-message')
.addClass(type === 'success' ? 'success-message' : 'error-message')
.text(message)
.show();
statusTimeoutId = window.setTimeout(() => {
$status.fadeOut();
}, 5000);
}
async function runAction($button, pendingText, action, messages) {
if (!$button.length) {
return;
}
const originalText = $button.text();
$button.prop('disabled', true).text(pendingText);
clearStatus();
try {
const result = await action();
if (messages?.success) {
const successMessage = typeof messages.success === 'function'
? messages.success(result)
: messages.success;
if (successMessage) {
updateStatus(successMessage, 'success');
}
}
} catch (error) {
console.error(messages?.log || 'Ошибка выполнения действия ROS:', error);
if (messages?.error) {
updateStatus(messages.error, 'error');
}
} finally {
$button.prop('disabled', false).text(originalText);
}
}
function resetCounters() {
instanceCounter = 0;
}
function getNextInstanceId() {
instanceCounter += 1;
return instanceCounter;
}
function createInstanceRow(instance = {}) {
const instanceId = getNextInstanceId();
return `
`;
}
function populateInstances() {
const instances = currentConfig.instances.length ? currentConfig.instances : [];
const $list = $(SELECTORS.instancesList);
resetCounters();
$list.empty();
instances.forEach(instance => {
$list.append(createInstanceRow(instance));
});
}
function renderROSForm() {
const $container = $(SELECTORS.container);
$container.html(`
`);
populateInstances();
attachEventHandlers();
}
function collectConfigFromForm() {
const instances = [];
$(SELECTORS.instancesList).find(`.${CLASS_NAMES.instance}`).each((_, element) => {
const $instance = $(element);
const host = $instance.find(`.${CLASS_NAMES.host}`).val().trim();
const username = $instance.find(`.${CLASS_NAMES.username}`).val().trim();
const $passwordField = $instance.find(`.${CLASS_NAMES.password}`);
const newPassword = $passwordField.val();
const originalPassword = $passwordField.data('original-password') || '';
const password = newPassword ? newPassword : originalPassword;
const VRF = $instance.find(`.${CLASS_NAMES.vrf}`).val().trim();
const gateway = $instance.find(`.${CLASS_NAMES.gateway}`).val().trim();
instances.push({
host,
username,
password,
VRF,
gateway
});
});
return { instances };
}
async function loadConfig() {
try {
const fullConfig = await JSONRPC.System.getComponentConfig(ROS_COMPONENT_NAME);
currentConfig = normalizeConfig(fullConfig);
return true;
} catch (error) {
console.error('Ошибка при загрузке конфига ROS:', error);
currentConfig = { instances: [] };
return false;
}
}
function handleAddInstance() {
const $list = $(SELECTORS.instancesList);
$list.append(createInstanceRow({
host: '',
username: '',
password: '',
VRF: 'main',
gateway: ''
}));
}
function handleRemoveInstance(event) {
event.preventDefault();
$(event.currentTarget).closest(`.${CLASS_NAMES.instance}`).remove();
}
async function handleSave() {
const $button = $(SELECTORS.saveButton);
clearStatus();
const newConfig = collectConfigFromForm();
await runAction($button, 'Применение...', async () => {
await JSONRPC.System.setComponentConfig(ROS_COMPONENT_NAME, newConfig);
currentConfig = normalizeConfig(newConfig);
populateInstances();
}, {
success: 'Конфигурация ROS успешно сохранена.',
error: 'Ошибка при сохранении конфигурации ROS.',
log: 'Ошибка сохранения конфига ROS'
});
}
function attachEventHandlers() {
$(SELECTORS.saveButton).off('click').on('click', handleSave);
$(SELECTORS.addInstanceButton).off('click').on('click', handleAddInstance);
$(SELECTORS.instancesList)
.off('click', `.${CLASS_NAMES.removeInstanceButton}`).on('click', `.${CLASS_NAMES.removeInstanceButton}`, handleRemoveInstance);
}
function detachEventHandlers() {
$(SELECTORS.saveButton).off('click');
$(SELECTORS.addInstanceButton).off('click');
$(SELECTORS.instancesList)
.off('click', `.${CLASS_NAMES.removeInstanceButton}`);
}
export const ROSConfig = {
render: () => `
Настройка ROS
`,
mount: async () => {
const success = await loadConfig();
if (success) {
renderROSForm();
} else {
$(SELECTORS.container).html('Не удалось загрузить конфигурацию ROS.
');
}
},
unmount: () => {
detachEventHandlers();
clearStatus();
currentConfig = { instances: [] };
}
};