Compare commits

..

3 Commits

Author SHA1 Message Date
Dmitry Popov
d38c828600 chore: release version v1.3.1 2024-10-09 13:12:57 +04:00
Dmitry Popov
24196efbac fix(Core): Add system "true security" correction 2024-10-09 12:55:39 +04:00
Dmitry Popov
83c76e3a67 chore: release version v1.3.1 2024-10-08 02:35:33 +04:00
73 changed files with 416 additions and 2147 deletions

View File

@@ -2,111 +2,6 @@
<!-- changelog --> <!-- changelog -->
## [v1.11.0](https://github.com/wanderer-industries/wanderer/compare/v1.10.0...v1.11.0) (2024-10-14)
### Features:
* Map: Add map level option to store custom labels
## [v1.10.0](https://github.com/wanderer-industries/wanderer/compare/v1.9.0...v1.10.0) (2024-10-13)
### Features:
* Map: Link signature on splash
## [v1.9.0](https://github.com/wanderer-industries/wanderer/compare/v1.8.0...v1.9.0) (2024-10-13)
### Features:
* Map: Link signature on splash
## [v1.8.0](https://github.com/wanderer-industries/wanderer/compare/v1.7.0...v1.8.0) (2024-10-13)
### Features:
* Map: Link signature on splash
## [v1.7.0](https://github.com/wanderer-industries/wanderer/compare/v1.6.0...v1.7.0) (2024-10-13)
### Features:
* Map: Link signature on splash
## [v1.6.0](https://github.com/wanderer-industries/wanderer/compare/v1.5.0...v1.6.0) (2024-10-13)
### Features:
* Map: Link signature on splash
## [v1.5.0](https://github.com/wanderer-industries/wanderer/compare/v1.4.0...v1.5.0) (2024-10-11)
### Features:
* Map: Follow Character on Map and auto select their current system
## [v1.4.0](https://github.com/wanderer-industries/wanderer/compare/v1.3.6...v1.4.0) (2024-10-11)
### Features:
* Map: Follow Character on Map and auto select their current system
## [v1.3.6](https://github.com/wanderer-industries/wanderer/compare/v1.3.5...v1.3.6) (2024-10-09)
### Bug Fixes:
* Signatures: Signatures update fixes
## [v1.3.5](https://github.com/wanderer-industries/wanderer/compare/v1.3.4...v1.3.5) (2024-10-09)
### Bug Fixes:
* Signatures: Signatures update fixes
## [v1.3.4](https://github.com/wanderer-industries/wanderer/compare/v1.3.3...v1.3.4) (2024-10-09)
## [v1.3.3](https://github.com/wanderer-industries/wanderer/compare/v1.3.2...v1.3.3) (2024-10-08)
## [v1.3.2](https://github.com/wanderer-industries/wanderer/compare/v1.3.1...v1.3.2) (2024-10-07)
## [v1.3.1](https://github.com/wanderer-industries/wanderer/compare/v1.3.0...v1.3.1) (2024-10-07) ## [v1.3.1](https://github.com/wanderer-industries/wanderer/compare/v1.3.0...v1.3.1) (2024-10-07)

View File

@@ -28,12 +28,6 @@ body {
font-weight: 500; font-weight: 500;
} }
#bg-canvas {
position: absolute;
width: 100vw;
height: 100vh;
}
.ccp-font { .ccp-font {
font-family: 'Shentox', 'Rogan', sans-serif !important; font-family: 'Shentox', 'Rogan', sans-serif !important;
} }

View File

@@ -11,7 +11,7 @@ const Characters = ({ data }: { data: CharacterTypeRaw[] }) => {
const handleSelect = useCallback( const handleSelect = useCallback(
(character: CharacterTypeRaw) => { (character: CharacterTypeRaw) => {
mapRef.current?.command(Commands.centerSystem, character?.location?.solar_system_id?.toString()); mapRef.current?.command(Commands.selectSystem, character?.location?.solar_system_id?.toString());
}, },
[mapRef], [mapRef],
); );

View File

@@ -46,7 +46,7 @@ export const useLabelsMenu = (
} }
// const labels = getLabels(system.labels); // const labels = getLabels(system.labels);
const hasLabels = labels?.list?.length > 0; const hasLabels = labels.list.length > 0;
const statusList = hasLabels ? LABELS_ORDER : LABELS_ORDER.slice(1); const statusList = hasLabels ? LABELS_ORDER : LABELS_ORDER.slice(1);
return [ return [

View File

@@ -48,19 +48,19 @@ export const useContextMenuSystemInfoHandlers = ({ hubs, outCommand, mapRef }: U
}, []); }, []);
const onAddSystem = useCallback(() => { const onAddSystem = useCallback(() => {
const { system: solarSystemId, outCommand, mapRef } = ref.current; const { system, outCommand, mapRef } = ref.current;
if (!solarSystemId) { if (!system) {
return; return;
} }
outCommand({ outCommand({
type: OutCommand.addSystem, type: OutCommand.addSystem,
data: { data: {
system_id: solarSystemId, system_id: system,
}, },
}); });
setTimeout(() => { setTimeout(() => {
mapRef.current?.command(Commands.centerSystem, solarSystemId); mapRef.current?.command(Commands.selectSystem, system);
setSystem(undefined); setSystem(undefined);
}, 200); }, 200);
}, []); }, []);

View File

