Merge upstream main (3.0.0) into feature/adguard
Upstream rewrote install.sh to 3.0.0. Re-apply the fork installer changes on top: point at the NeoTachyon Gitea repo (REPO_HOST/OWNER/NAME), use the Gitea API base for release resolution and support optional GITEA_USER/TOKEN auth for the API and downloads.
This commit is contained in:
+1182
-1178
File diff suppressed because it is too large
Load Diff
+1184
-1180
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TACHYON\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-17 13:43+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 13:43+0300\n"
|
||||
"POT-Creation-Date: 2026-09-17 19:42+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 19:42+0300\n"
|
||||
"Last-Translator: Dushnilin\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -273,10 +273,10 @@ msgid "Add URLs or local paths to .lst lists containing domains. IP entries are
|
||||
msgstr "Добавьте URL или локальные пути к спискам .lst, содержащим домены. IP-записи игнорируются."
|
||||
|
||||
msgid "Add URLs or local paths to .srs / .json / .lst / .txt lists. Only domain rules are supported."
|
||||
msgstr ""
|
||||
msgstr "Укажите URL или локальные пути к спискам .srs / .json / .lst / .txt. Поддерживаются только правила для доменов."
|
||||
|
||||
msgid "Add URLs or local paths to .srs / .json / .lst / .txt lists. Subnets are ignored by default."
|
||||
msgstr ""
|
||||
msgstr "Укажите URL или локальные пути к спискам .srs / .json / .lst / .txt. Подсети по умолчанию игнорируются."
|
||||
|
||||
msgid "Add URLTest / Priority group"
|
||||
msgstr "Добавить группу URLTest / Приоритет"
|
||||
@@ -1395,7 +1395,7 @@ msgid "Direct connection via ISP"
|
||||
msgstr "Прямое подключение через провайдера"
|
||||
|
||||
msgid "Direct Proxy"
|
||||
msgstr "Прямой прокси"
|
||||
msgstr "Direct Proxy"
|
||||
|
||||
msgid "Direct WAN"
|
||||
msgstr "Прямой WAN"
|
||||
@@ -1440,7 +1440,7 @@ msgid "DNS Blocking"
|
||||
msgstr "Блокировка DNS"
|
||||
|
||||
msgid "DNS Cache Size"
|
||||
msgstr ""
|
||||
msgstr "Размер кэша DNS"
|
||||
|
||||
msgid "DNS Check Interval"
|
||||
msgstr "Интервал проверки DNS"
|
||||
@@ -1797,7 +1797,7 @@ msgid "Enabled (always prioritize)"
|
||||
msgstr "Включено (всегда повышать приоритет)"
|
||||
|
||||
msgid "Enables high-capacity local DNS caching in dnsmasq to accelerate DNS queries and absorb transient latency during service restarts."
|
||||
msgstr ""
|
||||
msgstr "Включает емкий локальный кэш DNS в dnsmasq для ускорения запросов и устранения задержек при перезапуске служб."
|
||||
|
||||
msgid "Enables the background daemon that polls Telegram for commands and sends notifications."
|
||||
msgstr "Включает фоновый демон, который опрашивает Telegram на наличие команд и отправляет уведомления."
|
||||
@@ -3102,7 +3102,7 @@ msgid "Local Address"
|
||||
msgstr "Локальный адрес"
|
||||
|
||||
msgid "Local DNS Cache"
|
||||
msgstr ""
|
||||
msgstr "Локальный кэш DNS"
|
||||
|
||||
msgid "Local SOCKS proxy desynchronizer (ciadpi)"
|
||||
msgstr "Локальный десинхронизатор SOCKS-прокси (ciadpi)"
|
||||
@@ -3480,7 +3480,7 @@ msgid "Notify on Subscription Updates"
|
||||
msgstr "Уведомлять об обновлениях подписок"
|
||||
|
||||
msgid "Number of cached DNS domain entries in dnsmasq (default: 10000)."
|
||||
msgstr ""
|
||||
msgstr "Количество кэшируемых доменных записей в dnsmasq (по умолчанию: 10000)."
|
||||
|
||||
msgid "Number of consecutive failed checks required before switching DNS servers."
|
||||
msgstr "Количество последовательных неудачных проверок до переключения DNS-серверов."
|
||||
@@ -4287,7 +4287,7 @@ msgid "Rule Name"
|
||||
msgstr "Название правила"
|
||||
|
||||
msgid "Rule set must be an HTTP(S) URL or a local .srs / .json / .lst / .txt path"
|
||||
msgstr ""
|
||||
msgstr "Набор правил должен быть URL HTTP(S) или локальным путем к .srs / .json / .lst / .txt"
|
||||
|
||||
msgid "Rule set settings"
|
||||
msgstr "Настройки набора правил"
|
||||
@@ -5997,7 +5997,7 @@ msgid "Add URLs or local paths to .srs / .json lists. Subnets are ignored by def
|
||||
msgstr "Добавьте URL или локальные пути к спискам .srs / .json. Подсети игнорируются по умолчанию."
|
||||
|
||||
msgid "Plain .lst / .txt lists belong in \"Domain and IP lists\", not \"Rule sets\""
|
||||
msgstr ""
|
||||
msgstr "Текстовые списки .lst / .txt относятся к «Спискам доменов и IP», а не к «Наборам правил»"
|
||||
|
||||
msgid "Rule set must be an HTTP(S) URL or a local .srs / .json path"
|
||||
msgstr "Набор правил должен быть HTTP(S) URL или локальным путём .srs / .json"
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.28",
|
||||
"version": "1.3.29",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.28",
|
||||
"version": "1.3.29",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/parser": "7.28.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.28",
|
||||
"version": "1.3.29",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -47,6 +47,19 @@ interface IRenderSectionsProps {
|
||||
testingOutboundCodes?: Record<string, boolean>;
|
||||
}
|
||||
|
||||
const CONNECTION_ACTION_LABELS: Record<string, string> = {
|
||||
awg: 'AmneziaWG',
|
||||
warp: 'WARP',
|
||||
anytls: 'AnyTLS',
|
||||
snell: 'Snell',
|
||||
mieru: 'Mieru',
|
||||
sudoku: 'Sudoku',
|
||||
masque: 'MASQUE',
|
||||
openvpn: 'OpenVPN',
|
||||
fptn: 'FPTN',
|
||||
vpn: 'VPN',
|
||||
};
|
||||
|
||||
function renderFailedState() {
|
||||
return E(
|
||||
'div',
|
||||
@@ -529,89 +542,88 @@ function renderDefaultState({
|
||||
.join(' ');
|
||||
|
||||
if (isConnectionNode) {
|
||||
const statusText = latencyFetching
|
||||
? _('Checking...')
|
||||
: outbound.latency === -1 || outbound.latency < 0
|
||||
? _('Not responding')
|
||||
: outbound.runtimeAvailable
|
||||
? _('Connected')
|
||||
: _('Not connected');
|
||||
|
||||
const statusColor = latencyFetching
|
||||
? 'var(--warn-color-medium, orange)'
|
||||
: outbound.latency === -1 || outbound.latency < 0
|
||||
? 'var(--error-color-medium, red)'
|
||||
: outbound.runtimeAvailable
|
||||
? 'var(--success-color-medium, green)'
|
||||
: 'var(--error-color-medium, red)';
|
||||
|
||||
const latencyDisplay =
|
||||
outbound.latency && outbound.latency > 0
|
||||
? `${outbound.latency} ms`
|
||||
: '';
|
||||
|
||||
return E(
|
||||
'div',
|
||||
{
|
||||
class: className,
|
||||
style:
|
||||
'display: flex; align-items: center; justify-content: space-between; padding: 12px; min-width: 0; gap: 16px;',
|
||||
'display: flex; flex-direction: column; justify-content: space-between; padding: 12px; min-width: 0;',
|
||||
},
|
||||
[
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
style:
|
||||
'display: flex; align-items: center; gap: 12px; min-width: 0;',
|
||||
class: 'tachyon_dashboard-page__outbound-grid__item__header',
|
||||
style: 'margin-bottom: 8px;',
|
||||
},
|
||||
[
|
||||
E(
|
||||
'b',
|
||||
{
|
||||
style:
|
||||
'overflow-wrap: anywhere; word-break: break-all; min-width: 0;',
|
||||
},
|
||||
renderFlagEmojis(outbound.displayName),
|
||||
),
|
||||
outbound.prefix
|
||||
? E(
|
||||
'span',
|
||||
{
|
||||
class:
|
||||
'tachyon_dashboard-page__outbound-grid__item__prefix-badge',
|
||||
},
|
||||
renderFlagEmojis(outbound.prefix),
|
||||
)
|
||||
: '',
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
style:
|
||||
'opacity: 0.7; font-size: 13px; white-space: nowrap; flex-shrink: 0;',
|
||||
},
|
||||
[formatOutboundType(outbound.type, outbound.transport)].filter(
|
||||
Boolean,
|
||||
),
|
||||
),
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
class: getLatencyClass(),
|
||||
style: 'white-space: nowrap; flex-shrink: 0;',
|
||||
class:
|
||||
'tachyon_dashboard-page__outbound-grid__item__title-wrapper',
|
||||
},
|
||||
connectionStatusText,
|
||||
[
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
style: `color: ${statusColor}; font-weight: 500; font-size: 13px;`,
|
||||
},
|
||||
statusText,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
E(
|
||||
'button',
|
||||
'div',
|
||||
{
|
||||
type: 'button',
|
||||
class: 'btn dashboard-sections-grid-item-test-latency',
|
||||
style: 'padding: 4px 12px; height: 30px; flex-shrink: 0;',
|
||||
disabled: latencyFetching ? true : undefined,
|
||||
click: (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (latencyFetching) return;
|
||||
testLatency();
|
||||
},
|
||||
class: 'tachyon_dashboard-page__outbound-grid__item__footer',
|
||||
style:
|
||||
'display: flex; align-items: center; justify-content: space-between; gap: 8px;',
|
||||
},
|
||||
latencyFetching
|
||||
? [
|
||||
renderLoaderCircleIcon24(),
|
||||
E(
|
||||
'span',
|
||||
[
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
class: 'tachyon_dashboard-page__outbound-grid__item__type',
|
||||
style:
|
||||
'overflow: hidden; text-overflow: ellipsis; white-space: nowrap;',
|
||||
},
|
||||
renderFlagEmojis(outbound.displayName),
|
||||
),
|
||||
latencyDisplay
|
||||
? E(
|
||||
'div',
|
||||
{
|
||||
class: 'dashboard-sections-grid-item-test-latency__label',
|
||||
class: getLatencyClass(),
|
||||
style: 'white-space: nowrap; flex-shrink: 0;',
|
||||
},
|
||||
_('Checking...'),
|
||||
),
|
||||
]
|
||||
: E(
|
||||
'span',
|
||||
{ class: 'dashboard-sections-grid-item-test-latency__label' },
|
||||
_('Check Connection'),
|
||||
),
|
||||
latencyDisplay,
|
||||
)
|
||||
: '',
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -817,26 +829,6 @@ function renderDefaultState({
|
||||
);
|
||||
}
|
||||
|
||||
if (isConnectionNode) {
|
||||
return E(
|
||||
'div',
|
||||
{
|
||||
class: 'tachyon_dashboard-page__outbound-section',
|
||||
style: 'border: none; padding: 0;',
|
||||
},
|
||||
[
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
style:
|
||||
'display: flex; flex-direction: column; gap: 8px; padding: 0;',
|
||||
},
|
||||
[...section.outbounds.map((outbound) => renderOutbound(outbound))],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
const metadataNodes = (section.subscriptionMetadata || [])
|
||||
.map((metadata) => renderSubscriptionMetadata(metadata))
|
||||
.filter(Boolean) as HTMLElement[];
|
||||
@@ -907,6 +899,11 @@ function renderDefaultState({
|
||||
'openvpn',
|
||||
].includes(section.action || '');
|
||||
|
||||
const connectionTitle =
|
||||
(section.action &&
|
||||
CONNECTION_ACTION_LABELS[section.action]) ||
|
||||
selectedOutbound.displayName;
|
||||
|
||||
function getLatencyColor() {
|
||||
if (isConnectionNode) {
|
||||
if (latencyFetching)
|
||||
@@ -974,7 +971,10 @@ function renderDefaultState({
|
||||
E(
|
||||
'span',
|
||||
{ style: 'opacity: 0.7;' },
|
||||
selectedOutbound.displayName,
|
||||
isConnectionNode
|
||||
? connectionTitle
|
||||
: selectedOutbound.prefix ||
|
||||
selectedOutbound.displayName,
|
||||
),
|
||||
latencyText
|
||||
? E(
|
||||
@@ -986,7 +986,32 @@ function renderDefaultState({
|
||||
],
|
||||
);
|
||||
})()
|
||||
: '',
|
||||
: isConnectionNode
|
||||
? (() => {
|
||||
const selectedOutbound = section.outbounds.find(
|
||||
(o) => o.selected,
|
||||
);
|
||||
if (!selectedOutbound) return '';
|
||||
const connectionTitle =
|
||||
(section.action &&
|
||||
CONNECTION_ACTION_LABELS[section.action]) ||
|
||||
selectedOutbound.displayName;
|
||||
if (
|
||||
section.displayName.toLowerCase().trim() ===
|
||||
connectionTitle.toLowerCase().trim()
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
return E(
|
||||
'span',
|
||||
{
|
||||
style:
|
||||
'font-size: 13px; font-weight: normal; margin-left: 8px; opacity: 0.7;',
|
||||
},
|
||||
connectionTitle,
|
||||
);
|
||||
})()
|
||||
: '',
|
||||
],
|
||||
),
|
||||
E(
|
||||
|
||||
@@ -527,4 +527,81 @@ describe('renderSections', () => {
|
||||
expect(prefixBadge).not.toBeNull();
|
||||
expect(prefixBadge?.textContent).toBe('Geodema Network');
|
||||
});
|
||||
|
||||
it('renders connection node (AWG) with collapsible header and check connection action', () => {
|
||||
const section: any = {
|
||||
sectionName: 'AWG',
|
||||
displayName: 'AMNEZIA',
|
||||
action: 'awg',
|
||||
outbounds: [
|
||||
{
|
||||
code: 'awg-out',
|
||||
displayName: 'AmneziaWG 3.0',
|
||||
latency: 155,
|
||||
runtimeAvailable: true,
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 1. Collapsed state
|
||||
const collapsedEl = renderSections({
|
||||
loading: false,
|
||||
failed: false,
|
||||
section,
|
||||
isCollapsed: true,
|
||||
onTestLatency: vi.fn(),
|
||||
onChooseOutbound: vi.fn(),
|
||||
onCopyOutbound: vi.fn(),
|
||||
onShowUrlTestInfo: vi.fn(),
|
||||
onShowPriorityInfo: vi.fn(),
|
||||
onUpdateSubscription: vi.fn(),
|
||||
latencyFetching: false,
|
||||
subscriptionUpdating: false,
|
||||
});
|
||||
|
||||
const titleSec = collapsedEl.querySelector(
|
||||
'.tachyon_dashboard-page__outbound-section__title-section',
|
||||
);
|
||||
expect(titleSec).not.toBeNull();
|
||||
expect(titleSec?.textContent).toContain('AMNEZIA');
|
||||
expect(titleSec?.textContent).toContain('AmneziaWG');
|
||||
expect(titleSec?.textContent).toContain('155ms');
|
||||
expect(titleSec?.textContent).toContain('Check Connection');
|
||||
expect(
|
||||
collapsedEl.querySelector('.tachyon_dashboard-page__outbound-grid'),
|
||||
).toBeNull();
|
||||
|
||||
// 2. Expanded state
|
||||
const expandedEl = renderSections({
|
||||
loading: false,
|
||||
failed: false,
|
||||
section,
|
||||
isCollapsed: false,
|
||||
onTestLatency: vi.fn(),
|
||||
onChooseOutbound: vi.fn(),
|
||||
onCopyOutbound: vi.fn(),
|
||||
onShowUrlTestInfo: vi.fn(),
|
||||
onShowPriorityInfo: vi.fn(),
|
||||
onUpdateSubscription: vi.fn(),
|
||||
latencyFetching: false,
|
||||
subscriptionUpdating: false,
|
||||
});
|
||||
|
||||
const expandedTitleSec = expandedEl.querySelector(
|
||||
'.tachyon_dashboard-page__outbound-section__title-section',
|
||||
);
|
||||
expect(expandedTitleSec).not.toBeNull();
|
||||
expect(expandedTitleSec?.textContent).toContain('AMNEZIA');
|
||||
expect(expandedTitleSec?.textContent).toContain('AmneziaWG');
|
||||
expect(expandedTitleSec?.textContent).toContain('Check Connection');
|
||||
|
||||
const grid = expandedEl.querySelector(
|
||||
'.tachyon_dashboard-page__outbound-grid',
|
||||
);
|
||||
expect(grid).not.toBeNull();
|
||||
expect(grid?.textContent).toContain('Connected');
|
||||
expect(grid?.textContent).toContain('AmneziaWG 3.0');
|
||||
expect(grid?.textContent).toContain('155 ms');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user