fix: run prettier & remove unused fragments

This commit is contained in:
divocat
2025-10-07 00:50:39 +03:00
parent 7cb43ffb65
commit c78f97d64f
5 changed files with 283 additions and 301 deletions

View File

@@ -1,6 +1,5 @@
import { ValidationResult } from './types'; import { ValidationResult } from './types';
// TODO refactor current validation and add tests
export function validateVlessUrl(url: string): ValidationResult { export function validateVlessUrl(url: string): ValidationResult {
try { try {
const parsedUrl = new URL(url); const parsedUrl = new URL(url);

View File

@@ -23,12 +23,12 @@ async function uploadFile(filePath) {
const relativePath = path.relative(localDir, filePath); const relativePath = path.relative(localDir, filePath);
const remotePath = path.posix.join(remoteDir, relativePath); const remotePath = path.posix.join(remoteDir, relativePath);
console.log(`⬆️ Uploading: ${relativePath} -> ${remotePath}`); console.log(`Uploading: ${relativePath} -> ${remotePath}`);
try { try {
await sftp.fastPut(filePath, remotePath); await sftp.fastPut(filePath, remotePath);
console.log(`Uploaded: ${relativePath}`); console.log(`Uploaded: ${relativePath}`);
} catch (err) { } catch (err) {
console.error(`Failed: ${relativePath}: ${err.message}`); console.error(`Failed: ${relativePath}: ${err.message}`);
} }
} }
@@ -36,34 +36,32 @@ async function deleteFile(filePath) {
const relativePath = path.relative(localDir, filePath); const relativePath = path.relative(localDir, filePath);
const remotePath = path.posix.join(remoteDir, relativePath); const remotePath = path.posix.join(remoteDir, relativePath);
console.log(`🗑 Removing: ${relativePath}`); console.log(`Removing: ${relativePath}`);
try { try {
await sftp.delete(remotePath); await sftp.delete(remotePath);
console.log(`Removed: ${relativePath}`); console.log(`Removed: ${relativePath}`);
} catch (err) { } catch (err) {
console.warn(`⚠️ Could not delete ${relativePath}: ${err.message}`); console.warn(`Could not delete ${relativePath}: ${err.message}`);
} }
} }
async function uploadAllFiles() { async function uploadAllFiles() {
console.log('🚀 Uploading all files from', localDir); console.log('Uploading all files from', localDir);
const files = await glob(`${localDir}/**/*`, { nodir: true }); const files = await glob(`${localDir}/**/*`, { nodir: true });
for (const file of files) { for (const file of files) {
await uploadFile(file); await uploadFile(file);
} }
console.log('Initial upload complete!'); console.log('Initial upload complete!');
} }
async function main() { async function main() {
await sftp.connect(config); await sftp.connect(config);
console.log(`Connected to ${config.host}`); console.log(`Connected to ${config.host}`);
// 🔹 Загрузить всё при старте
await uploadAllFiles(); await uploadAllFiles();
// 🔹 Затем следить за изменениями
chokidar chokidar
.watch(localDir, { ignoreInitial: true }) .watch(localDir, { ignoreInitial: true })
.on('all', async (event, filePath) => { .on('all', async (event, filePath) => {
@@ -75,7 +73,7 @@ async function main() {
}); });
process.on('SIGINT', async () => { process.on('SIGINT', async () => {
console.log('🔌 Disconnecting...'); console.log('Disconnecting...');
await sftp.end(); await sftp.end();
process.exit(); process.exit();
}); });

View File

@@ -12,11 +12,11 @@ function createConfigSection(section) {
let o = s.tab('basic', _('Basic Settings')); let o = s.tab('basic', _('Basic Settings'));
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.ListValue, form.ListValue,
'mode', 'mode',
_('Connection Type'), _('Connection Type'),
_('Select between VPN and Proxy connection methods for traffic routing'), _('Select between VPN and Proxy connection methods for traffic routing'),
); );
o.value('proxy', 'Proxy'); o.value('proxy', 'Proxy');
o.value('vpn', 'VPN'); o.value('vpn', 'VPN');
@@ -24,11 +24,11 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.ListValue, form.ListValue,
'proxy_config_type', 'proxy_config_type',
_('Configuration Type'), _('Configuration Type'),
_('Select how to configure the proxy'), _('Select how to configure the proxy'),
); );
o.value('url', _('Connection URL')); o.value('url', _('Connection URL'));
o.value('outbound', _('Outbound Config')); o.value('outbound', _('Outbound Config'));
@@ -38,11 +38,11 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.TextValue, form.TextValue,
'proxy_string', 'proxy_string',
_('Proxy Configuration URL'), _('Proxy Configuration URL'),
'', '',
); );
o.depends('proxy_config_type', 'url'); o.depends('proxy_config_type', 'url');
o.rows = 5; o.rows = 5;
@@ -52,7 +52,7 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o.sectionDescriptions = new Map(); o.sectionDescriptions = new Map();
o.placeholder = o.placeholder =
'vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt\n// backup3 trojan://04agAQapcl@127.0.0.1:33641?type=tcp&security=none#trojan-tcp-none'; 'vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt\n// backup3 trojan://04agAQapcl@127.0.0.1:33641?type=tcp&security=none#trojan-tcp-none';
o.renderWidget = function (section_id, option_index, cfgvalue) { o.renderWidget = function (section_id, option_index, cfgvalue) {
const original = form.TextValue.prototype.renderWidget.apply(this, [ const original = form.TextValue.prototype.renderWidget.apply(this, [
@@ -66,9 +66,9 @@ function createConfigSection(section) {
if (cfgvalue) { if (cfgvalue) {
try { try {
const activeConfig = cfgvalue const activeConfig = cfgvalue
.split('\n') .split('\n')
.map((line) => line.trim()) .map((line) => line.trim())
.find((line) => line && !line.startsWith('//')); .find((line) => line && !line.startsWith('//'));
if (activeConfig) { if (activeConfig) {
if (activeConfig.includes('#')) { if (activeConfig.includes('#')) {
@@ -76,24 +76,24 @@ function createConfigSection(section) {
if (label && label.trim()) { if (label && label.trim()) {
const decodedLabel = decodeURIComponent(label); const decodedLabel = decodeURIComponent(label);
const descDiv = E( const descDiv = E(
'div', 'div',
{ class: 'cbi-value-description' }, { class: 'cbi-value-description' },
_('Current config: ') + decodedLabel, _('Current config: ') + decodedLabel,
); );
container.appendChild(descDiv); container.appendChild(descDiv);
} else { } else {
const descDiv = E( const descDiv = E(
'div', 'div',
{ class: 'cbi-value-description' }, { class: 'cbi-value-description' },
_('Config without description'), _('Config without description'),
); );
container.appendChild(descDiv); container.appendChild(descDiv);
} }
} else { } else {
const descDiv = E( const descDiv = E(
'div', 'div',
{ class: 'cbi-value-description' }, { class: 'cbi-value-description' },
_('Config without description'), _('Config without description'),
); );
container.appendChild(descDiv); container.appendChild(descDiv);
} }
@@ -101,19 +101,19 @@ function createConfigSection(section) {
} catch (e) { } catch (e) {
console.error('Error parsing config label:', e); console.error('Error parsing config label:', e);
const descDiv = E( const descDiv = E(
'div', 'div',
{ class: 'cbi-value-description' }, { class: 'cbi-value-description' },
_('Config without description'), _('Config without description'),
); );
container.appendChild(descDiv); container.appendChild(descDiv);
} }
} else { } else {
const defaultDesc = E( const defaultDesc = E(
'div', 'div',
{ class: 'cbi-value-description' }, { class: 'cbi-value-description' },
_( _(
'Enter connection string starting with vless:// or ss:// for proxy configuration. Add comments with // for backup configs', 'Enter connection string starting with vless:// or ss:// for proxy configuration. Add comments with // for backup configs',
), ),
); );
container.appendChild(defaultDesc); container.appendChild(defaultDesc);
} }
@@ -129,20 +129,20 @@ function createConfigSection(section) {
try { try {
const activeConfigs = value const activeConfigs = value
.split('\n') .split('\n')
.map((line) => line.trim()) .map((line) => line.trim())
.filter((line) => !line.startsWith('//')) .filter((line) => !line.startsWith('//'))
.filter(Boolean); .filter(Boolean);
if (!activeConfigs.length) { if (!activeConfigs.length) {
return _( return _(
'No active configuration found. One configuration is required.', 'No active configuration found. One configuration is required.',
); );
} }
if (activeConfigs.length > 1) { if (activeConfigs.length > 1) {
return _( return _(
'Multiply active configurations found. Please leave one configuration.', 'Multiply active configurations found. Please leave one configuration.',
); );
} }
@@ -159,11 +159,11 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.TextValue, form.TextValue,
'outbound_json', 'outbound_json',
_('Outbound Configuration'), _('Outbound Configuration'),
_('Enter complete outbound configuration in JSON format'), _('Enter complete outbound configuration in JSON format'),
); );
o.depends('proxy_config_type', 'outbound'); o.depends('proxy_config_type', 'outbound');
o.rows = 10; o.rows = 10;
@@ -184,10 +184,10 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'urltest_proxy_links', 'urltest_proxy_links',
_('URLTest Proxy Links'), _('URLTest Proxy Links'),
); );
o.depends('proxy_config_type', 'urltest'); o.depends('proxy_config_type', 'urltest');
o.placeholder = 'vless://, ss://, trojan:// links'; o.placeholder = 'vless://, ss://, trojan:// links';
@@ -208,11 +208,11 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'ss_uot', 'ss_uot',
_('Shadowsocks UDP over TCP'), _('Shadowsocks UDP over TCP'),
_('Apply for SS2022'), _('Apply for SS2022'),
); );
o.default = '0'; o.default = '0';
o.depends('mode', 'proxy'); o.depends('mode', 'proxy');
@@ -220,11 +220,11 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
widgets.DeviceSelect, widgets.DeviceSelect,
'interface', 'interface',
_('Network Interface'), _('Network Interface'),
_('Select network interface for VPN connection'), _('Select network interface for VPN connection'),
); );
o.depends('mode', 'vpn'); o.depends('mode', 'vpn');
o.ucisection = s.section; o.ucisection = s.section;
@@ -262,17 +262,17 @@ function createConfigSection(section) {
// Reject wireless-related devices // Reject wireless-related devices
const isWireless = const isWireless =
type === 'wifi' || type === 'wireless' || type.includes('wlan'); type === 'wifi' || type === 'wireless' || type.includes('wlan');
return !isWireless; return !isWireless;
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'domain_resolver_enabled', 'domain_resolver_enabled',
_('Domain Resolver'), _('Domain Resolver'),
_('Enable built-in DNS resolver for domains handled by this section'), _('Enable built-in DNS resolver for domains handled by this section'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
@@ -280,11 +280,11 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.ListValue, form.ListValue,
'domain_resolver_dns_type', 'domain_resolver_dns_type',
_('DNS Protocol Type'), _('DNS Protocol Type'),
_('Select the DNS protocol type for the domain resolver'), _('Select the DNS protocol type for the domain resolver'),
); );
o.value('doh', _('DNS over HTTPS (DoH)')); o.value('doh', _('DNS over HTTPS (DoH)'));
o.value('dot', _('DNS over TLS (DoT)')); o.value('dot', _('DNS over TLS (DoT)'));
@@ -295,11 +295,11 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Value, form.Value,
'domain_resolver_dns_server', 'domain_resolver_dns_server',
_('DNS Server'), _('DNS Server'),
_('Select or enter DNS server address'), _('Select or enter DNS server address'),
); );
Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => { Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
o.value(key, _(label)); o.value(key, _(label));
@@ -319,21 +319,21 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'community_lists_enabled', 'community_lists_enabled',
_('Community Lists'), _('Community Lists'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'community_lists', 'community_lists',
_('Service List'), _('Service List'),
_('Select predefined service for routing') + _('Select predefined service for routing') +
' <a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>', ' <a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>',
); );
o.placeholder = 'Service list'; o.placeholder = 'Service list';
@@ -357,50 +357,50 @@ function createConfigSection(section) {
let notifications = []; let notifications = [];
const selectedRegionalOptions = main.REGIONAL_OPTIONS.filter((opt) => const selectedRegionalOptions = main.REGIONAL_OPTIONS.filter((opt) =>
newValues.includes(opt), newValues.includes(opt),
); );
if (selectedRegionalOptions.length > 1) { if (selectedRegionalOptions.length > 1) {
const lastSelected = const lastSelected =
selectedRegionalOptions[selectedRegionalOptions.length - 1]; selectedRegionalOptions[selectedRegionalOptions.length - 1];
const removedRegions = selectedRegionalOptions.slice(0, -1); const removedRegions = selectedRegionalOptions.slice(0, -1);
newValues = newValues.filter( newValues = newValues.filter(
(v) => v === lastSelected || !main.REGIONAL_OPTIONS.includes(v), (v) => v === lastSelected || !main.REGIONAL_OPTIONS.includes(v),
); );
notifications.push( notifications.push(
E('p', { class: 'alert-message warning' }, [ E('p', { class: 'alert-message warning' }, [
E('strong', {}, _('Regional options cannot be used together')), E('strong', {}, _('Regional options cannot be used together')),
E('br'), E('br'),
_( _(
'Warning: %s cannot be used together with %s. Previous selections have been removed.', 'Warning: %s cannot be used together with %s. Previous selections have been removed.',
).format(removedRegions.join(', '), lastSelected), ).format(removedRegions.join(', '), lastSelected),
]), ]),
); );
} }
if (newValues.includes('russia_inside')) { if (newValues.includes('russia_inside')) {
const removedServices = newValues.filter( const removedServices = newValues.filter(
(v) => !main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v), (v) => !main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
); );
if (removedServices.length > 0) { if (removedServices.length > 0) {
newValues = newValues.filter((v) => newValues = newValues.filter((v) =>
main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v), main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
); );
notifications.push( notifications.push(
E('p', { class: 'alert-message warning' }, [ E('p', { class: 'alert-message warning' }, [
E('strong', {}, _('Russia inside restrictions')), E('strong', {}, _('Russia inside restrictions')),
E('br'), E('br'),
_( _(
'Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection.', 'Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection.',
).format( ).format(
main.ALLOWED_WITH_RUSSIA_INSIDE.map( main.ALLOWED_WITH_RUSSIA_INSIDE.map(
(key) => main.DOMAIN_LIST_OPTIONS[key], (key) => main.DOMAIN_LIST_OPTIONS[key],
) )
.filter((label) => label !== 'Russia inside') .filter((label) => label !== 'Russia inside')
.join(', '), .join(', '),
removedServices.join(', '), removedServices.join(', '),
), ),
]), ]),
); );
} }
} }
@@ -410,7 +410,7 @@ function createConfigSection(section) {
} }
notifications.forEach((notification) => notifications.forEach((notification) =>
ui.addNotification(null, notification), ui.addNotification(null, notification),
); );
lastValues = newValues; lastValues = newValues;
} catch (e) { } catch (e) {
@@ -421,11 +421,11 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.ListValue, form.ListValue,
'user_domain_list_type', 'user_domain_list_type',
_('User Domain List Type'), _('User Domain List Type'),
_('Select how to add your custom domains'), _('Select how to add your custom domains'),
); );
o.value('disabled', _('Disabled')); o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List')); o.value('dynamic', _('Dynamic List'));
@@ -435,13 +435,13 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'user_domains', 'user_domains',
_('User Domains'), _('User Domains'),
_( _(
'Enter domain names without protocols (example: sub.example.com or example.com)', 'Enter domain names without protocols (example: sub.example.com or example.com)',
), ),
); );
o.placeholder = 'Domains list'; o.placeholder = 'Domains list';
o.depends('user_domain_list_type', 'dynamic'); o.depends('user_domain_list_type', 'dynamic');
@@ -463,16 +463,16 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.TextValue, form.TextValue,
'user_domains_text', 'user_domains_text',
_('User Domains List'), _('User Domains List'),
_( _(
'Enter domain names separated by comma, space or newline. You can add comments after //', 'Enter domain names separated by comma, space or newline. You can add comments after //',
), ),
); );
o.placeholder = o.placeholder =
'example.com, sub.example.com\n// Social networks\ndomain.com test.com // personal domains'; 'example.com, sub.example.com\n// Social networks\ndomain.com test.com // personal domains';
o.depends('user_domain_list_type', 'text'); o.depends('user_domain_list_type', 'text');
o.rows = 8; o.rows = 8;
o.rmempty = false; o.rmempty = false;
@@ -487,7 +487,7 @@ function createConfigSection(section) {
if (!domains.length) { if (!domains.length) {
return _( return _(
'At least one valid domain must be specified. Comments-only content is not allowed.', 'At least one valid domain must be specified. Comments-only content is not allowed.',
); );
} }
@@ -495,8 +495,8 @@ function createConfigSection(section) {
if (!valid) { if (!valid) {
const errors = results const errors = results
.filter((validation) => !validation.valid) // Leave only failed validations .filter((validation) => !validation.valid) // Leave only failed validations
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors .map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
return [_('Validation errors:'), ...errors].join('\n'); return [_('Validation errors:'), ...errors].join('\n');
} }
@@ -505,22 +505,22 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'local_domain_lists_enabled', 'local_domain_lists_enabled',
_('Local Domain Lists'), _('Local Domain Lists'),
_('Use the list from the router filesystem'), _('Use the list from the router filesystem'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'local_domain_lists', 'local_domain_lists',
_('Local Domain List Paths'), _('Local Domain List Paths'),
_('Enter the list file path'), _('Enter the list file path'),
); );
o.placeholder = '/path/file.lst'; o.placeholder = '/path/file.lst';
o.depends('local_domain_lists_enabled', '1'); o.depends('local_domain_lists_enabled', '1');
@@ -542,22 +542,22 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'remote_domain_lists_enabled', 'remote_domain_lists_enabled',
_('Remote Domain Lists'), _('Remote Domain Lists'),
_('Download and use domain lists from remote URLs'), _('Download and use domain lists from remote URLs'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'remote_domain_lists', 'remote_domain_lists',
_('Remote Domain URLs'), _('Remote Domain URLs'),
_('Enter full URLs starting with http:// or https://'), _('Enter full URLs starting with http:// or https://'),
); );
o.placeholder = 'URL'; o.placeholder = 'URL';
o.depends('remote_domain_lists_enabled', '1'); o.depends('remote_domain_lists_enabled', '1');
@@ -579,22 +579,22 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'local_subnet_lists_enabled', 'local_subnet_lists_enabled',
_('Local Subnet Lists'), _('Local Subnet Lists'),
_('Use the list from the router filesystem'), _('Use the list from the router filesystem'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'local_subnet_lists', 'local_subnet_lists',
_('Local Subnet List Paths'), _('Local Subnet List Paths'),
_('Enter the list file path'), _('Enter the list file path'),
); );
o.placeholder = '/path/file.lst'; o.placeholder = '/path/file.lst';
o.depends('local_subnet_lists_enabled', '1'); o.depends('local_subnet_lists_enabled', '1');
@@ -616,11 +616,11 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.ListValue, form.ListValue,
'user_subnet_list_type', 'user_subnet_list_type',
_('User Subnet List Type'), _('User Subnet List Type'),
_('Select how to add your custom subnets'), _('Select how to add your custom subnets'),
); );
o.value('disabled', _('Disabled')); o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List')); o.value('dynamic', _('Dynamic List'));
@@ -630,13 +630,13 @@ function createConfigSection(section) {
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'user_subnets', 'user_subnets',
_('User Subnets'), _('User Subnets'),
_( _(
'Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses', 'Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses',
), ),
); );
o.placeholder = 'IP or subnet'; o.placeholder = 'IP or subnet';
o.depends('user_subnet_list_type', 'dynamic'); o.depends('user_subnet_list_type', 'dynamic');
@@ -658,16 +658,16 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.TextValue, form.TextValue,
'user_subnets_text', 'user_subnets_text',
_('User Subnets List'), _('User Subnets List'),
_( _(
'Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline. You can add comments after //', 'Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline. You can add comments after //',
), ),
); );
o.placeholder = o.placeholder =
'103.21.244.0/22\n// Google DNS\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 // Cloudflare and Quad9'; '103.21.244.0/22\n// Google DNS\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 // Cloudflare and Quad9';
o.depends('user_subnet_list_type', 'text'); o.depends('user_subnet_list_type', 'text');
o.rows = 10; o.rows = 10;
o.rmempty = false; o.rmempty = false;
@@ -682,7 +682,7 @@ function createConfigSection(section) {
if (!subnets.length) { if (!subnets.length) {
return _( return _(
'At least one valid subnet or IP must be specified. Comments-only content is not allowed.', 'At least one valid subnet or IP must be specified. Comments-only content is not allowed.',
); );
} }
@@ -690,8 +690,8 @@ function createConfigSection(section) {
if (!valid) { if (!valid) {
const errors = results const errors = results
.filter((validation) => !validation.valid) // Leave only failed validations .filter((validation) => !validation.valid) // Leave only failed validations
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors .map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
return [_('Validation errors:'), ...errors].join('\n'); return [_('Validation errors:'), ...errors].join('\n');
} }
@@ -700,22 +700,22 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'remote_subnet_lists_enabled', 'remote_subnet_lists_enabled',
_('Remote Subnet Lists'), _('Remote Subnet Lists'),
_('Download and use subnet lists from remote URLs'), _('Download and use subnet lists from remote URLs'),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'remote_subnet_lists', 'remote_subnet_lists',
_('Remote Subnet URLs'), _('Remote Subnet URLs'),
_('Enter full URLs starting with http:// or https://'), _('Enter full URLs starting with http:// or https://'),
); );
o.placeholder = 'URL'; o.placeholder = 'URL';
o.depends('remote_subnet_lists_enabled', '1'); o.depends('remote_subnet_lists_enabled', '1');
@@ -737,24 +737,24 @@ function createConfigSection(section) {
}; };
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.Flag, form.Flag,
'all_traffic_from_ip_enabled', 'all_traffic_from_ip_enabled',
_('IP for full redirection'), _('IP for full redirection'),
_( _(
'Specify local IP addresses whose traffic will always use the configured route', 'Specify local IP addresses whose traffic will always use the configured route',
), ),
); );
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o = s.taboption( o = s.taboption(
'basic', 'basic',
form.DynamicList, form.DynamicList,
'all_traffic_ip', 'all_traffic_ip',
_('Local IPs'), _('Local IPs'),
_('Enter valid IPv4 addresses'), _('Enter valid IPv4 addresses'),
); );
o.placeholder = 'IP'; o.placeholder = 'IP';
o.depends('all_traffic_from_ip_enabled', '1'); o.depends('all_traffic_from_ip_enabled', '1');

