Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "qortium-node",
"version": "1.4.3",
"version": "1.4.4",
"private": true,
"license": "0BSD",
"description": "A QDN app for inspecting a Qortium node.",
Expand Down
17 changes: 14 additions & 3 deletions src/settingsEditor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('settings editor helpers', () => {
minPeerVersion: { restartRequired: true, type: 'PEER_VERSION' },
maxStorageCapacity: { restartRequired: false, type: 'LONG' },
storagePolicy: { restartRequired: false, type: 'STORAGE_POLICY' },
uPnPEnabled: { restartRequired: true, type: 'BOOLEAN' },
},
};

Expand All @@ -40,6 +41,8 @@ describe('settings editor helpers', () => {
expect(normalizeEditableSettingValue('autoUpdateMode', 'NOTIFY')).toBe('NOTIFY');
expect(normalizeEditableSettingValue('autoUpdateMode', 'BAD')).toBe('OFF');
expect(normalizeEditableSettingValue('autoRestartEnabled', undefined)).toBe(false);
expect(normalizeEditableSettingValue('uPnPEnabled', undefined)).toBe(true);
expect(normalizeEditableSettingValue('uPnPEnabled', false)).toBe(false);
expect(normalizeEditableSettingValue('listenPort', '25000')).toBe(25000);
expect(normalizeEditableSettingValue('listenPort', '65536')).toBe(null);
expect(normalizeEditableSettingValue('minOutboundPeers', '0')).toBe(0);
Expand All @@ -53,12 +56,16 @@ describe('settings editor helpers', () => {
expect(normalizeEditableSettingValue('maxStorageCapacity', '123.5')).toBe(null);
});

it('maps transport dropdown selections to ordered Core transport arrays', () => {
it('maps transport capability selections regardless of Core array order', () => {
expect(getTransportSelectionValue(['IP'])).toBe('IP');
expect(getTransportSelectionValue(['IP', 'I2P'])).toBe('IP+I2P');
expect(getTransportSelectionValue(['I2P', 'IP'])).toBe('I2P+IP');
// Legacy I2P-preferred ordering still selects the combined option
expect(getTransportSelectionValue(['I2P', 'IP'])).toBe('IP+I2P');
expect(getTransportSelectionValue(['I2P'])).toBe('I2P');
expect(getTransportSelectionTransports('I2P+IP')).toEqual(['I2P', 'IP']);
expect(getTransportSelectionTransports('IP+I2P')).toEqual(['IP', 'I2P']);
expect(getTransportSelectionTransports('I2P')).toEqual(['I2P']);
// Retired ordering variant falls back to the combined option
expect(getTransportSelectionTransports('I2P+IP')).toEqual(['IP', 'I2P']);
});

it('formats and parses user-facing storage and chat retention units', () => {
Expand Down Expand Up @@ -127,6 +134,9 @@ describe('settings editor helpers', () => {
expect(canEditSetting('minDataPeers', metadata, true, false)).toBe(true);
expect(canEditSetting('minPeerVersion', metadata, true, false)).toBe(true);
expect(canEditSetting('maxStorageCapacity', metadata, true, false)).toBe(true);
expect(canEditSetting('uPnPEnabled', metadata, true, false)).toBe(true);
// Older Cores without uPnPEnabled in writable metadata stay read-only
expect(canEditSetting('uPnPEnabled', { writable: {} }, true, false)).toBe(false);
expect(canEditSetting('storagePolicy', metadata, false, false)).toBe(false);
expect(canEditSetting('storagePolicy', metadata, true, true)).toBe(false);
expect(canEditSetting('qdnEnabled', metadata, true, false)).toBe(false);
Expand All @@ -138,5 +148,6 @@ describe('settings editor helpers', () => {
it('detects restart-required settings in a patch', () => {
expect(patchHasRestartRequiredSettings({ storagePolicy: 'NONE' }, metadata)).toBe(false);
expect(patchHasRestartRequiredSettings({ allowedTransports: ['IP'] }, metadata)).toBe(true);
expect(patchHasRestartRequiredSettings({ uPnPEnabled: false }, metadata)).toBe(true);
});
});
17 changes: 13 additions & 4 deletions src/settingsEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ export const STORAGE_POLICY_OPTIONS = [
] as const;

export const TRANSPORT_OPTIONS = ['IP', 'I2P'] as const;
// Capability set only: Core treats transport order as a soft preference with
// reserved dial slots for the other transport (core PR #191), so the old
// "IP + I2P" vs "I2P + IP" ordering choice no longer changes behaviour enough
// to be worth the confusion.
export const TRANSPORT_SELECTION_OPTIONS = [
{ label: 'IP', transports: ['IP'] },
{ label: 'IP only', transports: ['IP'] },
{ label: 'IP + I2P', transports: ['IP', 'I2P'] },
{ label: 'I2P + IP', transports: ['I2P', 'IP'] },
{ label: 'I2P', transports: ['I2P'] },
{ label: 'I2P only', transports: ['I2P'] },
] as const;
export const AUTO_UPDATE_MODE_OPTIONS = ['OFF', 'CHECK_ONLY', 'NOTIFY', 'INSTALL'] as const;
export const STORAGE_CAPACITY_GIGABYTE_BYTES = 1_000_000_000;
Expand Down Expand Up @@ -47,6 +50,7 @@ export const PHASE_1_EDITABLE_SETTING_KEYS = [
'minDataPeers',
'minPeerVersion',
'allowConnectionsWithOlderPeerVersions',
'uPnPEnabled',
'qdnEnabled',
'storagePolicy',
'maxStorageCapacity',
Expand Down Expand Up @@ -89,6 +93,7 @@ const BOOLEAN_DEFAULTS: Record<BooleanEditableSettingKey, boolean> = {
publicDataEnabled: true,
qdnEnabled: true,
qdnPushOnPublishEnabled: true,
uPnPEnabled: true,
};

export function isPhase1EditableSetting(key: string): key is Phase1EditableSettingKey {
Expand Down Expand Up @@ -180,8 +185,12 @@ export function patchHasRestartRequiredSettings(patch: SettingsPatch, metadata:
}

export function getTransportSelectionValue(value: unknown) {
// Order-insensitive: ['I2P', 'IP'] (the legacy I2P-preferred ordering) still
// selects the combined option instead of falling back.
const transports = normalizeTransportList(value);
const serializedTransports = transports.join('+');
const serializedTransports = [...TRANSPORT_OPTIONS]
.filter((transport) => transports.includes(transport))
.join('+');

return TRANSPORT_SELECTION_OPTIONS.some((option) => option.transports.join('+') === serializedTransports)
? serializedTransports
Expand Down
2 changes: 2 additions & 0 deletions src/settingsView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ describe('settings view helpers', () => {
publicDataEnabled: true,
qdnEnabled: true,
storagePolicy: 'FOLLOWED_OR_VIEWED',
uPnPEnabled: true,
zUnknownSetting: true,
},
);
Expand All @@ -81,6 +82,7 @@ describe('settings view helpers', () => {
'minDataPeers',
'minPeerVersion',
'allowConnectionsWithOlderPeerVersions',
'uPnPEnabled',
'qdnEnabled',
'storagePolicy',
'maxStorageCapacity',
Expand Down