Adds an option to ignore return wormholes for auto-indexing and use a custom symbol instead. This also fixes chained index formatting for system auto-tags and labels.

- feat(bookmarks): Add settings to ignore return holes and use a custom symbol for auto-indexing
- feat(settings): Add a `dependsOn` property to conditionally render settings
- fix(systems): Correctly apply chained index formats for auto-tag and custom label
- refactor(bookmarks): Pass target system info to `handleAutoBookmark` for return hole detection
This commit is contained in:
Drew Bonasera
2026-05-01 06:57:17 -04:00
parent 702cb39679
commit 0a44a1403e
8 changed files with 163 additions and 70 deletions
@@ -36,6 +36,10 @@ export const useLinkSignature = ({ data, targetSystemClassGroup }: UseLinkSignat
const sourceSystem = systems.find((s: any) => s.system_static_info?.solar_system_id === data.solar_system_source);
const systemUuid = sourceSystem?.id || data.solar_system_source.toString();
const targetSystem = systems.find((s: any) => s.system_static_info?.solar_system_id === data.solar_system_target);
const targetSystemUuid = targetSystem?.id;
const targetSolarSystemIdStr = data.solar_system_target?.toString();
const signatureToLink = { ...signature, group: SignatureGroup.Wormhole };
const { updatedSignature, shouldUpdate } = await handleAutoBookmark(
@@ -46,6 +50,8 @@ export const useLinkSignature = ({ data, targetSystemClassGroup }: UseLinkSignat
data.solar_system_source.toString(),
wormholesData,
targetSystemClassGroup,
targetSystemUuid,
targetSolarSystemIdStr,
);
if (shouldUpdate) {
@@ -73,69 +79,70 @@ export const useLinkSignature = ({ data, targetSystemClassGroup }: UseLinkSignat
if (systemAutoTag || systemCustomLabelName) {
const info = parseSignatureCustomInfo(updatedSignature.custom_info);
const bIndex = info.bookmark_index ?? 0;
const startAtZero = userSettings?.bookmark_wormholes_start_at_zero;
const letter = numberToLetters(bIndex, startAtZero);
const targetSystem = systems.find(
(s: any) => s.system_static_info?.solar_system_id === data.solar_system_target,
);
if (info.bookmark_index !== undefined) {
const bIndex = info.bookmark_index;
const startAtZero = userSettings?.bookmark_wormholes_start_at_zero;
const letter = numberToLetters(bIndex, startAtZero);
if (targetSystem) {
if (systemAutoTag) {
let tagValue = '';
switch (systemAutoTag) {
case 'index':
case 'chain_index':
tagValue = bIndex.toString();
break;
case 'index_letter':
tagValue = letter;
break;
case 'chain_index_letters':
tagValue = info.bookmark_index_chained_letters === letter ? letter : bIndex.toString();
break;
if (targetSystem) {
if (systemAutoTag) {
let tagValue = '';
switch (systemAutoTag) {
case 'index':
tagValue = bIndex.toString();
break;
case 'chain_index':
tagValue = (info.bookmark_index_chained as string) || bIndex.toString();
break;
case 'index_letter':
tagValue = letter;
break;
case 'chain_index_letters':
tagValue = (info.bookmark_index_chained_letters as string) || letter;
break;
}
if (tagValue) {
await outCommand({
type: OutCommand.updateSystemTag,
data: {
system_id: targetSystem.id,
value: tagValue,
},
});
}
}
if (tagValue) {
await outCommand({
type: OutCommand.updateSystemTag,
data: {
system_id: targetSystem.id,
value: tagValue,
},
});
}
}
if (systemCustomLabelName) {
let labelValue = '';
switch (systemCustomLabelName) {
case 'index':
labelValue = bIndex.toString();
break;
case 'index_letter':
labelValue = letter;
break;
case 'chain_index':
labelValue = (info.bookmark_index_chained as string) || bIndex.toString();
break;
case 'chain_index_letters':
labelValue = (info.bookmark_index_chained_letters as string) || letter;
break;
}
if (systemCustomLabelName) {
let labelValue = '';
switch (systemCustomLabelName) {
case 'index':
labelValue = bIndex.toString();
break;
case 'index_letter':
labelValue = letter;
break;
case 'chain_index':
labelValue = (info.bookmark_index_chained as string) || bIndex.toString();
break;
case 'chain_index_letters':
labelValue = (info.bookmark_index_chained_letters as string) || letter;
break;
}
if (labelValue) {
const outLabel = new LabelsManager(targetSystem.labels ?? '');
outLabel.updateCustomLabel(labelValue);
if (labelValue) {
const outLabel = new LabelsManager(targetSystem.labels ?? '');
outLabel.updateCustomLabel(labelValue);
await outCommand({
type: OutCommand.updateSystemLabels,
data: {
system_id: targetSystem.id,
value: outLabel.toString(),
},
});
await outCommand({
type: OutCommand.updateSystemLabels,
data: {
system_id: targetSystem.id,
value: outLabel.toString(),
},
});
}
}
}
}
@@ -80,6 +80,13 @@ export const MapSettingsProvider = ({ children }: WithChildren) => {
const renderSettingItem = useCallback(
(item: SettingsListItem) => {
if (item.dependsOn) {
const dependsOnValue = refVars.current.mergedSettings[item.dependsOn];
if (!dependsOnValue) {
return null;
}
}
const currentValue = refVars.current.mergedSettings[item.prop];
if (item.type === 'checkbox') {
@@ -13,6 +13,8 @@ export const DEFAULT_REMOTE_SETTINGS = {
[UserSettingsRemoteProps.bookmark_auto_temp_name]: '',
[UserSettingsRemoteProps.system_auto_tag]: '',
[UserSettingsRemoteProps.system_custom_label_name]: '',
[UserSettingsRemoteProps.bookmark_return_hole_ignore]: false,
[UserSettingsRemoteProps.bookmark_return_hole_symbol]: '',
};
export const AUTO_FORMAT_OPTIONS = [
@@ -34,6 +36,8 @@ export const UserSettingsRemoteList = [
UserSettingsRemoteProps.bookmark_auto_temp_name,
UserSettingsRemoteProps.system_auto_tag,
UserSettingsRemoteProps.system_custom_label_name,
UserSettingsRemoteProps.bookmark_return_hole_ignore,
UserSettingsRemoteProps.bookmark_return_hole_symbol,
];
// export const COMMON_CHECKBOXES_PROPS: SettingsListItem[] = [
@@ -81,6 +85,17 @@ export const BOOKMARKS_SETTINGS_PROPS: SettingsListItem[] = [
label: 'Start wormhole indices at 0',
type: 'checkbox',
},
{
prop: UserSettingsRemoteProps.bookmark_return_hole_ignore,
label: 'Ignore return hole when creating indexes',
type: 'checkbox',
},
{
prop: UserSettingsRemoteProps.bookmark_return_hole_symbol,
label: 'Return hole symbol (use space for empty)',
type: 'text',
dependsOn: UserSettingsRemoteProps.bookmark_return_hole_ignore,
},
{
prop: UserSettingsRemoteProps.bookmark_auto_temp_name,
label: 'Auto-fill wormhole temporary name',
@@ -11,6 +11,8 @@ export enum UserSettingsRemoteProps {
bookmark_auto_temp_name = 'bookmark_auto_temp_name',
system_auto_tag = 'system_auto_tag',
system_custom_label_name = 'system_custom_label_name',
bookmark_return_hole_ignore = 'bookmark_return_hole_ignore',
bookmark_return_hole_symbol = 'bookmark_return_hole_symbol',
}
export type UserSettingsRemote = {
@@ -24,6 +26,8 @@ export type UserSettingsRemote = {
bookmark_auto_temp_name: string;
system_auto_tag: string;
system_custom_label_name: string;
bookmark_return_hole_ignore: boolean;
bookmark_return_hole_symbol: string;
};
export type UserSettings = UserSettingsRemote & InterfaceStoredSettings;
@@ -35,4 +39,5 @@ export type SettingsListItem = {
options?: { label: string; value: string }[];
placeholder?: string;
helperText?: string;
dependsOn?: keyof UserSettings;
};
@@ -129,6 +129,9 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
const targetSystemClassGroup = targetSystem?.system_static_info
? getSystemClassGroup(targetSystem.system_static_info.system_class)
: null;
const targetSystemUuid = targetSystem?.id;
const targetSolarSystemIdStr =
targetSystem?.system_static_info?.solar_system_id?.toString() || values.linked_system;
const currentSystem = systems.find((s: any) => s.id === systemId);
const solarSystemIdStr = currentSystem?.system_static_info?.solar_system_id?.toString() || systemId;
@@ -141,6 +144,8 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
solarSystemIdStr,
wormholesData,
targetSystemClassGroup,
targetSystemUuid,
targetSolarSystemIdStr,
);
out = updatedSignature;
}
@@ -110,6 +110,10 @@ export const calculateBookmarkIndex = (
const parentSigs = sigs.filter(sig => sig.linked_system?.solar_system_id?.toString() === currentSolarSystemId);
for (const parentSig of parentSigs) {
const parentInfo = parseSignatureCustomInfo(parentSig.custom_info);
// Return holes have their bookmark_index deleted, so we skip them to avoid hijacking the chain
if (parentInfo.bookmark_index === undefined) continue;
if (parentInfo.bookmark_index_chained != null) {
if (!parentBookmarkIndex || String(parentInfo.bookmark_index_chained).length < parentBookmarkIndex.length) {
parentBookmarkIndex = String(parentInfo.bookmark_index_chained);
@@ -162,7 +166,7 @@ export const formatBookmarkName = (
formatStr: string,
signature: SystemSignature,
destSystemClass: string | null,
bookmarkIndex: number,
bookmarkIndex: number | string,
wormholesData: Record<string, WormholeDataRaw> = {},
startAtZero: boolean = false,
mapping?: Record<string, string>,
@@ -180,12 +184,17 @@ export const formatBookmarkName = (
result = result.replace(/\{chain_index\}/g, () => info.bookmark_index_chained || bookmarkIndex.toString());
// Replace {index_letter}
result = result.replace(/\{index_letter\}/g, () => numberToLetters(bookmarkIndex, startAtZero));
result = result.replace(/\{index_letter\}/g, () =>
typeof bookmarkIndex === 'number' ? numberToLetters(bookmarkIndex, startAtZero) : bookmarkIndex.toString(),
);
// Replace {chain_index_letters}
result = result.replace(
/\{chain_index_letters\}/g,
() => info.bookmark_index_chained_letters || info.bookmark_index_chained || bookmarkIndex.toString(),
() =>
info.bookmark_index_chained_letters ||
info.bookmark_index_chained ||
(typeof bookmarkIndex === 'number' ? numberToLetters(bookmarkIndex, startAtZero) : bookmarkIndex.toString()),
);
// Replace {sig_letters} (first 3 chars of eve_id)
@@ -365,6 +374,8 @@ export const handleAutoBookmark = async (
currentSolarSystemId: string,
wormholesData: Record<string, WormholeDataRaw>,
targetSystemClassGroup: string | null,
targetSystemUuid?: string,
targetSolarSystemId?: string,
): Promise<{ updatedSignature: SystemSignature; shouldUpdate: boolean }> => {
let updatedSignature = signature;
let shouldUpdate = false;
@@ -378,8 +389,39 @@ export const handleAutoBookmark = async (
const info = parseSignatureCustomInfo(signature.custom_info);
let bookmarkIndex = info.bookmark_index;
let bookmarkIndexToUse: number | string = bookmarkIndex != null ? bookmarkIndex : '';
if (bookmarkIndex == null) {
let isReturnHole = false;
let symbol = '';
if (currentSettings?.bookmark_return_hole_ignore && (targetSystemUuid || targetSolarSystemId)) {
const targetSigsRaw = [
...(targetSystemUuid ? systemSignatures[targetSystemUuid] || [] : []),
...(targetSolarSystemId ? systemSignatures[targetSolarSystemId] || [] : []),
];
const uniqueTargetSigs = Array.from(new Map(targetSigsRaw.map(sig => [sig.eve_id, sig])).values());
isReturnHole = uniqueTargetSigs.some(
sig => sig.linked_system?.solar_system_id?.toString() === currentSolarSystemId.toString(),
);
if (isReturnHole) {
symbol = currentSettings.bookmark_return_hole_symbol || '';
if (symbol === ' ') symbol = '';
}
}
if (isReturnHole) {
if (info.bookmark_index !== undefined) {
delete info.bookmark_index;
}
info.bookmark_index_chained = symbol;
info.bookmark_index_chained_letters = symbol;
bookmarkIndexToUse = symbol;
updatedSignature = { ...signature, custom_info: JSON.stringify(info) };
shouldUpdate = true;
} else if (bookmarkIndex == null) {
const separator = currentSettings?.bookmark_custom_mapping?.chain_separator || '';
const calculated = calculateBookmarkIndex(
systemSignatures,
@@ -393,27 +435,35 @@ export const handleAutoBookmark = async (
info.bookmark_index = calculated.index;
info.bookmark_index_chained = calculated.chained;
info.bookmark_index_chained_letters = calculated.chainedLetters;
bookmarkIndexToUse = calculated.index;
updatedSignature = { ...signature, custom_info: JSON.stringify(info) };
shouldUpdate = true;
}
if (currentSettings?.bookmark_auto_temp_name && !updatedSignature.temporary_name) {
const needsTempNameUpdate =
!updatedSignature.temporary_name ||
(isReturnHole && updatedSignature.temporary_name !== symbol && currentSettings?.bookmark_auto_temp_name);
if (currentSettings?.bookmark_auto_temp_name && needsTempNameUpdate) {
let autoName = '';
switch (currentSettings.bookmark_auto_temp_name) {
case 'index':
autoName = bookmarkIndex.toString();
autoName = bookmarkIndexToUse.toString();
break;
case 'index_letter':
autoName = numberToLetters(bookmarkIndex, currentSettings.bookmark_wormholes_start_at_zero);
autoName =
typeof bookmarkIndexToUse === 'number'
? numberToLetters(bookmarkIndexToUse, currentSettings.bookmark_wormholes_start_at_zero)
: bookmarkIndexToUse.toString();
break;
case 'chain_index':
autoName = info.bookmark_index_chained || bookmarkIndex.toString();
autoName = info.bookmark_index_chained || bookmarkIndexToUse.toString();
break;
case 'chain_index_letters':
autoName = info.bookmark_index_chained_letters || info.bookmark_index_chained || bookmarkIndex.toString();
autoName = info.bookmark_index_chained_letters || info.bookmark_index_chained || bookmarkIndexToUse.toString();
break;
}
if (autoName) {
if (autoName !== '' || isReturnHole) {
updatedSignature = { ...updatedSignature, temporary_name: autoName };
shouldUpdate = true;
}
@@ -424,7 +474,7 @@ export const handleAutoBookmark = async (
currentSettings.bookmark_name_format,
updatedSignature,
targetSystemClassGroup,
bookmarkIndex,
bookmarkIndexToUse,
wormholesData,
currentSettings.bookmark_wormholes_start_at_zero,
currentSettings.bookmark_custom_mapping,
@@ -9,7 +9,9 @@ defmodule WandererApp.MapUserSettingsRepo do
"bookmark_name_format" => "",
"bookmark_custom_mapping" => %{},
"system_auto_tag" => "",
"system_custom_label_name" => ""
"system_custom_label_name" => "",
"bookmark_return_hole_ignore" => false,
"bookmark_return_hole_symbol" => ""
}
def get(map_id, user_id) do
@@ -242,7 +242,9 @@ defmodule WandererAppWeb.MapCoreEventHandler do
"bookmark_auto_copy",
"bookmark_auto_temp_name",
"system_auto_tag",
"system_custom_label_name"
"system_custom_label_name",
"bookmark_return_hole_ignore",
"bookmark_return_hole_symbol"
])
|> Jason.encode!()