View File

@@ -8,19 +8,19 @@
'require view.podkop.main as main'; 'require view.podkop.main as main';
function createDashboardSection(mainSection) { function createDashboardSection(mainSection) {
let o = mainSection.tab('dashboard', _('Dashboard')); let o = mainSection.tab('dashboard', _('Dashboard'));
o = mainSection.taboption('dashboard', form.DummyValue, '_status'); o = mainSection.taboption('dashboard', form.DummyValue, '_status');
o.rawhtml = true; o.rawhtml = true;
o.cfgvalue = () => { o.cfgvalue = () => {
main.initDashboardController() main.initDashboardController();
return main.renderDashboard() return main.renderDashboard();
}; };
} }
const EntryPoint = { const EntryPoint = {
createDashboardSection, createDashboardSection,
} };
return baseclass.extend(EntryPoint); return baseclass.extend(EntryPoint);

View File

@@ -10,88 +10,73 @@
'require view.podkop.main as main'; 'require view.podkop.main as main';
const EntryNode = { const EntryNode = {
async render() { async render() {
main.injectGlobalStyles(); main.injectGlobalStyles();
// main.getClashVersion() const podkopFormMap = new form.Map('podkop', '', null, ['main', 'extra']);
// .then(result => console.log('getClashVersion - then', result))
// .catch(err => console.log('getClashVersion - err', err))
// .finally(() => console.log('getClashVersion - finish'));
//
// main.getClashConfig()
// .then(result => console.log('getClashConfig - then', result))
// .catch(err => console.log('getClashConfig - err', err))
// .finally(() => console.log('getClashConfig - finish'));
//
// main.getClashProxies()
// .then(result => console.log('getClashProxies - then', result))
// .catch(err => console.log('getClashProxies - err', err))
// .finally(() => console.log('getClashProxies - finish'));
const podkopFormMap = new form.Map('podkop', '', null, ['main', 'extra']); // Main Section
const mainSection = podkopFormMap.section(form.TypedSection, 'main');
mainSection.anonymous = true;
// Main Section configSection.createConfigSection(mainSection);
const mainSection = podkopFormMap.section(form.TypedSection, 'main');
mainSection.anonymous = true;
configSection.createConfigSection(mainSection); // Additional Settings Tab (main section)
additionalTab.createAdditionalSection(mainSection);
// Additional Settings Tab (main section) // Diagnostics Tab (main section)
additionalTab.createAdditionalSection(mainSection); diagnosticTab.createDiagnosticsSection(mainSection);
const podkopFormMapPromise = podkopFormMap.render().then((node) => {
// Set up diagnostics event handlers
diagnosticTab.setupDiagnosticsEventHandlers(node);
// Diagnostics Tab (main section) // Start critical error polling for all tabs
diagnosticTab.createDiagnosticsSection(mainSection); utils.startErrorPolling();
const podkopFormMapPromise = podkopFormMap.render().then(node => {
// Set up diagnostics event handlers
diagnosticTab.setupDiagnosticsEventHandlers(node);
// Start critical error polling for all tabs // Add event listener to keep error polling active when switching tabs
const tabs = node.querySelectorAll('.cbi-tabmenu');
if (tabs.length > 0) {
tabs[0].addEventListener('click', function (e) {
const tab = e.target.closest('.cbi-tab');
if (tab) {
// Ensure error polling continues when switching tabs
utils.startErrorPolling(); utils.startErrorPolling();
}
// Add event listener to keep error polling active when switching tabs
const tabs = node.querySelectorAll('.cbi-tabmenu');
if (tabs.length > 0) {
tabs[0].addEventListener('click', function (e) {
const tab = e.target.closest('.cbi-tab');
if (tab) {
// Ensure error polling continues when switching tabs
utils.startErrorPolling();
}
});
}
// Add visibility change handler to manage error polling
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
utils.stopErrorPolling();
} else {
utils.startErrorPolling();
}
});
return node;
}); });
}
// Extra Section // Add visibility change handler to manage error polling
const extraSection = podkopFormMap.section(form.TypedSection, 'extra', _('Extra configurations')); document.addEventListener('visibilitychange', function () {
extraSection.anonymous = false; if (document.hidden) {
extraSection.addremove = true; utils.stopErrorPolling();
extraSection.addbtntitle = _('Add Section'); } else {
extraSection.multiple = true; utils.startErrorPolling();
configSection.createConfigSection(extraSection); }
});
return node;
});
// Initial dashboard render // Extra Section
dashboardTab.createDashboardSection(mainSection); const extraSection = podkopFormMap.section(
form.TypedSection,
'extra',
_('Extra configurations'),
);
extraSection.anonymous = false;
extraSection.addremove = true;
extraSection.addbtntitle = _('Add Section');
extraSection.multiple = true;
configSection.createConfigSection(extraSection);
// Inject dashboard actualizer logic // Initial dashboard render
// main.initDashboardController(); dashboardTab.createDashboardSection(mainSection);
// Inject core service // Inject core service
main.coreService(); main.coreService();
return podkopFormMapPromise; return podkopFormMapPromise;
} },
} };
return view.extend(EntryNode); return view.extend(EntryNode);