@@ -29,7 +29,7 @@ const SpaceToClass: Record<string, string> = {
}; };
const sortedLabels = (labels: string[]) => { const sortedLabels = (labels: string[]) => {
if (!labels) { if (labels === null) {
return []; return [];
} }

View File

@@ -5,6 +5,5 @@ export * from './useMapRemoveSystems';
export * from './useCommandsCharacters'; export * from './useCommandsCharacters';
export * from './useCommandsConnections'; export * from './useCommandsConnections';
export * from './useCommandsConnections'; export * from './useCommandsConnections';
export * from './useCenterSystem';
export * from './useSelectSystem'; export * from './useSelectSystem';
export * from './useMapCommands'; export * from './useMapCommands';

View File

@@ -1,18 +0,0 @@
import { useReactFlow } from 'reactflow';
import { useCallback, useRef } from 'react';
import { CommandCenterSystem } from '@/hooks/Mapper/types';
export const useCenterSystem = () => {
const rf = useReactFlow();
const ref = useRef({ rf });
ref.current = { rf };
return useCallback((systemId: CommandCenterSystem) => {
const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
if (!systemNode) {
return;
}
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
}, []);
};

View File

@@ -4,18 +4,18 @@ import { CommandSelectSystem } from '@/hooks/Mapper/types';
export const useSelectSystem = () => { export const useSelectSystem = () => {
const rf = useReactFlow(); const rf = useReactFlow();
const ref = useRef({ rf }); const ref = useRef({ rf });
ref.current = { rf }; ref.current = { rf };
return useCallback((systemId: CommandSelectSystem) => { return useCallback((systemId: CommandSelectSystem) => {
ref.current.rf.setNodes(nds => if (!ref.current?.rf) {
nds.map(node => { return;
return { }
...node, const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
selected: node.id === systemId, if (!systemNode) {
}; return;
}), }
);
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
}, []); }, []);
}; };

View File

@@ -1,4 +1,4 @@
import { ForwardedRef, useImperativeHandle, useRef } from 'react'; import { ForwardedRef, useImperativeHandle } from 'react';
import { import {
CommandAddConnections, CommandAddConnections,
CommandAddSystems, CommandAddSystems,
@@ -26,7 +26,6 @@ import {
useMapInit, useMapInit,
useMapRemoveSystems, useMapRemoveSystems,
useMapUpdateSystems, useMapUpdateSystems,
useCenterSystem,
useSelectSystem, useSelectSystem,
} from './api'; } from './api';
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts'; import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
@@ -36,12 +35,8 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
const mapAddSystems = useMapAddSystems(); const mapAddSystems = useMapAddSystems();
const mapUpdateSystems = useMapUpdateSystems(); const mapUpdateSystems = useMapUpdateSystems();
const removeSystems = useMapRemoveSystems(onSelectionChange); const removeSystems = useMapRemoveSystems(onSelectionChange);
const centerSystem = useCenterSystem();
const selectSystem = useSelectSystem(); const selectSystem = useSelectSystem();
const selectRef = useRef({ onSelectionChange });
selectRef.current = { onSelectionChange };
const { addConnections, removeConnections, updateConnection } = useCommandsConnections(); const { addConnections, removeConnections, updateConnection } = useCommandsConnections();
const { mapUpdated, killsUpdated } = useMapCommands(); const { mapUpdated, killsUpdated } = useMapCommands();
const { charactersUpdated, presentCharacters, characterAdded, characterRemoved, characterUpdated } = const { charactersUpdated, presentCharacters, characterAdded, characterRemoved, characterUpdated } =
@@ -96,32 +91,14 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
killsUpdated(data as CommandKillsUpdated); killsUpdated(data as CommandKillsUpdated);
break; break;
case Commands.centerSystem:
setTimeout(() => {
const systemId = `${data}`;
centerSystem(systemId as CommandSelectSystem);
}, 100);
break;
case Commands.selectSystem: case Commands.selectSystem:
setTimeout(() => { selectSystem(data as CommandSelectSystem);
const systemId = `${data}`;
selectRef.current.onSelectionChange({
systems: [systemId],
connections: [],
});
selectSystem(systemId as CommandSelectSystem);
}, 100);
break; break;
case Commands.routes: case Commands.routes:
// do nothing here // do nothing here
break; break;
case Commands.linkSignatureToSystem:
// do nothing here
break;
default: default:
console.warn(`Map handlers: Unknown command: ${type}`, data); console.warn(`Map handlers: Unknown command: ${type}`, data);
break; break;

View File

@@ -7,7 +7,7 @@ import { Button } from 'primereact/button';
import { OutCommand } from '@/hooks/Mapper/types'; import { OutCommand } from '@/hooks/Mapper/types';
import { IconField } from 'primereact/iconfield'; import { IconField } from 'primereact/iconfield';
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts'; import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
import { WdImageSize, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit'; import { WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
interface SystemCustomLabelDialog { interface SystemCustomLabelDialog {
systemId: string; systemId: string;
@@ -79,14 +79,14 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
// @ts-ignore // @ts-ignore
const handleInput = useCallback(e => { const handleInput = useCallback(e => {
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, ''); e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
}, []); }, []);
return ( return (
<Dialog <Dialog
header="Edit label" header="Edit label"
visible={visible} visible={visible}
draggable={true} draggable={false}
style={{ width: '250px' }} style={{ width: '250px' }}
onHide={onHide} onHide={onHide}
onShow={onShow} onShow={onShow}
@@ -100,13 +100,9 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
<IconField> <IconField>
{label !== '' && ( {label !== '' && (
<WdImgButton <WdImgButton
className="pi pi-trash text-red-400" className="pi pi-trash p-input-icon"
textSize={WdImageSize.large} textSize={WdImageSize.large}
tooltip={{ tooltip={{ content: 'Reset label' }}
content: 'Remove custom label',
className: 'pi p-input-icon',
position: TooltipPosition.top,
}}
onClick={handleReset} onClick={handleReset}
/> />
)} )}
@@ -115,7 +111,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
aria-describedby="username-help" aria-describedby="username-help"
autoComplete="off" autoComplete="off"
value={label} value={label}
maxLength={5} maxLength={3}
onChange={e => setLabel(e.target.value)} onChange={e => setLabel(e.target.value)}
// @ts-expect-error // @ts-expect-error
ref={inputRef} ref={inputRef}

View File

@@ -1,68 +0,0 @@
import { useCallback, useRef } from 'react';
import { Dialog } from 'primereact/dialog';
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
import { SystemSignature } from '@/hooks/Mapper/types';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { CommandLinkSignatureToSystem } from '@/hooks/Mapper/types';
import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent';
import {
Setting,
COSMIC_SIGNATURE,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
interface SystemLinkSignatureDialogProps {
data: CommandLinkSignatureToSystem;
setVisible: (visible: boolean) => void;
}
const signatureSettings: Setting[] = [{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }];
export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignatureDialogProps) => {
const { outCommand } = useMapRootState();
const ref = useRef({ outCommand });
ref.current = { outCommand };
const handleHide = useCallback(() => {
setVisible(false);
}, [setVisible]);
const handleSelect = useCallback(
(signature: SystemSignature) => {
if (!signature) {
return;
}
const { outCommand } = ref.current;
outCommand({
type: OutCommand.linkSignatureToSystem,
data: {
...data,
signature_eve_id: signature.eve_id,
},
});
setVisible(false);
},
[data, setVisible],
);
return (
<Dialog
header="Select signature to link"
visible
draggable={false}
style={{ width: '500px' }}
onHide={handleHide}
contentClassName="!p-0"
>
<SystemSignaturesContent
systemId={`${data.solar_system_source}`}
settings={signatureSettings}
onSelect={handleSelect}
selectable={true}
/>
</Dialog>
);
};

View File

@@ -1 +0,0 @@
export * from './SystemLinkSignatureDialog';

View File

@@ -90,7 +90,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
}, []); }, []);
const handleInput = useCallback((e: any) => { const handleInput = useCallback((e: any) => {
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, ''); e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
}, []); }, []);
return ( return (
@@ -160,7 +160,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
aria-describedby="label" aria-describedby="label"
autoComplete="off" autoComplete="off"
value={label} value={label}
maxLength={5} maxLength={3}
onChange={e => setLabel(e.target.value)} onChange={e => setLabel(e.target.value)}
onInput={handleInput} onInput={handleInput}
/> />

View File

@@ -2,4 +2,3 @@ export * from './Widget';
export * from './WidgetsGrid'; export * from './WidgetsGrid';
export * from './SystemSettingsDialog'; export * from './SystemSettingsDialog';
export * from './SystemCustomLabelDialog'; export * from './SystemCustomLabelDialog';
export * from './SystemLinkSignatureDialog';

View File

@@ -91,7 +91,7 @@ export const RoutesList = ({ data, onContextMenu }: RoutesListProps) => {
const { mapRef } = useMapRootState(); const { mapRef } = useMapRootState();
const handleClick = useCallback( const handleClick = useCallback(
(systemId: number) => mapRef.current?.command(Commands.centerSystem, systemId.toString()), (systemId: number) => mapRef.current?.command(Commands.selectSystem, systemId.toString()),
[mapRef], [mapRef],
); );

View File

@@ -5,14 +5,6 @@ import { Checkbox } from 'primereact/checkbox';
export type Setting = { key: string; name: string; value: boolean }; export type Setting = { key: string; name: string; value: boolean };
export const COSMIC_SIGNATURE = 'Cosmic Signature';
export const COSMIC_ANOMALY = 'Cosmic Anomaly';
export const DEPLOYABLE = 'Deployable';
export const STRUCTURE = 'Structure';
export const STARBASE = 'Starbase';
export const SHIP = 'Ship';
export const DRONE = 'Drone';
interface SystemSignatureSettingsDialogProps { interface SystemSignatureSettingsDialogProps {
settings: Setting[]; settings: Setting[];
onSave: (settings: Setting[]) => void; onSave: (settings: Setting[]) => void;

View File

@@ -1,17 +1,7 @@
import { Widget } from '@/hooks/Mapper/components/mapInterface/components'; import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
import { InfoDrawer, LayoutEventBlocker, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit'; import { InfoDrawer, LayoutEventBlocker, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
import { SystemSignaturesContent } from './SystemSignaturesContent'; import { SystemSignaturesContent } from './SystemSignaturesContent';
import { import { Setting, SystemSignatureSettingsDialog } from './SystemSignatureSettingsDialog';
Setting,
SystemSignatureSettingsDialog,
COSMIC_SIGNATURE,
COSMIC_ANOMALY,
DEPLOYABLE,
STRUCTURE,
STARBASE,
SHIP,
DRONE,
} from './SystemSignatureSettingsDialog';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
@@ -19,6 +9,14 @@ import { PrimeIcons } from 'primereact/api';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
export const COSMIC_SIGNATURE = 'Cosmic Signature';
export const COSMIC_ANOMALY = 'Cosmic Anomaly';
export const DEPLOYABLE = 'Deployable';
export const STRUCTURE = 'Structure';
export const STARBASE = 'Starbase';
export const SHIP = 'Ship';
export const DRONE = 'Drone';
const settings: Setting[] = [ const settings: Setting[] = [
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true }, { key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true },
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }, { key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true },

View File

@@ -24,7 +24,6 @@ import {
renderIcon, renderIcon,
renderName, renderName,
renderTimeLeft, renderTimeLeft,
renderLinkedSystem,
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders'; } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
// import { PrimeIcons } from 'primereact/api'; // import { PrimeIcons } from 'primereact/api';
import useLocalStorageState from 'use-local-storage-state'; import useLocalStorageState from 'use-local-storage-state';
@@ -42,17 +41,13 @@ const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = {
interface SystemSignaturesContentProps { interface SystemSignaturesContentProps {
systemId: string; systemId: string;
settings: Setting[]; settings: Setting[];
selectable?: boolean;
onSelect?: (signature: SystemSignature) => void;
} }
export const SystemSignaturesContent = ({ systemId, settings, selectable, onSelect }: SystemSignaturesContentProps) => { export const SystemSignaturesContent = ({ systemId, settings }: SystemSignaturesContentProps) => {
const { outCommand } = useMapRootState(); const { outCommand } = useMapRootState();
const [signatures, setSignatures, signaturesRef] = useRefState<SystemSignature[]>([]); const [signatures, setSignatures, signaturesRef] = useRefState<SystemSignature[]>([]);
const [selectedSignatures, setSelectedSignatures] = useState<SystemSignature[]>([]); const [selectedSignatures, setSelectedSignatures] = useState<SystemSignature[]>([]);
const [nameColumnWidth, setNameColumnWidth] = useState('auto'); const [nameColumnWidth, setNameColumnWidth] = useState('auto');
const [parsedSignatures, setParsedSignatures] = useState<SystemSignature[]>([]);
const [askUser, setAskUser] = useState(false);
const [hoveredSig, setHoveredSig] = useState<SystemSignature | null>(null); const [hoveredSig, setHoveredSig] = useState<SystemSignature | null>(null);
@@ -91,33 +86,12 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
data: { system_id: systemId }, data: { system_id: systemId },
}); });
setAskUser(false);
setSignatures(signatures); setSignatures(signatures);
}, [outCommand, systemId]); }, [outCommand, systemId]);
// const updateSignatures = useCallback(
// async (newSignatures: SystemSignature[], updateOnly: boolean) => {
// const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly);
// const { signatures: updatedSignatures } = await outCommand({
// type: OutCommand.updateSignatures,
// data: {
// system_id: systemId,
// added,
// updated,
// removed,
// },
// });
// setSignatures(() => updatedSignatures);
// setSelectedSignatures([]);
// },
// [outCommand, systemId],
// );
const handleUpdateSignatures = useCallback( const handleUpdateSignatures = useCallback(
async (newSignatures: SystemSignature[], updateOnly: boolean) => { async (newSignatures: SystemSignature[]) => {
const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly); const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures);
const { signatures: updatedSignatures } = await outCommand({ const { signatures: updatedSignatures } = await outCommand({
type: OutCommand.updateSignatures, type: OutCommand.updateSignatures,
@@ -136,76 +110,37 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
); );
const handleDeleteSelected = useCallback(async () => { const handleDeleteSelected = useCallback(async () => {
if (selectable) {
return;
}
if (selectedSignatures.length === 0) { if (selectedSignatures.length === 0) {
return; return;
} }
const selectedSignaturesEveIds = selectedSignatures.map(x => x.eve_id); const selectedSignaturesEveIds = selectedSignatures.map(x => x.eve_id);
await handleUpdateSignatures( await handleUpdateSignatures(signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)));
signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)), }, [handleUpdateSignatures, signatures, selectedSignatures]);
false,
);
}, [handleUpdateSignatures, selectable, signatures, selectedSignatures]);
const handleSelectAll = useCallback(() => { const handleSelectAll = useCallback(() => {
setSelectedSignatures(signatures); setSelectedSignatures(signatures);
}, [signatures]); }, [signatures]);
const handleReplaceAll = useCallback(() => {
handleUpdateSignatures(parsedSignatures, false);
setAskUser(false);
}, [parsedSignatures, handleUpdateSignatures]);
const handleUpdateOnly = useCallback(() => {
handleUpdateSignatures(parsedSignatures, true);
setAskUser(false);
}, [parsedSignatures, handleUpdateSignatures]);
const handleSelectSignatures = useCallback(
e => {
if (selectable) {
onSelect?.(e.value);
} else {
setSelectedSignatures(e.value);
}
},
[onSelect, selectable],
);
useHotkey(true, ['a'], handleSelectAll); useHotkey(true, ['a'], handleSelectAll);
useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected); useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected);
useEffect(() => { useEffect(() => {
if (selectable) {
return;
}
if (!clipboardContent) { if (!clipboardContent) {
return; return;
} }
const newSignatures = parseSignatures( const signatures = parseSignatures(
clipboardContent, clipboardContent,
settings.map(x => x.key), settings.map(x => x.key),
); );
const { removed } = getActualSigs(signaturesRef.current, newSignatures, false); handleUpdateSignatures(signatures);
}, [clipboardContent]);
if (!signaturesRef.current || !signaturesRef.current.length || !removed.length) {
handleUpdateSignatures(newSignatures, false);
} else {
setParsedSignatures(newSignatures);
setAskUser(true);
}
}, [clipboardContent, selectable]);
useEffect(() => { useEffect(() => {
if (!systemId) { if (!systemId) {
setSignatures([]); setSignatures([]);
setAskUser(false);
return; return;
} }
@@ -249,8 +184,7 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
// }; // };
return ( return (
<> <div ref={tableRef} className="h-full">
<div ref={tableRef} className={'h-full '}>
{filteredSignatures.length === 0 ? ( {filteredSignatures.length === 0 ? (
<div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm"> <div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm">
No signatures No signatures
@@ -261,10 +195,10 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
className={classes.Table} className={classes.Table}
value={filteredSignatures} value={filteredSignatures}
size="small" size="small"
selectionMode={selectable ? 'single' : 'multiple'} selectionMode="multiple"
selection={selectedSignatures} selection={selectedSignatures}
metaKeySelection metaKeySelection
onSelectionChange={handleSelectSignatures} onSelectionChange={e => setSelectedSignatures(e.value)}
dataKey="eve_id" dataKey="eve_id"
tableClassName="w-full select-none" tableClassName="w-full select-none"
resizableColumns={false} resizableColumns={false}
@@ -318,16 +252,6 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
hidden={compact || medium} hidden={compact || medium}
sortable sortable
></Column> ></Column>
<Column
field="linked_system"
header="Linked System"
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
body={renderLinkedSystem}
style={{ maxWidth: nameColumnWidth }}
hidden={compact}
sortable
></Column>
<Column <Column
field="updated_at" field="updated_at"
header="Updated" header="Updated"
@@ -352,27 +276,6 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
ref={tooltipRef} ref={tooltipRef}
content={hoveredSig ? <SignatureView {...hoveredSig} /> : null} content={hoveredSig ? <SignatureView {...hoveredSig} /> : null}
/> />
{askUser && (
<div className="absolute left-[1px] top-[29px] h-[calc(100%-30px)] w-[calc(100%-3px)] bg-stone-900/10 backdrop-blur-sm">
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center">
<div className="text-stone-400/80 text-sm">
<div className="flex flex-col text-center gap-2">
<button className="p-button p-component p-button-outlined p-button-sm btn-wide">
<span className="p-button-label p-c" onClick={handleUpdateOnly}>
Update
</span>
</button>
<button className="p-button p-component p-button-outlined p-button-sm btn-wide">
<span className="p-button-label p-c" onClick={handleReplaceAll}>
Update & Delete
</span>
</button>
</div> </div>
</div>
</div>
</div>
)}
</div>
</>
); );
}; };

View File

@@ -5,7 +5,6 @@ import { getState } from './getState.ts';
export const getActualSigs = ( export const getActualSigs = (
oldSignatures: SystemSignature[], oldSignatures: SystemSignature[],
newSignatures: SystemSignature[], newSignatures: SystemSignature[],
updateOnly: boolean,
): { added: SystemSignature[]; updated: SystemSignature[]; removed: SystemSignature[] } => { ): { added: SystemSignature[]; updated: SystemSignature[]; removed: SystemSignature[] } => {
const updated: SystemSignature[] = []; const updated: SystemSignature[] = [];
const removed: SystemSignature[] = []; const removed: SystemSignature[] = [];
@@ -21,10 +20,8 @@ export const getActualSigs = (
updated.push({ ...oldSig, group: newSig.group, name: newSig.name }); updated.push({ ...oldSig, group: newSig.group, name: newSig.name });
} }
} else { } else {
if (!updateOnly) {
removed.push(oldSig); removed.push(oldSig);
} }
}
}); });
const oldSignaturesIds = oldSignatures.map(x => x.eve_id); const oldSignaturesIds = oldSignatures.map(x => x.eve_id);

View File

@@ -7,9 +7,9 @@ export const getState = (_: string[], newSig: SystemSignature) => {
let state = -1; let state = -1;
if (!newSig.group || newSig.group === '') { if (!newSig.group || newSig.group === '') {
state = 0; state = 0;
} else if (!newSig.name || newSig.name === '') { } else if (!!newSig.group && newSig.group !== '' && newSig.name === '') {
state = 1; state = 1;
} else if (newSig.name !== '') { } else if (!!newSig.group && newSig.group !== '' && newSig.name !== '') {
state = 2; state = 2;
} }
return state; return state;

View File

@@ -1,4 +1,3 @@
export * from './renderIcon'; export * from './renderIcon';
export * from './renderName'; export * from './renderName';
export * from './renderTimeLeft'; export * from './renderTimeLeft';
export * from './renderLinkedSystem';

View File

@@ -1,20 +0,0 @@
import clsx from 'clsx';
import { SystemSignature } from '@/hooks/Mapper/types';
import { SystemViewStandalone } from '@/hooks/Mapper/components/ui-kit';
export const renderLinkedSystem = (row: SystemSignature) => {
if (!row.linked_system) {
return null;
}
return (
<span title={row.linked_system?.solar_system_name}>
<SystemViewStandalone
className={clsx('select-none text-center cursor-context-menu')}
hideRegion
{...row.linked_system}
/>
</span>
);
};

View File

@@ -6,7 +6,6 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { OnTheMap, RightBar } from '@/hooks/Mapper/components/mapRootContent/components'; import { OnTheMap, RightBar } from '@/hooks/Mapper/components/mapRootContent/components';
import { MapContextMenu } from '@/hooks/Mapper/components/mapRootContent/components/MapContextMenu/MapContextMenu.tsx'; import { MapContextMenu } from '@/hooks/Mapper/components/mapRootContent/components/MapContextMenu/MapContextMenu.tsx';
import { useSkipContextMenu } from '@/hooks/Mapper/hooks/useSkipContextMenu';
export interface MapRootContentProps {} export interface MapRootContentProps {}
@@ -20,8 +19,6 @@ export const MapRootContent = ({}: MapRootContentProps) => {
const handleShowOnTheMap = useCallback(() => setShowOnTheMap(true), []); const handleShowOnTheMap = useCallback(() => setShowOnTheMap(true), []);
useSkipContextMenu();
return ( return (
<Layout map={<MapWrapper refn={mapRef} />}> <Layout map={<MapWrapper refn={mapRef} />}>
{!isShowMenu ? ( {!isShowMenu ? (

View File

@@ -22,13 +22,6 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
}); });
}, [outCommand]); }, [outCommand]);
const handleOpenUserSettings = useCallback(() => {
outCommand({
type: OutCommand.openUserSettings,
data: null,
});
}, [outCommand]);
const toggleMinimap = useCallback(() => { const toggleMinimap = useCallback(() => {
setInterfaceSettings(x => ({ setInterfaceSettings(x => ({
...x, ...x,
@@ -66,17 +59,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button" type="button"
onClick={handleAddCharacter} onClick={handleAddCharacter}
> >
<i className="pi pi-user-plus"></i> <i className="pi pi-user-plus text-lg"></i>
</button>
</WdTooltipWrapper>
<WdTooltipWrapper content="User settings" position={TooltipPosition.left}>
<button
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
type="button"
onClick={handleOpenUserSettings}
>
<i className="pi pi-cog"></i>
</button> </button>
</WdTooltipWrapper> </WdTooltipWrapper>
@@ -86,7 +69,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button" type="button"
onClick={onShowOnTheMap} onClick={onShowOnTheMap}
> >
<i className="pi pi-hashtag"></i> <i className="pi pi-hashtag text-lg"></i>
</button> </button>
</WdTooltipWrapper> </WdTooltipWrapper>
</div> </div>
@@ -103,7 +86,11 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button" type="button"
onClick={toggleKSpace} onClick={toggleKSpace}
> >
<i className={interfaceSettings.isShowKSpace ? 'hero-cloud-solid' : 'hero-cloud'}></i> {interfaceSettings.isShowKSpace ? (
<i className="pi pi-star-fill text-lg"></i>
) : (
<i className="pi pi-star text-lg"></i>
)}
</button> </button>
</WdTooltipWrapper> </WdTooltipWrapper>
@@ -113,7 +100,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button" type="button"
onClick={toggleMinimap} onClick={toggleMinimap}
> >
<i className={isShowMinimap ? 'pi pi-eye' : 'pi pi-eye-slash'}></i> {isShowMinimap ? <i className="pi pi-eye text-lg"></i> : <i className="pi pi-eye-slash text-lg"></i>}
</button> </button>
</WdTooltipWrapper> </WdTooltipWrapper>
@@ -123,7 +110,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button" type="button"
onClick={toggleMenu} onClick={toggleMenu}
> >
<i className="pi pi-window-minimize"></i> <i className="pi pi-window-minimize text-lg"></i>
</button> </button>
</WdTooltipWrapper> </WdTooltipWrapper>
</div> </div>

View File

@@ -5,20 +5,13 @@ import { MapRootData, useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts'; import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
import isEqual from 'lodash.isequal'; import isEqual from 'lodash.isequal';
import { ContextMenuSystem, useContextMenuSystemHandlers } from '@/hooks/Mapper/components/contexts'; import { ContextMenuSystem, useContextMenuSystemHandlers } from '@/hooks/Mapper/components/contexts';
import { import { SystemCustomLabelDialog, SystemSettingsDialog } from '@/hooks/Mapper/components/mapInterface/components';
SystemCustomLabelDialog,
SystemSettingsDialog,
SystemLinkSignatureDialog,
} from '@/hooks/Mapper/components/mapInterface/components';
import classes from './MapWrapper.module.scss'; import classes from './MapWrapper.module.scss';
import { Connections } from '@/hooks/Mapper/components/mapRootContent/components/Connections'; import { Connections } from '@/hooks/Mapper/components/mapRootContent/components/Connections';
import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple'; import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple';
import { getSystemById } from '@/hooks/Mapper/helpers'; import { getSystemById } from '@/hooks/Mapper/helpers';
import { Node } from 'reactflow'; import { Node } from 'reactflow';
import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts';
import { useMapEventListener } from '@/hooks/Mapper/events';
import { STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/MapRootProvider'; import { STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/MapRootProvider';
interface MapWrapperProps { interface MapWrapperProps {
@@ -60,7 +53,6 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
); );
const [openSettings, setOpenSettings] = useState<string | null>(null); const [openSettings, setOpenSettings] = useState<string | null>(null);
const [openLinkSignatures, setOpenLinkSignatures] = useState<any | null>(null);
const [openCustomLabel, setOpenCustomLabel] = useState<string | null>(null); const [openCustomLabel, setOpenCustomLabel] = useState<string | null>(null);
const handleCommand: OutCommandHandler = useCallback( const handleCommand: OutCommandHandler = useCallback(
event => { event => {
@@ -68,9 +60,6 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
case OutCommand.openSettings: case OutCommand.openSettings:
setOpenSettings(event.data.system_id); setOpenSettings(event.data.system_id);
break; break;
case OutCommand.linkSignatureToSystem:
setOpenLinkSignatures(event.data);
break;
default: default:
return outCommand(event); return outCommand(event);
} }
@@ -99,14 +88,6 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
const handleConnectionDbClick = useCallback((e: SolarSystemConnection) => setSelectedConnection(e), []); const handleConnectionDbClick = useCallback((e: SolarSystemConnection) => setSelectedConnection(e), []);
useMapEventListener(event => {
switch (event.name) {
case Commands.linkSignatureToSystem:
setOpenLinkSignatures(event.data);
return true;
}
});
return ( return (
<> <>
<Map <Map
@@ -122,15 +103,19 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
/> />
{openSettings != null && ( {openSettings != null && (
<SystemSettingsDialog systemId={openSettings} visible setVisible={() => setOpenSettings(null)} /> <SystemSettingsDialog
systemId={openSettings}
visible={openSettings != null}
setVisible={() => setOpenSettings(null)}
/>
)} )}
{openCustomLabel != null && ( {openCustomLabel != null && (
<SystemCustomLabelDialog systemId={openCustomLabel} visible setVisible={() => setOpenCustomLabel(null)} /> <SystemCustomLabelDialog
)} systemId={openCustomLabel}
visible={openCustomLabel != null}
{openLinkSignatures != null && ( setVisible={() => setOpenCustomLabel(null)}
<SystemLinkSignatureDialog data={openLinkSignatures} setVisible={() => setOpenLinkSignatures(null)} /> />
)} )}
<Connections selectedConnection={selectedConnection} onHide={() => setSelectedConnection(null)} /> <Connections selectedConnection={selectedConnection} onHide={() => setSelectedConnection(null)} />

View File

@@ -37,7 +37,7 @@ export const CharacterCard = ({
const { mapRef } = useMapRootState(); const { mapRef } = useMapRootState();
const handleSelect = useCallback(() => { const handleSelect = useCallback(() => {
mapRef.current?.command(Commands.centerSystem, char?.location?.solar_system_id?.toString()); mapRef.current?.command(Commands.selectSystem, char?.location?.solar_system_id?.toString());
}, [mapRef, char]); }, [mapRef, char]);
return ( return (

View File

@@ -1,13 +0,0 @@
import { createEvent } from 'react-event-hook';
export interface MapEvent {
name: string;
data: {
solar_system_source: number;
solar_system_target: number;
};
}
const { useMapEventListener, emitMapEvent } = createEvent('map-event')<MapEvent>();
export { useMapEventListener, emitMapEvent };

View File

@@ -1,4 +1,4 @@
import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog'; import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures';
import { SystemSignature } from '@/hooks/Mapper/types'; import { SystemSignature } from '@/hooks/Mapper/types';
export const parseSignatures = (value: string, availableKeys: string[]): SystemSignature[] => { export const parseSignatures = (value: string, availableKeys: string[]): SystemSignature[] => {

View File

@@ -1,4 +1,3 @@
export * from './usePageVisibility'; export * from './usePageVisibility';
export * from './useClipboard'; export * from './useClipboard';
export * from './useHotkey'; export * from './useHotkey';
export * from './useSkipContextMenu';

View File

@@ -1,15 +0,0 @@
import { useEffect } from 'react';
export const useSkipContextMenu = () => {
useEffect(() => {
function handleContextMenu(e) {
e.preventDefault();
}
window.addEventListener(`contextmenu`, handleContextMenu);
return () => {
window.removeEventListener(`contextmenu`, handleContextMenu);
};
}, []);
};

View File

@@ -4,6 +4,7 @@ import { MapHandlers, MapUnionTypes, OutCommandHandler, SolarSystemConnection }
import { useMapRootHandlers } from '@/hooks/Mapper/mapRootProvider/hooks'; import { useMapRootHandlers } from '@/hooks/Mapper/mapRootProvider/hooks';
import { WithChildren } from '@/hooks/Mapper/types/common.ts'; import { WithChildren } from '@/hooks/Mapper/types/common.ts';
import useLocalStorageState from 'use-local-storage-state'; import useLocalStorageState from 'use-local-storage-state';
import { DEFAULT_SETTINGS } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
export type MapRootData = MapUnionTypes & { export type MapRootData = MapUnionTypes & {
selectedSystems: string[]; selectedSystems: string[];

View File

@@ -27,8 +27,6 @@ import {
useRoutes, useRoutes,
} from './api'; } from './api';
import { emitMapEvent } from '@/hooks/Mapper/events';
export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => { export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
const mapInit = useMapInit(); const mapInit = useMapInit();
const { addSystems, removeSystems, updateSystems } = useCommandsSystems(); const { addSystems, removeSystems, updateSystems } = useCommandsSystems();
@@ -87,18 +85,10 @@ export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
mapRoutes(data as CommandRoutes); mapRoutes(data as CommandRoutes);
break; break;
case Commands.centerSystem:
// do nothing here
break;
case Commands.selectSystem: case Commands.selectSystem:
// do nothing here // do nothing here
break; break;
case Commands.linkSignatureToSystem:
emitMapEvent({ name: Commands.linkSignatureToSystem, data });
break;
case Commands.killsUpdated: case Commands.killsUpdated:
// do nothing here // do nothing here
break; break;

View File

@@ -21,9 +21,7 @@ export enum Commands {
mapUpdated = 'map_updated', mapUpdated = 'map_updated',
killsUpdated = 'kills_updated', killsUpdated = 'kills_updated',
routes = 'routes', routes = 'routes',
centerSystem = 'center_system',
selectSystem = 'select_system', selectSystem = 'select_system',
linkSignatureToSystem = 'link_signature_to_system',
} }
export type Command = export type Command =
@@ -42,9 +40,7 @@ export type Command =
| Commands.mapUpdated | Commands.mapUpdated
| Commands.killsUpdated | Commands.killsUpdated
| Commands.routes | Commands.routes
| Commands.selectSystem | Commands.selectSystem;
| Commands.centerSystem
| Commands.linkSignatureToSystem;
export type CommandInit = { export type CommandInit = {
systems: SolarSystemRawType[]; systems: SolarSystemRawType[];
@@ -76,11 +72,6 @@ export type CommandMapUpdated = Partial<CommandInit>;
export type CommandRoutes = RoutesList; export type CommandRoutes = RoutesList;
export type CommandKillsUpdated = Kill[]; export type CommandKillsUpdated = Kill[];
export type CommandSelectSystem = string | undefined; export type CommandSelectSystem = string | undefined;
export type CommandCenterSystem = string | undefined;
export type CommandLinkSignatureToSystem = {
solar_system_source: number;
solar_system_target: number;
};
export interface CommandData { export interface CommandData {
[Commands.init]: CommandInit; [Commands.init]: CommandInit;
@@ -99,8 +90,6 @@ export interface CommandData {
[Commands.routes]: CommandRoutes; [Commands.routes]: CommandRoutes;
[Commands.killsUpdated]: CommandKillsUpdated; [Commands.killsUpdated]: CommandKillsUpdated;
[Commands.selectSystem]: CommandSelectSystem; [Commands.selectSystem]: CommandSelectSystem;
[Commands.centerSystem]: CommandCenterSystem;
[Commands.linkSignatureToSystem]: CommandLinkSignatureToSystem;
} }
export interface MapHandlers { export interface MapHandlers {
@@ -134,9 +123,7 @@ export enum OutCommand {
setAutopilotWaypoint = 'set_autopilot_waypoint', setAutopilotWaypoint = 'set_autopilot_waypoint',
addSystem = 'add_system', addSystem = 'add_system',
addCharacter = 'add_character', addCharacter = 'add_character',
openUserSettings = 'open_user_settings',
getPassages = 'get_passages', getPassages = 'get_passages',
linkSignatureToSystem = 'link_signature_to_system',
// Only UI commands // Only UI commands
openSettings = 'open_settings', openSettings = 'open_settings',

View File

@@ -1,12 +1,9 @@
import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types';
export type SystemSignature = { export type SystemSignature = {
eve_id: string; eve_id: string;
kind: string; kind: string;
name: string; name: string;
description?: string; description?: string;
group: string; group: string;
linked_system?: SolarSystemStaticInfoRaw;
updated_at?: string; updated_at?: string;
}; };

View File

@@ -65,7 +65,7 @@ export class LabelsManager {
} }
hasLabel(label: string) { hasLabel(label: string) {
return this.parsedLabels.labels?.includes(label); return this.parsedLabels.labels.includes(label);
} }
toggleLabel(label: string) { toggleLabel(label: string) {

View File

@@ -3,230 +3,7 @@ import 'phoenix_html';
import './live_reload.css'; import './live_reload.css';
const animateBg = function (bgCanvas) {
const { TweenMax, _ } = window;
/**
* Utility function for returning a random integer in a given range
* @param {Int} max
* @param {Int} min
*/
const randomInRange = (max, min) => Math.floor(Math.random() * (max - min + 1)) + min;
const BASE_SIZE = 1;
const VELOCITY_INC = 1.01;
const VELOCITY_INIT_INC = 0.525;
const JUMP_VELOCITY_INC = 0.55;
const JUMP_SIZE_INC = 1.15;
const SIZE_INC = 1.01;
const RAD = Math.PI / 180;
const WARP_COLORS = [
[197, 239, 247],
[25, 181, 254],
[77, 5, 232],
[165, 55, 253],
[255, 255, 255],
];
/**
* Class for storing the particle metadata
* position, size, length, speed etc.
*/
class Star {
STATE = {
alpha: Math.random(),
angle: randomInRange(0, 360) * RAD,
};
reset = () => {
const angle = randomInRange(0, 360) * (Math.PI / 180);
const vX = Math.cos(angle);
const vY = Math.sin(angle);
const travelled =
Math.random() > 0.5
? Math.random() * Math.max(window.innerWidth, window.innerHeight) + Math.random() * (window.innerWidth * 0.24)
: Math.random() * (window.innerWidth * 0.25);
this.STATE = {
...this.STATE,
iX: undefined,
iY: undefined,
active: travelled ? true : false,
x: Math.floor(vX * travelled) + window.innerWidth / 2,
vX,
y: Math.floor(vY * travelled) + window.innerHeight / 2,
vY,
size: BASE_SIZE,
};
};
constructor() {
this.reset();
}
}
const generateStarPool = size => new Array(size).fill().map(() => new Star());
// Class for the actual app
// Not too much happens in here
// Initiate the drawing process and listen for user interactions 👍
class JumpToHyperspace {
STATE = {
stars: generateStarPool(300),
bgAlpha: 0,
sizeInc: SIZE_INC,
velocity: VELOCITY_INC,
};
canvas = null;
context = null;
constructor(canvas) {
this.canvas = canvas;
this.context = canvas.getContext('2d');
this.bind();
this.setup();
this.render();
}
render = () => {
const {
STATE: { bgAlpha, velocity, sizeInc, initiating, jumping, stars },
context,
render,
} = this;
// Clear the canvas
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
if (bgAlpha > 0) {
context.fillStyle = `rgba(31, 58, 157, ${bgAlpha})`;
context.fillRect(0, 0, window.innerWidth, window.innerHeight);
}
// 1. Shall we add a new star
const nonActive = stars.filter(s => !s.STATE.active);
if (!initiating && nonActive.length > 0) {
// Introduce a star
nonActive[0].STATE.active = true;
}
// 2. Update the stars and draw them.
for (const star of stars.filter(s => s.STATE.active)) {
const { active, x, y, iX, iY, iVX, iVY, size, vX, vY } = star.STATE;
// Check if the star needs deactivating
if (
((iX || x) < 0 || (iX || x) > window.innerWidth || (iY || y) < 0 || (iY || y) > window.innerHeight) &&
active &&
!initiating
) {
star.reset(true);
} else if (active) {
const newIX = initiating ? iX : iX + iVX;
const newIY = initiating ? iY : iY + iVY;
const newX = x + vX;
const newY = y + vY;
// Just need to work out if it overtakes the original line that's all
const caught =
(vX < 0 && newIX < x) || (vX > 0 && newIX > x) || (vY < 0 && newIY < y) || (vY > 0 && newIY > y);
star.STATE = {
...star.STATE,
iX: caught ? undefined : newIX,
iY: caught ? undefined : newIY,
iVX: caught ? undefined : iVX * VELOCITY_INIT_INC,
iVY: caught ? undefined : iVY * VELOCITY_INIT_INC,
x: newX,
vX: star.STATE.vX * velocity,
y: newY,
vY: star.STATE.vY * velocity,
size: initiating ? size : size * (iX || iY ? SIZE_INC : sizeInc),
};
let color = `rgba(255, 255, 255, ${star.STATE.alpha})`;
if (jumping) {
const [r, g, b] = WARP_COLORS[randomInRange(0, WARP_COLORS.length)];
color = `rgba(${r}, ${g}, ${b}, ${star.STATE.alpha})`;
}
context.strokeStyle = color;
context.lineWidth = size;
context.beginPath();
context.moveTo(star.STATE.iX || x, star.STATE.iY || y);
context.lineTo(star.STATE.x, star.STATE.y);
context.stroke();
}
}
requestAnimationFrame(render);
};
initiate = () => {
if (this.STATE.jumping || this.STATE.initiating) return;
this.STATE = {
...this.STATE,
initiating: true,
initiateTimestamp: new Date().getTime(),
};
TweenMax.to(this.STATE, 0.25, { velocity: VELOCITY_INIT_INC, bgAlpha: 0.3 });
// When we initiate, stop the XY origin from moving so that we draw
// longer lines until the jump
for (const star of this.STATE.stars.filter(s => s.STATE.active)) {
star.STATE = {
...star.STATE,
iX: star.STATE.x,
iY: star.STATE.y,
iVX: star.STATE.vX,
iVY: star.STATE.vY,
};
}
};
jump = () => {
this.STATE = {
...this.STATE,
bgAlpha: 0,
jumping: true,
};
TweenMax.to(this.STATE, 0.25, { velocity: JUMP_VELOCITY_INC, bgAlpha: 0.75, sizeInc: JUMP_SIZE_INC });
setTimeout(() => {
this.STATE = {
...this.STATE,
jumping: false,
};
TweenMax.to(this.STATE, 0.25, { bgAlpha: 0, velocity: VELOCITY_INC, sizeInc: SIZE_INC });
}, 5000);
};
enter = () => {
if (this.STATE.jumping) return;
const { initiateTimestamp } = this.STATE;
this.STATE = {
...this.STATE,
initiating: false,
initiateTimestamp: undefined,
};
if (new Date().getTime() - initiateTimestamp > 600) {
this.jump();
} else {
TweenMax.to(this.STATE, 0.25, { velocity: VELOCITY_INC, bgAlpha: 0 });
}
};
bind = () => {
this.canvas.addEventListener('mousedown', this.initiate);
this.canvas.addEventListener('touchstart', this.initiate);
this.canvas.addEventListener('mouseup', this.enter);
this.canvas.addEventListener('touchend', this.enter);
};
setup = () => {
this.context.lineCap = 'round';
this.canvas.height = window.innerHeight;
this.canvas.width = window.innerWidth;
};
reset = () => {
this.STATE = {
...this.STATE,
stars: generateStarPool(300),
};
this.setup();
};
}
window.myJump = new JumpToHyperspace(bgCanvas);
window.addEventListener(
'resize',
_.debounce(() => {
window.myJump.reset();
}, 250),
);
};
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// animage background
const canvas = document.getElementById('bg-canvas');
if (canvas) {
animateBg(canvas);
}
// Select all buttons with the 'share-link' class // Select all buttons with the 'share-link' class
const buttons = document.querySelectorAll('button.copy-link'); const buttons = document.querySelectorAll('button.copy-link');

View File

@@ -28,7 +28,6 @@
"primeicons": "^7.0.0", "primeicons": "^7.0.0",
"primereact": "^10.6.5", "primereact": "^10.6.5",
"react-error-boundary": "^4.0.13", "react-error-boundary": "^4.0.13",
"react-event-hook": "^3.1.2",
"react-flow-renderer": "^10.3.17", "react-flow-renderer": "^10.3.17",
"react-grid-layout": "^1.3.4", "react-grid-layout": "^1.3.4",
"react-usestateref": "^1.0.9", "react-usestateref": "^1.0.9",

View File

@@ -3199,11 +3199,6 @@ react-error-boundary@^4.0.13:
dependencies: dependencies:
"@babel/runtime" "^7.12.5" "@babel/runtime" "^7.12.5"
react-event-hook@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/react-event-hook/-/react-event-hook-3.1.2.tgz#445e8f3b751f6abe4ef199f31bff47593c4c13d4"
integrity sha512-qQ9LXLdxmWRRZPlnqVjqlw7jovSvDosQEOyQ9cjPHhtDv8JIszjj0td1PuHJHrVW0LS8a1XeJhLe6i7S5u9SbQ==
react-flow-renderer@^10.3.17: react-flow-renderer@^10.3.17:
version "10.3.17" version "10.3.17"
resolved "https://registry.npmjs.org/react-flow-renderer/-/react-flow-renderer-10.3.17.tgz" resolved "https://registry.npmjs.org/react-flow-renderer/-/react-flow-renderer-10.3.17.tgz"

View File

@@ -60,7 +60,15 @@ config :dart_sass, :version, "1.54.5"
config :tailwind, :version, "3.2.7" config :tailwind, :version, "3.2.7"
config :wanderer_app, WandererApp.PromEx, manual_metrics_start_delay: :no_delay config :wanderer_app, WandererApp.PromEx,
manual_metrics_start_delay: :no_delay,
metrics_server: [
port: 4021,
path: "/metrics",
protocol: :http,
pool_size: 5,
cowboy_opts: [ip: {0, 0, 0, 0}]
]
config :wanderer_app, config :wanderer_app,
grafana_datasource_id: "wanderer" grafana_datasource_id: "wanderer"

View File

@@ -77,7 +77,7 @@ config :wanderer_app,
web_app_url: web_app_url, web_app_url: web_app_url,
git_sha: System.get_env("GIT_SHA", "111"), git_sha: System.get_env("GIT_SHA", "111"),
custom_route_base_url: System.get_env("CUSTOM_ROUTE_BASE_URL"), custom_route_base_url: System.get_env("CUSTOM_ROUTE_BASE_URL"),
invites: System.get_env("WANDERER_INVITES", "false") |> String.to_existing_atom(), invites: System.get_env("WANDERER_INVITES", "false") == "true",
admin_username: System.get_env("WANDERER_ADMIN_USERNAME", "admin"), admin_username: System.get_env("WANDERER_ADMIN_USERNAME", "admin"),
admin_password: System.get_env("WANDERER_ADMIN_PASSWORD"), admin_password: System.get_env("WANDERER_ADMIN_PASSWORD"),
admins: admins, admins: admins,

View File

@@ -19,7 +19,6 @@ defmodule WandererApp.Api do
resource WandererApp.Api.MapCharacterSettings resource WandererApp.Api.MapCharacterSettings
resource WandererApp.Api.MapSubscription resource WandererApp.Api.MapSubscription
resource WandererApp.Api.MapTransaction resource WandererApp.Api.MapTransaction
resource WandererApp.Api.MapUserSettings
resource WandererApp.Api.User resource WandererApp.Api.User
resource WandererApp.Api.ShipTypeInfo resource WandererApp.Api.ShipTypeInfo
resource WandererApp.Api.UserActivity resource WandererApp.Api.UserActivity

View File

@@ -18,7 +18,6 @@ defmodule WandererApp.Api.Map do
define(:update, action: :update) define(:update, action: :update)
define(:update_acls, action: :update_acls) define(:update_acls, action: :update_acls)
define(:update_hubs, action: :update_hubs) define(:update_hubs, action: :update_hubs)
define(:update_options, action: :update_options)
define(:assign_owner, action: :assign_owner) define(:assign_owner, action: :assign_owner)
define(:mark_as_deleted, action: :mark_as_deleted) define(:mark_as_deleted, action: :mark_as_deleted)
@@ -113,10 +112,6 @@ defmodule WandererApp.Api.Map do
accept [:hubs] accept [:hubs]
end end
update :update_options do
accept [:options]
end
update :mark_as_deleted do update :mark_as_deleted do
accept([]) accept([])
@@ -172,10 +167,6 @@ defmodule WandererApp.Api.Map do
allow_nil?(true) allow_nil?(true)
end end
attribute :options, :string do
allow_nil? true
end
create_timestamp(:inserted_at) create_timestamp(:inserted_at)
update_timestamp(:updated_at) update_timestamp(:updated_at)
end end

View File

@@ -14,7 +14,6 @@ defmodule WandererApp.Api.MapSystemSignature do
define(:all_active, action: :all_active) define(:all_active, action: :all_active)
define(:create, action: :create) define(:create, action: :create)
define(:update, action: :update) define(:update, action: :update)
define(:update_linked_system, action: :update_linked_system)
define(:by_id, define(:by_id,
get_by: [:id], get_by: [:id],
@@ -67,18 +66,13 @@ defmodule WandererApp.Api.MapSystemSignature do
:name, :name,
:description, :description,
:kind, :kind,
:group, :group
:linked_system_id
] ]
primary? true primary? true
require_atomic? false require_atomic? false
end end
update :update_linked_system do
accept [:linked_system_id]
end
read :by_system_id do read :by_system_id do
argument(:system_id, :string, allow_nil?: false) argument(:system_id, :string, allow_nil?: false)
@@ -105,10 +99,6 @@ defmodule WandererApp.Api.MapSystemSignature do
allow_nil? true allow_nil? true
end end
attribute :linked_system_id, :integer do
allow_nil? true
end
attribute :kind, :string attribute :kind, :string
attribute :group, :string attribute :group, :string

View File

@@ -1,54 +0,0 @@
defmodule WandererApp.Api.MapUserSettings do
@moduledoc false
use Ash.Resource,
domain: WandererApp.Api,
data_layer: AshPostgres.DataLayer
postgres do
repo(WandererApp.Repo)
table("map_user_settings_v1")
end
code_interface do
define(:create, action: :create)
define(:by_user_id,
get_by: [:map_id, :user_id],
action: :read
)
define(:update_settings, action: :update_settings)
end
actions do
default_accept [
:map_id,
:user_id,
:settings
]
defaults [:create, :read, :update, :destroy]
update :update_settings do
accept [:settings]
end
end
attributes do
uuid_primary_key :id
attribute :settings, :string do
allow_nil? true
end
end
relationships do
belongs_to :map, WandererApp.Api.Map, primary_key?: true, allow_nil?: false
belongs_to :user, WandererApp.Api.User, primary_key?: true, allow_nil?: false
end
identities do
identity :uniq_map_user, [:map_id, :user_id]
end
end

View File

@@ -6,7 +6,7 @@ defmodule WandererApp.Character do
@read_character_wallet_scope "esi-wallet.read_character_wallet.v1" @read_character_wallet_scope "esi-wallet.read_character_wallet.v1"
@read_corp_wallet_scope "esi-wallet.read_corporation_wallets.v1" @read_corp_wallet_scope "esi-wallet.read_corporation_wallets.v1"
def get_character(character_id) when not is_nil(character_id) do def get_character(character_id) do
case Cachex.get(:character_cache, character_id) do case Cachex.get(:character_cache, character_id) do
{:ok, nil} -> {:ok, nil} ->
case WandererApp.Api.Character.by_id(character_id) do case WandererApp.Api.Character.by_id(character_id) do
@@ -23,8 +23,6 @@ defmodule WandererApp.Character do
end end
end end
def get_character(_character_id), do: {:ok, nil}
def get_character!(character_id) do def get_character!(character_id) do
case get_character(character_id) do case get_character(character_id) do
{:ok, character} -> {:ok, character} ->

View File

@@ -19,47 +19,46 @@ defmodule WandererApp.Map.PositionCalculator do
def get_system_bounding_rect(_system), do: [{0, 0}, {0, 0}] def get_system_bounding_rect(_system), do: [{0, 0}, {0, 0}]
def get_new_system_position(nil, rtree_name, opts) do def get_new_system_position(nil, rtree_name) do
{:ok, {x, y}} = rtree_name |> check_system_available_positions(@start_x, @start_y, 1, opts) {:ok, {x, y}} = rtree_name |> _check_system_available_positions(@start_x, @start_y, 1)
%{x: x, y: y} %{x: x, y: y}
end end
def get_new_system_position( def get_new_system_position(
%{position_x: start_x, position_y: start_y} = _old_system, %{position_x: start_x, position_y: start_y} = _old_system,
rtree_name, rtree_name
opts
) do ) do
{:ok, {x, y}} = rtree_name |> check_system_available_positions(start_x, start_y, 1, opts) {:ok, {x, y}} = rtree_name |> _check_system_available_positions(start_x, start_y, 1)
%{x: x, y: y} %{x: x, y: y}
end end
defp check_system_available_positions(_rtree_name, _start_x, _start_y, 100, _opts), defp _check_system_available_positions(_rtree_name, _start_x, _start_y, 100) do
do: {:ok, {@start_x, @start_y}} {:ok, {@start_x, @start_y}}
end
defp check_system_available_positions(rtree_name, start_x, start_y, level, opts) do defp _check_system_available_positions(rtree_name, start_x, start_y, level) do
possible_positions = get_available_positions(level, start_x, start_y, opts) possible_positions = _get_available_positions(level, start_x, start_y)
case get_available_position(possible_positions, rtree_name) do case _get_available_position(possible_positions, rtree_name) do
{:ok, nil} -> {:ok, nil} ->
rtree_name |> check_system_available_positions(start_x, start_y, level + 1, opts) rtree_name |> _check_system_available_positions(start_x, start_y, level + 1)
{:ok, position} -> {:ok, position} ->
{:ok, position} {:ok, position}
end end
end end
defp get_available_position([], _rtree_name), do: {:ok, nil} defp _get_available_position([], _rtree_name), do: {:ok, nil}
defp get_available_position([position | rest], rtree_name) do defp _get_available_position([position | rest], rtree_name) do
if is_available_position(position, rtree_name) do if _is_available_position(position, rtree_name) do
{:ok, position} {:ok, position}
else else
get_available_position(rest, rtree_name) _get_available_position(rest, rtree_name)
end end
end end
defp is_available_position({x, y} = _position, rtree_name) do defp _is_available_position({x, y} = _position, rtree_name) do
case DDRT.query(get_system_bounding_rect(%{position_x: x, position_y: y}), rtree_name) do case DDRT.query(get_system_bounding_rect(%{position_x: x, position_y: y}), rtree_name) do
{:ok, []} -> {:ok, []} ->
true true
@@ -72,10 +71,9 @@ defmodule WandererApp.Map.PositionCalculator do
end end
end end
def get_available_positions(level, x, y, opts), def _get_available_positions(level, x, y), do: _adjusted_coordinates(1 + level * 2, x, y)
do: adjusted_coordinates(1 + level * 2, x, y, opts)
defp edge_coordinates(n, opts) when n > 1 do defp _edge_coordinates(n) when n > 1 do
min = -div(n, 2) min = -div(n, 2)
max = div(n, 2) max = div(n, 2)
# Top edge # Top edge
@@ -92,20 +90,16 @@ defmodule WandererApp.Map.PositionCalculator do
|> Enum.uniq() |> Enum.uniq()
end end
defp sorted_edge_coordinates(n, opts) when n > 1 do defp _sorted_edge_coordinates(n) when n > 1 do
coordinates = edge_coordinates(n, opts) coordinates = _edge_coordinates(n)
start_index = get_start_index(n, opts[:layout]) middle_right_index = div(n, 2)
Enum.slice(coordinates, start_index, length(coordinates) - start_index) ++ Enum.slice(coordinates, middle_right_index, length(coordinates) - middle_right_index) ++
Enum.slice(coordinates, 0, start_index) Enum.slice(coordinates, 0, middle_right_index)
end end
defp get_start_index(n, "left_to_right"), do: div(n, 2) defp _adjusted_coordinates(n, start_x, start_y) when n > 1 do
sorted_coords = _sorted_edge_coordinates(n)
defp get_start_index(n, "top_to_bottom"), do: div(n, 2) + n - 1
defp adjusted_coordinates(n, start_x, start_y, opts) when n > 1 do
sorted_coords = sorted_edge_coordinates(n, opts)
Enum.map(sorted_coords, fn {x, y} -> Enum.map(sorted_coords, fn {x, y} ->
{ {

View File

@@ -11,8 +11,7 @@ defmodule WandererApp.Map.Server.Impl do
defstruct [ defstruct [
:map_id, :map_id,
:rtree_name, :rtree_name,
map: nil, map: nil
map_opts: []
] ]
# @ccp1 -1 # @ccp1 -1
@@ -333,7 +332,7 @@ defmodule WandererApp.Map.Server.Impl do
end end
def delete_systems( def delete_systems(
%{map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = state, %{map_id: map_id, rtree_name: rtree_name} = state,
removed_ids, removed_ids,
user_id, user_id,
character_id character_id
@@ -352,7 +351,7 @@ defmodule WandererApp.Map.Server.Impl do
removed_ids removed_ids
|> Enum.each(fn solar_system_id -> |> Enum.each(fn solar_system_id ->
map_id map_id
|> WandererApp.MapSystemRepo.remove_from_map(solar_system_id, map_opts) |> WandererApp.MapSystemRepo.remove_from_map(solar_system_id)
|> case do |> case do
{:ok, _} -> {:ok, _} ->
:ok :ok
@@ -800,15 +799,6 @@ defmodule WandererApp.Map.Server.Impl do
} }
end end
def handle_event({:options_updated, options}, %{map: map, map_id: map_id} = state),
do: %{
state
| map_opts: [
layout: options |> Map.get("layout"),
store_custom_labels: options |> Map.get("store_custom_labels")
]
}
def handle_event({ref, _result}, %{map_id: _map_id} = state) do def handle_event({ref, _result}, %{map_id: _map_id} = state) do
Process.demonitor(ref, [:flush]) Process.demonitor(ref, [:flush])
@@ -848,12 +838,12 @@ defmodule WandererApp.Map.Server.Impl do
character_id, character_id,
location, location,
old_location, old_location,
%{map: map, map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = _state %{map: map, map_id: map_id, rtree_name: rtree_name} = _state
) do ) do
case is_nil(old_location.solar_system_id) and case is_nil(old_location.solar_system_id) and
_can_add_location(map.scope, location.solar_system_id) do _can_add_location(map.scope, location.solar_system_id) do
true -> true ->
:ok = maybe_add_system(map_id, location, nil, rtree_name, map_opts) :ok = maybe_add_system(map_id, location, nil, rtree_name)
_ -> _ ->
case _is_connection_valid( case _is_connection_valid(
@@ -862,9 +852,10 @@ defmodule WandererApp.Map.Server.Impl do
location.solar_system_id location.solar_system_id
) do ) do
true -> true ->
:ok = maybe_add_system(map_id, location, old_location, rtree_name, map_opts) {:ok, character} = WandererApp.Character.get_character(character_id)
:ok = maybe_add_system(map_id, old_location, location, rtree_name, map_opts) :ok = maybe_add_system(map_id, location, old_location, rtree_name)
:ok = maybe_add_connection(map_id, location, old_location, character_id) :ok = maybe_add_system(map_id, old_location, location, rtree_name)
:ok = maybe_add_connection(map_id, location, old_location, character)
_ -> _ ->
:ok :ok
@@ -1110,7 +1101,7 @@ defmodule WandererApp.Map.Server.Impl do
end)} end)}
defp _add_system( defp _add_system(
%{map_id: map_id, map_opts: map_opts, rtree_name: rtree_name} = state, %{map_id: map_id, rtree_name: rtree_name} = state,
%{ %{
solar_system_id: solar_system_id, solar_system_id: solar_system_id,
coordinates: coordinates coordinates: coordinates
@@ -1126,7 +1117,7 @@ defmodule WandererApp.Map.Server.Impl do
_ -> _ ->
%{x: x, y: y} = %{x: x, y: y} =
WandererApp.Map.PositionCalculator.get_new_system_position(nil, rtree_name, map_opts) WandererApp.Map.PositionCalculator.get_new_system_position(nil, rtree_name)
%{"x" => x, "y" => y} %{"x" => x, "y" => y}
end end
@@ -1271,27 +1262,20 @@ defmodule WandererApp.Map.Server.Impl do
defp _init_map( defp _init_map(
state, state,
%{characters: characters} = initial_map, %{characters: characters} = map,
subscription_settings, subscription_settings,
systems, systems,
connections connections
) do ) do
map = map =
initial_map map
|> WandererApp.Map.new() |> WandererApp.Map.new()
|> WandererApp.Map.update_subscription_settings!(subscription_settings) |> WandererApp.Map.update_subscription_settings!(subscription_settings)
|> WandererApp.Map.add_systems!(systems) |> WandererApp.Map.add_systems!(systems)
|> WandererApp.Map.add_connections!(connections) |> WandererApp.Map.add_connections!(connections)
|> WandererApp.Map.add_characters!(characters) |> WandererApp.Map.add_characters!(characters)
{:ok, map_options} = WandererApp.MapRepo.options_to_form_data(initial_map) %{state | map: map}
map_opts = [
layout: map_options |> Map.get("layout"),
store_custom_labels: map_options |> Map.get("store_custom_labels")
]
%{state | map: map, map_opts: map_opts}
end end
defp _init_map_systems(state, [] = _systems), do: state defp _init_map_systems(state, [] = _systems), do: state
@@ -1600,33 +1584,26 @@ defmodule WandererApp.Map.Server.Impl do
defp maybe_remove_connection(_map_id, _location, _old_location), do: :ok defp maybe_remove_connection(_map_id, _location, _old_location), do: :ok
defp maybe_add_connection(map_id, location, old_location, character_id) defp maybe_add_connection(map_id, location, old_location, character)
when not is_nil(location) and not is_nil(old_location) and when not is_nil(location) and not is_nil(old_location) and
not is_nil(old_location.solar_system_id) and not is_nil(old_location.solar_system_id) and
location.solar_system_id != old_location.solar_system_id do location.solar_system_id != old_location.solar_system_id do
character_id case character do
|> WandererApp.Character.get_character!()
|> case do
nil -> nil ->
:ok :ok
character -> _ ->
:telemetry.execute([:wanderer_app, :map, :character, :jump], %{count: 1}, %{}) :telemetry.execute([:wanderer_app, :map, :character, :jump], %{count: 1}, %{})
{:ok, _} = {:ok, _} =
WandererApp.Api.MapChainPassages.new(%{ WandererApp.Api.MapChainPassages.new(%{
map_id: map_id, map_id: map_id,
character_id: character_id, character_id: character.id,
ship_type_id: character.ship, ship_type_id: character.ship,
ship_name: character.ship_name, ship_name: character.ship_name,
solar_system_source_id: old_location.solar_system_id, solar_system_source_id: old_location.solar_system_id,
solar_system_target_id: location.solar_system_id solar_system_target_id: location.solar_system_id
}) })
broadcast!(map_id, :maybe_select_system, %{
character_id: character_id,
solar_system_id: location.solar_system_id
})
end end
case WandererApp.Map.check_connection(map_id, location, old_location) do case WandererApp.Map.check_connection(map_id, location, old_location) do
@@ -1638,17 +1615,8 @@ defmodule WandererApp.Map.Server.Impl do
solar_system_target: location.solar_system_id solar_system_target: location.solar_system_id
}) })
WandererApp.Map.add_connection(map_id, connection)
broadcast!(map_id, :add_connection, connection) broadcast!(map_id, :add_connection, connection)
WandererApp.Map.add_connection(map_id, connection)
broadcast!(map_id, :maybe_link_signature, %{
character_id: character_id,
solar_system_source: old_location.solar_system_id,
solar_system_target: location.solar_system_id
})
:ok
{:error, error} -> {:error, error} ->
@logger.debug(fn -> "Failed to add connection: #{inspect(error, pretty: true)}" end) @logger.debug(fn -> "Failed to add connection: #{inspect(error, pretty: true)}" end)
@@ -1656,13 +1624,13 @@ defmodule WandererApp.Map.Server.Impl do
end end
end end
defp maybe_add_connection(_map_id, _location, _old_location, _character_id), do: :ok defp maybe_add_connection(_map_id, _location, _old_location, _character), do: :ok
defp maybe_add_system(map_id, location, old_location, rtree_name, opts) defp maybe_add_system(map_id, location, old_location, rtree_name)
when not is_nil(location) do when not is_nil(location) do
case WandererApp.Map.check_location(map_id, location) do case WandererApp.Map.check_location(map_id, location) do
{:ok, location} -> {:ok, location} ->
{:ok, position} = calc_new_system_position(map_id, old_location, rtree_name, opts) {:ok, position} = calc_new_system_position(map_id, old_location, rtree_name)
case WandererApp.MapSystemRepo.get_by_map_and_solar_system_id( case WandererApp.MapSystemRepo.get_by_map_and_solar_system_id(
map_id, map_id,
@@ -1732,14 +1700,14 @@ defmodule WandererApp.Map.Server.Impl do
end end
end end
defp maybe_add_system(_map_id, _location, _old_location, _rtree_name, _opts), do: :ok defp maybe_add_system(_map_id, _location, _old_location, _rtree_name), do: :ok
defp calc_new_system_position(map_id, old_location, rtree_name, opts), defp calc_new_system_position(map_id, old_location, rtree_name) do
do:
{:ok, {:ok,
map_id map_id
|> WandererApp.Map.find_system_by_location(old_location) |> WandererApp.Map.find_system_by_location(old_location)
|> WandererApp.Map.PositionCalculator.get_new_system_position(rtree_name, opts)} |> WandererApp.Map.PositionCalculator.get_new_system_position(rtree_name)}
end
defp _broadcast_acl_updates( defp _broadcast_acl_updates(
{:ok, {:ok,

View File

@@ -1,8 +1,6 @@
defmodule WandererApp.MapRepo do defmodule WandererApp.MapRepo do
use WandererApp, :repository use WandererApp, :repository
@default_map_options %{"layout" => "left_to_right", "store_custom_labels" => false}
def get(map_id, relationships \\ []) do def get(map_id, relationships \\ []) do
map_id map_id
|> WandererApp.Api.Map.by_id() |> WandererApp.Api.Map.by_id()
@@ -30,17 +28,4 @@ defmodule WandererApp.MapRepo do
{:error, :map_not_found} {:error, :map_not_found}
end end
end end
def update_options(map, options),
do:
map
|> WandererApp.Api.Map.update_options(%{options: Jason.encode!(options)})
def options_to_form_data(%{options: options} = _map_options) when not is_nil(options), do: {:ok, Jason.decode!(options)}
def options_to_form_data(_), do: {:ok, @default_map_options}
def options_to_form_data!(options) do
{:ok, data} = options_to_form_data(options)
data
end
end end

View File

@@ -22,12 +22,14 @@ defmodule WandererApp.MapSystemRepo do
def get_visible_by_map(map_id), def get_visible_by_map(map_id),
do: WandererApp.Api.MapSystem.read_visible_by_map(%{map_id: map_id}) do: WandererApp.Api.MapSystem.read_visible_by_map(%{map_id: map_id})
def remove_from_map(map_id, solar_system_id, opts) do def remove_from_map(map_id, solar_system_id) do
WandererApp.Api.MapSystem.read_by_map_and_solar_system!(%{ WandererApp.Api.MapSystem.read_by_map_and_solar_system!(%{
map_id: map_id, map_id: map_id,
solar_system_id: solar_system_id solar_system_id: solar_system_id
}) })
|> cleanup_labels(opts) |> WandererApp.Api.MapSystem.update_labels!(%{
labels: nil
})
|> WandererApp.Api.MapSystem.update_tag!(%{ |> WandererApp.Api.MapSystem.update_tag!(%{
tag: nil tag: nil
}) })
@@ -37,29 +39,6 @@ defmodule WandererApp.MapSystemRepo do
{:error, error} {:error, error}
end end
def cleanup_labels(%{labels: labels} = system, opts) do
store_custom_labels? = Keyword.get(opts, :store_custom_labels, "false") |> String.to_existing_atom()
labels = get_filtered_labels(labels, store_custom_labels?)
system
|> WandererApp.Api.MapSystem.update_labels!(%{
labels: labels
})
end
def get_filtered_labels(labels, true) when is_binary(labels) do
labels
|> Jason.decode!()
|> case do
%{"customLabel" => customLabel} = labels when is_binary(customLabel) ->
%{"customLabel" => customLabel, "labels" => []}
|> Jason.encode!()
_ ->
nil
end
end
def get_filtered_labels(_, _store_custom_labels), do: nil
def update_name(system, update), def update_name(system, update),
do: do:
system system

View File

@@ -1,49 +0,0 @@
defmodule WandererApp.MapUserSettingsRepo do
use WandererApp, :repository
@default_form_data %{"select_on_spash" => "false", "link_signature_on_splash" => "false"}
def get(map_id, user_id) do
map_id
|> WandererApp.Api.MapUserSettings.by_user_id(user_id)
|> case do
{:ok, settings} ->
{:ok, settings}
_ ->
{:ok, nil}
end
end
def get!(map_id, user_id) do
WandererApp.Api.MapUserSettings.by_user_id(map_id, user_id)
|> case do
{:ok, user_settings} -> user_settings
_ -> nil
end
end
def create_or_update(map_id, user_id, settings) do
get!(map_id, user_id)
|> case do
user_settings when not is_nil(user_settings) ->
user_settings
|> WandererApp.Api.MapUserSettings.update_settings(%{settings: settings})
_ ->
WandererApp.Api.MapUserSettings.create(%{
map_id: map_id,
user_id: user_id,
settings: settings
})
end
end
def to_form_data(nil), do: {:ok, @default_form_data}
def to_form_data(%{settings: settings} = _user_settings), do: {:ok, Jason.decode!(settings)}
def to_form_data!(user_settings) do
{:ok, data} = to_form_data(user_settings)
data
end
end

View File

@@ -377,7 +377,7 @@ defmodule WandererAppWeb.CoreComponents do
~H""" ~H"""
<div phx-feedback-for={@name} class="form-control mt-8"> <div phx-feedback-for={@name} class="form-control mt-8">
<label class="label cursor-pointer gap-2"> <label class="label cursor-pointer">
<span class="label-text"><%= @label %></span> <span class="label-text"><%= @label %></span>
<input type="hidden" name={@name} value="false" /> <input type="hidden" name={@name} value="false" />
<input <input

View File

@@ -1,3 +1,3 @@
<main class="bg-stone-950"> <main class="bg-gradient-to-r from-stone-950 to-stone-900">
<%= @inner_content %> <%= @inner_content %>
</main> </main>

View File

@@ -1,5 +1,5 @@
<main <main
class="main flex-col !min-h-screen justify-between flex z-0 focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-stone-950 ccp-font" class="main flex-col !min-h-screen justify-between flex z-0 focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-gradient-to-r from-stone-950 to-stone-900 ccp-font"
phx-mounted={JS.remove_class("opacity-0")} phx-mounted={JS.remove_class("opacity-0")}
> >
<navbar class="navbar bg-base-100 !sticky top-0 z-50 bg-opacity-0 "> <navbar class="navbar bg-base-100 !sticky top-0 z-50 bg-opacity-0 ">

View File

@@ -5,7 +5,7 @@
</.connection_status> </.connection_status>
<main <main
class="main flex-1 relative z-0 overflow-hidden focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-stone-950 maps_bg ccp-font" class="main flex-1 relative z-0 overflow-hidden focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-gradient-to-r from-stone-950 to-stone-900 maps_bg ccp-font"
phx-mounted={JS.remove_class("opacity-0")} phx-mounted={JS.remove_class("opacity-0")}
> >
<%= @inner_content %> <%= @inner_content %>

View File

@@ -1,4 +1,4 @@
<div class="flex flex-col w-0 flex-1 overflow-hidden bg-stone-950"> <div class="flex flex-col w-0 flex-1 overflow-hidden bg-gradient-to-r from-stone-950 to-stone-900">
<.connection_status> <.connection_status>
Re-establishing connection... Re-establishing connection...
</.connection_status> </.connection_status>

View File

@@ -43,20 +43,6 @@
> >
</script> </script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
>
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
>
</script>
<script defer phx-track-static type="module" src={~p"/assets/app.js"} crossorigin="anonymous"> <script defer phx-track-static type="module" src={~p"/assets/app.js"} crossorigin="anonymous">
</script> </script>
<!-- Appzi: Capture Insightful Feedback --> <!-- Appzi: Capture Insightful Feedback -->

View File

@@ -1,5 +1,4 @@
<section class="prose prose-lg max-w-full w-full leading-normal tracking-normal text-indigo-400 bg-cover bg-fixed flex items-center justify-center"> <section class="prose prose-lg max-w-full w-full leading-normal tracking-normal text-indigo-400 bg-cover bg-fixed flex items-center justify-center">
<canvas id="bg-canvas"></canvas>
<div class="h-full w-full flex flex-col items-center"> <div class="h-full w-full flex flex-col items-center">
<!--Main--> <!--Main-->
<div class="artboard artboard-horizontal phone-3 pt-10 !h-40"> <div class="artboard artboard-horizontal phone-3 pt-10 !h-40">
@@ -12,20 +11,12 @@
</div> </div>
<!--Right Col--> <!--Right Col-->
<div :if={@invite_token_valid} class="overflow-hidden"> <div :if={@invite_token_valid} class="overflow-hidden">
<div class="!z-100 relative group alert items-center fade-in-scale text-white w-[224px] h-[44px] rounded p-px overflow-hidden"> <.link navigate={~p"/auth/eve?invite=#{@invite_token}"}>
<div class="group animate-rotate absolute inset-0 h-full w-full rounded-full bg-[conic-gradient(#0ea5e9_20deg,transparent_120deg)] group-hover:bg-[#0ea5e9]" /> <img src="https://web.ccpgamescdn.com/eveonlineassets/developers/eve-sso-login-black-large.png" />
<div class="!bg-black rounded w-[220px] h-[40px] flex items-center justify-center relative z-20">
<.link navigate={~p"/auth/eve?invite=#{@invite_token}"} class="opacity-100">
<img
src="https://web.ccpgamescdn.com/eveonlineassets/developers/eve-sso-login-black-large.png"
class="w-[220px] h-[40px]"
/>
</.link> </.link>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<div class="carousel carousel-center bg-neutral rounded-box max-w-[80%] space-x-4 p-4"> <div class="carousel carousel-center bg-neutral rounded-box max-w-[80%] space-x-4 p-4">
<%= for post <- @posts do %> <%= for post <- @posts do %>
<.link class="group carousel-item relative" navigate={~p"/news/#{post.id}"}> <.link class="group carousel-item relative" navigate={~p"/news/#{post.id}"}>

View File

@@ -319,13 +319,11 @@ defmodule WandererAppWeb.AccessListsLive do
@impl true @impl true
def handle_info({:search, text}, socket) do def handle_info({:search, text}, socket) do
active_character_id = first_character_id =
socket.assigns.current_user.characters socket.assigns.user_character_ids
|> Enum.filter(fn character -> not is_nil(character.refresh_token) end)
|> Enum.map(& &1.id)
|> Enum.at(0) |> Enum.at(0)
{:ok, options} = search(active_character_id, text) {:ok, options} = search(first_character_id, text)
send_update(LiveSelect.Component, options: options, id: socket.assigns.member_search_id) send_update(LiveSelect.Component, options: options, id: socket.assigns.member_search_id)
{:noreply, socket |> assign(member_search_options: options)} {:noreply, socket |> assign(member_search_options: options)}

View File

@@ -12,7 +12,7 @@ defmodule WandererAppWeb.AdminLive do
{:ok, socket.assigns.current_user.characters} {:ok, socket.assigns.current_user.characters}
) )
corp_wallet_character = admin_character =
socket.assigns.current_user.characters socket.assigns.current_user.characters
|> Enum.find(fn character -> |> Enum.find(fn character ->
WandererApp.Character.can_track_corp_wallet?(character) WandererApp.Character.can_track_corp_wallet?(character)
@@ -31,35 +31,39 @@ defmodule WandererAppWeb.AdminLive do
end) end)
socket = socket =
if not is_nil(corp_wallet_character) do if not is_nil(admin_character) do
{:ok, total_balance} = {:ok, total_balance} =
WandererApp.Character.TransactionsTracker.get_total_balance(corp_wallet_character.id) WandererApp.Character.TransactionsTracker.get_total_balance(admin_character.id)
{:ok, transactions} = {:ok, transactions} =
WandererApp.Character.TransactionsTracker.get_transactions(corp_wallet_character.id) WandererApp.Character.TransactionsTracker.get_transactions(admin_character.id)
socket
|> assign(
total_balance: total_balance,
transactions: transactions
)
else
socket
|> assign(
total_balance: 0,
transactions: []
)
end
{:ok, active_map_subscriptions} = {:ok, active_map_subscriptions} =
WandererApp.Api.MapSubscription.all_active() WandererApp.Api.MapSubscription.all_active()
socket
|> assign(
show_invites?: WandererApp.Env.invites(),
admin_character_id: admin_character.id,
total_balance: total_balance,
transactions: transactions,
user_character_ids: user_character_ids,
active_map_subscriptions: active_map_subscriptions
)
else
socket
|> assign(
admin_character_id: nil,
show_invites?: false,
total_balance: 0,
transactions: [],
active_map_subscriptions: []
)
end
{:ok, {:ok,
socket socket
|> assign( |> assign(
active_map_subscriptions: active_map_subscriptions,
show_invites?: WandererApp.Env.invites(),
user_character_ids: user_character_ids,
user_id: user_id, user_id: user_id,
invite_link: nil, invite_link: nil,
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?() map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?()
@@ -68,7 +72,7 @@ defmodule WandererAppWeb.AdminLive do
@impl true @impl true
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
{:ok, socket |> assign(user_id: nil)} {:ok, socket |> assign(user_id: nil, admin_character_id: nil)}
end end
@impl true @impl true

View File

@@ -113,45 +113,45 @@ defmodule WandererAppWeb.MapLive do
} }
} = socket } = socket
) do ) do
on_map_started(map_id, current_user, user_permissions) _on_map_started(map_id, current_user, user_permissions)
{:noreply, socket} {:noreply, socket}
end end
@impl true @impl true
def handle_info(:character_token_invalid, socket), def handle_info(:character_token_invalid, socket) do
do:
{:noreply, {:noreply,
socket socket
|> _put_invalid_token_message()} |> _put_invalid_token_message()}
end
@impl true @impl true
def handle_info(%{event: :add_system, payload: system}, socket), def handle_info(%{event: :add_system, payload: system}, socket) do
do:
{:noreply, {:noreply,
socket socket
|> push_map_event("add_systems", [map_ui_system(system)])} |> push_map_event("add_systems", [map_ui_system(system)])}
end
@impl true @impl true
def handle_info(%{event: :update_system, payload: system}, socket), def handle_info(%{event: :update_system, payload: system}, socket) do
do:
{:noreply, {:noreply,
socket socket
|> push_map_event("update_systems", [map_ui_system(system)])} |> push_map_event("update_systems", [map_ui_system(system)])}
end
@impl true @impl true
def handle_info(%{event: :update_connection, payload: connection}, socket), def handle_info(%{event: :update_connection, payload: connection}, socket) do
do:
{:noreply, {:noreply,
socket socket
|> push_map_event("update_connection", map_ui_connection(connection))} |> push_map_event("update_connection", map_ui_connection(connection))}
end
@impl true @impl true
def handle_info(%{event: :systems_removed, payload: solar_system_ids}, socket), def handle_info(%{event: :systems_removed, payload: solar_system_ids}, socket) do
do:
{:noreply, {:noreply,
socket socket
|> push_map_event("remove_systems", solar_system_ids)} |> push_map_event("remove_systems", solar_system_ids)}
end
@impl true @impl true
def handle_info(%{event: :remove_connections, payload: connections}, socket) do def handle_info(%{event: :remove_connections, payload: connections}, socket) do
@@ -177,97 +177,6 @@ defmodule WandererAppWeb.MapLive do
)} )}
end end
@impl true
def handle_info(
%{
event: :maybe_select_system,
payload: %{
character_id: character_id,
solar_system_id: solar_system_id
}
},
%{assigns: %{current_user: current_user, map_user_settings: map_user_settings}} = socket
) do
is_user_character? =
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
select_on_spash? =
map_user_settings
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|> Map.get("select_on_spash", "false")
|> String.to_existing_atom()
socket =
(is_user_character? && select_on_spash?)
|> case do
true ->
socket
|> push_map_event("select_system", solar_system_id)
false ->
socket
end
{:noreply, socket}
end
@impl true
def handle_info(
%{
event: :maybe_link_signature,
payload: %{
character_id: character_id,
solar_system_source: solar_system_source,
solar_system_target: solar_system_target
}
},
%{
assigns: %{
current_user: current_user,
map_id: map_id,
map_user_settings: map_user_settings
}
} = socket
) do
is_user_character? =
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
link_signature_on_splash? =
map_user_settings
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|> Map.get("link_signature_on_splash", "false")
|> String.to_existing_atom()
{:ok, signatures} =
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
map_id: map_id,
solar_system_id: solar_system_source
})
|> case do
{:ok, system} ->
{:ok, get_system_signatures(system.id)}
_ ->
{:ok, []}
end
socket =
(is_user_character? && link_signature_on_splash? && not (signatures |> Enum.empty?()))
|> case do
true ->
socket
|> push_map_event("link_signature_to_system", %{
solar_system_source: solar_system_source,
solar_system_target: solar_system_target
})
false ->
socket
end
{:noreply, socket}
end
@impl true @impl true
def handle_info(%{event: :update_map, payload: map_diff}, socket) do def handle_info(%{event: :update_map, payload: map_diff}, socket) do
{:noreply, {:noreply,
@@ -511,7 +420,6 @@ defmodule WandererAppWeb.MapLive do
{:map_start, {:map_start,
%{ %{
map_id: map_id, map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids, user_characters: user_character_eve_ids,
initial_data: initial_data, initial_data: initial_data,
events: events events: events
@@ -558,24 +466,20 @@ defmodule WandererAppWeb.MapLive do
{:map_loaded, {:map_loaded,
%{ %{
map_id: map_id, map_id: map_id,
user_characters: user_character_eve_ids,
initial_data: initial_data initial_data: initial_data
}}, }},
10 10
) )
{:noreply, {:noreply, socket}
socket
|> assign(
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
)}
end end
def handle_info( def handle_info(
{:map_loaded, {:map_loaded,
%{ %{
map_id: map_id, map_id: map_id,
user_characters: user_character_eve_ids,
initial_data: initial_data initial_data: initial_data
} = _loaded_data}, } = _loaded_data},
socket socket
@@ -584,7 +488,11 @@ defmodule WandererAppWeb.MapLive do
{:noreply, {:noreply,
socket socket
|> assign(map_loaded?: true) |> assign(
map_loaded?: true,
user_characters: user_character_eve_ids,
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
)
|> push_map_event( |> push_map_event(
"init", "init",
initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1)) initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1))
@@ -1105,7 +1013,7 @@ defmodule WandererAppWeb.MapLive do
s |> WandererApp.Api.MapSystemSignature.create!() s |> WandererApp.Api.MapSystemSignature.create!()
end) end)
{:reply, %{signatures: get_system_signatures(system.id)}, socket} {:reply, %{signatures: _get_system_signatures(system.id)}, socket}
_ -> _ ->
{:reply, %{signatures: []}, {:reply, %{signatures: []},
@@ -1136,7 +1044,7 @@ defmodule WandererAppWeb.MapLive do
solar_system_id: solar_system_id |> String.to_integer() solar_system_id: solar_system_id |> String.to_integer()
}) do }) do
{:ok, system} -> {:ok, system} ->
{:reply, %{signatures: get_system_signatures(system.id)}, socket} {:reply, %{signatures: _get_system_signatures(system.id)}, socket}
_ -> _ ->
{:reply, %{signatures: []}, socket} {:reply, %{signatures: []}, socket}
@@ -1564,93 +1472,7 @@ defmodule WandererAppWeb.MapLive do
end end
@impl true @impl true
def handle_event( def handle_event("noop", _, socket), do: {:noreply, socket}
"open_user_settings",
_,
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
) do
{:ok, user_settings_form} =
WandererApp.MapUserSettingsRepo.get!(map_id, current_user.id)
|> WandererApp.MapUserSettingsRepo.to_form_data()
{:noreply,
socket
|> assign(
show_user_settings?: true,
user_settings_form: user_settings_form |> to_form()
)}
end
@impl true
def handle_event(
"update_user_settings",
user_settings_form,
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
) do
settings =
user_settings_form
|> Map.take(["select_on_spash", "link_signature_on_splash"])
|> Jason.encode!()
{:ok, user_settings} =
WandererApp.MapUserSettingsRepo.create_or_update(map_id, current_user.id, settings)
{:noreply,
socket |> assign(user_settings_form: user_settings_form, map_user_settings: user_settings)}
end
@impl true
def handle_event(
"link_signature_to_system",
%{
"signature_eve_id" => signature_eve_id,
"solar_system_source" => solar_system_source,
"solar_system_target" => solar_system_target
},
socket
) do
socket
|> _check_user_permissions(:update_system)
|> case do
true ->
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
map_id: socket.assigns.map_id,
solar_system_id: solar_system_source
}) do
{:ok, system} ->
first_character_eve_id =
Map.get(socket.assigns, :user_characters, []) |> List.first()
case not is_nil(first_character_eve_id) do
true ->
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|> Enum.each(fn s ->
s
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
linked_system_id: solar_system_target
})
end)
{:noreply, socket}
_ ->
{:noreply,
socket
|> put_flash(
:error,
"You should enable tracking for at least one character to work with signatures."
)}
end
_ ->
{:noreply, socket}
end
_ ->
{:noreply, socket}
end
end
@impl true @impl true
def handle_event("show_activity", _, socket) do def handle_event("show_activity", _, socket) do
@@ -1673,10 +1495,6 @@ defmodule WandererAppWeb.MapLive do
def handle_event("hide_tracking", _, socket), def handle_event("hide_tracking", _, socket),
do: {:noreply, socket |> assign(show_tracking?: false)} do: {:noreply, socket |> assign(show_tracking?: false)}
@impl true
def handle_event("hide_user_settings", _, socket),
do: {:noreply, socket |> assign(show_user_settings?: false)}
@impl true @impl true
def handle_event( def handle_event(
"log_map_error", "log_map_error",
@@ -1695,27 +1513,19 @@ defmodule WandererAppWeb.MapLive do
})} })}
end end
@impl true
def handle_event("noop", _, socket), do: {:noreply, socket}
@impl true @impl true
def handle_event(event, body, socket) do def handle_event(event, body, socket) do
Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end) Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end)
{:noreply, socket} {:noreply, socket}
end end
defp on_map_started( defp _on_map_started(map_id, current_user, user_permissions) do
map_id, case user_permissions do
current_user, %{view_system: true, track_character: track_character} ->
%{view_system: true, track_character: track_character} = user_permissions {:ok, _} = current_user |> WandererApp.Api.User.update_last_map(%{last_map_id: map_id})
) do
with {:ok, _} <- current_user |> WandererApp.Api.User.update_last_map(%{last_map_id: map_id}), {:ok, tracked_map_characters} = _get_tracked_map_characters(map_id, current_user)
{:ok, map_user_settings} <- WandererApp.MapUserSettingsRepo.get(map_id, current_user.id),
{:ok, tracked_map_characters} <- _get_tracked_map_characters(map_id, current_user),
{:ok, characters_limit} <- map_id |> WandererApp.Map.get_characters_limit(),
{:ok, present_character_ids} <-
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", []),
{:ok, kills} <- WandererApp.Cache.lookup("map_#{map_id}:zkb_kills", Map.new()) do
user_character_eve_ids = tracked_map_characters |> Enum.map(& &1.eve_id) user_character_eve_ids = tracked_map_characters |> Enum.map(& &1.eve_id)
events = events =
@@ -1736,6 +1546,11 @@ defmodule WandererAppWeb.MapLive do
events events
end end
{:ok, characters_limit} = map_id |> WandererApp.Map.get_characters_limit()
{:ok, present_character_ids} =
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", [])
events = events =
case present_character_ids |> Enum.count() < characters_limit do case present_character_ids |> Enum.count() < characters_limit do
true -> true ->
@@ -1745,6 +1560,8 @@ defmodule WandererAppWeb.MapLive do
events ++ [:map_character_limit] events ++ [:map_character_limit]
end end
{:ok, kills} = WandererApp.Cache.lookup("map_#{map_id}:zkb_kills", Map.new())
initial_data = initial_data =
map_id map_id
|> _get_map_data() |> _get_map_data()
@@ -1768,7 +1585,6 @@ defmodule WandererAppWeb.MapLive do
map_id map_id
|> WandererApp.Map.list_systems!() |> WandererApp.Map.list_systems!()
|> Enum.map(&WandererApp.CachedInfo.get_system_static_info!(&1.solar_system_id)) |> Enum.map(&WandererApp.CachedInfo.get_system_static_info!(&1.solar_system_id))
|> Enum.map(&map_ui_system_static_info/1)
initial_data = initial_data =
initial_data initial_data
@@ -1782,7 +1598,7 @@ defmodule WandererAppWeb.MapLive do
) )
|> Map.put( |> Map.put(
:system_static_infos, :system_static_infos,
system_static_infos system_static_infos |> Enum.map(&map_ui_system_static_info/1)
) )
|> Map.put(:reset, true) |> Map.put(:reset, true)
@@ -1791,23 +1607,18 @@ defmodule WandererAppWeb.MapLive do
{:map_start, {:map_start,
%{ %{
map_id: map_id, map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids, user_characters: user_character_eve_ids,
initial_data: initial_data, initial_data: initial_data,
events: events events: events
}}, }},
10 10
) )
else
error -> _ ->
Logger.error(fn -> "map_start_error: #{error}" end)
Process.send_after(self(), :no_access, 10) Process.send_after(self(), :no_access, 10)
end end
end end
defp on_map_started(_map_id, _current_user, _user_permissions),
do: Process.send_after(self(), :no_access, 10)
defp _set_autopilot_waypoint( defp _set_autopilot_waypoint(
current_user, current_user,
character_eve_id, character_eve_id,
@@ -1929,11 +1740,11 @@ defmodule WandererAppWeb.MapLive do
end end
end end
defp get_system_signatures(system_id), defp _get_system_signatures(system_id),
do: do:
system_id system_id
|> WandererApp.Api.MapSystemSignature.by_system_id!() |> WandererApp.Api.MapSystemSignature.by_system_id!()
|> Enum.map(fn %{updated_at: updated_at, linked_system_id: linked_system_id} = s -> |> Enum.map(fn %{updated_at: updated_at} = s ->
s s
|> Map.take([ |> Map.take([
:system_id, :system_id,
@@ -1945,7 +1756,6 @@ defmodule WandererAppWeb.MapLive do
:group, :group,
:updated_at :updated_at
]) ])
|> Map.put(:linked_system, get_system_static_info(linked_system_id))
|> Map.put(:updated_at, updated_at |> Calendar.strftime("%Y/%m/%d %H:%M:%S")) |> Map.put(:updated_at, updated_at |> Calendar.strftime("%Y/%m/%d %H:%M:%S"))
end) end)
@@ -2011,7 +1821,14 @@ defmodule WandererAppWeb.MapLive do
} = _system, } = _system,
_include_static_data? \\ true _include_static_data? \\ true
) do ) do
system_static_info = get_system_static_info(solar_system_id) system_static_info =
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
{:ok, system_static_info} ->
map_ui_system_static_info(system_static_info)
_ ->
%{}
end
%{ %{
id: "#{solar_system_id}", id: "#{solar_system_id}",
@@ -2027,18 +1844,6 @@ defmodule WandererAppWeb.MapLive do
} }
end end
defp get_system_static_info(nil), do: nil
defp get_system_static_info(solar_system_id) do
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
{:ok, system_static_info} ->
map_ui_system_static_info(system_static_info)
_ ->
%{}
end
end
defp map_ui_system_static_info(nil), do: %{} defp map_ui_system_static_info(nil), do: %{}
defp map_ui_system_static_info(system_static_info), defp map_ui_system_static_info(system_static_info),

View File

@@ -149,25 +149,3 @@
</.table> </.table>
</.async_result> </.async_result>
</.modal> </.modal>
<.modal
:if={assigns |> Map.get(:show_user_settings?, false)}
id="map-user-settings-modal"
title="Map user settings"
show
on_cancel={JS.push("hide_user_settings")}
>
<.form
:let={f}
:if={assigns |> Map.get(:user_settings_form, false)}
for={@user_settings_form}
phx-change="update_user_settings"
>
<.input type="checkbox" field={f[:select_on_spash]} label="Auto select splashed systems" />
<.input
type="checkbox"
field={f[:link_signature_on_splash]}
label="Link splashed systems to signatures"
/>
</.form>
</.modal>

View File

@@ -5,8 +5,6 @@ defmodule WandererAppWeb.MapsLive do
alias BetterNumber, as: Number alias BetterNumber, as: Number
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
@impl true @impl true
def mount(_params, %{"user_id" => user_id} = _session, socket) when not is_nil(user_id) do def mount(_params, %{"user_id" => user_id} = _session, socket) when not is_nil(user_id) do
{:ok, active_characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id}) {:ok, active_characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id})
@@ -114,8 +112,6 @@ defmodule WandererAppWeb.MapsLive do
"auto_renew?" => true "auto_renew?" => true
} }
{:ok, options_form_data} = WandererApp.MapRepo.options_to_form_data(map)
{:ok, estimated_price, discount} = {:ok, estimated_price, discount} =
WandererApp.Map.SubscriptionManager.estimate_price(subscription_form, false) WandererApp.Map.SubscriptionManager.estimate_price(subscription_form, false)
@@ -134,7 +130,6 @@ defmodule WandererAppWeb.MapsLive do
active_settings_tab: "general", active_settings_tab: "general",
is_adding_subscription?: false, is_adding_subscription?: false,
selected_subscription: nil, selected_subscription: nil,
options_form: options_form_data |> to_form(),
map_subscriptions: map_subscriptions, map_subscriptions: map_subscriptions,
subscription_form: subscription_form |> to_form(), subscription_form: subscription_form |> to_form(),
estimated_price: estimated_price, estimated_price: estimated_price,
@@ -147,10 +142,6 @@ defmodule WandererAppWeb.MapsLive do
{"3 Months", "3"}, {"3 Months", "3"},
{"6 Months", "6"}, {"6 Months", "6"},
{"1 Year", "12"} {"1 Year", "12"}
],
layout_options: [
{"Left To Right", "left_to_right"},
{"Top To Bottom", "top_to_bottom"}
] ]
) )
|> allow_upload(:settings, |> allow_upload(:settings,
@@ -654,26 +645,6 @@ defmodule WandererAppWeb.MapsLive do
|> push_patch(to: ~p"/maps")} |> push_patch(to: ~p"/maps")}
end end
def handle_event(
"update_options",
options_form,
%{assigns: %{map_id: map_id, map: map}} = socket
) do
options =
options_form
|> Map.take(["layout", "store_custom_labels"])
{:ok, updated_map} = WandererApp.MapRepo.update_options(map, options)
@pubsub_client.broadcast(
WandererApp.PubSub,
"maps:#{map_id}",
{:options_updated, options}
)
{:noreply, socket |> assign(map: updated_map, options_form: options_form)}
end
@impl true @impl true
def handle_event("noop", _, socket) do def handle_event("noop", _, socket) do
{:noreply, socket} {:noreply, socket}

View File

@@ -26,6 +26,7 @@
> >
<figure class="absolute z-10 h-200 avatar w-full h-full"> <figure class="absolute z-10 h-200 avatar w-full h-full">
<img :if={map.scope === :all} class="absolute h-200" src="/images/all_back.webp" /> <img :if={map.scope === :all} class="absolute h-200" src="/images/all_back.webp" />
<img <img
:if={map.scope === :wormholes} :if={map.scope === :wormholes}
class="absolute h-200" class="absolute h-200"
@@ -189,6 +190,7 @@
> >
<div role="tablist" class="tabs tabs-bordered"> <div role="tablist" class="tabs tabs-bordered">
<a <a
:if={@map_subscriptions_enabled?}
role="tab" role="tab"
phx-click="change_settings_tab" phx-click="change_settings_tab"
phx-value-tab="general" phx-value-tab="general"
@@ -199,17 +201,6 @@
> >
<.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" />&nbsp;General <.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" />&nbsp;General
</a> </a>
<a
role="tab"
phx-click="change_settings_tab"
phx-value-tab="import"
class={[
"tab",
classes("tab-active": @active_settings_tab == "import")
]}
>
<.icon name="hero-document-arrow-down-solid" class="w-4 h-4" />&nbsp;Import/Export
</a>
<a <a
:if={@map_subscriptions_enabled?} :if={@map_subscriptions_enabled?}
role="tab" role="tab"
@@ -236,34 +227,6 @@
</a> </a>
</div> </div>
<.header :if={@active_settings_tab == "general"} class="bordered border-1 border-zinc-800"> <.header :if={@active_settings_tab == "general"} class="bordered border-1 border-zinc-800">
<:actions>
<.form
:let={f}
:if={assigns |> Map.get(:options_form, false)}
for={@options_form}
phx-change="update_options"
>
<div>
<div class="stat-title">Map systems layout</div>
<div class="stat-value text-white">
<.input
type="select"
field={f[:layout]}
class="p-dropdown p-component p-inputwrapper"
placeholder="Map default layout"
options={@layout_options}
/>
</div>
</div>
<.input
type="checkbox"
field={f[:store_custom_labels]}
label="Store system custom labels"
/>
</.form>
</:actions>
</.header>
<.header :if={@active_settings_tab == "import"} class="bordered border-1 border-zinc-800">
Import/Export Map Settings Import/Export Map Settings
<:actions> <:actions>
<.form :if={assigns |> Map.get(:import_form, false)} for={@import_form} phx-change="import"> <.form :if={assigns |> Map.get(:import_form, false)} for={@import_form} phx-change="import">

View File

@@ -58,8 +58,7 @@ defmodule WandererAppWeb.Router do
~w('unsafe-inline'), ~w('unsafe-inline'),
~w(https://unpkg.com), ~w(https://unpkg.com),
~w(https://w.appzi.io), ~w(https://w.appzi.io),
~w(https://www.googletagmanager.com), ~w(https://www.googletagmanager.com)
~w(https://cdnjs.cloudflare.com)
], ],
style_src: @style_src, style_src: @style_src,
img_src: @img_src, img_src: @img_src,

View File

@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
use Mix.Project use Mix.Project
@source_url "https://github.com/wanderer-industries/wanderer" @source_url "https://github.com/wanderer-industries/wanderer"
@version "1.11.0" @version "1.3.1"
def project do def project do
[ [

View File

@@ -100,9 +100,9 @@
"dest": "c5", "dest": "c5",
"src": ["c6"], "src": ["c6"],
"static": true, "static": true,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": [], "sibling_groups": [],
"typeID": 30711, "typeID": 30711,
"name": "V911" "name": "V911"
@@ -124,9 +124,9 @@
"dest": "c6", "dest": "c6",
"src": ["c6"], "src": ["c6"],
"static": true, "static": true,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": [], "sibling_groups": [],
"typeID": 30712, "typeID": 30712,
"name": "W237" "name": "W237"
@@ -172,9 +172,9 @@
"dest": "c6", "dest": "c6",
"src": ["c5"], "src": ["c5"],
"static": true, "static": true,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": [], "sibling_groups": [],
"typeID": 30703, "typeID": 30703,
"name": "V753" "name": "V753"
@@ -208,9 +208,9 @@
"dest": "c6", "dest": "c6",
"src": ["ls", "ns"], "src": ["ls", "ns"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "48", "lifetime": "48",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30646, "typeID": 30646,
"name": "U319" "name": "U319"
@@ -424,9 +424,9 @@
"dest": "ns", "dest": "ns",
"src": ["c5", "c6"], "src": ["c5", "c6"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "16", "lifetime": "16",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30706, "typeID": 30706,
"name": "Z142" "name": "Z142"
@@ -532,9 +532,9 @@
"dest": "ls", "dest": "ls",
"src": ["c4"], "src": ["c4"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30696, "typeID": 30696,
"name": "N290" "name": "N290"
@@ -616,9 +616,9 @@
"dest": "c5", "dest": "c5",
"src": ["c5"], "src": ["c5"],
"static": true, "static": true,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": [], "sibling_groups": [],
"typeID": 30702, "typeID": 30702,
"name": "H296" "name": "H296"
@@ -772,7 +772,7 @@
"dest": "c5", "dest": "c5",
"src": ["c2"], "src": ["c2"],
"static": true, "static": true,
"max_mass_per_jump": 375000000, "max_mass_per_jump": 300000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3000000000, "total_mass": 3000000000,
"sibling_groups": [["E545"]], "sibling_groups": [["E545"]],
@@ -796,9 +796,9 @@
"dest": "ns", "dest": "ns",
"src": ["ls", "ns"], "src": ["ls", "ns"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "16", "lifetime": "16",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30649, "typeID": 30649,
"name": "S199" "name": "S199"
@@ -844,9 +844,9 @@
"dest": "ls", "dest": "ls",
"src": ["ls", "ns"], "src": ["ls", "ns"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30648, "typeID": 30648,
"name": "N944" "name": "N944"
@@ -1024,9 +1024,9 @@
"dest": "c5", "dest": "c5",
"src": ["ls", "ns"], "src": ["ls", "ns"],
"static": false, "static": false,
"max_mass_per_jump": 2000000000, "max_mass_per_jump": 1350000000,
"lifetime": "24", "lifetime": "24",
"total_mass": 3300000000, "total_mass": 3000000000,
"sibling_groups": null, "sibling_groups": null,
"typeID": 30643, "typeID": 30643,
"name": "N432" "name": "N432"

View File

@@ -1,21 +0,0 @@
defmodule WandererApp.Repo.Migrations.AddMapOptions do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
alter table(:maps_v1) do
add :options, :text
end
end
def down do
alter table(:maps_v1) do
remove :options
end
end
end

View File

@@ -1,52 +0,0 @@
defmodule WandererApp.Repo.Migrations.AddMapUserSettings do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
create table(:map_user_settings_v1, primary_key: false) do
add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true
add :settings, :text
add :map_id,
references(:maps_v1,
column: :id,
name: "map_user_settings_v1_map_id_fkey",
type: :uuid,
prefix: "public"
),
primary_key: true,
null: false
add :user_id,
references(:user_v1,
column: :id,
name: "map_user_settings_v1_user_id_fkey",
type: :uuid,
prefix: "public"
),
primary_key: true,
null: false
end
create unique_index(:map_user_settings_v1, [:map_id, :user_id],
name: "map_user_settings_v1_uniq_map_user_index"
)
end
def down do
drop_if_exists unique_index(:map_user_settings_v1, [:map_id, :user_id],
name: "map_user_settings_v1_uniq_map_user_index"
)
drop constraint(:map_user_settings_v1, "map_user_settings_v1_map_id_fkey")
drop constraint(:map_user_settings_v1, "map_user_settings_v1_user_id_fkey")
drop table(:map_user_settings_v1)
end
end

View File

@@ -1,21 +0,0 @@
defmodule WandererApp.Repo.Migrations.AddSignatureLinkedSystem do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
alter table(:map_system_signatures_v1) do
add :linked_system_id, :bigint
end
end
def down do
alter table(:map_system_signatures_v1) do
remove :linked_system_id
end
end
end

View File

@@ -1,167 +0,0 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "eve_id",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "character_eve_id",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "name",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "description",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "linked_system_id",
"type": "bigint"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "kind",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "group",
"type": "text"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_system_signatures_v1_system_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "map_system_v1"
},
"size": null,
"source": "system_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "B437BC9E9F4607EBD235CBB39B814710E223D532CE09B952C9371257159008F4",
"identities": [
{
"all_tenants?": false,
"base_filter": null,
"index_name": "map_system_signatures_v1_uniq_system_eve_id_index",
"keys": [
{
"type": "atom",
"value": "system_id"
},
{
"type": "atom",
"value": "eve_id"
}
],
"name": "uniq_system_eve_id",
"nils_distinct?": true,
"where": null
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_system_signatures_v1"
}

View File

@@ -1,116 +0,0 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "settings",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_user_settings_v1_map_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "maps_v1"
},
"size": null,
"source": "map_id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_user_settings_v1_user_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "user_v1"
},
"size": null,
"source": "user_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "88FB044C6F66793E2247BF2CEE17F2E4ED52C007C3DDCE02B6EF583EDDD44D85",
"identities": [
{
"all_tenants?": false,
"base_filter": null,
"index_name": "map_user_settings_v1_uniq_map_user_index",
"keys": [
{
"type": "atom",
"value": "map_id"
},
{
"type": "atom",
"value": "user_id"
}
],
"name": "uniq_map_user",
"nils_distinct?": true,
"where": null
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_user_settings_v1"
}

View File

@@ -1,186 +0,0 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "name",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "slug",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "description",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "personal_note",
"type": "text"
},
{
"allow_nil?": true,
"default": "[]",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "hubs",
"type": [
"array",
"text"
]
},
{
"allow_nil?": false,
"default": "\"wormholes\"",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "scope",
"type": "text"
},
{
"allow_nil?": true,
"default": "false",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "deleted",
"type": "boolean"
},
{
"allow_nil?": true,
"default": "false",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "only_tracked_characters",
"type": "boolean"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "options",
"type": "text"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "maps_v1_owner_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "character_v1"
},
"size": null,
"source": "owner_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "E5FC6B5F1B9AD5E23163494C7C93A8002F9C812AFC7A26A8C33A344877086A03",
"identities": [
{
"all_tenants?": false,
"base_filter": null,
"index_name": "maps_v1_unique_slug_index",
"keys": [
{
"type": "atom",
"value": "slug"
}
],
"name": "unique_slug",
"nils_distinct?": true,
"where": null
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "maps_v1"
}