mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-04 14:55:34 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9511af4e6d | ||
|
|
7deaf1fd9f | ||
|
|
43cc5bd520 | ||
|
|
68b58aa520 | ||
|
|
dbadd09af3 | ||
|
|
fcbe2c754f | ||
|
|
ad4580677b | ||
|
|
01a6cc7d92 | ||
|
|
95ce95a187 | ||
|
|
ce8e6fbfb0 | ||
|
|
a20eaed76b | ||
|
|
419af72028 | ||
|
|
8e499522f6 | ||
|
|
84321b847e | ||
|
|
c969a4d465 | ||
|
|
0e12c850b6 | ||
|
|
442835dd9b | ||
|
|
b4ff99cb2e | ||
|
|
aa0ecbc998 | ||
|
|
cc412e93c0 | ||
|
|
1d36fadbfa | ||
|
|
56182bd87d | ||
|
|
d290ff92b3 | ||
|
|
298c5fd3b8 | ||
|
|
e365c43781 | ||
|
|
23a9f22ef4 | ||
|
|
242f437237 | ||
|
|
2eae8cffdb | ||
|
|
68ab3d4f72 | ||
|
|
1ea805aff0 | ||
|
|
6ce45349dc | ||
|
|
8f20cd9863 | ||
|
|
4ed0e85680 | ||
|
|
8ce9eb9955 |
113
CHANGELOG.md
113
CHANGELOG.md
@@ -2,16 +2,59 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.5.0](https://github.com/wanderer-industries/wanderer/compare/v1.4.0...v1.5.0) (2024-10-11)
|
||||
## [v1.12.0](https://github.com/wanderer-industries/wanderer/compare/v1.11.5...v1.12.0) (2024-10-16)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Map: Follow Character on Map and auto select their current system
|
||||
* Map: Prettify user settings
|
||||
|
||||
## [v1.4.0](https://github.com/wanderer-industries/wanderer/compare/v1.3.6...v1.4.0) (2024-10-11)
|
||||
## [v1.11.5](https://github.com/wanderer-industries/wanderer/compare/v1.11.4...v1.11.5) (2024-10-16)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.11.4](https://github.com/wanderer-industries/wanderer/compare/v1.11.3...v1.11.4) (2024-10-16)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.11.3](https://github.com/wanderer-industries/wanderer/compare/v1.11.2...v1.11.3) (2024-10-16)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.11.2](https://github.com/wanderer-industries/wanderer/compare/v1.11.1...v1.11.2) (2024-10-15)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.11.1](https://github.com/wanderer-industries/wanderer/compare/v1.11.0...v1.11.1) (2024-10-14)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.11.0](https://github.com/wanderer-industries/wanderer/compare/v1.10.0...v1.11.0) (2024-10-14)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Map: Add map level option to store custom labels
|
||||
|
||||
## [v1.10.0](https://github.com/wanderer-industries/wanderer/compare/v1.9.0...v1.10.0) (2024-10-13)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Map: Link signature on splash
|
||||
|
||||
## [v1.5.0](https://github.com/wanderer-industries/wanderer/compare/v1.4.0...v1.5.0) (2024-10-11)
|
||||
|
||||
|
||||
|
||||
@@ -29,35 +72,6 @@
|
||||
|
||||
* Signatures: Signatures update fixes
|
||||
|
||||
## [v1.3.5](https://github.com/wanderer-industries/wanderer/compare/v1.3.4...v1.3.5) (2024-10-09)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Signatures: Signatures update fixes
|
||||
|
||||
## [v1.3.4](https://github.com/wanderer-industries/wanderer/compare/v1.3.3...v1.3.4) (2024-10-09)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.3.3](https://github.com/wanderer-industries/wanderer/compare/v1.3.2...v1.3.3) (2024-10-08)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.3.2](https://github.com/wanderer-industries/wanderer/compare/v1.3.1...v1.3.2) (2024-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.3.1](https://github.com/wanderer-industries/wanderer/compare/v1.3.0...v1.3.1) (2024-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.3.0](https://github.com/wanderer-industries/wanderer/compare/v1.2.10...v1.3.0) (2024-10-07)
|
||||
|
||||
|
||||
@@ -71,26 +85,6 @@
|
||||
|
||||
* Map: Revision of sorting from also adding ability to sort all columns
|
||||
|
||||
## [v1.2.10](https://github.com/wanderer-industries/wanderer/compare/v1.2.9...v1.2.10) (2024-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.2.9](https://github.com/wanderer-industries/wanderer/compare/v1.2.8...v1.2.9) (2024-10-07)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.2.8](https://github.com/wanderer-industries/wanderer/compare/v1.2.7...v1.2.8) (2024-10-06)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.2.7](https://github.com/wanderer-industries/wanderer/compare/v1.2.6...v1.2.7) (2024-10-05)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.2.6](https://github.com/wanderer-industries/wanderer/compare/v1.2.5...v1.2.6) (2024-10-05)
|
||||
|
||||
|
||||
@@ -127,11 +121,6 @@
|
||||
|
||||
* Map: Fix map loading after select a different map.
|
||||
|
||||
## [v1.2.2](https://github.com/wanderer-industries/wanderer/compare/v1.2.1...v1.2.2) (2024-10-02)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.2.1](https://github.com/wanderer-industries/wanderer/compare/v1.2.0...v1.2.1) (2024-10-02)
|
||||
|
||||
|
||||
@@ -248,20 +237,10 @@
|
||||
|
||||
* docker: Fix DB connection in docker-compose internal network
|
||||
|
||||
## [v1.0.7](https://github.com/wanderer-industries/wanderer/compare/v1.0.6...v1.0.7) (2024-09-19)
|
||||
|
||||
## [v1.0.6](https://github.com/wanderer-industries/wanderer/compare/v1.0.5...v1.0.6) (2024-09-18)
|
||||
|
||||
## [v1.0.5](https://github.com/wanderer-industries/wanderer/compare/v1.0.4...v1.0.5) (2024-09-18)
|
||||
|
||||
## [v1.0.4](https://github.com/wanderer-industries/wanderer/compare/v1.0.3...v1.0.4) (2024-09-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* core: skip search results for failed character info request
|
||||
|
||||
## [v1.0.3](https://github.com/wanderer-industries/wanderer/compare/v1.0.2...v1.0.3) (2024-09-18)
|
||||
|
||||
## [v1.0.2](https://github.com/wanderer-industries/wanderer/compare/v1.0.1...v1.0.2) (2024-09-18)
|
||||
|
||||
## [v1.0.1](https://github.com/wanderer-industries/wanderer/compare/v1.0.0...v1.0.1) (2024-09-18)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Основной класс диалога */
|
||||
.p-dialog {
|
||||
body .p-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//position: absolute;
|
||||
@@ -7,11 +7,26 @@
|
||||
left: 0;
|
||||
//visibility: hidden;
|
||||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.2);
|
||||
transition: box-shadow 0.3s;
|
||||
background: #fff;
|
||||
z-index: 1000;
|
||||
border: 1px solid #212121;
|
||||
background: var(--surface-h);
|
||||
color: var(--text-color);
|
||||
|
||||
.p-dialog-header {
|
||||
background: #171717 !important;
|
||||
color: var(--text-color);
|
||||
|
||||
.p-dialog-header-icon:focus-visible {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.p-dialog-footer {
|
||||
border-top: 1px solid var(--surface-d);
|
||||
}
|
||||
}
|
||||
|
||||
/* Стиль видимого диалога */
|
||||
@@ -45,12 +60,12 @@
|
||||
justify-content: space-between;
|
||||
padding: 1rem;
|
||||
background: #f4f4f4;
|
||||
border-bottom: 1px solid #ddd;
|
||||
//border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Содержимое диалога */
|
||||
.p-dialog-content {
|
||||
padding: 1rem;
|
||||
padding: 0.5rem;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
@@ -78,23 +93,3 @@
|
||||
.p-dialog-header-close .pi {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
/* Тема Saga Blue (пример) */
|
||||
body .p-dialog {
|
||||
background: var(--surface-a);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
body .p-dialog .p-dialog-header,
|
||||
body .p-dialog .p-dialog-footer {
|
||||
background: var(--surface-b);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
body .p-dialog .p-dialog-header {
|
||||
border-bottom: 1px solid var(--surface-d);
|
||||
}
|
||||
|
||||
body .p-dialog .p-dialog-footer {
|
||||
border-top: 1px solid var(--surface-d);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
--surface-d: #3f4b5b;
|
||||
--surface-e: #2a323d;
|
||||
--surface-f: #2a323d;
|
||||
--surface-h: #171717;
|
||||
--text-color: rgba(255, 255, 255, 0.87);
|
||||
--text-color-secondary: rgba(255, 255, 255, 0.6);
|
||||
--primary-color: #8dd0ff;
|
||||
|
||||
@@ -46,7 +46,7 @@ export const useLabelsMenu = (
|
||||
}
|
||||
|
||||
// const labels = getLabels(system.labels);
|
||||
const hasLabels = labels.list.length > 0;
|
||||
const hasLabels = labels?.list?.length > 0;
|
||||
const statusList = hasLabels ? LABELS_ORDER : LABELS_ORDER.slice(1);
|
||||
|
||||
return [
|
||||
|
||||
@@ -29,7 +29,7 @@ const SpaceToClass: Record<string, string> = {
|
||||
};
|
||||
|
||||
const sortedLabels = (labels: string[]) => {
|
||||
if (labels === null) {
|
||||
if (!labels) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { useReactFlow } from 'reactflow';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { CommandCenterSystem } from '@/hooks/Mapper/types';
|
||||
|
||||
export const useCenterSystem = () => {
|
||||
const rf = useReactFlow();
|
||||
|
||||
const ref = useRef({ rf });
|
||||
ref.current = { rf };
|
||||
|
||||
return useCallback((systemId: CommandCenterSystem) => {
|
||||
if (!rf) {
|
||||
return;
|
||||
}
|
||||
const systemNode = rf.getNodes().find(x => x.data.id === systemId);
|
||||
const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
|
||||
if (!systemNode) {
|
||||
return;
|
||||
}
|
||||
rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
|
||||
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
|
||||
}, []);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useReactFlow } from 'reactflow';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { CommandSelectSystem } from '@/hooks/Mapper/types';
|
||||
|
||||
export const useSelectSystem = () => {
|
||||
const rf = useReactFlow();
|
||||
|
||||
const ref = useRef({ rf });
|
||||
ref.current = { rf };
|
||||
|
||||
return useCallback((systemId: CommandSelectSystem) => {
|
||||
if (!rf) {
|
||||
return;
|
||||
}
|
||||
rf.setNodes(nds =>
|
||||
ref.current.rf.setNodes(nds =>
|
||||
nds.map(node => {
|
||||
return {
|
||||
...node,
|
||||
|
||||
@@ -118,6 +118,10 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
|
||||
// do nothing here
|
||||
break;
|
||||
|
||||
case Commands.linkSignatureToSystem:
|
||||
// do nothing here
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(`Map handlers: Unknown command: ${type}`, data);
|
||||
break;
|
||||
|
||||
@@ -7,7 +7,7 @@ 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 } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { WdImageSize, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
interface SystemCustomLabelDialog {
|
||||
systemId: string;
|
||||
@@ -79,14 +79,14 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
||||
|
||||
// @ts-ignore
|
||||
const handleInput = useCallback(e => {
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
header="Edit label"
|
||||
visible={visible}
|
||||
draggable={false}
|
||||
draggable={true}
|
||||
style={{ width: '250px' }}
|
||||
onHide={onHide}
|
||||
onShow={onShow}
|
||||
@@ -100,9 +100,13 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
||||
<IconField>
|
||||
{label !== '' && (
|
||||
<WdImgButton
|
||||
className="pi pi-trash p-input-icon"
|
||||
className="pi pi-trash text-red-400"
|
||||
textSize={WdImageSize.large}
|
||||
tooltip={{ content: 'Reset label' }}
|
||||
tooltip={{
|
||||
content: 'Remove custom label',
|
||||
className: 'pi p-input-icon',
|
||||
position: TooltipPosition.top,
|
||||
}}
|
||||
onClick={handleReset}
|
||||
/>
|
||||
)}
|
||||
@@ -111,7 +115,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
||||
aria-describedby="username-help"
|
||||
autoComplete="off"
|
||||
value={label}
|
||||
maxLength={3}
|
||||
maxLength={5}
|
||||
onChange={e => setLabel(e.target.value)}
|
||||
// @ts-expect-error
|
||||
ref={inputRef}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
|
||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { CommandLinkSignatureToSystem } from '@/hooks/Mapper/types';
|
||||
import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent';
|
||||
import {
|
||||
Setting,
|
||||
COSMIC_SIGNATURE,
|
||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
|
||||
|
||||
interface SystemLinkSignatureDialogProps {
|
||||
data: CommandLinkSignatureToSystem;
|
||||
setVisible: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
const signatureSettings: Setting[] = [{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }];
|
||||
|
||||
export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignatureDialogProps) => {
|
||||
const { outCommand } = useMapRootState();
|
||||
|
||||
const ref = useRef({ outCommand });
|
||||
ref.current = { outCommand };
|
||||
|
||||
const handleHide = useCallback(() => {
|
||||
setVisible(false);
|
||||
}, [setVisible]);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(signature: SystemSignature) => {
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { outCommand } = ref.current;
|
||||
|
||||
outCommand({
|
||||
type: OutCommand.linkSignatureToSystem,
|
||||
data: {
|
||||
...data,
|
||||
signature_eve_id: signature.eve_id,
|
||||
},
|
||||
});
|
||||
setVisible(false);
|
||||
},
|
||||
[data, setVisible],
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
header="Select signature to link"
|
||||
visible
|
||||
draggable={false}
|
||||
style={{ width: '500px' }}
|
||||
onHide={handleHide}
|
||||
contentClassName="!p-0"
|
||||
>
|
||||
<SystemSignaturesContent
|
||||
systemId={`${data.solar_system_source}`}
|
||||
settings={signatureSettings}
|
||||
onSelect={handleSelect}
|
||||
selectable={true}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './SystemLinkSignatureDialog';
|
||||
@@ -90,7 +90,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
||||
}, []);
|
||||
|
||||
const handleInput = useCallback((e: any) => {
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
||||
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -160,7 +160,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
||||
aria-describedby="label"
|
||||
autoComplete="off"
|
||||
value={label}
|
||||
maxLength={3}
|
||||
maxLength={5}
|
||||
onChange={e => setLabel(e.target.value)}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from './Widget';
|
||||
export * from './WidgetsGrid';
|
||||
export * from './SystemSettingsDialog';
|
||||
export * from './SystemCustomLabelDialog';
|
||||
export * from './SystemLinkSignatureDialog';
|
||||
|
||||
@@ -5,6 +5,14 @@ import { Checkbox } from 'primereact/checkbox';
|
||||
|
||||
export type Setting = { key: string; name: string; value: boolean };
|
||||
|
||||
export const COSMIC_SIGNATURE = 'Cosmic Signature';
|
||||
export const COSMIC_ANOMALY = 'Cosmic Anomaly';
|
||||
export const DEPLOYABLE = 'Deployable';
|
||||
export const STRUCTURE = 'Structure';
|
||||
export const STARBASE = 'Starbase';
|
||||
export const SHIP = 'Ship';
|
||||
export const DRONE = 'Drone';
|
||||
|
||||
interface SystemSignatureSettingsDialogProps {
|
||||
settings: Setting[];
|
||||
onSave: (settings: Setting[]) => void;
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
||||
import { InfoDrawer, LayoutEventBlocker, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { SystemSignaturesContent } from './SystemSignaturesContent';
|
||||
import { Setting, SystemSignatureSettingsDialog } from './SystemSignatureSettingsDialog';
|
||||
import {
|
||||
Setting,
|
||||
SystemSignatureSettingsDialog,
|
||||
COSMIC_SIGNATURE,
|
||||
COSMIC_ANOMALY,
|
||||
DEPLOYABLE,
|
||||
STRUCTURE,
|
||||
STARBASE,
|
||||
SHIP,
|
||||
DRONE,
|
||||
} from './SystemSignatureSettingsDialog';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@@ -9,14 +19,6 @@ import { PrimeIcons } from 'primereact/api';
|
||||
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
|
||||
export const COSMIC_SIGNATURE = 'Cosmic Signature';
|
||||
export const COSMIC_ANOMALY = 'Cosmic Anomaly';
|
||||
export const DEPLOYABLE = 'Deployable';
|
||||
export const STRUCTURE = 'Structure';
|
||||
export const STARBASE = 'Starbase';
|
||||
export const SHIP = 'Ship';
|
||||
export const DRONE = 'Drone';
|
||||
|
||||
const settings: Setting[] = [
|
||||
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true },
|
||||
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true },
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
renderIcon,
|
||||
renderName,
|
||||
renderTimeLeft,
|
||||
renderLinkedSystem,
|
||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
||||
// import { PrimeIcons } from 'primereact/api';
|
||||
import useLocalStorageState from 'use-local-storage-state';
|
||||
@@ -41,8 +42,10 @@ const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = {
|
||||
interface SystemSignaturesContentProps {
|
||||
systemId: string;
|
||||
settings: Setting[];
|
||||
selectable?: boolean;
|
||||
onSelect?: (signature: SystemSignature) => void;
|
||||
}
|
||||
export const SystemSignaturesContent = ({ systemId, settings }: SystemSignaturesContentProps) => {
|
||||
export const SystemSignaturesContent = ({ systemId, settings, selectable, onSelect }: SystemSignaturesContentProps) => {
|
||||
const { outCommand } = useMapRootState();
|
||||
|
||||
const [signatures, setSignatures, signaturesRef] = useRefState<SystemSignature[]>([]);
|
||||
@@ -92,25 +95,25 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
setSignatures(signatures);
|
||||
}, [outCommand, systemId]);
|
||||
|
||||
const updateSignatures = useCallback(
|
||||
async (newSignatures: SystemSignature[], updateOnly: boolean) => {
|
||||
const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly);
|
||||
// const updateSignatures = useCallback(
|
||||
// async (newSignatures: SystemSignature[], updateOnly: boolean) => {
|
||||
// const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly);
|
||||
|
||||
const { signatures: updatedSignatures } = await outCommand({
|
||||
type: OutCommand.updateSignatures,
|
||||
data: {
|
||||
system_id: systemId,
|
||||
added,
|
||||
updated,
|
||||
removed,
|
||||
},
|
||||
});
|
||||
// const { signatures: updatedSignatures } = await outCommand({
|
||||
// type: OutCommand.updateSignatures,
|
||||
// data: {
|
||||
// system_id: systemId,
|
||||
// added,
|
||||
// updated,
|
||||
// removed,
|
||||
// },
|
||||
// });
|
||||
|
||||
setSignatures(() => updatedSignatures);
|
||||
setSelectedSignatures([]);
|
||||
},
|
||||
[outCommand, systemId],
|
||||
);
|
||||
// setSignatures(() => updatedSignatures);
|
||||
// setSelectedSignatures([]);
|
||||
// },
|
||||
// [outCommand, systemId],
|
||||
// );
|
||||
|
||||
const handleUpdateSignatures = useCallback(
|
||||
async (newSignatures: SystemSignature[], updateOnly: boolean) => {
|
||||
@@ -133,6 +136,9 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
);
|
||||
|
||||
const handleDeleteSelected = useCallback(async () => {
|
||||
if (selectable) {
|
||||
return;
|
||||
}
|
||||
if (selectedSignatures.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -141,7 +147,7 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)),
|
||||
false,
|
||||
);
|
||||
}, [handleUpdateSignatures, signatures, selectedSignatures]);
|
||||
}, [handleUpdateSignatures, selectable, signatures, selectedSignatures]);
|
||||
|
||||
const handleSelectAll = useCallback(() => {
|
||||
setSelectedSignatures(signatures);
|
||||
@@ -157,11 +163,26 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
setAskUser(false);
|
||||
}, [parsedSignatures, handleUpdateSignatures]);
|
||||
|
||||
const handleSelectSignatures = useCallback(
|
||||
e => {
|
||||
if (selectable) {
|
||||
onSelect?.(e.value);
|
||||
} else {
|
||||
setSelectedSignatures(e.value);
|
||||
}
|
||||
},
|
||||
[onSelect, selectable],
|
||||
);
|
||||
|
||||
useHotkey(true, ['a'], handleSelectAll);
|
||||
|
||||
useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clipboardContent) {
|
||||
return;
|
||||
}
|
||||
@@ -179,7 +200,7 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
setParsedSignatures(newSignatures);
|
||||
setAskUser(true);
|
||||
}
|
||||
}, [clipboardContent]);
|
||||
}, [clipboardContent, selectable]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!systemId) {
|
||||
@@ -240,10 +261,10 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
className={classes.Table}
|
||||
value={filteredSignatures}
|
||||
size="small"
|
||||
selectionMode="multiple"
|
||||
selectionMode={selectable ? 'single' : 'multiple'}
|
||||
selection={selectedSignatures}
|
||||
metaKeySelection
|
||||
onSelectionChange={e => setSelectedSignatures(e.value)}
|
||||
onSelectionChange={handleSelectSignatures}
|
||||
dataKey="eve_id"
|
||||
tableClassName="w-full select-none"
|
||||
resizableColumns={false}
|
||||
@@ -297,6 +318,16 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures
|
||||
hidden={compact || medium}
|
||||
sortable
|
||||
></Column>
|
||||
<Column
|
||||
field="linked_system"
|
||||
header="Linked System"
|
||||
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
body={renderLinkedSystem}
|
||||
style={{ maxWidth: nameColumnWidth }}
|
||||
hidden={compact}
|
||||
sortable
|
||||
></Column>
|
||||
|
||||
<Column
|
||||
field="updated_at"
|
||||
header="Updated"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './renderIcon';
|
||||
export * from './renderName';
|
||||
export * from './renderTimeLeft';
|
||||
export * from './renderLinkedSystem';
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { SystemViewStandalone } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export const renderLinkedSystem = (row: SystemSignature) => {
|
||||
if (!row.linked_system) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={row.linked_system?.solar_system_name}>
|
||||
<SystemViewStandalone
|
||||
className={clsx('select-none text-center cursor-context-menu')}
|
||||
hideRegion
|
||||
{...row.linked_system}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { useCallback, useState } from 'react';
|
||||
import { OnTheMap, RightBar } from '@/hooks/Mapper/components/mapRootContent/components';
|
||||
import { MapContextMenu } from '@/hooks/Mapper/components/mapRootContent/components/MapContextMenu/MapContextMenu.tsx';
|
||||
import { useSkipContextMenu } from '@/hooks/Mapper/hooks/useSkipContextMenu';
|
||||
import { MapSettings } from "@/hooks/Mapper/components/mapRootContent/components/MapSettings";
|
||||
|
||||
export interface MapRootContentProps {}
|
||||
|
||||
@@ -16,9 +17,11 @@ export const MapRootContent = ({}: MapRootContentProps) => {
|
||||
const { isShowMenu } = interfaceSettings;
|
||||
|
||||
const [showOnTheMap, setShowOnTheMap] = useState(false);
|
||||
const [showMapSettings, setShowMapSettings] = useState(false);
|
||||
const mapInterface = <MapInterface />;
|
||||
|
||||
const handleShowOnTheMap = useCallback(() => setShowOnTheMap(true), []);
|
||||
const handleShowMapSettings = useCallback(() => setShowMapSettings(true), []);
|
||||
|
||||
useSkipContextMenu();
|
||||
|
||||
@@ -31,18 +34,19 @@ export const MapRootContent = ({}: MapRootContentProps) => {
|
||||
{mapInterface}
|
||||
</div>
|
||||
<div className="absolute top-0 right-0 w-14 h-[calc(100%+3.5rem)] pointer-events-auto">
|
||||
<RightBar onShowOnTheMap={handleShowOnTheMap} />
|
||||
<RightBar onShowOnTheMap={handleShowOnTheMap} onShowMapSettings={handleShowMapSettings} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="absolute top-0 left-14 w-[calc(100%-3.5rem)] h-[calc(100%-3.5rem)] pointer-events-none">
|
||||
<Topbar>
|
||||
<MapContextMenu onShowOnTheMap={handleShowOnTheMap} />
|
||||
<MapContextMenu onShowOnTheMap={handleShowOnTheMap} onShowMapSettings={handleShowMapSettings} />
|
||||
</Topbar>
|
||||
{mapInterface}
|
||||
</div>
|
||||
)}
|
||||
<OnTheMap show={showOnTheMap} onHide={() => setShowOnTheMap(false)} />
|
||||
<MapSettings show={showMapSettings} onHide={() => setShowMapSettings(false)} />
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,10 +8,11 @@ import { MenuItem } from 'primereact/menuitem';
|
||||
|
||||
export interface MapContextMenuProps {
|
||||
onShowOnTheMap?: () => void;
|
||||
onShowMapSettings?: () => void;
|
||||
}
|
||||
|
||||
export const MapContextMenu = ({ onShowOnTheMap }: MapContextMenuProps) => {
|
||||
const { outCommand, interfaceSettings, setInterfaceSettings } = useMapRootState();
|
||||
export const MapContextMenu = ({ onShowOnTheMap, onShowMapSettings }: MapContextMenuProps) => {
|
||||
const { outCommand, setInterfaceSettings } = useMapRootState();
|
||||
|
||||
const menuRight = useRef<Menu>(null);
|
||||
|
||||
@@ -22,13 +23,6 @@ export const MapContextMenu = ({ onShowOnTheMap }: MapContextMenuProps) => {
|
||||
});
|
||||
}, [outCommand]);
|
||||
|
||||
const toggleMinimap = useCallback(() => {
|
||||
setInterfaceSettings(x => ({
|
||||
...x,
|
||||
isShowMinimap: !x.isShowMinimap,
|
||||
}));
|
||||
}, [setInterfaceSettings]);
|
||||
|
||||
const items = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
@@ -43,9 +37,9 @@ export const MapContextMenu = ({ onShowOnTheMap }: MapContextMenuProps) => {
|
||||
},
|
||||
{ separator: true },
|
||||
{
|
||||
label: interfaceSettings.isShowMinimap ? 'Hide minimap' : 'Show minimap',
|
||||
icon: `pi ${interfaceSettings.isShowMinimap ? 'pi-eye-slash' : 'pi-eye'}`,
|
||||
command: toggleMinimap,
|
||||
label: 'Settings',
|
||||
icon: `pi pi-cog`,
|
||||
command: onShowMapSettings,
|
||||
},
|
||||
{
|
||||
label: 'Dock menu',
|
||||
@@ -57,7 +51,7 @@ export const MapContextMenu = ({ onShowOnTheMap }: MapContextMenuProps) => {
|
||||
})),
|
||||
},
|
||||
] as MenuItem[];
|
||||
}, [handleAddCharacter, interfaceSettings.isShowMinimap, onShowOnTheMap, setInterfaceSettings, toggleMinimap]);
|
||||
}, [handleAddCharacter, onShowMapSettings, onShowOnTheMap, setInterfaceSettings]);
|
||||
|
||||
return (
|
||||
<div className="ml-1">
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
.verticalTabsContainer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
|
||||
:global {
|
||||
.p-tabview {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.p-tabview-panels {
|
||||
padding: 6px 1rem !important;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.p-tabview-nav-container {
|
||||
border-right: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.p-tabview-nav {
|
||||
flex-direction: column;
|
||||
width: 150px;
|
||||
min-height: 100%;
|
||||
border: none;
|
||||
|
||||
li {
|
||||
width: 100%;
|
||||
border-right: 4px solid var(--surface-hover);
|
||||
background-color: var(--surface-card);
|
||||
|
||||
transition: background-color 200ms, border-right-color 200ms;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--surface-hover);
|
||||
border-right: 4px solid var(--surface-100);
|
||||
}
|
||||
|
||||
.p-tabview-nav-link {
|
||||
transition: color 200ms;
|
||||
|
||||
justify-content: flex-end;
|
||||
padding: 10px;
|
||||
//background-color: var(--surface-card);
|
||||
background-color: initial;
|
||||
border: none;
|
||||
color: var(--gray-400);
|
||||
|
||||
border-radius: initial;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.p-tabview-selected {
|
||||
background-color: var(--surface-50);
|
||||
border-right: 4px solid var(--primary-color);
|
||||
|
||||
.p-tabview-nav-link {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
//background-color: var(--surface-hover);
|
||||
border-right: 4px solid var(--primary-color);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p-tabview-panel {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.CheckboxContainer {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
|
||||
& > span:nth-child(1) {
|
||||
color: var(--gray-200);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
& > :nth-child(2){
|
||||
border-bottom: 2px dotted #3f3f3f;
|
||||
height: 2px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Уменьшение размеров InputSwitch с использованием глобальных стилей */
|
||||
.smallInputSwitch {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:global {
|
||||
.p-inputswitch {
|
||||
height: 1rem;
|
||||
width: 2rem;
|
||||
&.p-inputswitch-checked {
|
||||
.p-inputswitch-slider::before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
}
|
||||
|
||||
&.p-highlight .p-inputswitch-slider:before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
|
||||
.p-inputswitch-slider::before {
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
margin-top: -0.4rem;
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import styles from './MapSettings.module.scss';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { TabPanel, TabView } from 'primereact/tabview';
|
||||
import { PrettySwitchbox } from './components';
|
||||
import { InterfaceStoredSettings, InterfaceStoredSettingsProps, useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
|
||||
export enum UserSettingsRemoteProps {
|
||||
link_signature_on_splash = 'link_signature_on_splash',
|
||||
select_on_spash = 'select_on_spash',
|
||||
}
|
||||
|
||||
export const DEFAULT_REMOTE_SETTINGS = {
|
||||
[UserSettingsRemoteProps.link_signature_on_splash]: false,
|
||||
[UserSettingsRemoteProps.select_on_spash]: false,
|
||||
};
|
||||
|
||||
export const UserSettingsRemoteList = [
|
||||
UserSettingsRemoteProps.link_signature_on_splash,
|
||||
UserSettingsRemoteProps.select_on_spash,
|
||||
];
|
||||
|
||||
export type UserSettingsRemote = {
|
||||
link_signature_on_splash: boolean;
|
||||
select_on_spash: boolean;
|
||||
};
|
||||
|
||||
export type UserSettings = UserSettingsRemote & InterfaceStoredSettings;
|
||||
|
||||
export interface MapSettingsProps {
|
||||
show: boolean;
|
||||
onHide: () => void;
|
||||
}
|
||||
|
||||
type CheckboxesList = {
|
||||
prop: keyof UserSettings;
|
||||
label: string;
|
||||
}[];
|
||||
|
||||
const COMMON_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
{ prop: InterfaceStoredSettingsProps.isShowMinimap, label: 'Show Minimap' },
|
||||
];
|
||||
|
||||
const SYSTEMS_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
{ prop: InterfaceStoredSettingsProps.isShowKSpace, label: 'Highlight Low/High-security systems' },
|
||||
{ prop: UserSettingsRemoteProps.select_on_spash, label: 'Auto-select splashed' },
|
||||
];
|
||||
|
||||
const SIGNATURES_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
{ prop: UserSettingsRemoteProps.link_signature_on_splash, label: 'Link signature on splash' },
|
||||
];
|
||||
|
||||
const UI_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
{ prop: InterfaceStoredSettingsProps.isShowMenu, label: 'Enable compact map menu bar' },
|
||||
];
|
||||
|
||||
export const MapSettings = ({ show, onHide }: MapSettingsProps) => {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const { outCommand, interfaceSettings, setInterfaceSettings } = useMapRootState();
|
||||
const [userRemoteSettings, setUserRemoteSettings] = useState<UserSettingsRemote>({ ...DEFAULT_REMOTE_SETTINGS });
|
||||
|
||||
const mergedSettings = useMemo(() => {
|
||||
return {
|
||||
...interfaceSettings,
|
||||
...userRemoteSettings,
|
||||
};
|
||||
}, [userRemoteSettings, interfaceSettings]);
|
||||
|
||||
const handleShow = async () => {
|
||||
const { user_settings } = await outCommand({
|
||||
type: OutCommand.getUserSettings,
|
||||
data: null,
|
||||
});
|
||||
|
||||
setUserRemoteSettings({
|
||||
...user_settings,
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangeChecked = useCallback(
|
||||
(prop: keyof UserSettings) => async (checked: boolean) => {
|
||||
// @ts-ignore
|
||||
if (UserSettingsRemoteList.includes(prop)) {
|
||||
const newRemoteSettings = {
|
||||
...userRemoteSettings,
|
||||
[prop]: checked,
|
||||
};
|
||||
|
||||
await outCommand({
|
||||
type: OutCommand.updateUserSettings,
|
||||
data: newRemoteSettings,
|
||||
});
|
||||
|
||||
setUserRemoteSettings(newRemoteSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
setInterfaceSettings({
|
||||
...interfaceSettings,
|
||||
[prop]: checked,
|
||||
});
|
||||
},
|
||||
[interfaceSettings, outCommand, setInterfaceSettings, userRemoteSettings],
|
||||
);
|
||||
|
||||
const renderCheckboxesList = (list: CheckboxesList) => {
|
||||
return list.map(x => {
|
||||
return (
|
||||
<PrettySwitchbox
|
||||
key={x.prop}
|
||||
label={x.label}
|
||||
checked={mergedSettings[x.prop]}
|
||||
setChecked={handleChangeChecked(x.prop)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
header="Map settings"
|
||||
visible={show}
|
||||
draggable={false}
|
||||
style={{ width: '550px' }}
|
||||
onShow={handleShow}
|
||||
onHide={() => {
|
||||
if (!show) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveIndex(0);
|
||||
onHide();
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className={styles.verticalTabsContainer}>
|
||||
<TabView
|
||||
activeIndex={activeIndex}
|
||||
onTabChange={e => setActiveIndex(e.index)}
|
||||
className={styles.verticalTabView}
|
||||
>
|
||||
<TabPanel header="Common" headerClassName={styles.verticalTabHeader}>
|
||||
<div className="w-full h-full flex flex-col gap-1">{renderCheckboxesList(COMMON_CHECKBOXES_PROPS)}</div>
|
||||
</TabPanel>
|
||||
<TabPanel header="Systems" headerClassName={styles.verticalTabHeader}>
|
||||
<div className="w-full h-full flex flex-col gap-1">
|
||||
{renderCheckboxesList(SYSTEMS_CHECKBOXES_PROPS)}
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel disabled header="Connections" headerClassName={styles.verticalTabHeader}>
|
||||
<p>Connections</p>
|
||||
</TabPanel>
|
||||
<TabPanel header="Signatures" headerClassName={styles.verticalTabHeader}>
|
||||
{renderCheckboxesList(SIGNATURES_CHECKBOXES_PROPS)}
|
||||
</TabPanel>
|
||||
<TabPanel header="User Interface" headerClassName={styles.verticalTabHeader}>
|
||||
{renderCheckboxesList(UI_CHECKBOXES_PROPS)}
|
||||
</TabPanel>
|
||||
</TabView>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
.CheckboxContainer {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
|
||||
& > span:nth-child(1) {
|
||||
color: var(--gray-200);
|
||||
font-size: 13px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
& > :nth-child(2){
|
||||
border-bottom: 2px dotted #3f3f3f;
|
||||
height: 1px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Уменьшение размеров InputSwitch с использованием глобальных стилей */
|
||||
.smallInputSwitch {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:global {
|
||||
.p-inputswitch {
|
||||
height: 1rem;
|
||||
width: 2rem;
|
||||
&.p-inputswitch-checked {
|
||||
.p-inputswitch-slider::before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
}
|
||||
|
||||
&.p-highlight .p-inputswitch-slider:before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
|
||||
.p-inputswitch-slider::before {
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
margin-top: -0.4rem;
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import styles from './MapSettings.module.scss';
|
||||
import { WdCheckbox } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
interface PrettySwitchboxProps {
|
||||
checked: boolean;
|
||||
setChecked: (checked: boolean) => void;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const PrettySwitchbox = ({ checked, setChecked, label }: PrettySwitchboxProps) => {
|
||||
return (
|
||||
<div className={styles.CheckboxContainer}>
|
||||
<span>{label}</span>
|
||||
<div />
|
||||
<div className={styles.smallInputSwitch}>
|
||||
<WdCheckbox size="m" label={''} value={checked} onChange={e => setChecked(e.checked ?? false)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './PrettySwitchbox';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './PrettySwitchbox';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './MapSettings';
|
||||
@@ -8,9 +8,10 @@ import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
interface RightBarProps {
|
||||
onShowOnTheMap?: () => void;
|
||||
onShowMapSettings?: () => void;
|
||||
}
|
||||
|
||||
export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
export const RightBar = ({ onShowOnTheMap, onShowMapSettings }: RightBarProps) => {
|
||||
const { outCommand, interfaceSettings, setInterfaceSettings } = useMapRootState();
|
||||
|
||||
const isShowMinimap = interfaceSettings.isShowMinimap === undefined ? true : interfaceSettings.isShowMinimap;
|
||||
@@ -22,13 +23,6 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
});
|
||||
}, [outCommand]);
|
||||
|
||||
const handleOpenUserSettings = useCallback(() => {
|
||||
outCommand({
|
||||
type: OutCommand.openUserSettings,
|
||||
data: null,
|
||||
});
|
||||
}, [outCommand]);
|
||||
|
||||
const toggleMinimap = useCallback(() => {
|
||||
setInterfaceSettings(x => ({
|
||||
...x,
|
||||
@@ -66,17 +60,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
type="button"
|
||||
onClick={handleAddCharacter}
|
||||
>
|
||||
<i className="pi pi-user-plus text-lg"></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
<WdTooltipWrapper content="User settings" position={TooltipPosition.left}>
|
||||
<button
|
||||
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
|
||||
type="button"
|
||||
onClick={handleOpenUserSettings}
|
||||
>
|
||||
<i className="pi pi-cog text-lg"></i>
|
||||
<i className="pi pi-user-plus"></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
@@ -86,12 +70,22 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
type="button"
|
||||
onClick={onShowOnTheMap}
|
||||
>
|
||||
<i className="pi pi-hashtag text-lg"></i>
|
||||
<i className="pi pi-hashtag"></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center mb-2 gap-1">
|
||||
<WdTooltipWrapper content="User settings" position={TooltipPosition.left}>
|
||||
<button
|
||||
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
|
||||
type="button"
|
||||
onClick={onShowMapSettings}
|
||||
>
|
||||
<i className="pi pi-cog"></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
<WdTooltipWrapper
|
||||
content={
|
||||
interfaceSettings.isShowKSpace ? 'Hide highlighting Imperial Space' : 'Show highlighting Imperial Space'
|
||||
@@ -103,11 +97,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
type="button"
|
||||
onClick={toggleKSpace}
|
||||
>
|
||||
{interfaceSettings.isShowKSpace ? (
|
||||
<i className="pi pi-heart-fill text-lg"></i>
|
||||
) : (
|
||||
<i className="pi pi-heart text-lg"></i>
|
||||
)}
|
||||
<i className={interfaceSettings.isShowKSpace ? 'hero-cloud-solid' : 'hero-cloud'}></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
@@ -117,7 +107,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
type="button"
|
||||
onClick={toggleMinimap}
|
||||
>
|
||||
{isShowMinimap ? <i className="pi pi-eye text-lg"></i> : <i className="pi pi-eye-slash text-lg"></i>}
|
||||
<i className={isShowMinimap ? 'pi pi-eye' : 'pi pi-eye-slash'}></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
@@ -127,7 +117,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
|
||||
type="button"
|
||||
onClick={toggleMenu}
|
||||
>
|
||||
<i className="pi pi-window-minimize text-lg"></i>
|
||||
<i className="pi pi-window-minimize"></i>
|
||||
</button>
|
||||
</WdTooltipWrapper>
|
||||
</div>
|
||||
|
||||
@@ -5,13 +5,20 @@ import { MapRootData, useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
|
||||
import isEqual from 'lodash.isequal';
|
||||
import { ContextMenuSystem, useContextMenuSystemHandlers } from '@/hooks/Mapper/components/contexts';
|
||||
import { SystemCustomLabelDialog, SystemSettingsDialog } from '@/hooks/Mapper/components/mapInterface/components';
|
||||
import {
|
||||
SystemCustomLabelDialog,
|
||||
SystemSettingsDialog,
|
||||
SystemLinkSignatureDialog,
|
||||
} from '@/hooks/Mapper/components/mapInterface/components';
|
||||
import classes from './MapWrapper.module.scss';
|
||||
import { Connections } from '@/hooks/Mapper/components/mapRootContent/components/Connections';
|
||||
import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple';
|
||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||
import { Node } from 'reactflow';
|
||||
|
||||
import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||
import { useMapEventListener } from '@/hooks/Mapper/events';
|
||||
|
||||
import { STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/MapRootProvider';
|
||||
|
||||
interface MapWrapperProps {
|
||||
@@ -53,6 +60,7 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
|
||||
);
|
||||
|
||||
const [openSettings, setOpenSettings] = useState<string | null>(null);
|
||||
const [openLinkSignatures, setOpenLinkSignatures] = useState<any | null>(null);
|
||||
const [openCustomLabel, setOpenCustomLabel] = useState<string | null>(null);
|
||||
const handleCommand: OutCommandHandler = useCallback(
|
||||
event => {
|
||||
@@ -60,6 +68,9 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
|
||||
case OutCommand.openSettings:
|
||||
setOpenSettings(event.data.system_id);
|
||||
break;
|
||||
case OutCommand.linkSignatureToSystem:
|
||||
setOpenLinkSignatures(event.data);
|
||||
break;
|
||||
default:
|
||||
return outCommand(event);
|
||||
}
|
||||
@@ -88,6 +99,14 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
|
||||
|
||||
const handleConnectionDbClick = useCallback((e: SolarSystemConnection) => setSelectedConnection(e), []);
|
||||
|
||||
useMapEventListener(event => {
|
||||
switch (event.name) {
|
||||
case Commands.linkSignatureToSystem:
|
||||
setOpenLinkSignatures(event.data);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Map
|
||||
@@ -103,19 +122,15 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => {
|
||||
/>
|
||||
|
||||
{openSettings != null && (
|
||||
<SystemSettingsDialog
|
||||
systemId={openSettings}
|
||||
visible={openSettings != null}
|
||||
setVisible={() => setOpenSettings(null)}
|
||||
/>
|
||||
<SystemSettingsDialog systemId={openSettings} visible setVisible={() => setOpenSettings(null)} />
|
||||
)}
|
||||
|
||||
{openCustomLabel != null && (
|
||||
<SystemCustomLabelDialog
|
||||
systemId={openCustomLabel}
|
||||
visible={openCustomLabel != null}
|
||||
setVisible={() => setOpenCustomLabel(null)}
|
||||
/>
|
||||
<SystemCustomLabelDialog systemId={openCustomLabel} visible setVisible={() => setOpenCustomLabel(null)} />
|
||||
)}
|
||||
|
||||
{openLinkSignatures != null && (
|
||||
<SystemLinkSignatureDialog data={openLinkSignatures} setVisible={() => setOpenLinkSignatures(null)} />
|
||||
)}
|
||||
|
||||
<Connections selectedConnection={selectedConnection} onHide={() => setSelectedConnection(null)} />
|
||||
|
||||
13
assets/js/hooks/Mapper/events/index.ts
Normal file
13
assets/js/hooks/Mapper/events/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { createEvent } from 'react-event-hook';
|
||||
|
||||
export interface MapEvent {
|
||||
name: string;
|
||||
data: {
|
||||
solar_system_source: number;
|
||||
solar_system_target: number;
|
||||
};
|
||||
}
|
||||
|
||||
const { useMapEventListener, emitMapEvent } = createEvent('map-event')<MapEvent>();
|
||||
|
||||
export { useMapEventListener, emitMapEvent };
|
||||
@@ -1,4 +1,4 @@
|
||||
import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures';
|
||||
import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog';
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
|
||||
export const parseSignatures = (value: string, availableKeys: string[]): SystemSignature[] => {
|
||||
|
||||
@@ -26,7 +26,13 @@ const INITIAL_DATA: MapRootData = {
|
||||
selectedConnections: [],
|
||||
};
|
||||
|
||||
type InterfaceStoredSettings = {
|
||||
export enum InterfaceStoredSettingsProps {
|
||||
isShowMenu = 'isShowMenu',
|
||||
isShowMinimap = 'isShowMinimap',
|
||||
isShowKSpace = 'isShowKSpace',
|
||||
}
|
||||
|
||||
export type InterfaceStoredSettings = {
|
||||
isShowMenu: boolean;
|
||||
isShowMinimap: boolean;
|
||||
isShowKSpace: boolean;
|
||||
|
||||
@@ -27,6 +27,8 @@ import {
|
||||
useRoutes,
|
||||
} from './api';
|
||||
|
||||
import { emitMapEvent } from '@/hooks/Mapper/events';
|
||||
|
||||
export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
|
||||
const mapInit = useMapInit();
|
||||
const { addSystems, removeSystems, updateSystems } = useCommandsSystems();
|
||||
@@ -93,6 +95,10 @@ export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
|
||||
// do nothing here
|
||||
break;
|
||||
|
||||
case Commands.linkSignatureToSystem:
|
||||
emitMapEvent({ name: Commands.linkSignatureToSystem, data });
|
||||
break;
|
||||
|
||||
case Commands.killsUpdated:
|
||||
// do nothing here
|
||||
break;
|
||||
|
||||
@@ -23,6 +23,7 @@ export enum Commands {
|
||||
routes = 'routes',
|
||||
centerSystem = 'center_system',
|
||||
selectSystem = 'select_system',
|
||||
linkSignatureToSystem = 'link_signature_to_system',
|
||||
}
|
||||
|
||||
export type Command =
|
||||
@@ -42,7 +43,8 @@ export type Command =
|
||||
| Commands.killsUpdated
|
||||
| Commands.routes
|
||||
| Commands.selectSystem
|
||||
| Commands.centerSystem;
|
||||
| Commands.centerSystem
|
||||
| Commands.linkSignatureToSystem;
|
||||
|
||||
export type CommandInit = {
|
||||
systems: SolarSystemRawType[];
|
||||
@@ -75,6 +77,10 @@ export type CommandRoutes = RoutesList;
|
||||
export type CommandKillsUpdated = Kill[];
|
||||
export type CommandSelectSystem = string | undefined;
|
||||
export type CommandCenterSystem = string | undefined;
|
||||
export type CommandLinkSignatureToSystem = {
|
||||
solar_system_source: number;
|
||||
solar_system_target: number;
|
||||
};
|
||||
|
||||
export interface CommandData {
|
||||
[Commands.init]: CommandInit;
|
||||
@@ -94,6 +100,7 @@ export interface CommandData {
|
||||
[Commands.killsUpdated]: CommandKillsUpdated;
|
||||
[Commands.selectSystem]: CommandSelectSystem;
|
||||
[Commands.centerSystem]: CommandCenterSystem;
|
||||
[Commands.linkSignatureToSystem]: CommandLinkSignatureToSystem;
|
||||
}
|
||||
|
||||
export interface MapHandlers {
|
||||
@@ -129,9 +136,13 @@ export enum OutCommand {
|
||||
addCharacter = 'add_character',
|
||||
openUserSettings = 'open_user_settings',
|
||||
getPassages = 'get_passages',
|
||||
linkSignatureToSystem = 'link_signature_to_system',
|
||||
|
||||
// Only UI commands
|
||||
openSettings = 'open_settings',
|
||||
|
||||
getUserSettings = 'get_user_settings',
|
||||
updateUserSettings = 'update_user_settings',
|
||||
}
|
||||
|
||||
export type OutCommandHandler = <T = any>(event: { type: OutCommand; data: any }) => Promise<T>;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types';
|
||||
|
||||
export type SystemSignature = {
|
||||
eve_id: string;
|
||||
kind: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
group: string;
|
||||
linked_system?: SolarSystemStaticInfoRaw;
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export class LabelsManager {
|
||||
}
|
||||
|
||||
hasLabel(label: string) {
|
||||
return this.parsedLabels.labels.includes(label);
|
||||
return this.parsedLabels.labels?.includes(label);
|
||||
}
|
||||
|
||||
toggleLabel(label: string) {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"primeicons": "^7.0.0",
|
||||
"primereact": "^10.6.5",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-event-hook": "^3.1.2",
|
||||
"react-flow-renderer": "^10.3.17",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-usestateref": "^1.0.9",
|
||||
|
||||
@@ -3199,6 +3199,11 @@ react-error-boundary@^4.0.13:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
|
||||
react-event-hook@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-event-hook/-/react-event-hook-3.1.2.tgz#445e8f3b751f6abe4ef199f31bff47593c4c13d4"
|
||||
integrity sha512-qQ9LXLdxmWRRZPlnqVjqlw7jovSvDosQEOyQ9cjPHhtDv8JIszjj0td1PuHJHrVW0LS8a1XeJhLe6i7S5u9SbQ==
|
||||
|
||||
react-flow-renderer@^10.3.17:
|
||||
version "10.3.17"
|
||||
resolved "https://registry.npmjs.org/react-flow-renderer/-/react-flow-renderer-10.3.17.tgz"
|
||||
|
||||
@@ -77,7 +77,7 @@ config :wanderer_app,
|
||||
web_app_url: web_app_url,
|
||||
git_sha: System.get_env("GIT_SHA", "111"),
|
||||
custom_route_base_url: System.get_env("CUSTOM_ROUTE_BASE_URL"),
|
||||
invites: System.get_env("WANDERER_INVITES", "false") == "true",
|
||||
invites: System.get_env("WANDERER_INVITES", "false") |> String.to_existing_atom(),
|
||||
admin_username: System.get_env("WANDERER_ADMIN_USERNAME", "admin"),
|
||||
admin_password: System.get_env("WANDERER_ADMIN_PASSWORD"),
|
||||
admins: admins,
|
||||
|
||||
@@ -14,6 +14,7 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
define(:all_active, action: :all_active)
|
||||
define(:create, action: :create)
|
||||
define(:update, action: :update)
|
||||
define(:update_linked_system, action: :update_linked_system)
|
||||
|
||||
define(:by_id,
|
||||
get_by: [:id],
|
||||
@@ -66,13 +67,18 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
:name,
|
||||
:description,
|
||||
:kind,
|
||||
:group
|
||||
:group,
|
||||
:linked_system_id
|
||||
]
|
||||
|
||||
primary? true
|
||||
require_atomic? false
|
||||
end
|
||||
|
||||
update :update_linked_system do
|
||||
accept [:linked_system_id]
|
||||
end
|
||||
|
||||
read :by_system_id do
|
||||
argument(:system_id, :string, allow_nil?: false)
|
||||
|
||||
@@ -99,6 +105,10 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
attribute :linked_system_id, :integer do
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
attribute :kind, :string
|
||||
attribute :group, :string
|
||||
|
||||
|
||||
@@ -52,15 +52,6 @@ defmodule WandererApp.Map do
|
||||
end
|
||||
end
|
||||
|
||||
def get_map_options!(map) do
|
||||
map
|
||||
|> Map.get(:options)
|
||||
|> case do
|
||||
nil -> %{"layout" => "left_to_right"}
|
||||
options -> Jason.decode!(options)
|
||||
end
|
||||
end
|
||||
|
||||
def update_map(map_id, map_update) do
|
||||
Cachex.get_and_update(:map_cache, map_id, fn map ->
|
||||
case map do
|
||||
|
||||
@@ -333,7 +333,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
end
|
||||
|
||||
def delete_systems(
|
||||
%{map_id: map_id, rtree_name: rtree_name} = state,
|
||||
%{map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = state,
|
||||
removed_ids,
|
||||
user_id,
|
||||
character_id
|
||||
@@ -352,7 +352,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
removed_ids
|
||||
|> Enum.each(fn solar_system_id ->
|
||||
map_id
|
||||
|> WandererApp.MapSystemRepo.remove_from_map(solar_system_id)
|
||||
|> WandererApp.MapSystemRepo.remove_from_map(solar_system_id, map_opts)
|
||||
|> case do
|
||||
{:ok, _} ->
|
||||
:ok
|
||||
@@ -801,7 +801,13 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
end
|
||||
|
||||
def handle_event({:options_updated, options}, %{map: map, map_id: map_id} = state),
|
||||
do: %{state | map_opts: [layout: options.layout]}
|
||||
do: %{
|
||||
state
|
||||
| map_opts: [
|
||||
layout: options |> Map.get("layout"),
|
||||
store_custom_labels: options |> Map.get("store_custom_labels")
|
||||
]
|
||||
}
|
||||
|
||||
def handle_event({ref, _result}, %{map_id: _map_id} = state) do
|
||||
Process.demonitor(ref, [:flush])
|
||||
@@ -1278,9 +1284,14 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
|> WandererApp.Map.add_connections!(connections)
|
||||
|> WandererApp.Map.add_characters!(characters)
|
||||
|
||||
map_options = WandererApp.Map.get_map_options!(initial_map)
|
||||
{:ok, map_options} = WandererApp.MapRepo.options_to_form_data(initial_map)
|
||||
|
||||
%{state | map: map, map_opts: [layout: map_options |> Map.get("layout")]}
|
||||
map_opts = [
|
||||
layout: map_options |> Map.get("layout"),
|
||||
store_custom_labels: map_options |> Map.get("store_custom_labels")
|
||||
]
|
||||
|
||||
%{state | map: map, map_opts: map_opts}
|
||||
end
|
||||
|
||||
defp _init_map_systems(state, [] = _systems), do: state
|
||||
@@ -1627,9 +1638,18 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
solar_system_target: location.solar_system_id
|
||||
})
|
||||
|
||||
broadcast!(map_id, :add_connection, connection)
|
||||
WandererApp.Map.add_connection(map_id, connection)
|
||||
|
||||
broadcast!(map_id, :add_connection, connection)
|
||||
|
||||
broadcast!(map_id, :maybe_link_signature, %{
|
||||
character_id: character_id,
|
||||
solar_system_source: old_location.solar_system_id,
|
||||
solar_system_target: location.solar_system_id
|
||||
})
|
||||
|
||||
:ok
|
||||
|
||||
{:error, error} ->
|
||||
@logger.debug(fn -> "Failed to add connection: #{inspect(error, pretty: true)}" end)
|
||||
:ok
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
defmodule WandererApp.MapRepo do
|
||||
use WandererApp, :repository
|
||||
|
||||
@default_map_options %{"layout" => "left_to_right", "store_custom_labels" => false}
|
||||
|
||||
def get(map_id, relationships \\ []) do
|
||||
map_id
|
||||
|> WandererApp.Api.Map.by_id()
|
||||
@@ -13,10 +15,23 @@ defmodule WandererApp.MapRepo do
|
||||
end
|
||||
end
|
||||
|
||||
def get_by_slug_with_permissions(map_slug, current_user),
|
||||
do:
|
||||
map_slug
|
||||
|> WandererApp.Api.Map.get_map_by_slug()
|
||||
|> load_user_permissions(current_user)
|
||||
|
||||
def load_relationships(map, []), do: {:ok, map}
|
||||
|
||||
def load_relationships(map, relationships), do: map |> Ash.load(relationships)
|
||||
|
||||
defp load_user_permissions({:ok, map}, current_user),
|
||||
do:
|
||||
map
|
||||
|> Ash.load([:acls, :user_permissions], actor: current_user)
|
||||
|
||||
defp load_user_permissions(error, _current_user), do: error
|
||||
|
||||
def update_hubs(map_id, hubs) do
|
||||
map_id
|
||||
|> WandererApp.Api.Map.by_id()
|
||||
@@ -28,4 +43,19 @@ defmodule WandererApp.MapRepo do
|
||||
{:error, :map_not_found}
|
||||
end
|
||||
end
|
||||
|
||||
def update_options(map, options),
|
||||
do:
|
||||
map
|
||||
|> WandererApp.Api.Map.update_options(%{options: Jason.encode!(options)})
|
||||
|
||||
def options_to_form_data(%{options: options} = _map_options) when not is_nil(options),
|
||||
do: {:ok, Jason.decode!(options)}
|
||||
|
||||
def options_to_form_data(_), do: {:ok, @default_map_options}
|
||||
|
||||
def options_to_form_data!(options) do
|
||||
{:ok, data} = options_to_form_data(options)
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,14 +22,12 @@ defmodule WandererApp.MapSystemRepo do
|
||||
def get_visible_by_map(map_id),
|
||||
do: WandererApp.Api.MapSystem.read_visible_by_map(%{map_id: map_id})
|
||||
|
||||
def remove_from_map(map_id, solar_system_id) do
|
||||
def remove_from_map(map_id, solar_system_id, opts) do
|
||||
WandererApp.Api.MapSystem.read_by_map_and_solar_system!(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id
|
||||
})
|
||||
|> WandererApp.Api.MapSystem.update_labels!(%{
|
||||
labels: nil
|
||||
})
|
||||
|> cleanup_labels(opts)
|
||||
|> WandererApp.Api.MapSystem.update_tag!(%{
|
||||
tag: nil
|
||||
})
|
||||
@@ -39,6 +37,33 @@ defmodule WandererApp.MapSystemRepo do
|
||||
{:error, error}
|
||||
end
|
||||
|
||||
def cleanup_labels(%{labels: labels} = system, opts) do
|
||||
store_custom_labels? =
|
||||
Keyword.get(opts, :store_custom_labels, "false") |> String.to_existing_atom()
|
||||
|
||||
labels = get_filtered_labels(labels, store_custom_labels?)
|
||||
|
||||
system
|
||||
|> WandererApp.Api.MapSystem.update_labels!(%{
|
||||
labels: labels
|
||||
})
|
||||
end
|
||||
|
||||
def get_filtered_labels(labels, true) when is_binary(labels) do
|
||||
labels
|
||||
|> Jason.decode!()
|
||||
|> case do
|
||||
%{"customLabel" => customLabel} = labels when is_binary(customLabel) ->
|
||||
%{"customLabel" => customLabel, "labels" => []}
|
||||
|> Jason.encode!()
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_filtered_labels(_, _store_custom_labels), do: nil
|
||||
|
||||
def update_name(system, update),
|
||||
do:
|
||||
system
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
defmodule WandererApp.MapUserSettingsRepo do
|
||||
use WandererApp, :repository
|
||||
|
||||
@default_form_data %{"select_on_spash" => "false"}
|
||||
@default_form_data %{"select_on_spash" => "false", "link_signature_on_splash" => "false"}
|
||||
|
||||
def get(map_id, user_id) do
|
||||
map_id
|
||||
|
||||
@@ -62,6 +62,7 @@ defmodule WandererAppWeb do
|
||||
use Phoenix.LiveView, @opts
|
||||
|
||||
unquote(html_helpers())
|
||||
defguard is_connected?(socket) when socket.transport_pid != nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<main class="bg-gradient-to-r from-stone-950 to-stone-900">
|
||||
<main class="bg-stone-950">
|
||||
<%= @inner_content %>
|
||||
</main>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<main
|
||||
class="main flex-col !min-h-screen justify-between flex z-0 focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-gradient-to-r from-stone-950 to-stone-900 ccp-font"
|
||||
class="main flex-col !min-h-screen justify-between flex z-0 focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-stone-950 ccp-font"
|
||||
phx-mounted={JS.remove_class("opacity-0")}
|
||||
>
|
||||
<navbar class="navbar bg-base-100 !sticky top-0 z-50 bg-opacity-0 ">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</.connection_status>
|
||||
|
||||
<main
|
||||
class="main flex-1 relative z-0 overflow-hidden focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-gradient-to-r from-stone-950 to-stone-900 maps_bg ccp-font"
|
||||
class="main flex-1 relative z-0 overflow-hidden focus:outline-none transition-all duration-500 opacity-0 phx-page-loading:opacity-0 bg-stone-950 maps_bg ccp-font"
|
||||
phx-mounted={JS.remove_class("opacity-0")}
|
||||
>
|
||||
<%= @inner_content %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="flex flex-col w-0 flex-1 overflow-hidden bg-gradient-to-r from-stone-950 to-stone-900">
|
||||
<div class="flex flex-col w-0 flex-1 overflow-hidden bg-stone-950">
|
||||
<.connection_status>
|
||||
Re-establishing connection...
|
||||
</.connection_status>
|
||||
|
||||
@@ -12,7 +12,7 @@ defmodule WandererAppWeb.AdminLive do
|
||||
{:ok, socket.assigns.current_user.characters}
|
||||
)
|
||||
|
||||
admin_character =
|
||||
corp_wallet_character =
|
||||
socket.assigns.current_user.characters
|
||||
|> Enum.find(fn character ->
|
||||
WandererApp.Character.can_track_corp_wallet?(character)
|
||||
@@ -31,39 +31,35 @@ defmodule WandererAppWeb.AdminLive do
|
||||
end)
|
||||
|
||||
socket =
|
||||
if not is_nil(admin_character) do
|
||||
if not is_nil(corp_wallet_character) do
|
||||
{:ok, total_balance} =
|
||||
WandererApp.Character.TransactionsTracker.get_total_balance(admin_character.id)
|
||||
WandererApp.Character.TransactionsTracker.get_total_balance(corp_wallet_character.id)
|
||||
|
||||
{:ok, transactions} =
|
||||
WandererApp.Character.TransactionsTracker.get_transactions(admin_character.id)
|
||||
|
||||
{:ok, active_map_subscriptions} =
|
||||
WandererApp.Api.MapSubscription.all_active()
|
||||
WandererApp.Character.TransactionsTracker.get_transactions(corp_wallet_character.id)
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
show_invites?: WandererApp.Env.invites(),
|
||||
admin_character_id: admin_character.id,
|
||||
total_balance: total_balance,
|
||||
transactions: transactions,
|
||||
user_character_ids: user_character_ids,
|
||||
active_map_subscriptions: active_map_subscriptions
|
||||
transactions: transactions
|
||||
)
|
||||
else
|
||||
socket
|
||||
|> assign(
|
||||
admin_character_id: nil,
|
||||
show_invites?: false,
|
||||
total_balance: 0,
|
||||
transactions: [],
|
||||
active_map_subscriptions: []
|
||||
transactions: []
|
||||
)
|
||||
end
|
||||
|
||||
{:ok, active_map_subscriptions} =
|
||||
WandererApp.Api.MapSubscription.all_active()
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(
|
||||
active_map_subscriptions: active_map_subscriptions,
|
||||
show_invites?: WandererApp.Env.invites(),
|
||||
user_character_ids: user_character_ids,
|
||||
user_id: user_id,
|
||||
invite_link: nil,
|
||||
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?()
|
||||
@@ -72,7 +68,7 @@ defmodule WandererAppWeb.AdminLive do
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, socket |> assign(user_id: nil, admin_character_id: nil)}
|
||||
{:ok, socket |> assign(user_id: nil)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -4,57 +4,14 @@ defmodule WandererAppWeb.MapLive do
|
||||
require Logger
|
||||
|
||||
@impl true
|
||||
def mount(params, _session, socket) do
|
||||
def mount(params, _session, socket) when is_connected?(socket) do
|
||||
socket =
|
||||
with %{"slug" => map_slug} <- params do
|
||||
socket
|
||||
|> _init_state(map_slug)
|
||||
else
|
||||
_ ->
|
||||
# redirect back to main
|
||||
socket
|
||||
|> assign(
|
||||
map_loaded?: false,
|
||||
maps_loading: false,
|
||||
selected_subscription: nil,
|
||||
maps: [],
|
||||
map: nil,
|
||||
map_id: nil,
|
||||
map_slug: nil,
|
||||
user_permissions: nil,
|
||||
form: to_form(%{"map_slug" => nil})
|
||||
)
|
||||
end
|
||||
|
||||
{:ok, socket |> assign(server_online: false)}
|
||||
end
|
||||
|
||||
defp _init_state(socket, map_slug) do
|
||||
current_user = socket.assigns.current_user
|
||||
|
||||
ErrorTracker.set_context(%{user_id: current_user.id})
|
||||
Task.async(fn -> _get_available_maps(current_user) end)
|
||||
|
||||
map_slug
|
||||
|> WandererApp.Api.Map.get_map_by_slug()
|
||||
|> _load_user_permissions(current_user)
|
||||
|> case do
|
||||
{:ok,
|
||||
%{
|
||||
id: map_id,
|
||||
deleted: false
|
||||
} = map} ->
|
||||
Process.send_after(self(), {:init_map, map}, 10)
|
||||
Process.send_after(self(), {:load_map, map_slug}, Enum.random(10..200))
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
map: map,
|
||||
map_id: map_id,
|
||||
map_loaded?: false,
|
||||
maps_loading: true,
|
||||
maps: [],
|
||||
user_permissions: nil,
|
||||
selected_subscription: nil,
|
||||
map_slug: map_slug,
|
||||
form: to_form(%{"map_slug" => map_slug})
|
||||
)
|
||||
@@ -63,26 +20,42 @@ defmodule WandererAppWeb.MapLive do
|
||||
attr: "data-loading",
|
||||
timeout: 2000
|
||||
})
|
||||
else
|
||||
_ ->
|
||||
# redirect back to main
|
||||
socket
|
||||
|> assign(
|
||||
maps_loading: false,
|
||||
map_id: nil,
|
||||
map_slug: nil,
|
||||
form: to_form(%{"map_slug" => nil})
|
||||
)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
deleted: true
|
||||
} = _map} ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Map was deleted by owner or administrator."
|
||||
)
|
||||
|> push_navigate(to: ~p"/maps")
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(
|
||||
map_loaded?: false,
|
||||
maps: [],
|
||||
server_online: false,
|
||||
selected_subscription: nil,
|
||||
user_permissions: nil
|
||||
)}
|
||||
end
|
||||
|
||||
{:error, _} ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Something went wrong. Please try one more time or submit an issue."
|
||||
)
|
||||
|> push_navigate(to: ~p"/maps")
|
||||
end
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(
|
||||
maps_loading: false,
|
||||
map_loaded?: false,
|
||||
maps: [],
|
||||
server_online: false,
|
||||
selected_subscription: nil,
|
||||
user_permissions: nil,
|
||||
form: to_form(%{"map_slug" => nil})
|
||||
)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -90,33 +63,12 @@ defmodule WandererAppWeb.MapLive do
|
||||
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
|
||||
end
|
||||
|
||||
defp apply_action(socket, :index, _params) do
|
||||
socket
|
||||
|> assign(:active_page, :map)
|
||||
end
|
||||
|
||||
defp apply_action(socket, :add_system, _params) do
|
||||
socket
|
||||
|> assign(:active_page, :map)
|
||||
|> assign(:page_title, "Add System")
|
||||
|> assign(:add_system_form, to_form(%{"system_id" => nil}))
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
%{event: :map_started},
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
user_permissions: user_permissions
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
on_map_started(map_id, current_user, user_permissions)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
socket
|
||||
),
|
||||
do: {:noreply, socket |> on_map_started()}
|
||||
|
||||
@impl true
|
||||
def handle_info(:character_token_invalid, socket),
|
||||
@@ -211,6 +163,63 @@ defmodule WandererAppWeb.MapLive do
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
%{
|
||||
event: :maybe_link_signature,
|
||||
payload: %{
|
||||
character_id: character_id,
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target
|
||||
}
|
||||
},
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
is_user_character? =
|
||||
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
|
||||
|
||||
link_signature_on_splash? =
|
||||
map_user_settings
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data!()
|
||||
|> Map.get("link_signature_on_splash", "false")
|
||||
|> String.to_existing_atom()
|
||||
|
||||
{:ok, signatures} =
|
||||
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_source
|
||||
})
|
||||
|> case do
|
||||
{:ok, system} ->
|
||||
{:ok, get_system_signatures(system.id)}
|
||||
|
||||
_ ->
|
||||
{:ok, []}
|
||||
end
|
||||
|
||||
socket =
|
||||
(is_user_character? && link_signature_on_splash? && not (signatures |> Enum.empty?()))
|
||||
|> case do
|
||||
true ->
|
||||
socket
|
||||
|> push_map_event("link_signature_to_system", %{
|
||||
solar_system_source: solar_system_source,
|
||||
solar_system_target: solar_system_target
|
||||
})
|
||||
|
||||
false ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(%{event: :update_map, payload: map_diff}, socket) do
|
||||
{:noreply,
|
||||
@@ -378,7 +387,49 @@ defmodule WandererAppWeb.MapLive do
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:init_map, map}, %{assigns: %{current_user: current_user}} = socket) do
|
||||
def handle_info({:load_map, map_slug}, %{assigns: %{current_user: current_user}} = socket) do
|
||||
ErrorTracker.set_context(%{user_id: current_user.id})
|
||||
Task.async(fn -> _get_available_maps(current_user) end)
|
||||
|
||||
map_slug
|
||||
|> WandererApp.MapRepo.get_by_slug_with_permissions(current_user)
|
||||
|> case do
|
||||
{:ok,
|
||||
%{
|
||||
id: map_id,
|
||||
deleted: false
|
||||
} = map} ->
|
||||
Process.send_after(self(), {:init_map, map}, 10)
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
deleted: true
|
||||
} = _map} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Map was deleted by owner or administrator."
|
||||
)
|
||||
|> push_navigate(to: ~p"/maps")}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Something went wrong. Please try one more time or submit an issue."
|
||||
)
|
||||
|> push_navigate(to: ~p"/maps")}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{:init_map, map},
|
||||
%{assigns: %{current_user: current_user, map_slug: map_slug}} = socket
|
||||
) do
|
||||
with %{
|
||||
id: map_id,
|
||||
deleted: false,
|
||||
@@ -416,126 +467,36 @@ defmodule WandererAppWeb.MapLive do
|
||||
cond do
|
||||
(only_tracked_characters and can_track? and all_character_tracked?) or
|
||||
(not only_tracked_characters and can_view?) ->
|
||||
Process.send_after(
|
||||
self(),
|
||||
{:map_init,
|
||||
%{
|
||||
map_id: map_id,
|
||||
page_title: map_name,
|
||||
user_permissions: user_permissions,
|
||||
tracked_character_ids: tracked_character_ids
|
||||
}},
|
||||
10
|
||||
)
|
||||
Phoenix.PubSub.subscribe(WandererApp.PubSub, map_id)
|
||||
{:ok, ui_loaded} = WandererApp.Cache.get_and_remove("map_#{map_slug}:ui_loaded", false)
|
||||
|
||||
if ui_loaded do
|
||||
maybe_start_map(map_id)
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(
|
||||
map_id: map_id,
|
||||
page_title: map_name,
|
||||
user_permissions: user_permissions,
|
||||
tracked_character_ids: tracked_character_ids,
|
||||
only_tracked_characters: only_tracked_characters
|
||||
)}
|
||||
|
||||
only_tracked_characters and can_track? and not all_character_tracked? ->
|
||||
Process.send_after(self(), :not_all_characters_tracked, 10)
|
||||
{:noreply, socket}
|
||||
|
||||
true ->
|
||||
Process.send_after(self(), :no_permissions, 10)
|
||||
{:noreply, socket}
|
||||
end
|
||||
else
|
||||
_ ->
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:map_init, %{map_id: map_id} = initial_data}, socket) do
|
||||
Phoenix.PubSub.subscribe(WandererApp.PubSub, map_id)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(initial_data)}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{:map_start,
|
||||
%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
} = _started_data},
|
||||
socket
|
||||
) do
|
||||
socket =
|
||||
events
|
||||
|> Enum.reduce(socket, fn event, socket ->
|
||||
case event do
|
||||
{:track_characters, map_characters, track_character} ->
|
||||
:ok = _track_characters(map_characters, map_id, track_character)
|
||||
:ok = _add_characters(map_characters, map_id, track_character)
|
||||
socket
|
||||
|
||||
:invalid_token_message ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"One of your characters has expired token. Please refresh it on characters page."
|
||||
)
|
||||
|
||||
:empty_tracked_characters ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:info,
|
||||
"You should enable tracking for at least one character to work with map."
|
||||
)
|
||||
|
||||
:map_character_limit ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Map reached its character limit, your characters won't be tracked. Please contact administrator."
|
||||
)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
end)
|
||||
|
||||
Process.send_after(
|
||||
self(),
|
||||
{:map_loaded,
|
||||
%{
|
||||
map_id: map_id,
|
||||
initial_data: initial_data
|
||||
}},
|
||||
10
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
|
||||
)}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{:map_loaded,
|
||||
%{
|
||||
map_id: map_id,
|
||||
initial_data: initial_data
|
||||
} = _loaded_data},
|
||||
socket
|
||||
) do
|
||||
map_characters = map_id |> WandererApp.Map.list_characters()
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(map_loaded?: true)
|
||||
|> push_map_event(
|
||||
"init",
|
||||
initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1))
|
||||
)
|
||||
|> push_event("js-exec", %{
|
||||
to: "#map-loader",
|
||||
attr: "data-loaded"
|
||||
})}
|
||||
end
|
||||
|
||||
def handle_info(:no_access, socket),
|
||||
@@ -579,10 +540,6 @@ defmodule WandererAppWeb.MapLive do
|
||||
maps: maps
|
||||
)}
|
||||
|
||||
{:map_started_data, started_data} ->
|
||||
Process.send_after(self(), {:map_start, started_data}, 100)
|
||||
{:noreply, socket}
|
||||
|
||||
{:map_error, map_error} ->
|
||||
Process.send_after(self(), map_error, 100)
|
||||
{:noreply, socket}
|
||||
@@ -614,13 +571,15 @@ defmodule WandererAppWeb.MapLive do
|
||||
def handle_info(_event, socket), do: {:noreply, socket}
|
||||
|
||||
@impl true
|
||||
def handle_event("ui_loaded", _body, %{assigns: %{map_id: map_id}} = socket) do
|
||||
{:ok, map_started} = WandererApp.Cache.lookup("map_#{map_id}:started", false)
|
||||
def handle_event("ui_loaded", _body, %{assigns: %{map_slug: map_slug} = assigns} = socket) do
|
||||
assigns
|
||||
|> Map.get(:map_id)
|
||||
|> case do
|
||||
map_id when not is_nil(map_id) ->
|
||||
maybe_start_map(map_id)
|
||||
|
||||
if map_started do
|
||||
Process.send_after(self(), %{event: :map_started}, 10)
|
||||
else
|
||||
WandererApp.Map.Manager.start_map(map_id)
|
||||
_ ->
|
||||
WandererApp.Cache.insert("map_#{map_slug}:ui_loaded", true)
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
@@ -1048,7 +1007,7 @@ defmodule WandererAppWeb.MapLive do
|
||||
s |> WandererApp.Api.MapSystemSignature.create!()
|
||||
end)
|
||||
|
||||
{:reply, %{signatures: _get_system_signatures(system.id)}, socket}
|
||||
{:reply, %{signatures: get_system_signatures(system.id)}, socket}
|
||||
|
||||
_ ->
|
||||
{:reply, %{signatures: []},
|
||||
@@ -1079,7 +1038,7 @@ defmodule WandererAppWeb.MapLive do
|
||||
solar_system_id: solar_system_id |> String.to_integer()
|
||||
}) do
|
||||
{:ok, system} ->
|
||||
{:reply, %{signatures: _get_system_signatures(system.id)}, socket}
|
||||
{:reply, %{signatures: get_system_signatures(system.id)}, socket}
|
||||
|
||||
_ ->
|
||||
{:reply, %{signatures: []}, socket}
|
||||
@@ -1371,14 +1330,24 @@ defmodule WandererAppWeb.MapLive do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("add_character", _, %{assigns: assigns} = socket) do
|
||||
def handle_event(
|
||||
"add_character",
|
||||
_,
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
user_permissions: user_permissions
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: assigns.map_id}) do
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
|
||||
case assigns.user_permissions.track_character do
|
||||
case user_permissions.track_character do
|
||||
true ->
|
||||
{:noreply,
|
||||
socket
|
||||
@@ -1387,10 +1356,14 @@ defmodule WandererAppWeb.MapLive do
|
||||
character_settings: character_settings
|
||||
)
|
||||
|> assign_async(:characters, fn ->
|
||||
WandererApp.Maps.load_characters(
|
||||
assigns.map |> Ash.load!(:acls),
|
||||
{:ok, map} =
|
||||
map_id
|
||||
|> WandererApp.MapRepo.get([:acls])
|
||||
|
||||
map
|
||||
|> WandererApp.Maps.load_characters(
|
||||
character_settings,
|
||||
assigns.current_user.id
|
||||
current_user.id
|
||||
)
|
||||
end)}
|
||||
|
||||
@@ -1410,24 +1383,33 @@ defmodule WandererAppWeb.MapLive do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("toggle_track", %{"character-id" => character_id}, socket) do
|
||||
map = socket.assigns.map
|
||||
character_settings = socket.assigns.character_settings
|
||||
|
||||
def handle_event(
|
||||
"toggle_track",
|
||||
%{"character-id" => character_id},
|
||||
%{
|
||||
assigns: %{
|
||||
map_id: map_id,
|
||||
map_slug: map_slug,
|
||||
character_settings: character_settings,
|
||||
current_user: current_user,
|
||||
only_tracked_characters: only_tracked_characters
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
socket =
|
||||
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
|
||||
nil ->
|
||||
{:ok, map_character_settings} =
|
||||
WandererApp.Api.MapCharacterSettings.create(%{
|
||||
character_id: character_id,
|
||||
map_id: map.id,
|
||||
map_id: map_id,
|
||||
tracked: true
|
||||
})
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = _track_characters([character], map.id, true)
|
||||
:ok = _add_characters([character], map.id, true)
|
||||
:ok = _track_characters([character], map_id, true)
|
||||
:ok = _add_characters([character], map_id, true)
|
||||
|
||||
socket
|
||||
|
||||
@@ -1440,16 +1422,16 @@ defmodule WandererAppWeb.MapLive do
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = _untrack_characters([character], map.id)
|
||||
:ok = _remove_characters([character], map.id)
|
||||
:ok = _untrack_characters([character], map_id)
|
||||
:ok = _remove_characters([character], map_id)
|
||||
|
||||
if map.only_tracked_characters do
|
||||
if only_tracked_characters do
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for all characters that have access to this map first!"
|
||||
)
|
||||
|> push_navigate(to: ~p"/tracking/#{map.slug}")
|
||||
|> push_navigate(to: ~p"/tracking/#{map_slug}")
|
||||
else
|
||||
socket
|
||||
end
|
||||
@@ -1461,8 +1443,8 @@ defmodule WandererAppWeb.MapLive do
|
||||
|
||||
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
|
||||
|
||||
:ok = _track_characters([character], map.id, true)
|
||||
:ok = _add_characters([character], map.id, true)
|
||||
:ok = _track_characters([character], map_id, true)
|
||||
:ok = _add_characters([character], map_id, true)
|
||||
|
||||
socket
|
||||
end
|
||||
@@ -1470,12 +1452,12 @@ defmodule WandererAppWeb.MapLive do
|
||||
|
||||
%{result: characters} = socket.assigns.characters
|
||||
|
||||
{:ok, map_characters} = _get_tracked_map_characters(map.id, socket.assigns.current_user)
|
||||
{:ok, map_characters} = _get_tracked_map_characters(map_id, current_user)
|
||||
|
||||
user_character_eve_ids = map_characters |> Enum.map(& &1.eve_id)
|
||||
|
||||
{:ok, character_settings} =
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map.id}) do
|
||||
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
|
||||
{:ok, settings} -> {:ok, settings}
|
||||
_ -> {:ok, []}
|
||||
end
|
||||
@@ -1524,13 +1506,29 @@ defmodule WandererAppWeb.MapLive do
|
||||
)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event(
|
||||
"get_user_settings",
|
||||
_,
|
||||
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
|
||||
) do
|
||||
{:ok, user_settings} =
|
||||
WandererApp.MapUserSettingsRepo.get!(map_id, current_user.id)
|
||||
|> WandererApp.MapUserSettingsRepo.to_form_data()
|
||||
|
||||
{:reply, %{user_settings: user_settings}, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event(
|
||||
"update_user_settings",
|
||||
user_settings_form,
|
||||
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
|
||||
) do
|
||||
settings = user_settings_form |> Map.take(["select_on_spash"]) |> Jason.encode!()
|
||||
settings =
|
||||
user_settings_form
|
||||
|> Map.take(["select_on_spash", "link_signature_on_splash"])
|
||||
|> Jason.encode!()
|
||||
|
||||
{:ok, user_settings} =
|
||||
WandererApp.MapUserSettingsRepo.create_or_update(map_id, current_user.id, settings)
|
||||
@@ -1540,7 +1538,57 @@ defmodule WandererAppWeb.MapLive do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("noop", _, socket), do: {:noreply, socket}
|
||||
def handle_event(
|
||||
"link_signature_to_system",
|
||||
%{
|
||||
"signature_eve_id" => signature_eve_id,
|
||||
"solar_system_source" => solar_system_source,
|
||||
"solar_system_target" => solar_system_target
|
||||
},
|
||||
socket
|
||||
) do
|
||||
socket
|
||||
|> _check_user_permissions(:update_system)
|
||||
|> case do
|
||||
true ->
|
||||
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
|
||||
map_id: socket.assigns.map_id,
|
||||
solar_system_id: solar_system_source
|
||||
}) do
|
||||
{:ok, system} ->
|
||||
first_character_eve_id =
|
||||
Map.get(socket.assigns, :user_characters, []) |> List.first()
|
||||
|
||||
case not is_nil(first_character_eve_id) do
|
||||
true ->
|
||||
WandererApp.Api.MapSystemSignature.by_system_id!(system.id)
|
||||
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|
||||
|> Enum.each(fn s ->
|
||||
s
|
||||
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
|
||||
linked_system_id: solar_system_target
|
||||
})
|
||||
end)
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
_ ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"You should enable tracking for at least one character to work with signatures."
|
||||
)}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("show_activity", _, socket) do
|
||||
@@ -1585,16 +1633,110 @@ defmodule WandererAppWeb.MapLive do
|
||||
})}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("noop", _, socket), do: {:noreply, socket}
|
||||
|
||||
@impl true
|
||||
def handle_event(event, body, socket) do
|
||||
Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp apply_action(socket, :index, _params) do
|
||||
socket
|
||||
|> assign(:active_page, :map)
|
||||
end
|
||||
|
||||
defp apply_action(socket, :add_system, _params) do
|
||||
socket
|
||||
|> assign(:active_page, :map)
|
||||
|> assign(:page_title, "Add System")
|
||||
|> assign(:add_system_form, to_form(%{"system_id" => nil}))
|
||||
end
|
||||
|
||||
defp maybe_start_map(map_id) do
|
||||
{:ok, map_started} = WandererApp.Cache.lookup("map_#{map_id}:started", false)
|
||||
|
||||
if map_started do
|
||||
Process.send_after(self(), %{event: :map_started}, 10)
|
||||
else
|
||||
WandererApp.Map.Manager.start_map(map_id)
|
||||
end
|
||||
end
|
||||
|
||||
defp map_start(
|
||||
socket,
|
||||
%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
} = _started_data
|
||||
) do
|
||||
socket =
|
||||
events
|
||||
|> Enum.reduce(socket, fn event, socket ->
|
||||
case event do
|
||||
{:track_characters, map_characters, track_character} ->
|
||||
:ok = _track_characters(map_characters, map_id, track_character)
|
||||
:ok = _add_characters(map_characters, map_id, track_character)
|
||||
socket
|
||||
|
||||
:invalid_token_message ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"One of your characters has expired token. Please refresh it on characters page."
|
||||
)
|
||||
|
||||
:empty_tracked_characters ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:info,
|
||||
"You should enable tracking for at least one character to work with map."
|
||||
)
|
||||
|
||||
:map_character_limit ->
|
||||
socket
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Map reached its character limit, your characters won't be tracked. Please contact administrator."
|
||||
)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
end)
|
||||
|
||||
map_characters = map_id |> WandererApp.Map.list_characters()
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
map_loaded?: true,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
|
||||
)
|
||||
|> push_map_event(
|
||||
"init",
|
||||
initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1))
|
||||
)
|
||||
|> push_event("js-exec", %{
|
||||
to: "#map-loader",
|
||||
attr: "data-loaded"
|
||||
})
|
||||
end
|
||||
|
||||
defp on_map_started(
|
||||
map_id,
|
||||
current_user,
|
||||
%{view_system: true, track_character: track_character} = user_permissions
|
||||
%{
|
||||
assigns: %{
|
||||
current_user: current_user,
|
||||
map_id: map_id,
|
||||
user_permissions:
|
||||
%{view_system: true, track_character: track_character} = user_permissions
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
with {:ok, _} <- current_user |> WandererApp.Api.User.update_last_map(%{last_map_id: map_id}),
|
||||
{:ok, map_user_settings} <- WandererApp.MapUserSettingsRepo.get(map_id, current_user.id),
|
||||
@@ -1673,27 +1815,27 @@ defmodule WandererAppWeb.MapLive do
|
||||
)
|
||||
|> Map.put(:reset, true)
|
||||
|
||||
Process.send_after(
|
||||
self(),
|
||||
{:map_start,
|
||||
%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
}},
|
||||
10
|
||||
)
|
||||
socket
|
||||
|> map_start(%{
|
||||
map_id: map_id,
|
||||
map_user_settings: map_user_settings,
|
||||
user_characters: user_character_eve_ids,
|
||||
initial_data: initial_data,
|
||||
events: events
|
||||
})
|
||||
else
|
||||
error ->
|
||||
Logger.error(fn -> "map_start_error: #{error}" end)
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp on_map_started(_map_id, _current_user, _user_permissions),
|
||||
do: Process.send_after(self(), :no_access, 10)
|
||||
defp on_map_started(socket) do
|
||||
Process.send_after(self(), :no_access, 10)
|
||||
socket
|
||||
end
|
||||
|
||||
defp _set_autopilot_waypoint(
|
||||
current_user,
|
||||
@@ -1718,13 +1860,6 @@ defmodule WandererAppWeb.MapLive do
|
||||
end
|
||||
end
|
||||
|
||||
defp _load_user_permissions({:ok, map}, current_user) do
|
||||
map
|
||||
|> Ash.load([:acls, :user_permissions], actor: current_user)
|
||||
end
|
||||
|
||||
defp _load_user_permissions(error, _current_user), do: error
|
||||
|
||||
defp _get_map_data(map_id, include_static_data? \\ true) do
|
||||
{:ok, hubs} = map_id |> WandererApp.Map.list_hubs()
|
||||
{:ok, connections} = map_id |> WandererApp.Map.list_connections()
|
||||
@@ -1816,11 +1951,11 @@ defmodule WandererAppWeb.MapLive do
|
||||
end
|
||||
end
|
||||
|
||||
defp _get_system_signatures(system_id),
|
||||
defp get_system_signatures(system_id),
|
||||
do:
|
||||
system_id
|
||||
|> WandererApp.Api.MapSystemSignature.by_system_id!()
|
||||
|> Enum.map(fn %{updated_at: updated_at} = s ->
|
||||
|> Enum.map(fn %{updated_at: updated_at, linked_system_id: linked_system_id} = s ->
|
||||
s
|
||||
|> Map.take([
|
||||
:system_id,
|
||||
@@ -1832,6 +1967,7 @@ defmodule WandererAppWeb.MapLive do
|
||||
:group,
|
||||
:updated_at
|
||||
])
|
||||
|> Map.put(:linked_system, get_system_static_info(linked_system_id))
|
||||
|> Map.put(:updated_at, updated_at |> Calendar.strftime("%Y/%m/%d %H:%M:%S"))
|
||||
end)
|
||||
|
||||
@@ -1897,14 +2033,7 @@ defmodule WandererAppWeb.MapLive do
|
||||
} = _system,
|
||||
_include_static_data? \\ true
|
||||
) do
|
||||
system_static_info =
|
||||
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
|
||||
{:ok, system_static_info} ->
|
||||
map_ui_system_static_info(system_static_info)
|
||||
|
||||
_ ->
|
||||
%{}
|
||||
end
|
||||
system_static_info = get_system_static_info(solar_system_id)
|
||||
|
||||
%{
|
||||
id: "#{solar_system_id}",
|
||||
@@ -1920,6 +2049,18 @@ defmodule WandererAppWeb.MapLive do
|
||||
}
|
||||
end
|
||||
|
||||
defp get_system_static_info(nil), do: nil
|
||||
|
||||
defp get_system_static_info(solar_system_id) do
|
||||
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
|
||||
{:ok, system_static_info} ->
|
||||
map_ui_system_static_info(system_static_info)
|
||||
|
||||
_ ->
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
defp map_ui_system_static_info(nil), do: %{}
|
||||
|
||||
defp map_ui_system_static_info(system_static_info),
|
||||
|
||||
@@ -164,5 +164,10 @@
|
||||
phx-change="update_user_settings"
|
||||
>
|
||||
<.input type="checkbox" field={f[:select_on_spash]} label="Auto select splashed systems" />
|
||||
<.input
|
||||
type="checkbox"
|
||||
field={f[:link_signature_on_splash]}
|
||||
label="Link splashed systems to signatures"
|
||||
/>
|
||||
</.form>
|
||||
</.modal>
|
||||
|
||||
@@ -114,12 +114,7 @@ defmodule WandererAppWeb.MapsLive do
|
||||
"auto_renew?" => true
|
||||
}
|
||||
|
||||
options_form =
|
||||
map.options
|
||||
|> case do
|
||||
nil -> %{"layout" => "left_to_right"}
|
||||
options -> Jason.decode!(options)
|
||||
end
|
||||
{:ok, options_form_data} = WandererApp.MapRepo.options_to_form_data(map)
|
||||
|
||||
{:ok, estimated_price, discount} =
|
||||
WandererApp.Map.SubscriptionManager.estimate_price(subscription_form, false)
|
||||
@@ -139,7 +134,7 @@ defmodule WandererAppWeb.MapsLive do
|
||||
active_settings_tab: "general",
|
||||
is_adding_subscription?: false,
|
||||
selected_subscription: nil,
|
||||
options_form: options_form |> to_form(),
|
||||
options_form: options_form_data |> to_form(),
|
||||
map_subscriptions: map_subscriptions,
|
||||
subscription_form: subscription_form |> to_form(),
|
||||
estimated_price: estimated_price,
|
||||
@@ -661,16 +656,14 @@ defmodule WandererAppWeb.MapsLive do
|
||||
|
||||
def handle_event(
|
||||
"update_options",
|
||||
%{
|
||||
"layout" => layout
|
||||
} = options_form,
|
||||
options_form,
|
||||
%{assigns: %{map_id: map_id, map: map}} = socket
|
||||
) do
|
||||
options = %{layout: layout}
|
||||
options =
|
||||
options_form
|
||||
|> Map.take(["layout", "store_custom_labels"])
|
||||
|
||||
updated_map =
|
||||
map
|
||||
|> WandererApp.Api.Map.update_options!(%{options: Jason.encode!(options)})
|
||||
{:ok, updated_map} = WandererApp.MapRepo.update_options(map, options)
|
||||
|
||||
@pubsub_client.broadcast(
|
||||
WandererApp.PubSub,
|
||||
|
||||
@@ -243,16 +243,23 @@
|
||||
for={@options_form}
|
||||
phx-change="update_options"
|
||||
>
|
||||
<div class="stat-title">Map systems layout</div>
|
||||
<div class="stat-value text-white">
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:layout]}
|
||||
class="p-dropdown p-component p-inputwrapper"
|
||||
placeholder="Map default layout"
|
||||
options={@layout_options}
|
||||
/>
|
||||
<div>
|
||||
<div class="stat-title">Map systems layout</div>
|
||||
<div class="stat-value text-white">
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:layout]}
|
||||
class="p-dropdown p-component p-inputwrapper"
|
||||
placeholder="Map default layout"
|
||||
options={@layout_options}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
type="checkbox"
|
||||
field={f[:store_custom_labels]}
|
||||
label="Store system custom labels"
|
||||
/>
|
||||
</.form>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
2
mix.exs
2
mix.exs
@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
@version "1.5.0"
|
||||
@version "1.12.0"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
||||
@@ -100,9 +100,9 @@
|
||||
"dest": "c5",
|
||||
"src": ["c6"],
|
||||
"static": true,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": [],
|
||||
"typeID": 30711,
|
||||
"name": "V911"
|
||||
@@ -124,9 +124,9 @@
|
||||
"dest": "c6",
|
||||
"src": ["c6"],
|
||||
"static": true,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": [],
|
||||
"typeID": 30712,
|
||||
"name": "W237"
|
||||
@@ -172,9 +172,9 @@
|
||||
"dest": "c6",
|
||||
"src": ["c5"],
|
||||
"static": true,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": [],
|
||||
"typeID": 30703,
|
||||
"name": "V753"
|
||||
@@ -208,9 +208,9 @@
|
||||
"dest": "c6",
|
||||
"src": ["ls", "ns"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "48",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30646,
|
||||
"name": "U319"
|
||||
@@ -424,9 +424,9 @@
|
||||
"dest": "ns",
|
||||
"src": ["c5", "c6"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "16",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30706,
|
||||
"name": "Z142"
|
||||
@@ -532,9 +532,9 @@
|
||||
"dest": "ls",
|
||||
"src": ["c4"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30696,
|
||||
"name": "N290"
|
||||
@@ -616,9 +616,9 @@
|
||||
"dest": "c5",
|
||||
"src": ["c5"],
|
||||
"static": true,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": [],
|
||||
"typeID": 30702,
|
||||
"name": "H296"
|
||||
@@ -772,7 +772,7 @@
|
||||
"dest": "c5",
|
||||
"src": ["c2"],
|
||||
"static": true,
|
||||
"max_mass_per_jump": 300000000,
|
||||
"max_mass_per_jump": 375000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"sibling_groups": [["E545"]],
|
||||
@@ -796,9 +796,9 @@
|
||||
"dest": "ns",
|
||||
"src": ["ls", "ns"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "16",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30649,
|
||||
"name": "S199"
|
||||
@@ -844,9 +844,9 @@
|
||||
"dest": "ls",
|
||||
"src": ["ls", "ns"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30648,
|
||||
"name": "N944"
|
||||
@@ -1024,9 +1024,9 @@
|
||||
"dest": "c5",
|
||||
"src": ["ls", "ns"],
|
||||
"static": false,
|
||||
"max_mass_per_jump": 1350000000,
|
||||
"max_mass_per_jump": 2000000000,
|
||||
"lifetime": "24",
|
||||
"total_mass": 3000000000,
|
||||
"total_mass": 3300000000,
|
||||
"sibling_groups": null,
|
||||
"typeID": 30643,
|
||||
"name": "N432"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
defmodule WandererApp.Repo.Migrations.AddSignatureLinkedSystem do
|
||||
@moduledoc """
|
||||
Updates resources based on their most recent snapshots.
|
||||
|
||||
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||
"""
|
||||
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
alter table(:map_system_signatures_v1) do
|
||||
add :linked_system_id, :bigint
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
alter table(:map_system_signatures_v1) do
|
||||
remove :linked_system_id
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "fragment(\"gen_random_uuid()\")",
|
||||
"generated?": false,
|
||||
"primary_key?": true,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "id",
|
||||
"type": "uuid"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "eve_id",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "character_eve_id",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "name",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "description",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "linked_system_id",
|
||||
"type": "bigint"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "kind",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "group",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "inserted_at",
|
||||
"type": "utc_datetime_usec"
|
||||
},
|
||||
{
|
||||
"allow_nil?": false,
|
||||
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": null,
|
||||
"size": null,
|
||||
"source": "updated_at",
|
||||
"type": "utc_datetime_usec"
|
||||
},
|
||||
{
|
||||
"allow_nil?": true,
|
||||
"default": "nil",
|
||||
"generated?": false,
|
||||
"primary_key?": false,
|
||||
"references": {
|
||||
"deferrable": false,
|
||||
"destination_attribute": "id",
|
||||
"destination_attribute_default": null,
|
||||
"destination_attribute_generated": null,
|
||||
"index?": false,
|
||||
"match_type": null,
|
||||
"match_with": null,
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"name": "map_system_signatures_v1_system_id_fkey",
|
||||
"on_delete": null,
|
||||
"on_update": null,
|
||||
"primary_key?": true,
|
||||
"schema": "public",
|
||||
"table": "map_system_v1"
|
||||
},
|
||||
"size": null,
|
||||
"source": "system_id",
|
||||
"type": "uuid"
|
||||
}
|
||||
],
|
||||
"base_filter": null,
|
||||
"check_constraints": [],
|
||||
"custom_indexes": [],
|
||||
"custom_statements": [],
|
||||
"has_create_action": true,
|
||||
"hash": "B437BC9E9F4607EBD235CBB39B814710E223D532CE09B952C9371257159008F4",
|
||||
"identities": [
|
||||
{
|
||||
"all_tenants?": false,
|
||||
"base_filter": null,
|
||||
"index_name": "map_system_signatures_v1_uniq_system_eve_id_index",
|
||||
"keys": [
|
||||
{
|
||||
"type": "atom",
|
||||
"value": "system_id"
|
||||
},
|
||||
{
|
||||
"type": "atom",
|
||||
"value": "eve_id"
|
||||
}
|
||||
],
|
||||
"name": "uniq_system_eve_id",
|
||||
"nils_distinct?": true,
|
||||
"where": null
|
||||
}
|
||||
],
|
||||
"multitenancy": {
|
||||
"attribute": null,
|
||||
"global": null,
|
||||
"strategy": null
|
||||
},
|
||||
"repo": "Elixir.WandererApp.Repo",
|
||||
"schema": null,
|
||||
"table": "map_system_signatures_v1"
|
||||
}
|
||||
Reference in New Issue
Block a user