Compare commits
64 Commits
v1.78.1
...
show-temp-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b4852d5b4 | ||
|
|
5343c34488 | ||
|
|
4878be1a53 | ||
|
|
1ff689c26c | ||
|
|
79b660e899 | ||
|
|
665a679bd5 | ||
|
|
7bd634eb95 | ||
|
|
c3b5a77a86 | ||
|
|
12f39a0133 | ||
|
|
ffc2a86e95 | ||
|
|
82babf41a2 | ||
|
|
81055b4fbd | ||
|
|
5070a59f88 | ||
|
|
65d5bf960d | ||
|
|
8fc4cb190e | ||
|
|
095a4b2362 | ||
|
|
fafc631e49 | ||
|
|
e56383c8b1 | ||
|
|
b9c26bdb04 | ||
|
|
8aeaa81752 | ||
|
|
b16ec0490f | ||
|
|
eceaf1d73b | ||
|
|
34cf668a33 | ||
|
|
c22d410c9f | ||
|
|
fc6af867f2 | ||
|
|
2d96114984 | ||
|
|
fd7e19e490 | ||
|
|
f7d996f5b2 | ||
|
|
f8ab1383ab | ||
|
|
e1559aac94 | ||
|
|
2e17cce5cd | ||
|
|
8fb831f171 | ||
|
|
cb84f34515 | ||
|
|
272cce1a77 | ||
|
|
e0e3ed1580 | ||
|
|
c4c848cf37 | ||
|
|
32d25d86eb | ||
|
|
863adccac1 | ||
|
|
2d527e1d16 | ||
|
|
9a64ad6fa7 | ||
|
|
5ce472ebff | ||
|
|
76588af12f | ||
|
|
134f169eb9 | ||
|
|
7c2d731c4c | ||
|
|
c7e2a290cf | ||
|
|
5ea966892a | ||
|
|
b879db76b7 | ||
|
|
d13a628029 | ||
|
|
7c1e2595e3 | ||
|
|
a99e8a915e | ||
|
|
36f424da0b | ||
|
|
c0a65d5a23 | ||
|
|
02e31333d2 | ||
|
|
d69616119d | ||
|
|
dbc770d40b | ||
|
|
e69a8fece5 | ||
|
|
3b24c760ff | ||
|
|
3801f0be18 | ||
|
|
f3104db2e4 | ||
|
|
4bfe60b75c | ||
|
|
6a44d10c56 | ||
|
|
c789b69b54 | ||
|
|
302fb0642d | ||
|
|
33acd55eaa |
@@ -13,4 +13,4 @@ export WANDERER_KILLS_BASE_URL="ws://host.docker.internal:4004"
|
||||
export WANDERER_SSE_ENABLED="true"
|
||||
export WANDERER_WEBHOOKS_ENABLED="true"
|
||||
export WANDERER_SSE_MAX_CONNECTIONS="1000"
|
||||
export WANDERER_WEBHOOK_TIMEOUT_MS="15000"
|
||||
export WANDERER_WEBHOOK_TIMEOUT_MS="15000"
|
||||
|
||||
126
CHANGELOG.md
@@ -2,6 +2,132 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.81.5](https://github.com/wanderer-industries/wanderer/compare/v1.81.4...v1.81.5) (2025-10-09)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Update connection ship size based on linked signature type
|
||||
|
||||
## [v1.81.4](https://github.com/wanderer-industries/wanderer/compare/v1.81.3...v1.81.4) (2025-10-09)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed signature to system link issues
|
||||
|
||||
## [v1.81.3](https://github.com/wanderer-industries/wanderer/compare/v1.81.2...v1.81.3) (2025-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed cancel ping errors
|
||||
|
||||
## [v1.81.2](https://github.com/wanderer-industries/wanderer/compare/v1.81.1...v1.81.2) (2025-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* api dropping custom name
|
||||
|
||||
## [v1.81.1](https://github.com/wanderer-industries/wanderer/compare/v1.81.0...v1.81.1) (2025-10-02)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed characters tracking updates.
|
||||
|
||||
## [v1.81.0](https://github.com/wanderer-industries/wanderer/compare/v1.80.0...v1.81.0) (2025-10-02)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* core: fix pwa icons + add screen in manifest
|
||||
|
||||
## [v1.80.0](https://github.com/wanderer-industries/wanderer/compare/v1.79.6...v1.80.0) (2025-10-02)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Core: Added PWA web manifest
|
||||
|
||||
## [v1.79.6](https://github.com/wanderer-industries/wanderer/compare/v1.79.5...v1.79.6) (2025-10-01)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed modals auto-save on Enter.
|
||||
|
||||
## [v1.79.5](https://github.com/wanderer-industries/wanderer/compare/v1.79.4...v1.79.5) (2025-10-01)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed system details modal auto-save on Enter.
|
||||
|
||||
## [v1.79.4](https://github.com/wanderer-industries/wanderer/compare/v1.79.3...v1.79.4) (2025-09-30)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed updating connection time status based on linked signature data. Fixed FR gas sites parsing.
|
||||
|
||||
## [v1.79.3](https://github.com/wanderer-industries/wanderer/compare/v1.79.2...v1.79.3) (2025-09-27)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed connection passages count
|
||||
|
||||
## [v1.79.2](https://github.com/wanderer-industries/wanderer/compare/v1.79.1...v1.79.2) (2025-09-26)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.79.1](https://github.com/wanderer-industries/wanderer/compare/v1.79.0...v1.79.1) (2025-09-26)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.79.0](https://github.com/wanderer-industries/wanderer/compare/v1.78.1...v1.79.0) (2025-09-26)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Core: Updated connections EOL logic
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Map: Fixed eslint problems
|
||||
|
||||
* Map: Update lifetime design and buttons
|
||||
|
||||
* Map: Update wormhole lifetime UI and removed unnecessary code
|
||||
|
||||
## [v1.78.1](https://github.com/wanderer-industries/wanderer/compare/v1.78.0...v1.78.1) (2025-09-24)
|
||||
|
||||
|
||||
|
||||
@@ -18,5 +18,28 @@ module.exports = {
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
"linebreak-style": "off",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"name": "primereact/button",
|
||||
"importNames": ["Button"],
|
||||
"message": "Use WdButton instead Button"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"react/forbid-elements": [
|
||||
"error",
|
||||
{
|
||||
"forbid": [
|
||||
{
|
||||
"element": "Button",
|
||||
"message": "Use WdButton instead Button"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,8 +5,7 @@ import { SolarSystemRawType } from '@/hooks/Mapper/types';
|
||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||
import clsx from 'clsx';
|
||||
import { GRADIENT_MENU_ACTIVE_CLASSES } from '@/hooks/Mapper/constants.ts';
|
||||
import { LayoutEventBlocker } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { Button } from 'primereact/button';
|
||||
import { LayoutEventBlocker, WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
const AVAILABLE_TAGS = [
|
||||
'A',
|
||||
@@ -61,7 +60,7 @@ export const useTagMenu = (
|
||||
<LayoutEventBlocker className="flex flex-col gap-1 w-[200px] h-full px-2">
|
||||
<div className="grid grid-cols-[auto_auto_auto_auto_auto_auto] gap-1">
|
||||
{AVAILABLE_TAGS.map(x => (
|
||||
<Button
|
||||
<WdButton
|
||||
outlined={system?.tag !== x}
|
||||
severity="warning"
|
||||
key={x}
|
||||
@@ -71,9 +70,9 @@ export const useTagMenu = (
|
||||
onClick={() => system?.tag !== x && onSystemTag(x)}
|
||||
>
|
||||
{x}
|
||||
</Button>
|
||||
</WdButton>
|
||||
))}
|
||||
<Button
|
||||
<WdButton
|
||||
disabled={!isSelectedTag}
|
||||
icon="pi pi-ban"
|
||||
size="small"
|
||||
@@ -81,7 +80,7 @@ export const useTagMenu = (
|
||||
outlined
|
||||
severity="help"
|
||||
onClick={() => onSystemTag()}
|
||||
></Button>
|
||||
></WdButton>
|
||||
</div>
|
||||
</LayoutEventBlocker>
|
||||
);
|
||||
|
||||
@@ -19,3 +19,14 @@
|
||||
.SelectedItem {
|
||||
background-color: var(--selected-item-bg);
|
||||
}
|
||||
|
||||
.FastActions {
|
||||
:global {
|
||||
.p-menuitem-content {
|
||||
background-color: initial !important;
|
||||
}
|
||||
.p-menuitem-content:hover {
|
||||
background-color: initial !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ContextMenu } from 'primereact/contextmenu';
|
||||
import { MenuItem } from 'primereact/menuitem';
|
||||
import React, { RefObject, useMemo } from 'react';
|
||||
import { Edge } from 'reactflow';
|
||||
import { LifetimeActionsWrapper } from '@/hooks/Mapper/components/map/components/ContextMenuConnection/LifetimeActionsWrapper.tsx';
|
||||
import classes from './ContextMenuConnection.module.scss';
|
||||
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic.ts';
|
||||
import { isNullsecSpace } from '@/hooks/Mapper/components/map/helpers/isKnownSpace.ts';
|
||||
@@ -20,7 +21,7 @@ import { isNullsecSpace } from '@/hooks/Mapper/components/map/helpers/isKnownSpa
|
||||
export interface ContextMenuConnectionProps {
|
||||
contextMenuRef: RefObject<ContextMenu>;
|
||||
onDeleteConnection(): void;
|
||||
onChangeTimeState(): void;
|
||||
onChangeTimeState(lifetime: TimeStatus): void;
|
||||
onChangeMassState(state: MassState): void;
|
||||
onChangeShipSizeStatus(state: ShipSizeStatus): void;
|
||||
onChangeType(type: ConnectionType): void;
|
||||
@@ -80,12 +81,10 @@ export const ContextMenuConnection: React.FC<ContextMenuConnectionProps> = ({
|
||||
|
||||
return [
|
||||
{
|
||||
label: `EOL`,
|
||||
className: clsx({
|
||||
[classes.ConnectionTimeEOL]: edge.data?.time_status === TimeStatus.eol,
|
||||
}),
|
||||
icon: PrimeIcons.CLOCK,
|
||||
command: onChangeTimeState,
|
||||
className: clsx(classes.FastActions, '!h-[54px]'),
|
||||
template: () => {
|
||||
return <LifetimeActionsWrapper lifetime={edge.data?.time_status} onChangeLifetime={onChangeTimeState} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: `Frigate`,
|
||||
@@ -121,7 +120,6 @@ export const ContextMenuConnection: React.FC<ContextMenuConnectionProps> = ({
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
{
|
||||
label: `Ship Size`,
|
||||
icon: PrimeIcons.CLOUD,
|
||||
@@ -169,7 +167,7 @@ export const ContextMenuConnection: React.FC<ContextMenuConnectionProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContextMenu model={items} ref={contextMenuRef} onHide={onHide} breakpoint="767px" />
|
||||
<ContextMenu model={items} ref={contextMenuRef} onHide={onHide} breakpoint="767px" className="!w-[250px]" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { LayoutEventBlocker } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { WdLifetimeSelector, WdLifetimeSelectorProps } from '@/hooks/Mapper/components/ui-kit/WdLifetimeSelector.tsx';
|
||||
|
||||
export const LifetimeActionsWrapper = (props: WdLifetimeSelectorProps) => {
|
||||
return (
|
||||
<LayoutEventBlocker className="flex flex-col gap-1 w-[100%] h-full px-2 pt-[4px]">
|
||||
<div className="text-[12px] text-stone-500 font-semibold">Life time:</div>
|
||||
|
||||
<WdLifetimeSelector {...props} />
|
||||
</LayoutEventBlocker>
|
||||
);
|
||||
};
|
||||
@@ -30,7 +30,7 @@ export const useContextMenuConnectionHandlers = () => {
|
||||
setEdge(undefined);
|
||||
};
|
||||
|
||||
const onChangeTimeState = () => {
|
||||
const onChangeTimeState = (lifetime: TimeStatus) => {
|
||||
if (!edge || !edge.data) {
|
||||
return;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export const useContextMenuConnectionHandlers = () => {
|
||||
data: {
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
value: edge.data.time_status === TimeStatus.default ? TimeStatus.eol : TimeStatus.default,
|
||||
value: lifetime,
|
||||
},
|
||||
});
|
||||
setEdge(undefined);
|
||||
|
||||
@@ -5,6 +5,16 @@
|
||||
stroke: #80a5c5;
|
||||
stroke-width: 3px;
|
||||
|
||||
&.time1 {
|
||||
stroke: #f11ab2;
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
&.time4 {
|
||||
stroke: #a654e3;
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
&.TimeCrit {
|
||||
stroke: #f11ab2;
|
||||
stroke-width: 4px;
|
||||
|
||||
@@ -80,7 +80,8 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
||||
id={`back_${id}`}
|
||||
className={clsx(classes.EdgePathBack, {
|
||||
[classes.Tick]: isThickConnections,
|
||||
[classes.TimeCrit]: isWormhole && data.time_status === TimeStatus.eol,
|
||||
[classes.time1]: isWormhole && data.time_status === TimeStatus._1h,
|
||||
[classes.time4]: isWormhole && data.time_status === TimeStatus._4h,
|
||||
[classes.Hovered]: hovered,
|
||||
[classes.Gate]: isGate,
|
||||
[classes.Bridge]: isBridge,
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { SystemViewStandalone, WdButton, WHClassView, WHEffectView } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { AutoComplete } from 'primereact/autocomplete';
|
||||
import { OutCommand, SearchSystemItem } from '@/hooks/Mapper/types';
|
||||
import { SystemViewStandalone, WHClassView, WHEffectView } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { AutoComplete } from 'primereact/autocomplete';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import classes from './AddSystemDialog.module.scss';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace.ts';
|
||||
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
||||
import clsx from 'clsx';
|
||||
|
||||
export type SearchOnSubmitCallback = (item: SearchSystemItem) => void;
|
||||
|
||||
@@ -34,6 +33,7 @@ export const AddSystemDialog = ({
|
||||
data: { wormholesData },
|
||||
} = useMapRootState();
|
||||
|
||||
// TODO fix it
|
||||
const inputRef = useRef<any>();
|
||||
const onShow = useCallback(() => {
|
||||
inputRef.current?.focus();
|
||||
@@ -62,6 +62,7 @@ export const AddSystemDialog = ({
|
||||
},
|
||||
});
|
||||
|
||||
// TODO fix it
|
||||
let prepared = (result.systems as SearchSystemItem[]).sort((a, b) => {
|
||||
const amatch = a.label.indexOf(query);
|
||||
const bmatch = b.label.indexOf(query);
|
||||
@@ -114,90 +115,93 @@ export const AddSystemDialog = ({
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-3 px-1.5">
|
||||
<div className="flex flex-col gap-2 py-3.5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<IconField>
|
||||
<AutoComplete
|
||||
ref={inputRef}
|
||||
multiple
|
||||
showEmptyMessage
|
||||
scrollHeight="300px"
|
||||
value={selectedItem}
|
||||
suggestions={filteredItems}
|
||||
completeMethod={searchItems}
|
||||
onChange={e => {
|
||||
setSelectedItem(e.value.length < 2 ? e.value : [e.value[e.value.length - 1]]);
|
||||
}}
|
||||
emptyMessage="Not found any system..."
|
||||
placeholder="Type here..."
|
||||
field="label"
|
||||
id="value"
|
||||
className="w-full"
|
||||
itemTemplate={(item: SearchSystemItem) => {
|
||||
const { security, system_class, effect_power, effect_name, statics } = item.system_static_info;
|
||||
const sortedStatics = sortWHClasses(wormholesData, statics);
|
||||
const isWH = isWormholeSpace(system_class);
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col gap-3 px-1.5">
|
||||
<div className="flex flex-col gap-2 py-3.5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<IconField>
|
||||
<AutoComplete
|
||||
ref={inputRef}
|
||||
multiple
|
||||
showEmptyMessage
|
||||
scrollHeight="300px"
|
||||
value={selectedItem}
|
||||
suggestions={filteredItems}
|
||||
completeMethod={searchItems}
|
||||
onChange={e => {
|
||||
setSelectedItem(e.value.length < 2 ? e.value : [e.value[e.value.length - 1]]);
|
||||
}}
|
||||
emptyMessage="Not found any system..."
|
||||
placeholder="Type here..."
|
||||
field="label"
|
||||
id="value"
|
||||
className="w-full"
|
||||
itemTemplate={(item: SearchSystemItem) => {
|
||||
const { security, system_class, effect_power, effect_name, statics } = item.system_static_info;
|
||||
const sortedStatics = sortWHClasses(wormholesData, statics);
|
||||
const isWH = isWormholeSpace(system_class);
|
||||
|
||||
return (
|
||||
<div className={clsx('flex gap-1.5', classes.SearchItem)}>
|
||||
<SystemViewStandalone
|
||||
security={security}
|
||||
system_class={system_class}
|
||||
solar_system_id={item.value}
|
||||
class_title={item.class_title}
|
||||
solar_system_name={item.label}
|
||||
region_name={item.region_name}
|
||||
/>
|
||||
|
||||
{effect_name && isWH && (
|
||||
<WHEffectView
|
||||
effectName={effect_name}
|
||||
effectPower={effect_power}
|
||||
className={classes.SearchItemEffect}
|
||||
return (
|
||||
<div className={clsx('flex gap-1.5', classes.SearchItem)}>
|
||||
<SystemViewStandalone
|
||||
security={security}
|
||||
system_class={system_class}
|
||||
solar_system_id={item.value}
|
||||
class_title={item.class_title}
|
||||
solar_system_name={item.label}
|
||||
region_name={item.region_name}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isWH && (
|
||||
<div className="flex gap-1 grow justify-between">
|
||||
<div></div>
|
||||
<div className="flex gap-1">
|
||||
{sortedStatics.map(x => (
|
||||
<WHClassView key={x} whClassName={x} />
|
||||
))}
|
||||
{effect_name && isWH && (
|
||||
<WHEffectView
|
||||
effectName={effect_name}
|
||||
effectPower={effect_power}
|
||||
className={classes.SearchItemEffect}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isWH && (
|
||||
<div className="flex gap-1 grow justify-between">
|
||||
<div></div>
|
||||
<div className="flex gap-1">
|
||||
{sortedStatics.map(x => (
|
||||
<WHClassView key={x} whClassName={x} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
selectedItemTemplate={(item: SearchSystemItem) => (
|
||||
<SystemViewStandalone
|
||||
security={item.system_static_info.security}
|
||||
system_class={item.system_static_info.system_class}
|
||||
solar_system_id={item.value}
|
||||
class_title={item.class_title}
|
||||
solar_system_name={item.label}
|
||||
region_name={item.region_name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</IconField>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
selectedItemTemplate={(item: SearchSystemItem) => (
|
||||
<SystemViewStandalone
|
||||
security={item.system_static_info.security}
|
||||
system_class={item.system_static_info.system_class}
|
||||
solar_system_id={item.value}
|
||||
class_title={item.class_title}
|
||||
solar_system_name={item.label}
|
||||
region_name={item.region_name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</IconField>
|
||||
|
||||
<span className="text-[12px] text-stone-400 ml-1">*to search type at least 2 symbols.</span>
|
||||
<span className="text-[12px] text-stone-400 ml-1">*to search type at least 2 symbols.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<WdButton
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
outlined
|
||||
disabled={!selectedItem || selectedItem.length !== 1}
|
||||
size="small"
|
||||
label="Submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
outlined
|
||||
disabled={!selectedItem || selectedItem.length !== 1}
|
||||
size="small"
|
||||
label="Submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
SystemView,
|
||||
TimeAgo,
|
||||
TooltipPosition,
|
||||
WdButton,
|
||||
WdImgButton,
|
||||
WdImgButtonTooltip,
|
||||
} from '@/hooks/Mapper/components/ui-kit';
|
||||
@@ -13,7 +14,6 @@ import { PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||
import { Commands, OutCommand, PingType } from '@/hooks/Mapper/types';
|
||||
import clsx from 'clsx';
|
||||
import { PrimeIcons } from 'primereact/api';
|
||||
import { Button } from 'primereact/button';
|
||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
@@ -256,7 +256,7 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
|
||||
)}
|
||||
></Toast>
|
||||
|
||||
<Button
|
||||
<WdButton
|
||||
icon="pi pi-bell"
|
||||
severity="warning"
|
||||
aria-label="Notification"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { TooltipPosition, WdButton, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||
import { WdImageSize, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
interface SystemCustomLabelDialog {
|
||||
systemId: string;
|
||||
@@ -126,7 +125,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
||||
<WdButton type="submit" onClick={handleSave} outlined size="small" label="Save"></WdButton>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -9,10 +9,9 @@ import {
|
||||
} from '@/hooks/Mapper/components/map/constants.ts';
|
||||
import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent';
|
||||
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
||||
import { getWhSize } from '@/hooks/Mapper/helpers/getWhSize';
|
||||
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { CommandLinkSignatureToSystem, SignatureGroup, SystemSignature, TimeStatus } from '@/hooks/Mapper/types';
|
||||
import { CommandLinkSignatureToSystem, SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||
import { SETTINGS_KEYS, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
||||
|
||||
@@ -116,14 +115,14 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
|
||||
);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
async (signature: SystemSignature) => {
|
||||
(signature: SystemSignature) => {
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { outCommand } = ref.current;
|
||||
|
||||
await outCommand({
|
||||
outCommand({
|
||||
type: OutCommand.linkSignatureToSystem,
|
||||
data: {
|
||||
...data,
|
||||
@@ -131,32 +130,9 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
|
||||
},
|
||||
});
|
||||
|
||||
if (parseSignatureCustomInfo(signature.custom_info).isEOL === true) {
|
||||
await outCommand({
|
||||
type: OutCommand.updateConnectionTimeStatus,
|
||||
data: {
|
||||
source: data.solar_system_source,
|
||||
target: data.solar_system_target,
|
||||
value: TimeStatus.eol,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const whShipSize = getWhSize(wormholes, signature.type);
|
||||
if (whShipSize !== undefined && whShipSize !== null) {
|
||||
await outCommand({
|
||||
type: OutCommand.updateConnectionShipSizeType,
|
||||
data: {
|
||||
source: data.solar_system_source,
|
||||
target: data.solar_system_target,
|
||||
value: whShipSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
},
|
||||
[data, setVisible, wormholes],
|
||||
[data, setVisible],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { SystemView, WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { PingType } from '@/hooks/Mapper/types/ping.ts';
|
||||
import { SystemView } from '@/hooks/Mapper/components/ui-kit';
|
||||
import clsx from 'clsx';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
const PING_TITLES = {
|
||||
[PingType.Rally]: 'RALLY',
|
||||
@@ -63,7 +62,7 @@ export const SystemPingDialog = ({ systemId, type, visible, setVisible }: System
|
||||
</div>
|
||||
}
|
||||
visible={visible}
|
||||
draggable={false}
|
||||
draggable={true}
|
||||
style={{ width: '450px' }}
|
||||
onShow={onShow}
|
||||
onHide={() => {
|
||||
@@ -92,7 +91,7 @@ export const SystemPingDialog = ({ systemId, type, visible, setVisible }: System
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} size="small" severity="danger" label="Ping!"></Button>
|
||||
<WdButton type="submit" onClick={handleSave} size="small" severity="danger" label="Ping!" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { TooltipPosition, WdButton, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { TooltipPosition, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
interface SystemSettingsDialog {
|
||||
systemId: string;
|
||||
@@ -226,7 +225,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
||||
<WdButton onClick={handleSave} outlined size="small" label="Save" type="submit" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useRouteProvider } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
|
||||
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import {
|
||||
RoutesType,
|
||||
useRouteProvider,
|
||||
} from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
|
||||
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
||||
|
||||
interface RoutesSettingsDialog {
|
||||
visible: boolean;
|
||||
@@ -83,7 +81,7 @@ export const RoutesSettingsDialog = ({ visible, setVisible }: RoutesSettingsDial
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} outlined size="small" label="Apply"></Button>
|
||||
<WdButton onClick={handleSave} outlined size="small" label="Apply"></WdButton>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { TabPanel, TabView } from 'primereact/tabview';
|
||||
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
@@ -10,6 +9,7 @@ import {
|
||||
SIGNATURE_SETTINGS,
|
||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
|
||||
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
interface SystemSignatureSettingsDialogProps {
|
||||
settings: SignatureSettingsType;
|
||||
@@ -92,7 +92,7 @@ export const SystemSignatureSettingsDialog = ({
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
||||
<WdButton onClick={handleSave} outlined size="small" label="Save" />
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { Button } from 'primereact/button';
|
||||
import { AutoComplete } from 'primereact/autocomplete';
|
||||
import { Calendar } from 'primereact/calendar';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { StructureItem, StructureStatus, statusesRequiringTimer, formatToISO } from '../helpers';
|
||||
import { formatToISO, statusesRequiringTimer, StructureItem, StructureStatus } from '../helpers';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
interface StructuresEditDialogProps {
|
||||
visible: boolean;
|
||||
@@ -54,14 +54,13 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
|
||||
// If user typed more text but we have partial match in prevResults
|
||||
if (newQuery.startsWith(prevQuery) && prevResults.length > 0) {
|
||||
const filtered = prevResults.filter(item =>
|
||||
item.label.toLowerCase().includes(newQuery.toLowerCase()),
|
||||
);
|
||||
const filtered = prevResults.filter(item => item.label.toLowerCase().includes(newQuery.toLowerCase()));
|
||||
setOwnerSuggestions(filtered);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO fix it
|
||||
const { results = [] } = await outCommand({
|
||||
type: OutCommand.getCorporationNames,
|
||||
data: { search: newQuery },
|
||||
@@ -96,9 +95,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
// when user picks a corp from auto-complete
|
||||
const handleSelectOwner = (selected: { label: string; value: string }) => {
|
||||
setOwnerInput(selected.label);
|
||||
setEditData(prev =>
|
||||
prev ? { ...prev, ownerName: selected.label, ownerId: selected.value } : null,
|
||||
);
|
||||
setEditData(prev => (prev ? { ...prev, ownerName: selected.label, ownerId: selected.value } : null));
|
||||
};
|
||||
|
||||
const handleStatusChange = (val: string) => {
|
||||
@@ -125,6 +122,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
// fetch corporation ticker if we have an ownerId
|
||||
if (editData.ownerId) {
|
||||
try {
|
||||
// TODO fix it
|
||||
const { ticker } = await outCommand({
|
||||
type: OutCommand.getCorporationTicker,
|
||||
data: { corp_id: editData.ownerId },
|
||||
@@ -157,11 +155,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
<div className="flex flex-col gap-2 text-[14px]">
|
||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||
<span>Type:</span>
|
||||
<input
|
||||
readOnly
|
||||
className="p-inputtext p-component cursor-not-allowed"
|
||||
value={editData.structureType ?? ''}
|
||||
/>
|
||||
<input readOnly className="p-inputtext p-component cursor-not-allowed" value={editData.structureType ?? ''} />
|
||||
</label>
|
||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||
<span>Name:</span>
|
||||
@@ -204,10 +198,12 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
|
||||
{statusesRequiringTimer.includes(editData.status) && (
|
||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||
<span>Timer <br /> (Eve Time):</span>
|
||||
<span>
|
||||
Timer <br /> (Eve Time):
|
||||
</span>
|
||||
<Calendar
|
||||
value={editData.endTime ? new Date(editData.endTime) : undefined}
|
||||
onChange={(e) => handleChange('endTime', e.value ?? '')}
|
||||
onChange={e => handleChange('endTime', e.value ?? '')}
|
||||
showTime
|
||||
hourFormat="24"
|
||||
dateFormat="yy-mm-dd"
|
||||
@@ -227,8 +223,8 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end items-center gap-2 mt-4">
|
||||
<Button label="Delete" severity="danger" className="p-button-sm" onClick={handleDeleteClick} />
|
||||
<Button label="Save" className="p-button-sm" onClick={handleSaveClick} />
|
||||
<WdButton label="Delete" severity="danger" className="p-button-sm" onClick={handleDeleteClick} />
|
||||
<WdButton label="Save" className="p-button-sm" onClick={handleSaveClick} />
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { Button } from 'primereact/button';
|
||||
import { WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { SystemView, TooltipPosition, WdButton, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { PrimeIcons } from 'primereact/api';
|
||||
import {
|
||||
AddSystemDialog,
|
||||
SearchOnSubmitCallback,
|
||||
} from '@/hooks/Mapper/components/mapInterface/components/AddSystemDialog';
|
||||
import { SystemView, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
|
||||
interface KillsSettingsDialogProps {
|
||||
@@ -158,7 +156,7 @@ export const KillsSettingsDialog: React.FC<KillsSettingsDialogProps> = ({ visibl
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end mt-4">
|
||||
<Button onClick={handleApply} label="Apply" outlined size="small" />
|
||||
<WdButton onClick={handleApply} label="Apply" outlined size="small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { Button } from 'primereact/button';
|
||||
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||
@@ -10,6 +9,7 @@ import { MapUserSettings, RemoteAdminSettingsResponse } from '@/hooks/Mapper/map
|
||||
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
||||
import fastDeepEqual from 'fast-deep-equal';
|
||||
import { useDetectSettingsChanged } from '@/hooks/Mapper/components/hooks';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export const AdminSettings = () => {
|
||||
const {
|
||||
@@ -92,7 +92,7 @@ export const AdminSettings = () => {
|
||||
<div className="w-full h-full flex flex-col gap-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div>
|
||||
<Button
|
||||
<WdButton
|
||||
// @ts-ignore
|
||||
ref={cfRef}
|
||||
onClick={cfShow}
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
import { useMapSettings } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/MapSettingsProvider.tsx';
|
||||
import { SettingsListItem } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/types.ts';
|
||||
import { useCallback } from 'react';
|
||||
import { Button } from 'primereact/button';
|
||||
import { TooltipPosition, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { TooltipPosition, WdButton, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
||||
|
||||
@@ -42,7 +41,7 @@ export const CommonSettings = () => {
|
||||
<div className="grid grid-cols-[1fr_auto]">
|
||||
<div />
|
||||
<WdTooltipWrapper content="This dangerous action. And can not be undone" position={TooltipPosition.top}>
|
||||
<Button
|
||||
<WdButton
|
||||
// @ts-ignore
|
||||
ref={cfRef}
|
||||
className="py-[4px]"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { Button } from 'primereact/button';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { Divider } from 'primereact/divider';
|
||||
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
type SaveDefaultSettingsReturn = { success: boolean; error: string };
|
||||
|
||||
@@ -65,7 +65,7 @@ export const DefaultSettings = () => {
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<div>
|
||||
<Button
|
||||
<WdButton
|
||||
onClick={handleSaveAsDefault}
|
||||
icon="pi pi-save"
|
||||
size="small"
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
||||
import { Button } from 'primereact/button';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts';
|
||||
import { callToastSuccess } from '@/hooks/Mapper/helpers';
|
||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
||||
import { RemoteAdminSettingsResponse } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export const ServerSettings = () => {
|
||||
const {
|
||||
@@ -64,7 +64,7 @@ export const ServerSettings = () => {
|
||||
<div className="w-full h-full flex flex-col gap-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div>
|
||||
<Button
|
||||
<WdButton
|
||||
// @ts-ignore
|
||||
ref={cfRef}
|
||||
onClick={cfShow}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/compon
|
||||
import { WIDGETS_CHECKBOXES_PROPS, WidgetsIds } from '@/hooks/Mapper/components/mapInterface/constants.tsx';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { Button } from 'primereact/button';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export interface WidgetsSettingsProps {}
|
||||
|
||||
@@ -33,7 +32,7 @@ export const WidgetsSettings = ({}: WidgetsSettingsProps) => {
|
||||
|
||||
<div className="grid grid-cols-[1fr_auto]">
|
||||
<div />
|
||||
<Button className="py-[4px]" onClick={resetWidgets} outlined size="small" label="Reset Widgets"></Button>
|
||||
<WdButton className="py-[4px]" onClick={resetWidgets} outlined size="small" label="Reset Widgets" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SettingsListItem, UserSettingsRemoteProps } from './types.ts';
|
||||
import { InterfaceStoredSettingsProps } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { AvailableThemes, MiniMapPlacement, PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||
import { SettingsListItem, UserSettingsRemoteProps } from './types.ts';
|
||||
|
||||
export const DEFAULT_REMOTE_SETTINGS = {
|
||||
[UserSettingsRemoteProps.link_signature_on_splash]: false,
|
||||
@@ -51,7 +51,7 @@ export const SIGNATURES_CHECKBOXES_PROPS: SettingsListItem[] = [
|
||||
export const CONNECTIONS_CHECKBOXES_PROPS: SettingsListItem[] = [
|
||||
{
|
||||
prop: UserSettingsRemoteProps.delete_connection_with_sigs,
|
||||
label: 'Delete connections to linked signatures',
|
||||
label: 'Delete connections with linked signatures',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
} from '@/hooks/Mapper/mapRootProvider/constants.ts';
|
||||
import { MapUserSettings } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||
import { saveTextFile } from '@/hooks/Mapper/utils';
|
||||
import { Button } from 'primereact/button';
|
||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
const createSettings = function <T>(lsSettings: string | null, defaultValues: T) {
|
||||
return {
|
||||
@@ -139,7 +139,7 @@ export const OldSettingsDialog = () => {
|
||||
className="w-[640px] h-[400px] text-text-color min-h-0"
|
||||
footer={
|
||||
<div className="flex items-center justify-end">
|
||||
<Button
|
||||
<WdButton
|
||||
// @ts-ignore
|
||||
ref={cfRef}
|
||||
onClick={cfShow}
|
||||
@@ -168,7 +168,7 @@ export const OldSettingsDialog = () => {
|
||||
<div className="h-[30px]"></div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Button
|
||||
<WdButton
|
||||
onClick={handleExportClipboard}
|
||||
icon="pi pi-copy"
|
||||
size="small"
|
||||
@@ -176,7 +176,7 @@ export const OldSettingsDialog = () => {
|
||||
label="Export to Clipboard"
|
||||
/>
|
||||
|
||||
<Button
|
||||
<WdButton
|
||||
onClick={handleExportAsFile}
|
||||
icon="pi pi-download"
|
||||
size="small"
|
||||
|
||||
@@ -8,11 +8,14 @@ import {
|
||||
} from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { SystemsSettingsProvider } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/Provider.tsx';
|
||||
import { Button } from 'primereact/button';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { getWhSize } from '@/hooks/Mapper/helpers/getWhSize';
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
type SystemSignaturePrepared = Omit<SystemSignature, 'linked_system'> & { linked_system: string };
|
||||
type SystemSignaturePrepared = Omit<SystemSignature, 'linked_system'> & {
|
||||
linked_system: string;
|
||||
k162Type: string;
|
||||
time_status: TimeStatus;
|
||||
};
|
||||
|
||||
export interface MapSettingsProps {
|
||||
systemId: string;
|
||||
@@ -22,10 +25,7 @@ export interface MapSettingsProps {
|
||||
}
|
||||
|
||||
export const SignatureSettings = ({ systemId, show, onHide, signatureData }: MapSettingsProps) => {
|
||||
const {
|
||||
outCommand,
|
||||
data: { wormholes },
|
||||
} = useMapRootState();
|
||||
const { outCommand } = useMapRootState();
|
||||
|
||||
const handleShow = async () => {};
|
||||
const signatureForm = useForm<Partial<SystemSignaturePrepared>>({});
|
||||
@@ -52,41 +52,13 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
||||
solar_system_target: values.linked_system,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: need fix
|
||||
if (values.isEOL) {
|
||||
await outCommand({
|
||||
type: OutCommand.updateConnectionTimeStatus,
|
||||
data: {
|
||||
source: systemId,
|
||||
target: values.linked_system,
|
||||
value: TimeStatus.eol,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (values.type) {
|
||||
const whShipSize = getWhSize(wormholes, values.type);
|
||||
if (whShipSize !== undefined && whShipSize !== null) {
|
||||
await outCommand({
|
||||
type: OutCommand.updateConnectionShipSizeType,
|
||||
data: {
|
||||
source: systemId,
|
||||
target: values.linked_system,
|
||||
value: whShipSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out = {
|
||||
...out,
|
||||
custom_info: JSON.stringify({
|
||||
// TODO: need fix
|
||||
k162Type: values.k162Type,
|
||||
// TODO: need fix
|
||||
isEOL: values.isEOL,
|
||||
time_status: values.time_status,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -153,7 +125,7 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
||||
signatureForm.reset();
|
||||
onHide();
|
||||
},
|
||||
[signatureData, signatureForm, outCommand, systemId, onHide, wormholes],
|
||||
[signatureData, signatureForm, outCommand, systemId, onHide],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -165,18 +137,17 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
||||
const { linked_system, custom_info, ...rest } = signatureData;
|
||||
|
||||
let k162Type = null;
|
||||
let isEOL = false;
|
||||
let time_status = TimeStatus._24h;
|
||||
if (custom_info) {
|
||||
const customInfo = JSON.parse(custom_info);
|
||||
k162Type = customInfo.k162Type;
|
||||
isEOL = customInfo.isEOL;
|
||||
time_status = customInfo.time_status;
|
||||
}
|
||||
|
||||
signatureForm.reset({
|
||||
linked_system: linked_system?.solar_system_id.toString() ?? undefined,
|
||||
// TODO: need fix
|
||||
k162Type: k162Type,
|
||||
isEOL: isEOL,
|
||||
time_status: time_status,
|
||||
...rest,
|
||||
});
|
||||
}, [signatureForm, signatureData]);
|
||||
@@ -185,7 +156,8 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
||||
<Dialog
|
||||
header={`Signature Edit [${signatureData?.eve_id}]`}
|
||||
visible={show}
|
||||
draggable={true}
|
||||
draggable
|
||||
resizable={false}
|
||||
style={{ width: '390px' }}
|
||||
onShow={handleShow}
|
||||
onHide={() => {
|
||||
@@ -220,8 +192,8 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
||||
<div className="flex gap-2 justify-end px-[0.75rem] pb-[0.5rem]">
|
||||
<WdButton type="submit" outlined size="small" label="Save" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { InputSwitch } from 'primereact/inputswitch';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
|
||||
export interface SignatureEOLCheckboxProps {
|
||||
name: string;
|
||||
defaultValue?: boolean;
|
||||
}
|
||||
|
||||
export const SignatureEOLCheckbox = ({ name, defaultValue = false }: SignatureEOLCheckboxProps) => {
|
||||
const { control } = useFormContext<SystemSignature>();
|
||||
|
||||
return (
|
||||
<Controller
|
||||
// @ts-ignore
|
||||
name={name}
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
render={({ field }) => {
|
||||
return <InputSwitch className="my-1" checked={!!field.value} onChange={e => field.onChange(e.value)} />;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './SignatureEOLCheckbox.tsx';
|
||||
@@ -3,7 +3,7 @@ import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { SignatureWormholeTypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureWormholeTypeSelect';
|
||||
import { SignatureK162TypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
||||
import { SignatureLeadsToSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureLeadsToSelect';
|
||||
import { SignatureEOLCheckbox } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureEOLCheckbox';
|
||||
import { SignatureLifetimeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureLifetimeSelect.tsx';
|
||||
import { SignatureTempName } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureTempName.tsx';
|
||||
|
||||
export const SignatureGroupContentWormholes = () => {
|
||||
@@ -29,10 +29,10 @@ export const SignatureGroupContentWormholes = () => {
|
||||
<SignatureLeadsToSelect name="linked_system" />
|
||||
</label>
|
||||
|
||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
||||
<span>EOL:</span>
|
||||
<SignatureEOLCheckbox name="isEOL" />
|
||||
</label>
|
||||
<div className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
||||
<span>Lifetime:</span>
|
||||
<SignatureLifetimeSelect name="time_status" />
|
||||
</div>
|
||||
|
||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
||||
<span>Temp. Name:</span>
|
||||
|
||||
@@ -20,7 +20,7 @@ const renderLinkedSystemItem = (option: { value: string }) => {
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<SystemView systemId={value} className={classes.SystemView} />
|
||||
<SystemView systemId={value} className={classes.SystemView} showCustomName={true} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -37,7 +37,7 @@ const renderLinkedSystemValue = (option: { value: string }) => {
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<SystemView systemId={option.value} className={classes.SystemView} />
|
||||
<SystemView systemId={option.value} className={classes.SystemView} showCustomName={true} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { WdLifetimeSelector } from '@/hooks/Mapper/components/ui-kit/WdLifetimeSelector.tsx';
|
||||
|
||||
export interface SignatureEOLCheckboxProps {
|
||||
name: string;
|
||||
defaultValue?: boolean;
|
||||
}
|
||||
|
||||
export const SignatureLifetimeSelect = ({ name, defaultValue = false }: SignatureEOLCheckboxProps) => {
|
||||
const { control } = useFormContext<SystemSignature>();
|
||||
|
||||
return (
|
||||
<div className="my-1">
|
||||
<Controller
|
||||
// @ts-ignore
|
||||
name={name}
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
render={({ field }) => {
|
||||
// @ts-ignore
|
||||
return <WdLifetimeSelector lifetime={field.value} onChangeLifetime={e => field.onChange(e)} />;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './SignatureGroupSelect';
|
||||
export * from './SignatureGroupContent';
|
||||
export * from './SignatureK162TypeSelect';
|
||||
export * from './SignatureLifetimeSelect';
|
||||
|
||||
@@ -42,5 +42,5 @@ export const SystemView = ({ systemId, systemInfo: customSystemInfo, showCustomN
|
||||
return <SystemViewStandalone {...rest} {...systemInfo} />;
|
||||
}
|
||||
|
||||
return <SystemViewStandalone customName={mapSystemInfo.name ?? undefined} {...rest} {...systemInfo} />;
|
||||
return <SystemViewStandalone customName={mapSystemInfo.temporary_name ?? mapSystemInfo.name ?? undefined} {...rest} {...systemInfo} />;
|
||||
};
|
||||
|
||||
7
assets/js/hooks/Mapper/components/ui-kit/WdButton.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Button, ButtonProps } from 'primereact/button';
|
||||
|
||||
export const WdButton = ({ type = 'button', ...props }: ButtonProps) => {
|
||||
// eslint-disable-next-line react/forbid-elements
|
||||
return <Button {...props} type={type} />;
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
import { WdButton } from '@/hooks/Mapper/components/ui-kit/WdButton.tsx';
|
||||
import { TimeStatus } from '@/hooks/Mapper/types';
|
||||
import clsx from 'clsx';
|
||||
import { BUILT_IN_TOOLTIP_OPTIONS } from './constants.ts';
|
||||
|
||||
const LIFE_TIME = [
|
||||
{
|
||||
id: TimeStatus._1h,
|
||||
label: '1H',
|
||||
className: 'bg-purple-400 hover:!bg-purple-400',
|
||||
inactiveClassName: 'bg-purple-400/30',
|
||||
description: 'Less than one 1 hours remaining',
|
||||
},
|
||||
{
|
||||
id: TimeStatus._4h,
|
||||
label: '4H',
|
||||
className: 'bg-purple-300 hover:!bg-purple-300',
|
||||
inactiveClassName: 'bg-purple-300/30',
|
||||
description: 'Less than one 4 hours remaining',
|
||||
},
|
||||
{
|
||||
id: TimeStatus._4h30m,
|
||||
label: '4.5H',
|
||||
className: 'bg-indigo-300 hover:!bg-indigo-300',
|
||||
inactiveClassName: 'bg-indigo-300/30',
|
||||
description: 'Less than one 4.5 hours remaining. All small holes have such lifetime.',
|
||||
},
|
||||
{
|
||||
id: TimeStatus._16h,
|
||||
label: '16H',
|
||||
className: 'bg-orange-300 hover:!bg-orange-300',
|
||||
inactiveClassName: 'bg-orange-400/30',
|
||||
description: 'Less than one 16 hours remaining',
|
||||
},
|
||||
{
|
||||
id: TimeStatus._24h,
|
||||
label: '24H',
|
||||
className: 'bg-orange-300 hover:!bg-orange-300',
|
||||
inactiveClassName: 'bg-orange-400/30',
|
||||
description: 'Less than one 24 hours remaining',
|
||||
},
|
||||
{
|
||||
id: TimeStatus._48h,
|
||||
label: '48H',
|
||||
className: 'bg-orange-300 hover:!bg-orange-300',
|
||||
inactiveClassName: 'bg-orange-400/30',
|
||||
description: 'Less than one 24 hours remaining. Related only with C6. B041, B520, U319, C391.',
|
||||
},
|
||||
];
|
||||
|
||||
export interface WdLifetimeSelectorProps {
|
||||
lifetime?: TimeStatus;
|
||||
onChangeLifetime(lifetime: TimeStatus): void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const WdLifetimeSelector = ({
|
||||
lifetime = TimeStatus._24h,
|
||||
onChangeLifetime,
|
||||
className,
|
||||
}: WdLifetimeSelectorProps) => {
|
||||
return (
|
||||
<form>
|
||||
<div className={clsx('grid grid-cols-[1fr_1fr_1fr_1fr_1fr_1fr] gap-1', className)}>
|
||||
{LIFE_TIME.map(x => (
|
||||
<WdButton
|
||||
key={x.id}
|
||||
outlined={false}
|
||||
value={x.label}
|
||||
tooltip={x.description}
|
||||
tooltipOptions={BUILT_IN_TOOLTIP_OPTIONS}
|
||||
size="small"
|
||||
className={clsx(
|
||||
`py-[1px] justify-center min-w-auto w-auto border-0 text-[12px] font-bold leading-[20px]`,
|
||||
{ [x.inactiveClassName]: lifetime !== x.id },
|
||||
x.className,
|
||||
)}
|
||||
onClick={() => onChangeLifetime(x.id)}
|
||||
>
|
||||
{x.label}
|
||||
</WdButton>
|
||||
))}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
6
assets/js/hooks/Mapper/components/ui-kit/constants.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const BUILT_IN_TOOLTIP_OPTIONS = {
|
||||
mouseTrack: true,
|
||||
mouseTrackLeft: 10,
|
||||
className:
|
||||
'rounded-[3px] bg-stone-900/90 px-1 py-1 [&_.p-tooltip-text]:!text-stone-300 text-[13px] [&_.p-tooltip-text]:!p-1',
|
||||
};
|
||||
@@ -21,3 +21,5 @@ export * from './LoadingWrapper';
|
||||
export * from './WdMenuItem';
|
||||
export * from './MenuItemWithInfo';
|
||||
export * from './MarkdownTextViewer.tsx';
|
||||
export * from './WdButton.tsx';
|
||||
export * from './constants.ts';
|
||||
|
||||
@@ -11,8 +11,13 @@ export enum MassState {
|
||||
}
|
||||
|
||||
export enum TimeStatus {
|
||||
default,
|
||||
eol,
|
||||
reserved, // TODO: this reserved for not broke prev solution
|
||||
_1h,
|
||||
_4h,
|
||||
_4h30m,
|
||||
_16h,
|
||||
_24h,
|
||||
_48h,
|
||||
}
|
||||
|
||||
export enum ShipSizeStatus {
|
||||
|
||||
@@ -122,7 +122,7 @@ export enum SignatureGroupRU {
|
||||
export enum SignatureGroupFR {
|
||||
CosmicSignature = 'Signature cosmique (groupe)',
|
||||
Wormhole = 'Trou de ver',
|
||||
GasSite = 'Site de gaz',
|
||||
GasSite = 'Site de collecte de gaz',
|
||||
RelicSite = 'Site de reliques',
|
||||
DataSite = 'Site de données',
|
||||
OreSite = 'Site de minerai',
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'phoenix_html';
|
||||
import './live_reload.css';
|
||||
|
||||
const animateBg = function (bgCanvas) {
|
||||
const { TweenMax, _ } = window;
|
||||
const { TweenMax } = window;
|
||||
/**
|
||||
* Utility function for returning a random integer in a given range
|
||||
* @param {Int} max
|
||||
@@ -212,12 +212,6 @@ const animateBg = function (bgCanvas) {
|
||||
};
|
||||
}
|
||||
window.myJump = new JumpToHyperspace(bgCanvas);
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
_.debounce(() => {
|
||||
window.myJump.reset();
|
||||
}, 250),
|
||||
);
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
BIN
assets/static/apple-touch-icon.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/static/favicon-96x96.png
Executable file
|
After Width: | Height: | Size: 977 B |
33
assets/static/site.webmanifest
Executable file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Wanderer",
|
||||
"short_name": "Wanderer",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#171717",
|
||||
"background_color": "#171717",
|
||||
"display": "standalone",
|
||||
"start_url": "/",
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "web-app-manifest.webp",
|
||||
"sizes": "720x1280",
|
||||
"type": "image/webp"
|
||||
},
|
||||
{
|
||||
"src": "web-app-manifest-wide.webp",
|
||||
"sizes": "1280x720",
|
||||
"type": "image/webp",
|
||||
"form_factor": "wide"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
assets/static/web-app-manifest-192x192.png
Executable file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/static/web-app-manifest-512x512.png
Executable file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/static/web-app-manifest-wide.webp
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/static/web-app-manifest.webp
Normal file
|
After Width: | Height: | Size: 61 KiB |
@@ -147,8 +147,13 @@ defmodule WandererApp.Api.MapConnection do
|
||||
allow_nil?(true)
|
||||
end
|
||||
|
||||
# where 0 - normal
|
||||
# where 1 - end of life
|
||||
# 0 - normal (env settings)
|
||||
# 1 - EOL 1h
|
||||
# 2 - EOL 4h
|
||||
# 3 - EOL 4.5h
|
||||
# 4 - EOL 16h
|
||||
# 5 - EOL 24h
|
||||
# 6 - EOL 48h
|
||||
attribute :time_status, :integer do
|
||||
default(0)
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
end
|
||||
end
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(60)
|
||||
)
|
||||
@@ -256,7 +256,7 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
WandererApp.Character.update_character_state(character_id, character_state)
|
||||
WandererApp.Map.Server.Impl.broadcast!(map_id, :untrack_character, character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(30)
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
@check_location_errors_interval :timer.minutes(1)
|
||||
@update_ship_interval :timer.seconds(2)
|
||||
@update_info_interval :timer.minutes(2)
|
||||
@update_wallet_interval :timer.minutes(1)
|
||||
@update_wallet_interval :timer.minutes(10)
|
||||
|
||||
@logger Application.compile_env(:wanderer_app, :logger)
|
||||
|
||||
@@ -180,7 +180,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_online(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
@@ -241,12 +241,12 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
WandererApp.Character.Tracker.check_offline(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> @logger.error("Error in check_offline: #{inspect(reason)}")
|
||||
error -> @logger.error("Error in check_offline: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
@@ -281,12 +281,12 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> @logger.error("Error in check_online_errors: #{inspect(reason)}")
|
||||
error -> @logger.error("Error in check_online_errors: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
@@ -321,12 +321,12 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> @logger.error("Error in check_ship_errors: #{inspect(reason)}")
|
||||
error -> @logger.error("Error in check_ship_errors: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
@@ -361,12 +361,12 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> @logger.error("Error in check_location_errors: #{inspect(reason)}")
|
||||
error -> @logger.error("Error in check_location_errors: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
@@ -395,7 +395,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_location(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
@@ -436,7 +436,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_ship(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
@@ -478,12 +478,12 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
WandererApp.Character.Tracker.update_info(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> Logger.error("Error in update_info: #{inspect(reason)}")
|
||||
error -> Logger.error("Error in update_info: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
@@ -521,13 +521,13 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_wallet(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
timeout: :timer.minutes(5),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> Logger.error("Error in update_wallet: #{inspect(reason)}")
|
||||
error -> Logger.error("Error in update_wallet: #{inspect(error)}")
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
|
||||
@@ -253,7 +253,7 @@ defmodule WandererApp.Esi.ApiClient do
|
||||
fn destination ->
|
||||
get_routes(origin, destination, params, opts)
|
||||
end,
|
||||
max_concurrency: 20,
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
timeout: :timer.seconds(30),
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|
||||
@@ -254,7 +254,7 @@ defmodule WandererApp.Map.Manager do
|
||||
|
||||
:timer.sleep(@maps_start_interval)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(60)
|
||||
)
|
||||
|
||||
@@ -49,7 +49,7 @@ defmodule WandererApp.Map.ZkbDataFetcher do
|
||||
@logger.error(Exception.message(e))
|
||||
end
|
||||
end,
|
||||
max_concurrency: 10,
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn _ -> :ok end)
|
||||
|
||||
@@ -19,6 +19,7 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
@medium_ship_size 1
|
||||
@large_ship_size 2
|
||||
@xlarge_ship_size 3
|
||||
@capital_ship_size 4
|
||||
|
||||
# System class constants
|
||||
@c1_system_class 1
|
||||
@@ -35,6 +36,12 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
do_create(attrs, map_id, char_id)
|
||||
end
|
||||
|
||||
def small_ship_size(), do: @small_ship_size
|
||||
def medium_ship_size(), do: @medium_ship_size
|
||||
def large_ship_size(), do: @large_ship_size
|
||||
def freight_ship_size(), do: @xlarge_ship_size
|
||||
def capital_ship_size(), do: @capital_ship_size
|
||||
|
||||
defp do_create(attrs, map_id, char_id) do
|
||||
with {:ok, source} <- parse_int(attrs["solar_system_source"], "solar_system_source"),
|
||||
{:ok, target} <- parse_int(attrs["solar_system_target"], "solar_system_target"),
|
||||
|
||||
@@ -22,7 +22,7 @@ defmodule WandererApp.Map.Server.AclsImpl do
|
||||
fn acl_id ->
|
||||
update_acl(acl_id)
|
||||
end,
|
||||
max_concurrency: 10,
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
timeout: :timer.seconds(15)
|
||||
)
|
||||
|> Enum.reduce(
|
||||
|
||||
@@ -122,14 +122,22 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
||||
[]
|
||||
)
|
||||
|
||||
{:ok, %{acls: acls}} =
|
||||
WandererApp.MapRepo.get(map_id,
|
||||
acls: [
|
||||
:owner_id,
|
||||
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
|
||||
]
|
||||
)
|
||||
if Enum.empty?(invalidate_character_ids) do
|
||||
:ok
|
||||
else
|
||||
{:ok, %{acls: acls}} =
|
||||
WandererApp.MapRepo.get(map_id,
|
||||
acls: [
|
||||
:owner_id,
|
||||
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
|
||||
]
|
||||
)
|
||||
|
||||
process_invalidate_characters(invalidate_character_ids, map_id, owner_id, acls)
|
||||
end
|
||||
end
|
||||
|
||||
defp process_invalidate_characters(invalidate_character_ids, map_id, owner_id, acls) do
|
||||
invalidate_character_ids
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
@@ -166,20 +174,24 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
||||
end
|
||||
end,
|
||||
timeout: :timer.seconds(60),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, {:remove_character, character_id}} ->
|
||||
remove_and_untrack_characters(map_id, [character_id])
|
||||
:ok
|
||||
|> Enum.reduce([], fn
|
||||
{:ok, {:remove_character, character_id}}, acc ->
|
||||
[character_id | acc]
|
||||
|
||||
{:ok, _result} ->
|
||||
:ok
|
||||
{:ok, _result}, acc ->
|
||||
acc
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}, acc ->
|
||||
Logger.error("Error in cleanup_characters: #{inspect(reason)}")
|
||||
acc
|
||||
end)
|
||||
|> case do
|
||||
[] -> :ok
|
||||
character_ids_to_remove -> remove_and_untrack_characters(map_id, character_ids_to_remove)
|
||||
end
|
||||
end
|
||||
|
||||
defp remove_and_untrack_characters(map_id, character_ids) do
|
||||
@@ -293,7 +305,7 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
||||
:ok
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
require Logger
|
||||
|
||||
alias WandererApp.Map.Server.Impl
|
||||
alias WandererApp.Map.Server.SignaturesImpl
|
||||
|
||||
# @ccp1 -1
|
||||
@c1 1
|
||||
@@ -68,8 +69,35 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
|
||||
# this class of systems will guaranty that no one real class will take that place
|
||||
# @unknown 100_100
|
||||
#
|
||||
|
||||
# default (env) setting, not EOL
|
||||
@connection_time_status_default 0
|
||||
# EOL 1h
|
||||
@connection_time_status_eol 1
|
||||
# EOL 4h
|
||||
@connection_time_status_eol_4 2
|
||||
# EOL 4.5h
|
||||
@connection_time_status_eol_4_5 3
|
||||
# EOL 16h
|
||||
@connection_time_status_eol_16 4
|
||||
# EOL 24h
|
||||
@connection_time_status_eol_24 5
|
||||
# EOL 48h
|
||||
@connection_time_status_eol_48 6
|
||||
|
||||
# EOL 1h
|
||||
@connection_eol_minutes 60
|
||||
# EOL 4h
|
||||
@connection_eol_4_minutes 4 * 60
|
||||
# EOL 4.5h
|
||||
@connection_eol_4_5_minutes 4.5 * 60
|
||||
# EOL 16h
|
||||
@connection_eol_16_minutes 16 * 60
|
||||
# EOL 24h
|
||||
@connection_eol_24_minutes 24 * 60
|
||||
# EOL 48h
|
||||
@connection_eol_48_minutes 48 * 60
|
||||
|
||||
@connection_type_wormhole 0
|
||||
@connection_type_stargate 1
|
||||
@connection_type_bridge 2
|
||||
@@ -187,7 +215,8 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
),
|
||||
do:
|
||||
update_connection(state, :update_time_status, [:time_status], connection_update, fn
|
||||
%{time_status: old_time_status}, %{id: connection_id, time_status: time_status} ->
|
||||
%{time_status: old_time_status},
|
||||
%{id: connection_id, time_status: time_status} = updated_connection ->
|
||||
case time_status == @connection_time_status_eol do
|
||||
true ->
|
||||
if old_time_status != @connection_time_status_eol do
|
||||
@@ -195,6 +224,8 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
"map_#{map_id}:conn_#{connection_id}:mark_eol_time",
|
||||
DateTime.utc_now()
|
||||
)
|
||||
|
||||
set_start_time(map_id, connection_id, DateTime.utc_now())
|
||||
end
|
||||
|
||||
_ ->
|
||||
@@ -203,6 +234,10 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
set_start_time(map_id, connection_id, DateTime.utc_now())
|
||||
end
|
||||
end
|
||||
|
||||
if time_status != old_time_status do
|
||||
maybe_update_linked_signature_time_status(map_id, updated_connection)
|
||||
end
|
||||
end)
|
||||
|
||||
def update_connection_type(
|
||||
@@ -243,35 +278,38 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
state =
|
||||
map_id
|
||||
|> WandererApp.Map.list_connections!()
|
||||
|> Enum.filter(fn %{
|
||||
id: connection_id,
|
||||
inserted_at: inserted_at,
|
||||
solar_system_source: solar_system_source_id,
|
||||
solar_system_target: solar_system_target_id,
|
||||
type: type
|
||||
} ->
|
||||
connection_start_time = get_start_time(map_id, connection_id)
|
||||
|
||||
type == @connection_type_wormhole &&
|
||||
DateTime.diff(DateTime.utc_now(), connection_start_time, :hour) >=
|
||||
connection_auto_eol_hours &&
|
||||
is_connection_valid(
|
||||
:wormholes,
|
||||
solar_system_source_id,
|
||||
solar_system_target_id
|
||||
)
|
||||
end)
|
||||
|> Enum.reduce(state, fn %{
|
||||
id: connection_id,
|
||||
solar_system_source: solar_system_source_id,
|
||||
solar_system_target: solar_system_target_id
|
||||
solar_system_target: solar_system_target_id,
|
||||
time_status: time_status,
|
||||
type: type
|
||||
},
|
||||
state ->
|
||||
state
|
||||
|> update_connection_time_status(%{
|
||||
solar_system_source_id: solar_system_source_id,
|
||||
solar_system_target_id: solar_system_target_id,
|
||||
time_status: @connection_time_status_eol
|
||||
})
|
||||
if type == @connection_type_wormhole do
|
||||
connection_start_time = get_start_time(map_id, connection_id)
|
||||
new_time_status = get_new_time_status(connection_start_time, time_status)
|
||||
|
||||
if new_time_status != time_status &&
|
||||
is_connection_valid(
|
||||
:wormholes,
|
||||
solar_system_source_id,
|
||||
solar_system_target_id
|
||||
) do
|
||||
set_start_time(map_id, connection_id, DateTime.utc_now())
|
||||
|
||||
state
|
||||
|> update_connection_time_status(%{
|
||||
solar_system_source_id: solar_system_source_id,
|
||||
solar_system_target_id: solar_system_target_id,
|
||||
time_status: new_time_status
|
||||
})
|
||||
else
|
||||
state
|
||||
end
|
||||
else
|
||||
state
|
||||
end
|
||||
end)
|
||||
|
||||
state =
|
||||
@@ -281,37 +319,38 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
id: connection_id,
|
||||
solar_system_source: solar_system_source_id,
|
||||
solar_system_target: solar_system_target_id,
|
||||
time_status: time_status,
|
||||
type: type
|
||||
} ->
|
||||
connection_mark_eol_time =
|
||||
get_connection_mark_eol_time(map_id, connection_id)
|
||||
|
||||
reverse_connection =
|
||||
WandererApp.Map.get_connection(
|
||||
map_id,
|
||||
solar_system_target_id,
|
||||
solar_system_source_id
|
||||
)
|
||||
|
||||
is_connection_exist =
|
||||
is_connection_exist(
|
||||
map_id,
|
||||
solar_system_source_id,
|
||||
solar_system_target_id
|
||||
) || not is_nil(reverse_connection)
|
||||
|
||||
is_connection_valid =
|
||||
is_connection_valid(
|
||||
:wormholes,
|
||||
solar_system_source_id,
|
||||
solar_system_target_id
|
||||
)
|
||||
) ||
|
||||
not is_nil(
|
||||
WandererApp.Map.get_connection(
|
||||
map_id,
|
||||
solar_system_target_id,
|
||||
solar_system_source_id
|
||||
)
|
||||
)
|
||||
|
||||
not is_connection_exist ||
|
||||
(type == @connection_type_wormhole && is_connection_valid &&
|
||||
DateTime.diff(DateTime.utc_now(), connection_mark_eol_time, :hour) >=
|
||||
(type == @connection_type_wormhole &&
|
||||
time_status == @connection_time_status_eol &&
|
||||
is_connection_valid(
|
||||
:wormholes,
|
||||
solar_system_source_id,
|
||||
solar_system_target_id
|
||||
) &&
|
||||
DateTime.diff(
|
||||
DateTime.utc_now(),
|
||||
get_connection_mark_eol_time(map_id, connection_id),
|
||||
:hour
|
||||
) >=
|
||||
connection_auto_expire_hours - connection_auto_eol_hours +
|
||||
+connection_eol_expire_timeout_hours)
|
||||
connection_eol_expire_timeout_hours)
|
||||
end)
|
||||
|> Enum.reduce(state, fn %{
|
||||
solar_system_source: solar_system_source_id,
|
||||
@@ -327,30 +366,103 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
state
|
||||
end
|
||||
|
||||
defp maybe_update_linked_signature_time_status(
|
||||
map_id,
|
||||
%{
|
||||
time_status: time_status,
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target
|
||||
} = updated_connection
|
||||
) do
|
||||
source_system =
|
||||
WandererApp.Map.find_system_by_location(
|
||||
map_id,
|
||||
%{solar_system_id: solar_system_source}
|
||||
)
|
||||
|
||||
target_system =
|
||||
WandererApp.Map.find_system_by_location(
|
||||
map_id,
|
||||
%{solar_system_id: solar_system_target}
|
||||
)
|
||||
|
||||
source_linked_signatures =
|
||||
find_linked_signatures(source_system, target_system)
|
||||
|
||||
target_linked_signatures = find_linked_signatures(target_system, source_system)
|
||||
|
||||
update_signatures_time_status(
|
||||
map_id,
|
||||
source_system.solar_system_id,
|
||||
source_linked_signatures,
|
||||
time_status
|
||||
)
|
||||
|
||||
update_signatures_time_status(
|
||||
map_id,
|
||||
target_system.solar_system_id,
|
||||
target_linked_signatures,
|
||||
time_status
|
||||
)
|
||||
end
|
||||
|
||||
defp find_linked_signatures(
|
||||
%{id: source_system_id} = _source_system,
|
||||
%{solar_system_id: solar_system_id, linked_sig_eve_id: linked_sig_eve_id} =
|
||||
_target_system
|
||||
)
|
||||
when not is_nil(linked_sig_eve_id) do
|
||||
{:ok, signatures} =
|
||||
WandererApp.Api.MapSystemSignature.by_linked_system_id(solar_system_id)
|
||||
|
||||
signatures |> Enum.filter(fn sig -> sig.system_id == source_system_id end)
|
||||
end
|
||||
|
||||
defp find_linked_signatures(_source_system, _target_system), do: []
|
||||
|
||||
defp update_signatures_time_status(_map_id, _solar_system_id, [], _time_status), do: :ok
|
||||
|
||||
defp update_signatures_time_status(map_id, solar_system_id, signatures, time_status) do
|
||||
signatures
|
||||
|> Enum.each(fn %{custom_info: custom_info_json} = sig ->
|
||||
update_params =
|
||||
if not is_nil(custom_info_json) do
|
||||
updated_custom_info =
|
||||
custom_info_json
|
||||
|> Jason.decode!()
|
||||
|> Map.merge(%{"time_status" => time_status})
|
||||
|> Jason.encode!()
|
||||
|
||||
%{custom_info: updated_custom_info}
|
||||
else
|
||||
updated_custom_info = Jason.encode!(%{"time_status" => time_status})
|
||||
%{custom_info: updated_custom_info}
|
||||
end
|
||||
|
||||
SignaturesImpl.apply_update_signature(%{map_id: map_id}, sig, update_params)
|
||||
end)
|
||||
|
||||
Impl.broadcast!(map_id, :signatures_updated, solar_system_id)
|
||||
end
|
||||
|
||||
def maybe_add_connection(map_id, location, old_location, character_id, is_manual)
|
||||
when not is_nil(location) and not is_nil(old_location) and
|
||||
not is_nil(old_location.solar_system_id) and
|
||||
location.solar_system_id != old_location.solar_system_id do
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
|
||||
if not is_manual do
|
||||
character_id
|
||||
|> WandererApp.Character.get_character!()
|
||||
|> case do
|
||||
nil ->
|
||||
:ok
|
||||
:telemetry.execute([:wanderer_app, :map, :character, :jump], %{count: 1}, %{})
|
||||
|
||||
character ->
|
||||
:telemetry.execute([:wanderer_app, :map, :character, :jump], %{count: 1}, %{})
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.Api.MapChainPassages.new(%{
|
||||
map_id: map_id,
|
||||
character_id: character_id,
|
||||
ship_type_id: character.ship,
|
||||
ship_name: character.ship_name,
|
||||
solar_system_source_id: old_location.solar_system_id,
|
||||
solar_system_target_id: location.solar_system_id
|
||||
})
|
||||
end
|
||||
{:ok, _} =
|
||||
WandererApp.Api.MapChainPassages.new(%{
|
||||
map_id: map_id,
|
||||
character_id: character_id,
|
||||
ship_type_id: character.ship,
|
||||
ship_name: character.ship_name,
|
||||
solar_system_source_id: old_location.solar_system_id,
|
||||
solar_system_target_id: location.solar_system_id
|
||||
})
|
||||
end
|
||||
|
||||
case WandererApp.Map.check_connection(map_id, location, old_location) do
|
||||
@@ -369,37 +481,19 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
@connection_type_wormhole
|
||||
end
|
||||
|
||||
# Check if either system is C1 before creating the connection
|
||||
{:ok, source_system_info} = get_system_static_info(old_location.solar_system_id)
|
||||
{:ok, target_system_info} = get_system_static_info(location.solar_system_id)
|
||||
|
||||
# Set ship size type based on system classes and special rules
|
||||
ship_size_type =
|
||||
get_ship_size_type(
|
||||
old_location.solar_system_id,
|
||||
location.solar_system_id,
|
||||
connection_type
|
||||
)
|
||||
|
||||
time_status =
|
||||
if connection_type == @connection_type_wormhole do
|
||||
cond do
|
||||
# C1 systems always get medium
|
||||
source_system_info.system_class == @c1 or target_system_info.system_class == @c1 ->
|
||||
@medium_ship_size
|
||||
|
||||
# C13 systems always get frigate
|
||||
source_system_info.system_class == @c13 or target_system_info.system_class == @c13 ->
|
||||
@frigate_ship_size
|
||||
|
||||
# C4 to null gets frigate (unless C4 is shattered)
|
||||
(source_system_info.system_class == @c4 and target_system_info.system_class == @ns and
|
||||
not source_system_info.is_shattered) or
|
||||
(target_system_info.system_class == @c4 and
|
||||
source_system_info.system_class == @ns and
|
||||
not target_system_info.is_shattered) ->
|
||||
@frigate_ship_size
|
||||
|
||||
true ->
|
||||
# Default to large for other wormhole connections
|
||||
@large_ship_size
|
||||
end
|
||||
@connection_time_status_eol_24
|
||||
else
|
||||
# Default to large for non-wormhole connections
|
||||
@large_ship_size
|
||||
@connection_time_status_default
|
||||
end
|
||||
|
||||
{:ok, connection} =
|
||||
@@ -408,7 +502,8 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
solar_system_source: old_location.solar_system_id,
|
||||
solar_system_target: location.solar_system_id,
|
||||
type: connection_type,
|
||||
ship_size_type: ship_size_type
|
||||
ship_size_type: ship_size_type,
|
||||
time_status: time_status
|
||||
})
|
||||
|
||||
if connection_type == @connection_type_wormhole do
|
||||
@@ -435,8 +530,6 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
time_status: connection.time_status
|
||||
})
|
||||
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
|
||||
{:ok, _} =
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_connection_added, %{
|
||||
character_id: character_id,
|
||||
@@ -483,12 +576,12 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
end
|
||||
end
|
||||
|
||||
def set_start_time(map_id, connection_id, start_time) do
|
||||
WandererApp.Cache.put(
|
||||
"map_#{map_id}:conn_#{connection_id}:start_time",
|
||||
start_time
|
||||
)
|
||||
end
|
||||
def set_start_time(map_id, connection_id, start_time),
|
||||
do:
|
||||
WandererApp.Cache.put(
|
||||
"map_#{map_id}:conn_#{connection_id}:start_time",
|
||||
start_time
|
||||
)
|
||||
|
||||
def can_add_location(_scope, nil), do: false
|
||||
|
||||
@@ -681,4 +774,79 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
state
|
||||
end
|
||||
end
|
||||
|
||||
defp get_ship_size_type(
|
||||
source_solar_system_id,
|
||||
target_solar_system_id,
|
||||
@connection_type_wormhole
|
||||
) do
|
||||
# Check if either system is C1 before creating the connection
|
||||
{:ok, source_system_info} = get_system_static_info(source_solar_system_id)
|
||||
{:ok, target_system_info} = get_system_static_info(target_solar_system_id)
|
||||
|
||||
cond do
|
||||
# C1 systems always get medium
|
||||
source_system_info.system_class == @c1 or target_system_info.system_class == @c1 ->
|
||||
@medium_ship_size
|
||||
|
||||
# C13 systems always get frigate
|
||||
source_system_info.system_class == @c13 or target_system_info.system_class == @c13 ->
|
||||
@frigate_ship_size
|
||||
|
||||
# C4 to null gets frigate (unless C4 is shattered)
|
||||
(source_system_info.system_class == @c4 and target_system_info.system_class == @ns and
|
||||
not source_system_info.is_shattered) or
|
||||
(target_system_info.system_class == @c4 and
|
||||
source_system_info.system_class == @ns and
|
||||
not target_system_info.is_shattered) ->
|
||||
@frigate_ship_size
|
||||
|
||||
true ->
|
||||
# Default to large for other wormhole connections
|
||||
@large_ship_size
|
||||
end
|
||||
end
|
||||
|
||||
# Default to large for non-wormhole connections
|
||||
defp get_ship_size_type(_source_solar_system_id, _target_solar_system_id, _connection_type),
|
||||
do: @large_ship_size
|
||||
|
||||
defp get_new_time_status(_start_time, @connection_time_status_default),
|
||||
do: @connection_time_status_eol_24
|
||||
|
||||
defp get_new_time_status(start_time, old_time_status) do
|
||||
left_minutes =
|
||||
get_time_status_minutes(old_time_status) -
|
||||
DateTime.diff(DateTime.utc_now(), start_time, :minute)
|
||||
|
||||
cond do
|
||||
left_minutes <= @connection_eol_minutes ->
|
||||
@connection_time_status_eol
|
||||
|
||||
left_minutes <= @connection_eol_4_minutes ->
|
||||
@connection_time_status_eol_4
|
||||
|
||||
left_minutes <= @connection_eol_4_5_minutes ->
|
||||
@connection_time_status_eol_4_5
|
||||
|
||||
left_minutes <= @connection_eol_16_minutes ->
|
||||
@connection_time_status_eol_16
|
||||
|
||||
left_minutes <= @connection_eol_24_minutes ->
|
||||
@connection_time_status_eol_24
|
||||
|
||||
left_minutes <= @connection_eol_48_minutes ->
|
||||
@connection_time_status_eol_48
|
||||
|
||||
true ->
|
||||
@connection_time_status_default
|
||||
end
|
||||
end
|
||||
|
||||
defp get_time_status_minutes(@connection_time_status_eol), do: @connection_eol_minutes
|
||||
defp get_time_status_minutes(@connection_time_status_eol_4), do: @connection_eol_4_minutes
|
||||
defp get_time_status_minutes(@connection_time_status_eol_4_5), do: @connection_eol_4_5_minutes
|
||||
defp get_time_status_minutes(@connection_time_status_eol_16), do: @connection_eol_16_minutes
|
||||
defp get_time_status_minutes(@connection_time_status_eol_24), do: @connection_eol_24_minutes
|
||||
defp get_time_status_minutes(@connection_time_status_eol_48), do: @connection_eol_48_minutes
|
||||
end
|
||||
|
||||
@@ -26,7 +26,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
|
||||
@systems_cleanup_timeout :timer.minutes(30)
|
||||
@characters_cleanup_timeout :timer.minutes(5)
|
||||
@connections_cleanup_timeout :timer.minutes(2)
|
||||
@connections_cleanup_timeout :timer.minutes(1)
|
||||
|
||||
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
|
||||
@backup_state_timeout :timer.minutes(1)
|
||||
@@ -104,7 +104,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
)
|
||||
|
||||
Process.send_after(self(), :update_presence, @update_presence_timeout)
|
||||
Process.send_after(self(), :cleanup_connections, 5_000)
|
||||
Process.send_after(self(), :cleanup_connections, @connections_cleanup_timeout)
|
||||
Process.send_after(self(), :cleanup_systems, 10_000)
|
||||
Process.send_after(self(), :cleanup_characters, @characters_cleanup_timeout)
|
||||
Process.send_after(self(), :backup_state, @backup_state_timeout)
|
||||
|
||||
@@ -17,51 +17,53 @@ defmodule WandererApp.Map.Server.PingsImpl do
|
||||
user_id: user_id
|
||||
} = ping_info
|
||||
) do
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
with {:ok, character} <- WandererApp.Character.get_character(character_id),
|
||||
system <-
|
||||
WandererApp.Map.find_system_by_location(map_id, %{
|
||||
solar_system_id: solar_system_id |> String.to_integer()
|
||||
}),
|
||||
{:ok, ping} <-
|
||||
WandererApp.MapPingsRepo.create(%{
|
||||
map_id: map_id,
|
||||
character_id: character_id,
|
||||
system_id: system.id,
|
||||
message: message,
|
||||
type: type
|
||||
}) do
|
||||
Impl.broadcast!(
|
||||
map_id,
|
||||
:ping_added,
|
||||
ping |> Map.merge(%{character_eve_id: character.eve_id, solar_system_id: solar_system_id})
|
||||
)
|
||||
|
||||
system =
|
||||
WandererApp.Map.find_system_by_location(map_id, %{
|
||||
solar_system_id: solar_system_id |> String.to_integer()
|
||||
})
|
||||
# Broadcast rally point events to external clients (webhooks/SSE)
|
||||
if type == 1 do
|
||||
WandererApp.ExternalEvents.broadcast(map_id, :rally_point_added, %{
|
||||
rally_point_id: ping.id,
|
||||
solar_system_id: solar_system_id,
|
||||
system_id: system.id,
|
||||
character_id: character_id,
|
||||
character_name: character.name,
|
||||
character_eve_id: character.eve_id,
|
||||
system_name: system.name,
|
||||
message: message,
|
||||
created_at: ping.inserted_at
|
||||
})
|
||||
end
|
||||
|
||||
{:ok, ping} =
|
||||
WandererApp.MapPingsRepo.create(%{
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_rally_added, %{
|
||||
character_id: character_id,
|
||||
user_id: user_id,
|
||||
map_id: map_id,
|
||||
character_id: character_id,
|
||||
system_id: system.id,
|
||||
message: message,
|
||||
type: type
|
||||
solar_system_id: "#{solar_system_id}"
|
||||
})
|
||||
|
||||
Impl.broadcast!(
|
||||
map_id,
|
||||
:ping_added,
|
||||
ping |> Map.merge(%{character_eve_id: character.eve_id, solar_system_id: solar_system_id})
|
||||
)
|
||||
|
||||
# Broadcast rally point events to external clients (webhooks/SSE)
|
||||
if type == 1 do
|
||||
WandererApp.ExternalEvents.broadcast(map_id, :rally_point_added, %{
|
||||
rally_point_id: ping.id,
|
||||
solar_system_id: solar_system_id,
|
||||
system_id: system.id,
|
||||
character_id: character_id,
|
||||
character_name: character.name,
|
||||
character_eve_id: character.eve_id,
|
||||
system_name: system.name,
|
||||
message: message,
|
||||
created_at: ping.inserted_at
|
||||
})
|
||||
state
|
||||
else
|
||||
error ->
|
||||
Logger.error("Failed to add_ping: #{inspect(error, pretty: true)}")
|
||||
state
|
||||
end
|
||||
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_rally_added, %{
|
||||
character_id: character_id,
|
||||
user_id: user_id,
|
||||
map_id: map_id,
|
||||
solar_system_id: "#{solar_system_id}"
|
||||
})
|
||||
|
||||
state
|
||||
end
|
||||
|
||||
def cancel_ping(
|
||||
@@ -73,39 +75,42 @@ defmodule WandererApp.Map.Server.PingsImpl do
|
||||
type: type
|
||||
} = ping_info
|
||||
) do
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
|
||||
{:ok, %{system: %{id: system_id, name: system_name, solar_system_id: solar_system_id}} = ping} =
|
||||
WandererApp.MapPingsRepo.get_by_id(ping_id)
|
||||
|
||||
:ok = WandererApp.MapPingsRepo.destroy(ping)
|
||||
|
||||
Impl.broadcast!(map_id, :ping_cancelled, %{
|
||||
id: ping_id,
|
||||
solar_system_id: solar_system_id,
|
||||
type: type
|
||||
})
|
||||
|
||||
# Broadcast rally point removal events to external clients (webhooks/SSE)
|
||||
if type == 1 do
|
||||
WandererApp.ExternalEvents.broadcast(map_id, :rally_point_removed, %{
|
||||
with {:ok, character} <- WandererApp.Character.get_character(character_id),
|
||||
{:ok,
|
||||
%{system: %{id: system_id, name: system_name, solar_system_id: solar_system_id}} = ping} <-
|
||||
WandererApp.MapPingsRepo.get_by_id(ping_id),
|
||||
:ok <- WandererApp.MapPingsRepo.destroy(ping) do
|
||||
Impl.broadcast!(map_id, :ping_cancelled, %{
|
||||
id: ping_id,
|
||||
solar_system_id: solar_system_id,
|
||||
system_id: system_id,
|
||||
character_id: character_id,
|
||||
character_name: character.name,
|
||||
character_eve_id: character.eve_id,
|
||||
system_name: system_name
|
||||
type: type
|
||||
})
|
||||
|
||||
# Broadcast rally point removal events to external clients (webhooks/SSE)
|
||||
if type == 1 do
|
||||
WandererApp.ExternalEvents.broadcast(map_id, :rally_point_removed, %{
|
||||
id: ping_id,
|
||||
solar_system_id: solar_system_id,
|
||||
system_id: system_id,
|
||||
character_id: character_id,
|
||||
character_name: character.name,
|
||||
character_eve_id: character.eve_id,
|
||||
system_name: system_name
|
||||
})
|
||||
end
|
||||
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_rally_cancelled, %{
|
||||
character_id: character_id,
|
||||
user_id: user_id,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
state
|
||||
else
|
||||
error ->
|
||||
Logger.error("Failed to cancel_ping: #{inspect(error, pretty: true)}")
|
||||
state
|
||||
end
|
||||
|
||||
WandererApp.User.ActivityTracker.track_map_event(:map_rally_cancelled, %{
|
||||
character_id: character_id,
|
||||
user_id: user_id,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|
||||
state
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,7 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
|
||||
alias WandererApp.Character
|
||||
alias WandererApp.User.ActivityTracker
|
||||
alias WandererApp.Map.Server.{Impl, ConnectionsImpl, SystemsImpl}
|
||||
alias WandererApp.Utils.EVEUtil
|
||||
|
||||
@doc """
|
||||
Public entrypoint for updating signatures on a map system.
|
||||
@@ -92,7 +93,7 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
|
||||
|> Enum.filter(&(&1.eve_id in updated_ids))
|
||||
|> Enum.each(fn existing ->
|
||||
update = Enum.find(updated_sigs, &(&1.eve_id == existing.eve_id))
|
||||
apply_update_signature(existing, update)
|
||||
apply_update_signature(state, existing, update)
|
||||
end)
|
||||
|
||||
# 3. Additions & restorations
|
||||
@@ -209,13 +210,19 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
|
||||
MapSystemSignature.update!(sig, %{deleted: true})
|
||||
end
|
||||
|
||||
defp apply_update_signature(%MapSystemSignature{} = existing, update_params)
|
||||
when not is_nil(update_params) do
|
||||
def apply_update_signature(
|
||||
state,
|
||||
%MapSystemSignature{} = existing,
|
||||
update_params
|
||||
)
|
||||
when not is_nil(update_params) do
|
||||
case MapSystemSignature.update(
|
||||
existing,
|
||||
update_params |> Map.put(:update_forced_at, DateTime.utc_now())
|
||||
) do
|
||||
{:ok, _updated} ->
|
||||
{:ok, updated} ->
|
||||
maybe_update_connection_time_status(state, existing, updated)
|
||||
maybe_update_connection_mass_status(state, existing, updated)
|
||||
:ok
|
||||
|
||||
{:error, reason} ->
|
||||
@@ -223,6 +230,52 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_update_connection_time_status(
|
||||
state,
|
||||
%{custom_info: old_custom_info} = old_sig,
|
||||
%{custom_info: new_custom_info, system_id: system_id, linked_system_id: linked_system_id} =
|
||||
updated_sig
|
||||
)
|
||||
when not is_nil(linked_system_id) do
|
||||
old_time_status = get_time_status(old_custom_info)
|
||||
new_time_status = get_time_status(new_custom_info)
|
||||
|
||||
if old_time_status != new_time_status do
|
||||
{:ok, source_system} = MapSystem.by_id(system_id)
|
||||
|
||||
ConnectionsImpl.update_connection_time_status(state, %{
|
||||
solar_system_source_id: source_system.solar_system_id,
|
||||
solar_system_target_id: linked_system_id,
|
||||
time_status: new_time_status
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_update_connection_time_status(_state, _old_sig, _updated_sig), do: :ok
|
||||
|
||||
defp maybe_update_connection_mass_status(
|
||||
state,
|
||||
%{type: old_type} = old_sig,
|
||||
%{type: new_type, system_id: system_id, linked_system_id: linked_system_id} =
|
||||
updated_sig
|
||||
)
|
||||
when not is_nil(linked_system_id) do
|
||||
if old_type != new_type do
|
||||
{:ok, source_system} = MapSystem.by_id(system_id)
|
||||
signature_ship_size_type = EVEUtil.get_wh_size(new_type)
|
||||
|
||||
if not is_nil(signature_ship_size_type) do
|
||||
ConnectionsImpl.update_connection_ship_size_type(state, %{
|
||||
solar_system_source_id: source_system.solar_system_id,
|
||||
solar_system_target_id: linked_system_id,
|
||||
ship_size_type: signature_ship_size_type
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_update_connection_mass_status(_state, _old_sig, _updated_sig), do: :ok
|
||||
|
||||
defp track_activity(event, map_id, solar_system_id, user_id, character_id, signatures) do
|
||||
ActivityTracker.track_map_event(event, %{
|
||||
map_id: map_id,
|
||||
@@ -251,4 +304,12 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_time_status(nil), do: nil
|
||||
|
||||
defp get_time_status(custom_info_json) do
|
||||
custom_info_json
|
||||
|> Jason.decode!()
|
||||
|> Map.get("time_status")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,7 +41,7 @@ defmodule WandererApp.Maps do
|
||||
system |> Map.take(@minimum_route_attrs)
|
||||
end
|
||||
end,
|
||||
max_concurrency: 10
|
||||
max_concurrency: System.schedulers_online() * 4
|
||||
)
|
||||
|> Enum.map(fn {:ok, val} -> val end)
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ defmodule WandererApp.Utils.EVEUtil do
|
||||
Utility functions for EVE Online related operations.
|
||||
"""
|
||||
|
||||
alias WandererApp.Map.Operations.Connections
|
||||
|
||||
@doc """
|
||||
Generates a URL for a character portrait.
|
||||
|
||||
@@ -28,4 +30,28 @@ defmodule WandererApp.Utils.EVEUtil do
|
||||
def get_portrait_url(eve_id, size) do
|
||||
"https://images.evetech.net/characters/#{eve_id}/portrait?size=#{size}"
|
||||
end
|
||||
|
||||
def get_wh_size(nil), do: nil
|
||||
def get_wh_size("K162"), do: nil
|
||||
|
||||
def get_wh_size(wh_type_name) do
|
||||
{:ok, wormhole_types} = WandererApp.CachedInfo.get_wormhole_types()
|
||||
|
||||
wormhole_types
|
||||
|> Enum.find(fn wh_type_data -> wh_type_data.name == wh_type_name end)
|
||||
|> case do
|
||||
%{max_mass_per_jump: max_mass_per_jump} when not is_nil(max_mass_per_jump) ->
|
||||
get_connection_size_status(max_mass_per_jump)
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp get_connection_size_status(5_000_000), do: Connections.small_ship_size()
|
||||
defp get_connection_size_status(62_000_000), do: Connections.medium_ship_size()
|
||||
defp get_connection_size_status(375_000_000), do: Connections.large_ship_size()
|
||||
defp get_connection_size_status(1_000_000_000), do: Connections.freight_ship_size()
|
||||
defp get_connection_size_status(2_000_000_000), do: Connections.capital_ship_size()
|
||||
defp get_connection_size_status(_max_mass_per_jump), do: Connections.large_ship_size()
|
||||
end
|
||||
|
||||
@@ -17,7 +17,9 @@ defmodule WandererAppWeb do
|
||||
those modules here.
|
||||
"""
|
||||
|
||||
def static_paths, do: ~w(assets fonts images icons favicon.ico robots.txt woff woff2 lottie)
|
||||
def static_paths,
|
||||
do:
|
||||
~w(assets fonts images icons favicon.ico site.webmanifest apple-touch-icon.png web-app-manifest-192x192.png web-app-manifest-512x512.png web-app-manifest.webp web-app-manifest-wide.webp robots.txt woff woff2 lottie)
|
||||
|
||||
def router do
|
||||
quote do
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
{assigns[:page_title] || "Welcome"}
|
||||
</.live_title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
||||
|
||||
<link
|
||||
|
||||
@@ -1,4 +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">
|
||||
<!--Main-->
|
||||
@@ -26,7 +26,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="posts-container" class="bg-neutral rounded-box max-w-[90%] p-4 max-h-[60vh] overflow-y-auto">
|
||||
<div
|
||||
id="posts-container"
|
||||
class="bg-neutral rounded-box max-w-[90%] p-4 max-h-[60vh] overflow-y-auto"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
<%= for post <- @posts do %>
|
||||
<.link class="group carousel-item relative" navigate={~p"/news/#{post.id}"}>
|
||||
|
||||
@@ -80,6 +80,11 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
properties: %{
|
||||
solar_system_id: %Schema{type: :integer, description: "EVE solar system ID"},
|
||||
solar_system_name: %Schema{type: :string, description: "EVE solar system name"},
|
||||
custom_name: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "Custom name for the system"
|
||||
},
|
||||
position_x: %Schema{type: :integer, description: "X coordinate"},
|
||||
position_y: %Schema{type: :integer, description: "Y coordinate"},
|
||||
status: %Schema{
|
||||
@@ -98,6 +103,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
example: %{
|
||||
solar_system_id: 30_000_142,
|
||||
solar_system_name: "Jita",
|
||||
custom_name: "Trade Hub",
|
||||
position_x: 100,
|
||||
position_y: 200,
|
||||
visible: true,
|
||||
@@ -113,6 +119,11 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
description: "EVE solar system name",
|
||||
nullable: true
|
||||
},
|
||||
custom_name: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "Custom name for the system"
|
||||
},
|
||||
position_x: %Schema{type: :integer, description: "X coordinate", nullable: true},
|
||||
position_y: %Schema{type: :integer, description: "Y coordinate", nullable: true},
|
||||
status: %Schema{
|
||||
@@ -130,6 +141,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
},
|
||||
example: %{
|
||||
solar_system_name: "Jita",
|
||||
custom_name: "Trade Hub",
|
||||
position_x: 101,
|
||||
position_y: 202,
|
||||
visible: false,
|
||||
|
||||
@@ -118,6 +118,7 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
||||
|
||||
optional = [
|
||||
"solar_system_name",
|
||||
"custom_name",
|
||||
"position_x",
|
||||
"position_y",
|
||||
"coordinates",
|
||||
@@ -151,6 +152,7 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
||||
def extract_update_params(params) when is_map(params) do
|
||||
allowed = [
|
||||
"solar_system_name",
|
||||
"custom_name",
|
||||
"position_x",
|
||||
"position_y",
|
||||
"coordinates",
|
||||
|
||||
@@ -339,7 +339,7 @@ defmodule WandererAppWeb.MapRoutesEventHandler do
|
||||
destination_id
|
||||
)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
max_concurrency: System.schedulers_online() * 4,
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.minutes(1)
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule WandererAppWeb.MapSignaturesEventHandler do
|
||||
require Logger
|
||||
|
||||
alias WandererAppWeb.{MapEventHandler, MapCoreEventHandler}
|
||||
alias WandererApp.Utils.EVEUtil
|
||||
|
||||
def handle_server_event(
|
||||
%{
|
||||
@@ -178,44 +179,69 @@ defmodule WandererAppWeb.MapSignaturesEventHandler do
|
||||
}
|
||||
} = socket
|
||||
)
|
||||
when not is_nil(main_character_id) do
|
||||
when not is_nil(main_character_id) and not is_nil(solar_system_source) and
|
||||
not is_nil(solar_system_target) do
|
||||
with solar_system_source <- get_integer(solar_system_source),
|
||||
solar_system_target <- get_integer(solar_system_target),
|
||||
{:ok, source_system} <-
|
||||
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_source
|
||||
}),
|
||||
signature <-
|
||||
source_system when not is_nil(source_system) <-
|
||||
WandererApp.Map.find_system_by_location(
|
||||
map_id,
|
||||
%{solar_system_id: solar_system_source}
|
||||
),
|
||||
signature when not is_nil(signature) <-
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(source_system.id)
|
||||
|> Enum.find(fn s -> s.eve_id == signature_eve_id end),
|
||||
target_system <-
|
||||
target_system when not is_nil(target_system) <-
|
||||
WandererApp.Map.find_system_by_location(
|
||||
map_id,
|
||||
%{solar_system_id: solar_system_target}
|
||||
) do
|
||||
if not is_nil(signature) do
|
||||
signature
|
||||
|> WandererApp.Api.MapSystemSignature.update_group!(%{group: "Wormhole"})
|
||||
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
|
||||
linked_system_id: solar_system_target
|
||||
signature
|
||||
|> WandererApp.Api.MapSystemSignature.update_group!(%{group: "Wormhole"})
|
||||
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
|
||||
linked_system_id: solar_system_target
|
||||
})
|
||||
|
||||
if is_nil(target_system.linked_sig_eve_id) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_system_linked_sig_eve_id(%{
|
||||
solar_system_id: solar_system_target,
|
||||
linked_sig_eve_id: signature_eve_id
|
||||
})
|
||||
|
||||
if not is_nil(target_system) &&
|
||||
is_nil(target_system.linked_sig_eve_id) do
|
||||
if not is_nil(signature.temporary_name) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_system_linked_sig_eve_id(%{
|
||||
|> WandererApp.Map.Server.update_system_temporary_name(%{
|
||||
solar_system_id: solar_system_target,
|
||||
linked_sig_eve_id: signature_eve_id
|
||||
temporary_name: signature.temporary_name
|
||||
})
|
||||
end
|
||||
|
||||
if not is_nil(signature.temporary_name) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_system_temporary_name(%{
|
||||
solar_system_id: solar_system_target,
|
||||
temporary_name: signature.temporary_name
|
||||
})
|
||||
signature_time_status =
|
||||
if not is_nil(signature.custom_info) do
|
||||
signature.custom_info |> Jason.decode!() |> Map.get("time_status")
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
if not is_nil(signature_time_status) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_connection_time_status(%{
|
||||
solar_system_source_id: solar_system_source,
|
||||
solar_system_target_id: solar_system_target,
|
||||
time_status: signature_time_status
|
||||
})
|
||||
end
|
||||
|
||||
signature_ship_size_type = EVEUtil.get_wh_size(signature.type)
|
||||
|
||||
if not is_nil(signature_ship_size_type) do
|
||||
map_id
|
||||
|> WandererApp.Map.Server.update_connection_ship_size_type(%{
|
||||
solar_system_source_id: solar_system_source,
|
||||
solar_system_target_id: solar_system_target,
|
||||
ship_size_type: signature_ship_size_type
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
2
mix.exs
@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
|
||||
@version "1.78.1"
|
||||
@version "1.81.5"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
||||
BIN
priv/static/apple-touch-icon.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
priv/static/favicon-96x96.png
Executable file
|
After Width: | Height: | Size: 977 B |
33
priv/static/site.webmanifest
Executable file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Wanderer",
|
||||
"short_name": "Wanderer",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#171717",
|
||||
"background_color": "#171717",
|
||||
"display": "standalone",
|
||||
"start_url": "/",
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "web-app-manifest.webp",
|
||||
"sizes": "720x1280",
|
||||
"type": "image/webp"
|
||||
},
|
||||
{
|
||||
"src": "web-app-manifest-wide.webp",
|
||||
"sizes": "1280x720",
|
||||
"type": "image/webp",
|
||||
"form_factor": "wide"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
priv/static/web-app-manifest-192x192.png
Executable file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
priv/static/web-app-manifest-512x512.png
Executable file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
priv/static/web-app-manifest-wide.webp
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
priv/static/web-app-manifest.webp
Normal file
|
After Width: | Height: | Size: 61 KiB |
@@ -127,6 +127,31 @@ defmodule WandererAppWeb.MapSystemAPIControllerSuccessTest do
|
||||
assert updated_system["position_y"] == 400.0
|
||||
end
|
||||
|
||||
test "UPDATE: successfully updates custom_name", %{conn: conn, map: map} do
|
||||
system =
|
||||
insert(:map_system, %{
|
||||
map_id: map.id,
|
||||
solar_system_id: 30_000_142,
|
||||
name: "Jita",
|
||||
position_x: 100,
|
||||
position_y: 200
|
||||
})
|
||||
|
||||
update_params = %{
|
||||
"custom_name" => "My Trade Hub"
|
||||
}
|
||||
|
||||
conn = put(conn, ~p"/api/maps/#{map.slug}/systems/#{system.id}", update_params)
|
||||
|
||||
response = json_response(conn, 200)
|
||||
|
||||
assert %{
|
||||
"data" => updated_system
|
||||
} = response
|
||||
|
||||
assert updated_system["custom_name"] == "My Trade Hub"
|
||||
end
|
||||
|
||||
test "DELETE: successfully deletes a system", %{conn: conn, map: map} do
|
||||
system =
|
||||
insert(:map_system, %{
|
||||
|
||||