mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-11-14 21:26:10 +00:00
Compare commits
323 Commits
v1.75.20
...
refactor-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c18d241c77 | ||
|
|
8b42908a5c | ||
|
|
6d32505a59 | ||
|
|
fe8a34c77d | ||
|
|
d12cafcca8 | ||
|
|
38a9c76ff0 | ||
|
|
d6c30b4a53 | ||
|
|
53a81daaf5 | ||
|
|
92081c99e3 | ||
|
|
d78020d2f5 | ||
|
|
fb1a9b440d | ||
|
|
0141ac46e3 | ||
|
|
d2bf6a8f86 | ||
|
|
1844e4c757 | ||
|
|
d407efe805 | ||
|
|
021e04d87a | ||
|
|
7844c9db34 | ||
|
|
355beb8394 | ||
|
|
d82eeba792 | ||
|
|
0396b05e58 | ||
|
|
9494a9eb37 | ||
|
|
8238f84ac7 | ||
|
|
1cf19b2a50 | ||
|
|
e8543fd2f8 | ||
|
|
c7f360e1fa | ||
|
|
a2b83f7f0c | ||
|
|
ae5689a403 | ||
|
|
c46af1d286 | ||
|
|
d17ba2168c | ||
|
|
80c14716eb | ||
|
|
8541fcd29b | ||
|
|
65d6acd7fb | ||
|
|
8b5f83d6b2 | ||
|
|
5e18891f4b | ||
|
|
74e0b85748 | ||
|
|
81d3495b65 | ||
|
|
d1959ca09f | ||
|
|
ec7a5ecf10 | ||
|
|
70b9ec99ba | ||
|
|
7147d79166 | ||
|
|
1dad9316bd | ||
|
|
872f7dcf48 | ||
|
|
02b450325e | ||
|
|
136bc4cbb9 | ||
|
|
dab49df9aa | ||
|
|
6286087f3e | ||
|
|
4ce7160f79 | ||
|
|
2913bf19b0 | ||
|
|
7bd6be6fd0 | ||
|
|
705daa286b | ||
|
|
614d06be66 | ||
|
|
dec3e9a7ce | ||
|
|
0017ac3373 | ||
|
|
ae34744578 | ||
|
|
76885058ef | ||
|
|
fccb007036 | ||
|
|
a9f8901bd5 | ||
|
|
8ae968b5be | ||
|
|
beffd45e4f | ||
|
|
4488d81e8d | ||
|
|
618cc8c5f1 | ||
|
|
3fb22a877e | ||
|
|
8759409b82 | ||
|
|
245647ae6a | ||
|
|
eb7d33ea07 | ||
|
|
3575b16def | ||
|
|
a6fb680be8 | ||
|
|
9e17df5544 | ||
|
|
683fde7be4 | ||
|
|
ee68ce92a2 | ||
|
|
8b4e38d795 | ||
|
|
4995202627 | ||
|
|
986b997a6a | ||
|
|
9a957af759 | ||
|
|
c5a0a96016 | ||
|
|
8715a6c0ac | ||
|
|
c9810095aa | ||
|
|
69eb888469 | ||
|
|
748347df9a | ||
|
|
aa4d49027c | ||
|
|
a9d7387e40 | ||
|
|
dc4d260c9b | ||
|
|
dc430491bf | ||
|
|
42cd261ea7 | ||
|
|
35af4fdc09 | ||
|
|
8bb4998e59 | ||
|
|
c825a3f4c4 | ||
|
|
5343c34488 | ||
|
|
4878be1a53 | ||
|
|
1ff689c26c | ||
|
|
79b660e899 | ||
|
|
665a679bd5 | ||
|
|
7bd634eb95 | ||
|
|
c3b5a77a86 | ||
|
|
8498846d9c | ||
|
|
12f39a0133 | ||
|
|
ffc2a86e95 | ||
|
|
82babf41a2 | ||
|
|
81055b4fbd | ||
|
|
5070a59f88 | ||
|
|
65d5bf960d | ||
|
|
8fc4cb190e | ||
|
|
c6c065dbb9 | ||
|
|
8ba34533d7 | ||
|
|
095a4b2362 | ||
|
|
fafc631e49 | ||
|
|
e56383c8b1 | ||
|
|
b9c26bdb04 | ||
|
|
8aeaa81752 | ||
|
|
b16ec0490f | ||
|
|
eceaf1d73b | ||
|
|
34cf668a33 | ||
|
|
c22d410c9f | ||
|
|
fc6af867f2 | ||
|
|
2d96114984 | ||
|
|
fd7e19e490 | ||
|
|
f7d996f5b2 | ||
|
|
f8ab1383ab | ||
|
|
e1559aac94 | ||
|
|
2e17cce5cd | ||
|
|
8fb831f171 | ||
|
|
cb84f34515 | ||
|
|
272cce1a77 | ||
|
|
e0e3ed1580 | ||
|
|
c4c848cf37 | ||
|
|
d33a2e3a5b | ||
|
|
5c8753fb96 | ||
|
|
32d25d86eb | ||
|
|
863adccac1 | ||
|
|
2d527e1d16 | ||
|
|
9a64ad6fa7 | ||
|
|
5ce472ebff | ||
|
|
76588af12f | ||
|
|
134f169eb9 | ||
|
|
7c2d731c4c | ||
|
|
c7e2a290cf | ||
|
|
5ea966892a | ||
|
|
b879db76b7 | ||
|
|
d13a628029 | ||
|
|
7c1e2595e3 | ||
|
|
a99e8a915e | ||
|
|
36f424da0b | ||
|
|
c0a65d5a23 | ||
|
|
02e31333d2 | ||
|
|
d69616119d | ||
|
|
f89cd5f44f | ||
|
|
abe4951251 | ||
|
|
dbc770d40b | ||
|
|
e69a8fece5 | ||
|
|
cf20be8a77 | ||
|
|
450bcb649c | ||
|
|
a00395351e | ||
|
|
3b24c760ff | ||
|
|
3801f0be18 | ||
|
|
5508fbee2f | ||
|
|
51ff4e7f36 | ||
|
|
f3104db2e4 | ||
|
|
602b1028c3 | ||
|
|
4f98e979a2 | ||
|
|
e0f46c4af7 | ||
|
|
bc8a9a2b85 | ||
|
|
c2b03f925d | ||
|
|
efa2e52054 | ||
|
|
cedf5761f8 | ||
|
|
f601bb8751 | ||
|
|
c39d2a56d2 | ||
|
|
34d3d92afd | ||
|
|
805722bbe8 | ||
|
|
fe3e38343b | ||
|
|
616e82c497 | ||
|
|
ab7e47b91f | ||
|
|
cf1c103a46 | ||
|
|
71202a4a29 | ||
|
|
a7e0ceac4c | ||
|
|
6bce701aab | ||
|
|
f8b9e206a5 | ||
|
|
4c1ec2004b | ||
|
|
ebed74d239 | ||
|
|
c789b69b54 | ||
|
|
24c32511d8 | ||
|
|
302fb0642d | ||
|
|
06e7b6e3eb | ||
|
|
33acd55eaa | ||
|
|
dec82e89c2 | ||
|
|
f5ac5bc4ec | ||
|
|
b6c680e802 | ||
|
|
5fa57c13b4 | ||
|
|
acc81fda44 | ||
|
|
7ab5acf45f | ||
|
|
0d4ffbcc22 | ||
|
|
a9253ac2df | ||
|
|
d00b4843a7 | ||
|
|
6068de2c71 | ||
|
|
73da427c6b | ||
|
|
9b7ec0ddfe | ||
|
|
c2f5f14c44 | ||
|
|
0b7c3588d5 | ||
|
|
a51fac5736 | ||
|
|
726c3d0704 | ||
|
|
8dd564dbd0 | ||
|
|
e33c65cddc | ||
|
|
f2fbd2ead0 | ||
|
|
123a2e45eb | ||
|
|
f8d2d9c680 | ||
|
|
9dcbef9a79 | ||
|
|
0b14857a12 | ||
|
|
bd3d516f60 | ||
|
|
40d0bd8cea | ||
|
|
873946a1a6 | ||
|
|
968deeb254 | ||
|
|
959041be52 | ||
|
|
3319520179 | ||
|
|
580fcf3657 | ||
|
|
53dae7c520 | ||
|
|
6d59d709f1 | ||
|
|
4343e9070c | ||
|
|
b62373fb5f | ||
|
|
3da98f8e56 | ||
|
|
494d24952e | ||
|
|
8a6b17bd7b | ||
|
|
d2e859a74e | ||
|
|
4a78d55d22 | ||
|
|
dc252b8c4b | ||
|
|
c433205e89 | ||
|
|
d6bc5b57b1 | ||
|
|
280a286266 | ||
|
|
d5c18b5de3 | ||
|
|
7452e5d011 | ||
|
|
71674b0d52 | ||
|
|
5b4824bd5d | ||
|
|
deda16a7da | ||
|
|
0b7c067de7 | ||
|
|
0d0db8c129 | ||
|
|
9f1b7994a3 | ||
|
|
378df0ac70 | ||
|
|
0e4a132f69 | ||
|
|
631746375d | ||
|
|
7dc01dad54 | ||
|
|
8a9807d3e5 | ||
|
|
39df3c97ce | ||
|
|
46c1ccdfcc | ||
|
|
8817536038 | ||
|
|
c3bb23a6ee | ||
|
|
7e9c4c575e | ||
|
|
5a70eee91e | ||
|
|
228f6990a1 | ||
|
|
d80ed0e70e | ||
|
|
4576c75737 | ||
|
|
67764faaa7 | ||
|
|
91dd0b27ae | ||
|
|
99dcf49fbc | ||
|
|
6fb3edbfd6 | ||
|
|
26f13ce857 | ||
|
|
e9b475c0a8 | ||
|
|
7752010092 | ||
|
|
d3705b3ed7 | ||
|
|
1394e2897e | ||
|
|
5117a1c5af | ||
|
|
3c62403f33 | ||
|
|
a4760f5162 | ||
|
|
b071070431 | ||
|
|
3bcb9628e7 | ||
|
|
e62c4cf5bf | ||
|
|
af46962ce4 | ||
|
|
0b0967830b | ||
|
|
172251a208 | ||
|
|
8a6fb63d55 | ||
|
|
9652959e5e | ||
|
|
825ef46d41 | ||
|
|
ad9f7c6b95 | ||
|
|
b960b5c149 | ||
|
|
0f092d21f9 | ||
|
|
031576caa6 | ||
|
|
7a97a96c42 | ||
|
|
2efb2daba0 | ||
|
|
4374c39924 | ||
|
|
15711495c7 | ||
|
|
236f803427 | ||
|
|
6772130f2a | ||
|
|
ddd72f3fac | ||
|
|
6e262835ef | ||
|
|
2f3b8ddc5f | ||
|
|
cea3a74b34 | ||
|
|
867941a233 | ||
|
|
3ff388a16d | ||
|
|
f4248e9ab9 | ||
|
|
507b3289c7 | ||
|
|
9e1dfc48d5 | ||
|
|
518cbc7b5d | ||
|
|
ccc8db0620 | ||
|
|
7cfb663efd | ||
|
|
e5103cc925 | ||
|
|
26458f5a19 | ||
|
|
79d5ec6caf | ||
|
|
034d461ab6 | ||
|
|
2e9c1c170c | ||
|
|
24ad3b2c61 | ||
|
|
288f55dc2f | ||
|
|
78dbea6267 | ||
|
|
6a9e53141d | ||
|
|
05e6994520 | ||
|
|
1a4dc67eb9 | ||
|
|
31d87a116b | ||
|
|
c47796d590 | ||
|
|
c7138a41ee | ||
|
|
96f04c70a9 | ||
|
|
87a8bc09ab | ||
|
|
5f5661d559 | ||
|
|
35ca87790e | ||
|
|
ae43e4a57c | ||
|
|
b91712a01a | ||
|
|
b20007b341 | ||
|
|
6a24e1188b | ||
|
|
5894efc1aa | ||
|
|
a05612d243 | ||
|
|
48de874d6b | ||
|
|
91e6da316f | ||
|
|
fa60bd81a1 | ||
|
|
a08a69c5be | ||
|
|
74f7ad155d | ||
|
|
f58ebad0ec | ||
|
|
7ca4eb3b8f | ||
|
|
854524a03c |
@@ -13,4 +13,4 @@ export WANDERER_KILLS_BASE_URL="ws://host.docker.internal:4004"
|
|||||||
export WANDERER_SSE_ENABLED="true"
|
export WANDERER_SSE_ENABLED="true"
|
||||||
export WANDERER_WEBHOOKS_ENABLED="true"
|
export WANDERER_WEBHOOKS_ENABLED="true"
|
||||||
export WANDERER_SSE_MAX_CONNECTIONS="1000"
|
export WANDERER_SSE_MAX_CONNECTIONS="1000"
|
||||||
export WANDERER_WEBHOOK_TIMEOUT_MS="15000"
|
export WANDERER_WEBHOOK_TIMEOUT_MS="15000"
|
||||||
|
|||||||
6
.github/workflows/docker-arm.yml
vendored
6
.github/workflows/docker-arm.yml
vendored
@@ -123,11 +123,9 @@ jobs:
|
|||||||
id: get-content
|
id: get-content
|
||||||
with:
|
with:
|
||||||
stringToTruncate: |
|
stringToTruncate: |
|
||||||
📣 Wanderer **ARM** release available 🎉
|
📣 Wanderer **ARM** release available 🎉
|
||||||
|
|
||||||
[wandererltd/community-edition-arm:${{ steps.get-latest-tag.outputs.tag }}](https://hub.docker.com/r/wandererltd/community-edition-arm/tags)
|
**Version**: :${{ steps.get-latest-tag.outputs.tag }}
|
||||||
|
|
||||||
**Version**: ${{ steps.get-latest-tag.outputs.tag }}
|
|
||||||
|
|
||||||
${{ steps.extract-changelog.outputs.body }}
|
${{ steps.extract-changelog.outputs.body }}
|
||||||
maxLength: 500
|
maxLength: 500
|
||||||
|
|||||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -125,8 +125,6 @@ jobs:
|
|||||||
stringToTruncate: |
|
stringToTruncate: |
|
||||||
📣 Wanderer new release available 🎉
|
📣 Wanderer new release available 🎉
|
||||||
|
|
||||||
[wandererltd/community-edition:${{ steps.get-latest-tag.outputs.tag }}](https://hub.docker.com/r/wandererltd/community-edition/tags)
|
|
||||||
|
|
||||||
**Version**: ${{ steps.get-latest-tag.outputs.tag }}
|
**Version**: ${{ steps.get-latest-tag.outputs.tag }}
|
||||||
|
|
||||||
${{ steps.extract-changelog.outputs.body }}
|
${{ steps.extract-changelog.outputs.body }}
|
||||||
|
|||||||
2419
CHANGELOG.md
2419
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -18,5 +18,28 @@ module.exports = {
|
|||||||
'react/react-in-jsx-scope': 'off',
|
'react/react-in-jsx-scope': 'off',
|
||||||
'@typescript-eslint/ban-ts-comment': 'off',
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
"linebreak-style": "off",
|
"linebreak-style": "off",
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"name": "primereact/button",
|
||||||
|
"importNames": ["Button"],
|
||||||
|
"message": "Use WdButton instead Button"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"react/forbid-elements": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"forbid": [
|
||||||
|
{
|
||||||
|
"element": "Button",
|
||||||
|
"message": "Use WdButton instead Button"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useMapperHandlers } from './useMapperHandlers';
|
|||||||
import { MapRootContent } from '@/hooks/Mapper/components/mapRootContent/MapRootContent.tsx';
|
import { MapRootContent } from '@/hooks/Mapper/components/mapRootContent/MapRootContent.tsx';
|
||||||
import { MapRootProvider } from '@/hooks/Mapper/mapRootProvider';
|
import { MapRootProvider } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import './common-styles/main.scss';
|
import './common-styles/main.scss';
|
||||||
|
import { ToastProvider } from '@/hooks/Mapper/ToastProvider.tsx';
|
||||||
|
|
||||||
const ErrorFallback = () => {
|
const ErrorFallback = () => {
|
||||||
return <div className="!z-100 absolute w-screen h-screen bg-transparent"></div>;
|
return <div className="!z-100 absolute w-screen h-screen bg-transparent"></div>;
|
||||||
@@ -39,13 +40,15 @@ export default function MapRoot({ hooks }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimeReactProvider>
|
<PrimeReactProvider>
|
||||||
<MapRootProvider fwdRef={providerRef} outCommand={handleCommand}>
|
<ToastProvider>
|
||||||
<ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}>
|
<MapRootProvider fwdRef={providerRef} outCommand={handleCommand}>
|
||||||
<ReactFlowProvider>
|
<ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}>
|
||||||
<MapRootContent />
|
<ReactFlowProvider>
|
||||||
</ReactFlowProvider>
|
<MapRootContent />
|
||||||
</ErrorBoundary>
|
</ReactFlowProvider>
|
||||||
</MapRootProvider>
|
</ErrorBoundary>
|
||||||
|
</MapRootProvider>
|
||||||
|
</ToastProvider>
|
||||||
</PrimeReactProvider>
|
</PrimeReactProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
31
assets/js/hooks/Mapper/ToastProvider.tsx
Normal file
31
assets/js/hooks/Mapper/ToastProvider.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { createContext, useContext, useRef } from 'react';
|
||||||
|
import { Toast } from 'primereact/toast';
|
||||||
|
import type { ToastMessage } from 'primereact/toast';
|
||||||
|
|
||||||
|
interface ToastContextValue {
|
||||||
|
toastRef: React.RefObject<Toast>;
|
||||||
|
show: (message: ToastMessage | ToastMessage[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ToastContext = createContext<ToastContextValue | null>(null);
|
||||||
|
|
||||||
|
export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
const toastRef = useRef<Toast>(null);
|
||||||
|
|
||||||
|
const show = (message: ToastMessage | ToastMessage[]) => {
|
||||||
|
toastRef.current?.show(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToastContext.Provider value={{ toastRef, show }}>
|
||||||
|
<Toast ref={toastRef} position="top-right" />
|
||||||
|
{children}
|
||||||
|
</ToastContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useToast = (): ToastContextValue => {
|
||||||
|
const context = useContext(ToastContext);
|
||||||
|
if (!context) throw new Error('useToast must be used within a ToastProvider');
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@@ -284,3 +284,7 @@
|
|||||||
border-left-color: #e67e22;
|
border-left-color: #e67e22;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-dialog-header-icon.p-dialog-header-close.p-link {
|
||||||
|
position: relative;
|
||||||
|
left: 6px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
// import './tailwind.css';
|
// import './tailwind.css';
|
||||||
//@import 'primereact/resources/themes/bootstrap4-dark-blue/theme.css';
|
@use 'primereact/resources/primereact.min.css';
|
||||||
//@import 'primereact/resources/themes/lara-dark-purple/theme.css';
|
@use 'primeicons/primeicons.css';
|
||||||
//@import "prime-fixes";
|
|
||||||
@import 'primereact/resources/primereact.min.css';
|
|
||||||
//@import 'primeflex/primeflex.css';
|
|
||||||
@import 'primeicons/primeicons.css';
|
|
||||||
//@import 'primereact/resources/primereact.css';
|
|
||||||
|
|
||||||
|
|
||||||
@import "fixes";
|
@use "fixes";
|
||||||
@import "prime-fixes";
|
@use "prime-fixes";
|
||||||
@import "custom-scrollbar";
|
@use "custom-scrollbar";
|
||||||
@import "tooltip";
|
@use "tooltip";
|
||||||
@import "context-menu";
|
@use "context-menu";
|
||||||
|
|
||||||
|
|
||||||
.fixedImportant {
|
.fixedImportant {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.vertical-tabs-container {
|
.vertical-tabs-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 400px;
|
min-height: 200px;
|
||||||
|
|
||||||
.p-tabview {
|
.p-tabview {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
@import "fix-dialog";
|
@use "fix-dialog";
|
||||||
@import "fix-popup";
|
@use "fix-popup";
|
||||||
@import "fix-tabs";
|
@use "fix-tabs";
|
||||||
//@import "fix-input";
|
|
||||||
|
|
||||||
//@import "theme";
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import { SolarSystemRawType } from '@/hooks/Mapper/types';
|
|||||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { GRADIENT_MENU_ACTIVE_CLASSES } from '@/hooks/Mapper/constants.ts';
|
import { GRADIENT_MENU_ACTIVE_CLASSES } from '@/hooks/Mapper/constants.ts';
|
||||||
import { LayoutEventBlocker } from '@/hooks/Mapper/components/ui-kit';
|
import { LayoutEventBlocker, WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
|
|
||||||
const AVAILABLE_TAGS = [
|
const AVAILABLE_TAGS = [
|
||||||
'A',
|
'A',
|
||||||
@@ -61,7 +60,7 @@ export const useTagMenu = (
|
|||||||
<LayoutEventBlocker className="flex flex-col gap-1 w-[200px] h-full px-2">
|
<LayoutEventBlocker className="flex flex-col gap-1 w-[200px] h-full px-2">
|
||||||
<div className="grid grid-cols-[auto_auto_auto_auto_auto_auto] gap-1">
|
<div className="grid grid-cols-[auto_auto_auto_auto_auto_auto] gap-1">
|
||||||
{AVAILABLE_TAGS.map(x => (
|
{AVAILABLE_TAGS.map(x => (
|
||||||
<Button
|
<WdButton
|
||||||
outlined={system?.tag !== x}
|
outlined={system?.tag !== x}
|
||||||
severity="warning"
|
severity="warning"
|
||||||
key={x}
|
key={x}
|
||||||
@@ -71,9 +70,9 @@ export const useTagMenu = (
|
|||||||
onClick={() => system?.tag !== x && onSystemTag(x)}
|
onClick={() => system?.tag !== x && onSystemTag(x)}
|
||||||
>
|
>
|
||||||
{x}
|
{x}
|
||||||
</Button>
|
</WdButton>
|
||||||
))}
|
))}
|
||||||
<Button
|
<WdButton
|
||||||
disabled={!isSelectedTag}
|
disabled={!isSelectedTag}
|
||||||
icon="pi pi-ban"
|
icon="pi pi-ban"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -81,7 +80,7 @@ export const useTagMenu = (
|
|||||||
outlined
|
outlined
|
||||||
severity="help"
|
severity="help"
|
||||||
onClick={() => onSystemTag()}
|
onClick={() => onSystemTag()}
|
||||||
></Button>
|
></WdButton>
|
||||||
</div>
|
</div>
|
||||||
</LayoutEventBlocker>
|
</LayoutEventBlocker>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -118,7 +118,11 @@ export const useContextMenuSystemItems = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isShowPingBtn) {
|
if (isShowPingBtn) {
|
||||||
return <WdMenuItem icon={iconClasses}>{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}</WdMenuItem>;
|
return (
|
||||||
|
<WdMenuItem icon={iconClasses} className="!ml-[-2px]">
|
||||||
|
{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}
|
||||||
|
</WdMenuItem>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -126,7 +130,7 @@ export const useContextMenuSystemItems = ({
|
|||||||
infoTitle="Locked. Ping can be set only for one system."
|
infoTitle="Locked. Ping can be set only for one system."
|
||||||
infoClass="pi-lock text-stone-500 mr-[12px]"
|
infoClass="pi-lock text-stone-500 mr-[12px]"
|
||||||
>
|
>
|
||||||
<WdMenuItem disabled icon={iconClasses}>
|
<WdMenuItem disabled icon={iconClasses} className="!ml-[-2px]">
|
||||||
{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}
|
{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}
|
||||||
</WdMenuItem>
|
</WdMenuItem>
|
||||||
</MenuItemWithInfo>
|
</MenuItemWithInfo>
|
||||||
|
|||||||
@@ -2,25 +2,60 @@ import React, { RefObject, useMemo } from 'react';
|
|||||||
import { ContextMenu } from 'primereact/contextmenu';
|
import { ContextMenu } from 'primereact/contextmenu';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { MenuItem } from 'primereact/menuitem';
|
import { MenuItem } from 'primereact/menuitem';
|
||||||
|
import { checkPermissions } from '@/hooks/Mapper/components/map/helpers';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { MenuItemWithInfo, WdMenuItem } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
export interface ContextMenuSystemMultipleProps {
|
export interface ContextMenuSystemMultipleProps {
|
||||||
contextMenuRef: RefObject<ContextMenu>;
|
contextMenuRef: RefObject<ContextMenu>;
|
||||||
onDeleteSystems(): void;
|
onDeleteSystems(): void;
|
||||||
|
onCopySystems(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContextMenuSystemMultiple: React.FC<ContextMenuSystemMultipleProps> = ({
|
export const ContextMenuSystemMultiple: React.FC<ContextMenuSystemMultipleProps> = ({
|
||||||
contextMenuRef,
|
contextMenuRef,
|
||||||
onDeleteSystems,
|
onDeleteSystems,
|
||||||
|
onCopySystems,
|
||||||
}) => {
|
}) => {
|
||||||
|
const {
|
||||||
|
data: { options, userPermissions },
|
||||||
|
} = useMapRootState();
|
||||||
|
|
||||||
const items: MenuItem[] = useMemo(() => {
|
const items: MenuItem[] = useMemo(() => {
|
||||||
|
const allowCopy = checkPermissions(userPermissions, options.allowed_copy_for);
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
icon: PrimeIcons.TRASH,
|
icon: clsx(PrimeIcons.TRASH, 'text-red-400'),
|
||||||
command: onDeleteSystems,
|
command: onDeleteSystems,
|
||||||
},
|
},
|
||||||
|
{ separator: true },
|
||||||
|
{
|
||||||
|
label: 'Copy',
|
||||||
|
icon: PrimeIcons.COPY,
|
||||||
|
command: onCopySystems,
|
||||||
|
disabled: !allowCopy,
|
||||||
|
template: () => {
|
||||||
|
if (allowCopy) {
|
||||||
|
return <WdMenuItem icon="pi pi-copy">Copy</WdMenuItem>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItemWithInfo
|
||||||
|
infoTitle="Action is blocked because you don’t have permission to Copy."
|
||||||
|
infoClass={clsx(PrimeIcons.QUESTION_CIRCLE, 'text-stone-500 mr-[12px]')}
|
||||||
|
tooltipWrapperClassName="flex"
|
||||||
|
>
|
||||||
|
<WdMenuItem disabled icon="pi pi-copy">
|
||||||
|
Copy
|
||||||
|
</WdMenuItem>
|
||||||
|
</MenuItemWithInfo>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}, [onDeleteSystems]);
|
}, [onCopySystems, onDeleteSystems, options, userPermissions]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -6,27 +6,34 @@ import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
|
|||||||
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
|
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
|
||||||
import { useDeleteSystems } from '@/hooks/Mapper/components/contexts/hooks';
|
import { useDeleteSystems } from '@/hooks/Mapper/components/contexts/hooks';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { encodeJsonToUriBase64 } from '@/hooks/Mapper/utils';
|
||||||
|
import { useToast } from '@/hooks/Mapper/ToastProvider.tsx';
|
||||||
|
|
||||||
export const useContextMenuSystemMultipleHandlers = () => {
|
export const useContextMenuSystemMultipleHandlers = () => {
|
||||||
const {
|
const {
|
||||||
data: { pings },
|
data: { pings, connections },
|
||||||
} = useMapRootState();
|
} = useMapRootState();
|
||||||
|
|
||||||
|
const { show } = useToast();
|
||||||
|
|
||||||
const contextMenuRef = useRef<ContextMenu | null>(null);
|
const contextMenuRef = useRef<ContextMenu | null>(null);
|
||||||
const [systems, setSystems] = useState<Node<SolarSystemRawType>[]>();
|
const [systems, setSystems] = useState<Node<SolarSystemRawType>[]>();
|
||||||
|
|
||||||
const { deleteSystems } = useDeleteSystems();
|
const { deleteSystems } = useDeleteSystems();
|
||||||
|
|
||||||
const ping = useMemo(() => (pings.length === 1 ? pings[0] : undefined), [pings]);
|
const ping = useMemo(() => (pings.length === 1 ? pings[0] : undefined), [pings]);
|
||||||
|
const refVars = useRef({ systems, ping, connections, deleteSystems });
|
||||||
|
refVars.current = { systems, ping, connections, deleteSystems };
|
||||||
|
|
||||||
const handleSystemMultipleContext: NodeSelectionMouseHandler = (ev, systems_) => {
|
const handleSystemMultipleContext = useCallback<NodeSelectionMouseHandler>((ev, systems_) => {
|
||||||
setSystems(systems_);
|
setSystems(systems_);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ctxManager.next('ctxSysMult', contextMenuRef.current);
|
ctxManager.next('ctxSysMult', contextMenuRef.current);
|
||||||
contextMenuRef.current?.show(ev);
|
contextMenuRef.current?.show(ev);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const onDeleteSystems = useCallback(() => {
|
const onDeleteSystems = useCallback(() => {
|
||||||
|
const { systems, ping, deleteSystems } = refVars.current;
|
||||||
|
|
||||||
if (!systems) {
|
if (!systems) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -41,11 +48,34 @@ export const useContextMenuSystemMultipleHandlers = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteSystems(sysToDel);
|
deleteSystems(sysToDel);
|
||||||
}, [deleteSystems, systems, ping]);
|
}, []);
|
||||||
|
|
||||||
|
const onCopySystems = useCallback(async () => {
|
||||||
|
const { systems, connections } = refVars.current;
|
||||||
|
if (!systems) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectionToCopy = connections.filter(
|
||||||
|
c => systems.filter(s => [c.target, c.source].includes(s.id)).length == 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(
|
||||||
|
encodeJsonToUriBase64({ systems: systems.map(x => x.data), connections: connectionToCopy }),
|
||||||
|
);
|
||||||
|
|
||||||
|
show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Copied to clipboard',
|
||||||
|
detail: `Successfully copied to clipboard - [${systems.length}] systems and [${connectionToCopy.length}] connections`,
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleSystemMultipleContext,
|
handleSystemMultipleContext,
|
||||||
contextMenuRef,
|
contextMenuRef,
|
||||||
onDeleteSystems,
|
onDeleteSystems,
|
||||||
|
onCopySystems,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
|
||||||
import { LayoutEventBlocker, TooltipPosition, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
import { LayoutEventBlocker, TooltipPosition, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { ANOIK_ICON, DOTLAN_ICON, ZKB_ICON } from '@/hooks/Mapper/icons';
|
import { ANOIK_ICON, DOTLAN_ICON, ZKB_ICON } from '@/hooks/Mapper/icons';
|
||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
|
||||||
import classes from './FastSystemActions.module.scss';
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
|
import classes from './FastSystemActions.module.scss';
|
||||||
|
|
||||||
export interface FastSystemActionsProps {
|
export interface FastSystemActionsProps {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
@@ -27,7 +27,7 @@ export const FastSystemActions = ({
|
|||||||
ref.current = { systemId, systemName, regionName, isWH };
|
ref.current = { systemId, systemName, regionName, isWH };
|
||||||
|
|
||||||
const handleOpenZKB = useCallback(
|
const handleOpenZKB = useCallback(
|
||||||
() => window.open(`https://zkillboard.com/system/${ref.current.systemId}`, '_blank'),
|
() => window.open(`https://zkillboard.com/system/${ref.current.systemId}/`, '_blank'),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,4 @@ export type WaypointSetContextHandlerProps = {
|
|||||||
destination: string;
|
destination: string;
|
||||||
};
|
};
|
||||||
export type WaypointSetContextHandler = (props: WaypointSetContextHandlerProps) => void;
|
export type WaypointSetContextHandler = (props: WaypointSetContextHandlerProps) => void;
|
||||||
export type NodeSelectionMouseHandler =
|
export type NodeSelectionMouseHandler = (event: React.MouseEvent<Element, MouseEvent>, nodes: Node[]) => void;
|
||||||
| ((event: React.MouseEvent<Element, MouseEvent>, nodes: Node[]) => void)
|
|
||||||
| undefined;
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MapUserSettings, SettingsWithVersion } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
import { MapUserSettings, SettingsWrapper } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
|
|
||||||
export const REQUIRED_KEYS = [
|
export const REQUIRED_KEYS = [
|
||||||
'widgets',
|
'widgets',
|
||||||
@@ -19,11 +19,8 @@ export class MapUserSettingsParseError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNumber = (v: unknown): v is number => typeof v === 'number' && !Number.isNaN(v);
|
/** Minimal check that an object matches SettingsWrapper<*> */
|
||||||
|
const isSettings = (v: unknown): v is SettingsWrapper<unknown> => typeof v === 'object' && v !== null;
|
||||||
/** Minimal check that an object matches SettingsWithVersion<*> */
|
|
||||||
const isSettingsWithVersion = (v: unknown): v is SettingsWithVersion<unknown> =>
|
|
||||||
typeof v === 'object' && v !== null && isNumber((v as any).version) && 'settings' in (v as any);
|
|
||||||
|
|
||||||
/** Ensure every required key is present */
|
/** Ensure every required key is present */
|
||||||
const hasAllRequiredKeys = (v: unknown): v is Record<RequiredKeys, unknown> =>
|
const hasAllRequiredKeys = (v: unknown): v is Record<RequiredKeys, unknown> =>
|
||||||
@@ -52,8 +49,8 @@ export const parseMapUserSettings = (json: unknown): MapUserSettings => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const key of REQUIRED_KEYS) {
|
for (const key of REQUIRED_KEYS) {
|
||||||
if (!isSettingsWithVersion((data as any)[key])) {
|
if (!isSettings((data as any)[key])) {
|
||||||
throw new MapUserSettingsParseError(`"${key}" must match SettingsWithVersion<T>`);
|
throw new MapUserSettingsParseError(`"${key}" must match SettingsWrapper<T>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
assets/js/hooks/Mapper/components/hooks/useLocalCounter.ts
Normal file
26
assets/js/hooks/Mapper/components/hooks/useLocalCounter.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { CharacterTypeRaw } from '@/hooks/Mapper/types';
|
||||||
|
|
||||||
|
export type UseLocalCounterProps = {
|
||||||
|
charactersInSystem: Array<CharacterTypeRaw>;
|
||||||
|
userCharacters: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLocalCharacters = ({ charactersInSystem, userCharacters }: UseLocalCounterProps) => {
|
||||||
|
return charactersInSystem
|
||||||
|
.map(char => ({
|
||||||
|
...char,
|
||||||
|
compact: true,
|
||||||
|
isOwn: userCharacters.includes(char.eve_id),
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useLocalCounter = ({ charactersInSystem, userCharacters }: UseLocalCounterProps) => {
|
||||||
|
const localCounterCharacters = useMemo(
|
||||||
|
() => getLocalCharacters({ charactersInSystem, userCharacters }),
|
||||||
|
[charactersInSystem, userCharacters],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { localCounterCharacters };
|
||||||
|
};
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { ForwardedRef, forwardRef, MouseEvent, useCallback, useEffect, useMemo } from 'react';
|
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
|
||||||
|
import { PingData, SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
|
||||||
|
import { MapHandlers, OutCommand, OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||||
|
import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
|
||||||
|
import type { PanelPosition } from '@reactflow/core';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { ForwardedRef, forwardRef, MouseEvent, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -16,8 +22,6 @@ import ReactFlow, {
|
|||||||
import 'reactflow/dist/style.css';
|
import 'reactflow/dist/style.css';
|
||||||
import classes from './Map.module.scss';
|
import classes from './Map.module.scss';
|
||||||
import { MapProvider, useMapState } from './MapProvider';
|
import { MapProvider, useMapState } from './MapProvider';
|
||||||
import { useEdgesState, useMapHandlers, useNodesState, useUpdateNodes } from './hooks';
|
|
||||||
import { MapHandlers, OutCommand, OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers.ts';
|
|
||||||
import {
|
import {
|
||||||
ContextMenuConnection,
|
ContextMenuConnection,
|
||||||
ContextMenuRoot,
|
ContextMenuRoot,
|
||||||
@@ -26,26 +30,11 @@ import {
|
|||||||
useContextMenuRootHandlers,
|
useContextMenuRootHandlers,
|
||||||
} from './components';
|
} from './components';
|
||||||
import { getBehaviorForTheme } from './helpers/getThemeBehavior';
|
import { getBehaviorForTheme } from './helpers/getThemeBehavior';
|
||||||
import { OnMapAddSystemCallback, OnMapSelectionChange } from './map.types';
|
import { useEdgesState, useMapHandlers, useNodesState, useUpdateNodes } from './hooks';
|
||||||
import { SESSION_KEY } from '@/hooks/Mapper/constants.ts';
|
|
||||||
import { PingData, SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
|
|
||||||
import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
|
|
||||||
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { useBackgroundVars } from './hooks/useBackgroundVars';
|
import { useBackgroundVars } from './hooks/useBackgroundVars';
|
||||||
import type { PanelPosition } from '@reactflow/core';
|
import { MapViewport, OnMapAddSystemCallback, OnMapSelectionChange } from './map.types';
|
||||||
|
import type { Viewport } from '@reactflow/core/dist/esm/types';
|
||||||
const DEFAULT_VIEW_PORT = { zoom: 1, x: 0, y: 0 };
|
import { usePrevious } from 'primereact/hooks';
|
||||||
|
|
||||||
const getViewPortFromStore = () => {
|
|
||||||
const restored = localStorage.getItem(SESSION_KEY.viewPort);
|
|
||||||
|
|
||||||
if (!restored) {
|
|
||||||
return { ...DEFAULT_VIEW_PORT };
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parse(restored);
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialNodes: Node<SolarSystemRawType>[] = [
|
const initialNodes: Node<SolarSystemRawType>[] = [
|
||||||
// {
|
// {
|
||||||
@@ -88,6 +77,7 @@ interface MapCompProps {
|
|||||||
onConnectionInfoClick?(e: SolarSystemConnection): void;
|
onConnectionInfoClick?(e: SolarSystemConnection): void;
|
||||||
onAddSystem?: OnMapAddSystemCallback;
|
onAddSystem?: OnMapAddSystemCallback;
|
||||||
onSelectionContextMenu?: NodeSelectionMouseHandler;
|
onSelectionContextMenu?: NodeSelectionMouseHandler;
|
||||||
|
onChangeViewport?: (viewport: MapViewport) => void;
|
||||||
minimapClasses?: string;
|
minimapClasses?: string;
|
||||||
isShowMinimap?: boolean;
|
isShowMinimap?: boolean;
|
||||||
onSystemContextMenu: (event: MouseEvent<Element>, systemId: string) => void;
|
onSystemContextMenu: (event: MouseEvent<Element>, systemId: string) => void;
|
||||||
@@ -99,6 +89,7 @@ interface MapCompProps {
|
|||||||
pings: PingData[];
|
pings: PingData[];
|
||||||
minimapPlacement?: PanelPosition;
|
minimapPlacement?: PanelPosition;
|
||||||
localShowShipName?: boolean;
|
localShowShipName?: boolean;
|
||||||
|
defaultViewport?: Viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapComp = ({
|
const MapComp = ({
|
||||||
@@ -119,19 +110,25 @@ const MapComp = ({
|
|||||||
pings,
|
pings,
|
||||||
minimapPlacement = 'bottom-right',
|
minimapPlacement = 'bottom-right',
|
||||||
localShowShipName = false,
|
localShowShipName = false,
|
||||||
|
onChangeViewport,
|
||||||
|
defaultViewport,
|
||||||
}: MapCompProps) => {
|
}: MapCompProps) => {
|
||||||
const { getNodes } = useReactFlow();
|
const { getNodes, setViewport } = useReactFlow();
|
||||||
const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes);
|
||||||
const [edges, , onEdgesChange] = useEdgesState<Edge<SolarSystemConnection>>(initialEdges);
|
const [edges, , onEdgesChange] = useEdgesState<Edge<SolarSystemConnection>>(initialEdges);
|
||||||
|
|
||||||
useMapHandlers(refn, onSelectionChange);
|
useMapHandlers(refn, onSelectionChange);
|
||||||
useUpdateNodes(nodes);
|
useUpdateNodes(nodes);
|
||||||
const { handleRootContext, ...rootCtxProps } = useContextMenuRootHandlers({ onAddSystem });
|
|
||||||
|
const { handleRootContext, ...rootCtxProps } = useContextMenuRootHandlers({ onAddSystem, onCommand });
|
||||||
const { handleConnectionContext, ...connectionCtxProps } = useContextMenuConnectionHandlers();
|
const { handleConnectionContext, ...connectionCtxProps } = useContextMenuConnectionHandlers();
|
||||||
const { update } = useMapState();
|
const { update } = useMapState();
|
||||||
const { variant, gap, size, color } = useBackgroundVars(theme);
|
const { variant, gap, size, color } = useBackgroundVars(theme);
|
||||||
const { isPanAndDrag, nodeComponent, connectionMode } = getBehaviorForTheme(theme || 'default');
|
const { isPanAndDrag, nodeComponent, connectionMode } = getBehaviorForTheme(theme || 'default');
|
||||||
|
|
||||||
|
const refVars = useRef({ onChangeViewport });
|
||||||
|
refVars.current = { onChangeViewport };
|
||||||
|
|
||||||
const nodeTypes = useMemo(() => {
|
const nodeTypes = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
custom: nodeComponent,
|
custom: nodeComponent,
|
||||||
@@ -187,9 +184,10 @@ const MapComp = ({
|
|||||||
[onSelectionChange],
|
[onSelectionChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMoveEnd: OnMoveEnd = (_, viewport) => {
|
const handleMoveEnd: OnMoveEnd = useCallback((_, viewport) => {
|
||||||
localStorage.setItem(SESSION_KEY.viewPort, JSON.stringify(viewport));
|
// @ts-ignore
|
||||||
};
|
refVars.current.onChangeViewport?.(viewport);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleNodesChange = useCallback(
|
const handleNodesChange = useCallback(
|
||||||
(changes: NodeChange[]) => {
|
(changes: NodeChange[]) => {
|
||||||
@@ -218,6 +216,19 @@ const MapComp = ({
|
|||||||
}));
|
}));
|
||||||
}, [showKSpaceBG, isThickConnections, pings, update, localShowShipName]);
|
}, [showKSpaceBG, isThickConnections, pings, update, localShowShipName]);
|
||||||
|
|
||||||
|
const prevViewport = usePrevious(defaultViewport);
|
||||||
|
useEffect(() => {
|
||||||
|
if (defaultViewport == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevViewport == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setViewport(defaultViewport);
|
||||||
|
}, [defaultViewport, prevViewport, setViewport]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@@ -232,7 +243,7 @@ const MapComp = ({
|
|||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
// TODO we need save into session all of this
|
// TODO we need save into session all of this
|
||||||
// and on any action do either
|
// and on any action do either
|
||||||
defaultViewport={getViewPortFromStore()}
|
defaultViewport={defaultViewport}
|
||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
connectionMode={connectionMode}
|
connectionMode={connectionMode}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export type MapData = MapUnionTypes & {
|
|||||||
isThickConnections: boolean;
|
isThickConnections: boolean;
|
||||||
linkedSigEveId: string;
|
linkedSigEveId: string;
|
||||||
localShowShipName: boolean;
|
localShowShipName: boolean;
|
||||||
|
systemHighlighted: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface MapProviderProps {
|
interface MapProviderProps {
|
||||||
@@ -44,6 +45,7 @@ const INITIAL_DATA: MapData = {
|
|||||||
userHubs: [],
|
userHubs: [],
|
||||||
pings: [],
|
pings: [],
|
||||||
localShowShipName: false,
|
localShowShipName: false,
|
||||||
|
systemHighlighted: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface MapContextProps {
|
export interface MapContextProps {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
@use '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
||||||
|
|
||||||
.ConnectionTimeEOL {
|
.ConnectionTimeEOL {
|
||||||
background-image: linear-gradient(207deg, transparent, var(--conn-time-eol));
|
background-image: linear-gradient(207deg, transparent, var(--conn-time-eol));
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
background-image: linear-gradient(207deg, transparent, var(--conn-frigate));
|
background-image: linear-gradient(207deg, transparent, var(--conn-frigate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ConnectionBridge {
|
||||||
|
background-image: linear-gradient(207deg, transparent, var(--conn-bridge));
|
||||||
|
}
|
||||||
|
|
||||||
.ConnectionSave {
|
.ConnectionSave {
|
||||||
background-image: linear-gradient(207deg, transparent, var(--conn-save));
|
background-image: linear-gradient(207deg, transparent, var(--conn-save));
|
||||||
}
|
}
|
||||||
@@ -15,3 +19,14 @@
|
|||||||
.SelectedItem {
|
.SelectedItem {
|
||||||
background-color: var(--selected-item-bg);
|
background-color: var(--selected-item-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.FastActions {
|
||||||
|
:global {
|
||||||
|
.p-menuitem-content {
|
||||||
|
background-color: initial !important;
|
||||||
|
}
|
||||||
|
.p-menuitem-content:hover {
|
||||||
|
background-color: initial !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
import React, { RefObject, useMemo } from 'react';
|
|
||||||
import { ContextMenu } from 'primereact/contextmenu';
|
|
||||||
import { PrimeIcons } from 'primereact/api';
|
|
||||||
import { MenuItem } from 'primereact/menuitem';
|
|
||||||
import { ConnectionType, MassState, ShipSizeStatus, SolarSystemConnection, TimeStatus } from '@/hooks/Mapper/types';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import classes from './ContextMenuConnection.module.scss';
|
|
||||||
import {
|
import {
|
||||||
MASS_STATE_NAMES,
|
MASS_STATE_NAMES,
|
||||||
MASS_STATE_NAMES_ORDER,
|
MASS_STATE_NAMES_ORDER,
|
||||||
@@ -13,14 +6,25 @@ import {
|
|||||||
SHIP_SIZES_NAMES_SHORT,
|
SHIP_SIZES_NAMES_SHORT,
|
||||||
SHIP_SIZES_SIZE,
|
SHIP_SIZES_SIZE,
|
||||||
} from '@/hooks/Mapper/components/map/constants.ts';
|
} from '@/hooks/Mapper/components/map/constants.ts';
|
||||||
|
import { ConnectionType, MassState, ShipSizeStatus, SolarSystemConnection, TimeStatus } from '@/hooks/Mapper/types';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { PrimeIcons } from 'primereact/api';
|
||||||
|
import { ContextMenu } from 'primereact/contextmenu';
|
||||||
|
import { MenuItem } from 'primereact/menuitem';
|
||||||
|
import React, { RefObject, useMemo } from 'react';
|
||||||
import { Edge } from 'reactflow';
|
import { Edge } from 'reactflow';
|
||||||
|
import { LifetimeActionsWrapper } from '@/hooks/Mapper/components/map/components/ContextMenuConnection/LifetimeActionsWrapper.tsx';
|
||||||
|
import classes from './ContextMenuConnection.module.scss';
|
||||||
|
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic.ts';
|
||||||
|
import { isNullsecSpace } from '@/hooks/Mapper/components/map/helpers/isKnownSpace.ts';
|
||||||
|
|
||||||
export interface ContextMenuConnectionProps {
|
export interface ContextMenuConnectionProps {
|
||||||
contextMenuRef: RefObject<ContextMenu>;
|
contextMenuRef: RefObject<ContextMenu>;
|
||||||
onDeleteConnection(): void;
|
onDeleteConnection(): void;
|
||||||
onChangeTimeState(): void;
|
onChangeTimeState(lifetime: TimeStatus): void;
|
||||||
onChangeMassState(state: MassState): void;
|
onChangeMassState(state: MassState): void;
|
||||||
onChangeShipSizeStatus(state: ShipSizeStatus): void;
|
onChangeShipSizeStatus(state: ShipSizeStatus): void;
|
||||||
|
onChangeType(type: ConnectionType): void;
|
||||||
onToggleMassSave(isLocked: boolean): void;
|
onToggleMassSave(isLocked: boolean): void;
|
||||||
onHide(): void;
|
onHide(): void;
|
||||||
edge?: Edge<SolarSystemConnection>;
|
edge?: Edge<SolarSystemConnection>;
|
||||||
@@ -32,6 +36,7 @@ export const ContextMenuConnection: React.FC<ContextMenuConnectionProps> = ({
|
|||||||
onChangeTimeState,
|
onChangeTimeState,
|
||||||
onChangeMassState,
|
onChangeMassState,
|
||||||
onChangeShipSizeStatus,
|
onChangeShipSizeStatus,
|
||||||
|
onChangeType,
|
||||||
onToggleMassSave,
|
onToggleMassSave,
|
||||||
onHide,
|
onHide,
|
||||||
edge,
|
edge,
|
||||||
@@ -41,88 +46,128 @@ export const ContextMenuConnection: React.FC<ContextMenuConnectionProps> = ({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sourceInfo = getSystemStaticInfo(edge.data?.source);
|
||||||
|
const targetInfo = getSystemStaticInfo(edge.data?.target);
|
||||||
|
|
||||||
|
const bothNullsec =
|
||||||
|
sourceInfo && targetInfo && isNullsecSpace(sourceInfo.system_class) && isNullsecSpace(targetInfo.system_class);
|
||||||
|
|
||||||
const isFrigateSize = edge.data?.ship_size_type === ShipSizeStatus.small;
|
const isFrigateSize = edge.data?.ship_size_type === ShipSizeStatus.small;
|
||||||
const isWormhole = edge.data?.type !== ConnectionType.gate;
|
|
||||||
|
if (edge.data?.type === ConnectionType.bridge) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: `Set as Wormhole`,
|
||||||
|
icon: 'pi hero-arrow-uturn-left',
|
||||||
|
command: () => onChangeType(ConnectionType.wormhole),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Disconnect',
|
||||||
|
icon: PrimeIcons.TRASH,
|
||||||
|
command: onDeleteConnection,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edge.data?.type === ConnectionType.gate) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Disconnect',
|
||||||
|
icon: PrimeIcons.TRASH,
|
||||||
|
command: onDeleteConnection,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...(isWormhole
|
{
|
||||||
|
className: clsx(classes.FastActions, '!h-[54px]'),
|
||||||
|
template: () => {
|
||||||
|
return <LifetimeActionsWrapper lifetime={edge.data?.time_status} onChangeLifetime={onChangeTimeState} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: `Frigate`,
|
||||||
|
className: clsx({
|
||||||
|
[classes.ConnectionFrigate]: isFrigateSize,
|
||||||
|
}),
|
||||||
|
icon: PrimeIcons.CLOUD,
|
||||||
|
command: () =>
|
||||||
|
onChangeShipSizeStatus(
|
||||||
|
edge.data?.ship_size_type === ShipSizeStatus.small ? ShipSizeStatus.large : ShipSizeStatus.small,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: `Save mass`,
|
||||||
|
className: clsx({
|
||||||
|
[classes.ConnectionSave]: edge.data?.locked,
|
||||||
|
}),
|
||||||
|
icon: PrimeIcons.LOCK,
|
||||||
|
command: () => onToggleMassSave(!edge.data?.locked),
|
||||||
|
},
|
||||||
|
...(!isFrigateSize
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
label: `EOL`,
|
label: `Mass status`,
|
||||||
className: clsx({
|
icon: PrimeIcons.CHART_PIE,
|
||||||
[classes.ConnectionTimeEOL]: edge.data?.time_status === TimeStatus.eol,
|
items: MASS_STATE_NAMES_ORDER.map(x => ({
|
||||||
}),
|
label: MASS_STATE_NAMES[x],
|
||||||
icon: PrimeIcons.CLOCK,
|
|
||||||
command: onChangeTimeState,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: `Frigate`,
|
|
||||||
className: clsx({
|
|
||||||
[classes.ConnectionFrigate]: isFrigateSize,
|
|
||||||
}),
|
|
||||||
icon: PrimeIcons.CLOUD,
|
|
||||||
command: () =>
|
|
||||||
onChangeShipSizeStatus(
|
|
||||||
edge.data?.ship_size_type === ShipSizeStatus.small ? ShipSizeStatus.large : ShipSizeStatus.small,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: `Save mass`,
|
|
||||||
className: clsx({
|
|
||||||
[classes.ConnectionSave]: edge.data?.locked,
|
|
||||||
}),
|
|
||||||
icon: PrimeIcons.LOCK,
|
|
||||||
command: () => onToggleMassSave(!edge.data?.locked),
|
|
||||||
},
|
|
||||||
...(!isFrigateSize
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
label: `Mass status`,
|
|
||||||
icon: PrimeIcons.CHART_PIE,
|
|
||||||
items: MASS_STATE_NAMES_ORDER.map(x => ({
|
|
||||||
label: MASS_STATE_NAMES[x],
|
|
||||||
className: clsx({
|
|
||||||
[classes.SelectedItem]: edge.data?.mass_status === x,
|
|
||||||
}),
|
|
||||||
command: () => onChangeMassState(x),
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
|
|
||||||
{
|
|
||||||
label: `Ship Size`,
|
|
||||||
icon: PrimeIcons.CLOUD,
|
|
||||||
items: SHIP_SIZES_NAMES_ORDER.map(x => ({
|
|
||||||
label: (
|
|
||||||
<div className="grid grid-cols-[20px_120px_1fr_40px] gap-2 items-center">
|
|
||||||
<div className="text-[12px] font-bold text-stone-400">{SHIP_SIZES_NAMES_SHORT[x]}</div>
|
|
||||||
<div>{SHIP_SIZES_NAMES[x]}</div>
|
|
||||||
<div></div>
|
|
||||||
<div className="flex justify-end whitespace-nowrap text-[12px] font-bold text-stone-500">
|
|
||||||
{SHIP_SIZES_SIZE[x]} t.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) as unknown as string, // TODO my lovely kostyl
|
|
||||||
className: clsx({
|
className: clsx({
|
||||||
[classes.SelectedItem]: edge.data?.ship_size_type === x,
|
[classes.SelectedItem]: edge.data?.mass_status === x,
|
||||||
}),
|
}),
|
||||||
command: () => onChangeShipSizeStatus(x),
|
command: () => onChangeMassState(x),
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
{
|
||||||
|
label: `Ship Size`,
|
||||||
|
icon: PrimeIcons.CLOUD,
|
||||||
|
items: SHIP_SIZES_NAMES_ORDER.map(x => ({
|
||||||
|
label: (
|
||||||
|
<div className="grid grid-cols-[20px_120px_1fr_40px] gap-2 items-center">
|
||||||
|
<div className="text-[12px] font-bold text-stone-400">{SHIP_SIZES_NAMES_SHORT[x]}</div>
|
||||||
|
<div>{SHIP_SIZES_NAMES[x]}</div>
|
||||||
|
<div></div>
|
||||||
|
<div className="flex justify-end whitespace-nowrap text-[12px] font-bold text-stone-500">
|
||||||
|
{SHIP_SIZES_SIZE[x]} t.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) as unknown as string, // TODO my lovely kostyl
|
||||||
|
className: clsx({
|
||||||
|
[classes.SelectedItem]: edge.data?.ship_size_type === x,
|
||||||
|
}),
|
||||||
|
command: () => onChangeShipSizeStatus(x),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
...(bothNullsec
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: `Set as Bridge`,
|
||||||
|
icon: 'pi hero-forward',
|
||||||
|
command: () => onChangeType(ConnectionType.bridge),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
label: 'Disconnect',
|
label: 'Disconnect',
|
||||||
icon: PrimeIcons.TRASH,
|
icon: PrimeIcons.TRASH,
|
||||||
command: onDeleteConnection,
|
command: onDeleteConnection,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [edge, onChangeTimeState, onDeleteConnection, onChangeShipSizeStatus, onToggleMassSave, onChangeMassState]);
|
}, [
|
||||||
|
edge,
|
||||||
|
onChangeTimeState,
|
||||||
|
onDeleteConnection,
|
||||||
|
onChangeType,
|
||||||
|
onChangeShipSizeStatus,
|
||||||
|
onToggleMassSave,
|
||||||
|
onChangeMassState,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ContextMenu model={items} ref={contextMenuRef} onHide={onHide} breakpoint="767px" />
|
<ContextMenu model={items} ref={contextMenuRef} onHide={onHide} breakpoint="767px" className="!w-[250px]" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { LayoutEventBlocker } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import { WdLifetimeSelector, WdLifetimeSelectorProps } from '@/hooks/Mapper/components/ui-kit/WdLifetimeSelector.tsx';
|
||||||
|
|
||||||
|
export const LifetimeActionsWrapper = (props: WdLifetimeSelectorProps) => {
|
||||||
|
return (
|
||||||
|
<LayoutEventBlocker className="flex flex-col gap-1 w-[100%] h-full px-2 pt-[4px]">
|
||||||
|
<div className="text-[12px] text-stone-500 font-semibold">Life time:</div>
|
||||||
|
|
||||||
|
<WdLifetimeSelector {...props} />
|
||||||
|
</LayoutEventBlocker>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -30,7 +30,7 @@ export const useContextMenuConnectionHandlers = () => {
|
|||||||
setEdge(undefined);
|
setEdge(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangeTimeState = () => {
|
const onChangeTimeState = (lifetime: TimeStatus) => {
|
||||||
if (!edge || !edge.data) {
|
if (!edge || !edge.data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ export const useContextMenuConnectionHandlers = () => {
|
|||||||
data: {
|
data: {
|
||||||
source: edge.source,
|
source: edge.source,
|
||||||
target: edge.target,
|
target: edge.target,
|
||||||
value: edge.data.time_status === TimeStatus.default ? TimeStatus.eol : TimeStatus.default,
|
value: lifetime,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setEdge(undefined);
|
setEdge(undefined);
|
||||||
|
|||||||
@@ -2,22 +2,70 @@ import React, { RefObject, useMemo } from 'react';
|
|||||||
import { ContextMenu } from 'primereact/contextmenu';
|
import { ContextMenu } from 'primereact/contextmenu';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { MenuItem } from 'primereact/menuitem';
|
import { MenuItem } from 'primereact/menuitem';
|
||||||
|
import { PasteSystemsAndConnections } from '@/hooks/Mapper/components/map/components';
|
||||||
|
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||||
|
import { checkPermissions } from '@/hooks/Mapper/components/map/helpers';
|
||||||
|
import { MenuItemWithInfo, WdMenuItem } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
export interface ContextMenuRootProps {
|
export interface ContextMenuRootProps {
|
||||||
contextMenuRef: RefObject<ContextMenu>;
|
contextMenuRef: RefObject<ContextMenu>;
|
||||||
|
pasteSystemsAndConnections: PasteSystemsAndConnections | undefined;
|
||||||
onAddSystem(): void;
|
onAddSystem(): void;
|
||||||
|
onPasteSystemsAnsConnections(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContextMenuRoot: React.FC<ContextMenuRootProps> = ({ contextMenuRef, onAddSystem }) => {
|
export const ContextMenuRoot: React.FC<ContextMenuRootProps> = ({
|
||||||
|
contextMenuRef,
|
||||||
|
onAddSystem,
|
||||||
|
onPasteSystemsAnsConnections,
|
||||||
|
pasteSystemsAndConnections,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
data: { options, userPermissions },
|
||||||
|
} = useMapState();
|
||||||
|
|
||||||
const items: MenuItem[] = useMemo(() => {
|
const items: MenuItem[] = useMemo(() => {
|
||||||
|
const allowPaste = checkPermissions(userPermissions, options.allowed_paste_for);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: 'Add System',
|
label: 'Add System',
|
||||||
icon: PrimeIcons.PLUS,
|
icon: PrimeIcons.PLUS,
|
||||||
command: onAddSystem,
|
command: onAddSystem,
|
||||||
},
|
},
|
||||||
|
...(pasteSystemsAndConnections != null
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
icon: 'pi pi-clipboard',
|
||||||
|
disabled: !allowPaste,
|
||||||
|
command: onPasteSystemsAnsConnections,
|
||||||
|
template: () => {
|
||||||
|
if (allowPaste) {
|
||||||
|
return (
|
||||||
|
<WdMenuItem icon="pi pi-clipboard">
|
||||||
|
Paste
|
||||||
|
</WdMenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItemWithInfo
|
||||||
|
infoTitle="Action is blocked because you don’t have permission to Paste."
|
||||||
|
infoClass={clsx(PrimeIcons.QUESTION_CIRCLE, 'text-stone-500 mr-[12px]')}
|
||||||
|
tooltipWrapperClassName="flex"
|
||||||
|
>
|
||||||
|
<WdMenuItem disabled icon="pi pi-clipboard">
|
||||||
|
Paste
|
||||||
|
</WdMenuItem>
|
||||||
|
</MenuItemWithInfo>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
];
|
];
|
||||||
}, [onAddSystem]);
|
}, [userPermissions, options, onAddSystem, pasteSystemsAndConnections, onPasteSystemsAnsConnections]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,36 +1,76 @@
|
|||||||
import { useReactFlow, XYPosition } from 'reactflow';
|
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
|
||||||
import { ContextMenu } from 'primereact/contextmenu';
|
|
||||||
import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
|
|
||||||
import { OnMapAddSystemCallback } from '@/hooks/Mapper/components/map/map.types.ts';
|
import { OnMapAddSystemCallback } from '@/hooks/Mapper/components/map/map.types.ts';
|
||||||
|
import { recenterSystemsByBounds } from '@/hooks/Mapper/helpers/recenterSystems.ts';
|
||||||
|
import { OutCommand, OutCommandHandler, SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
|
||||||
|
import { decodeUriBase64ToJson } from '@/hooks/Mapper/utils';
|
||||||
|
import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
|
||||||
|
import { ContextMenu } from 'primereact/contextmenu';
|
||||||
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
|
import { useReactFlow, XYPosition } from 'reactflow';
|
||||||
|
|
||||||
|
export type PasteSystemsAndConnections = {
|
||||||
|
systems: SolarSystemRawType[];
|
||||||
|
connections: SolarSystemConnection[];
|
||||||
|
};
|
||||||
|
|
||||||
type UseContextMenuRootHandlers = {
|
type UseContextMenuRootHandlers = {
|
||||||
onAddSystem?: OnMapAddSystemCallback;
|
onAddSystem?: OnMapAddSystemCallback;
|
||||||
|
onCommand?: OutCommandHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useContextMenuRootHandlers = ({ onAddSystem }: UseContextMenuRootHandlers = {}) => {
|
export const useContextMenuRootHandlers = ({ onAddSystem, onCommand }: UseContextMenuRootHandlers = {}) => {
|
||||||
const rf = useReactFlow();
|
const rf = useReactFlow();
|
||||||
const contextMenuRef = useRef<ContextMenu | null>(null);
|
const contextMenuRef = useRef<ContextMenu | null>(null);
|
||||||
const [position, setPosition] = useState<XYPosition | null>(null);
|
const [position, setPosition] = useState<XYPosition | null>(null);
|
||||||
|
const [pasteSystemsAndConnections, setPasteSystemsAndConnections] = useState<PasteSystemsAndConnections>();
|
||||||
|
|
||||||
const handleRootContext = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleRootContext = async (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
setPosition(rf.project({ x: e.clientX, y: e.clientY }));
|
setPosition(rf.project({ x: e.clientX, y: e.clientY }));
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
ctxManager.next('ctxRoot', contextMenuRef.current);
|
ctxManager.next('ctxRoot', contextMenuRef.current);
|
||||||
contextMenuRef.current?.show(e);
|
contextMenuRef.current?.show(e);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
const result = decodeUriBase64ToJson(text);
|
||||||
|
setPasteSystemsAndConnections(result as PasteSystemsAndConnections);
|
||||||
|
} catch (err) {
|
||||||
|
setPasteSystemsAndConnections(undefined);
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ref = useRef({ onAddSystem, position });
|
const ref = useRef({ onAddSystem, position, pasteSystemsAndConnections, onCommand });
|
||||||
ref.current = { onAddSystem, position };
|
ref.current = { onAddSystem, position, pasteSystemsAndConnections, onCommand };
|
||||||
|
|
||||||
const onAddSystemCallback = useCallback(() => {
|
const onAddSystemCallback = useCallback(() => {
|
||||||
ref.current.onAddSystem?.({ coordinates: position });
|
ref.current.onAddSystem?.({ coordinates: position });
|
||||||
}, [position]);
|
}, [position]);
|
||||||
|
|
||||||
|
const onPasteSystemsAnsConnections = useCallback(async () => {
|
||||||
|
const { pasteSystemsAndConnections, onCommand, position } = ref.current;
|
||||||
|
if (!position || !onCommand || !pasteSystemsAndConnections) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { systems } = recenterSystemsByBounds(pasteSystemsAndConnections.systems);
|
||||||
|
|
||||||
|
await onCommand({
|
||||||
|
type: OutCommand.manualPasteSystemsAndConnections,
|
||||||
|
data: {
|
||||||
|
systems: systems.map(({ position: srcPos, ...rest }) => ({
|
||||||
|
position: { x: Math.round(srcPos.x + position.x), y: Math.round(srcPos.y + position.y) },
|
||||||
|
...rest,
|
||||||
|
})),
|
||||||
|
connections: pasteSystemsAndConnections.connections,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleRootContext,
|
handleRootContext,
|
||||||
|
pasteSystemsAndConnections,
|
||||||
contextMenuRef,
|
contextMenuRef,
|
||||||
onAddSystem: onAddSystemCallback,
|
onAddSystem: onAddSystemCallback,
|
||||||
|
onPasteSystemsAnsConnections,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ export const KillsCounter = ({
|
|||||||
className={className}
|
className={className}
|
||||||
tooltipClassName="!px-0"
|
tooltipClassName="!px-0"
|
||||||
size={size}
|
size={size}
|
||||||
interactive={true}
|
interactive
|
||||||
|
smallPaddings
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</WdTooltipWrapper>
|
</WdTooltipWrapper>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hoverTarget {
|
.hoverTarget {
|
||||||
padding: 0.5rem;
|
padding: 2px;
|
||||||
margin: -0.5rem;
|
margin: -2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,19 @@ interface LocalCounterProps {
|
|||||||
localCounterCharacters: Array<CharItemProps>;
|
localCounterCharacters: Array<CharItemProps>;
|
||||||
hasUserCharacters: boolean;
|
hasUserCharacters: boolean;
|
||||||
showIcon?: boolean;
|
showIcon?: boolean;
|
||||||
|
disableInteractive?: boolean;
|
||||||
|
className?: string;
|
||||||
|
contentClassName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LocalCounter = ({ localCounterCharacters, hasUserCharacters, showIcon = true }: LocalCounterProps) => {
|
export const LocalCounter = ({
|
||||||
|
className,
|
||||||
|
contentClassName,
|
||||||
|
localCounterCharacters,
|
||||||
|
hasUserCharacters,
|
||||||
|
showIcon = true,
|
||||||
|
disableInteractive,
|
||||||
|
}: LocalCounterProps) => {
|
||||||
const {
|
const {
|
||||||
data: { localShowShipName },
|
data: { localShowShipName },
|
||||||
} = useMapState();
|
} = useMapState();
|
||||||
@@ -42,16 +52,30 @@ export const LocalCounter = ({ localCounterCharacters, hasUserCharacters, showIc
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(classes.TooltipActive, {
|
className={clsx(
|
||||||
[classes.Pathfinder]: theme === AvailableThemes.pathfinder,
|
classes.TooltipActive,
|
||||||
})}
|
{
|
||||||
|
[classes.Pathfinder]: theme === AvailableThemes.pathfinder,
|
||||||
|
},
|
||||||
|
className,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<WdTooltipWrapper content={pilotTooltipContent} position={TooltipPosition.right} offset={0} interactive={true}>
|
<WdTooltipWrapper
|
||||||
|
content={pilotTooltipContent}
|
||||||
|
position={TooltipPosition.right}
|
||||||
|
offset={0}
|
||||||
|
interactive={!disableInteractive}
|
||||||
|
smallPaddings
|
||||||
|
>
|
||||||
<div className={clsx(classes.hoverTarget)}>
|
<div className={clsx(classes.hoverTarget)}>
|
||||||
<div
|
<div
|
||||||
className={clsx(classes.localCounter, {
|
className={clsx(
|
||||||
[classes.hasUserCharacters]: hasUserCharacters,
|
classes.localCounter,
|
||||||
})}
|
{
|
||||||
|
[classes.hasUserCharacters]: hasUserCharacters,
|
||||||
|
},
|
||||||
|
contentClassName,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{showIcon && <i className="pi pi-users" />}
|
{showIcon && <i className="pi pi-users" />}
|
||||||
<span>{localCounterCharacters.length}</span>
|
<span>{localCounterCharacters.length}</span>
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
@import '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
@use '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
||||||
|
|
||||||
.EdgePathBack {
|
.EdgePathBack {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: #80a5c5;
|
stroke: #80a5c5;
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
|
|
||||||
|
&.time1 {
|
||||||
|
stroke: #f11ab2;
|
||||||
|
stroke-width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.time4 {
|
||||||
|
stroke: #a654e3;
|
||||||
|
stroke-width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
&.TimeCrit {
|
&.TimeCrit {
|
||||||
stroke: #f11ab2;
|
stroke: #f11ab2;
|
||||||
stroke-width: 4px;
|
stroke-width: 4px;
|
||||||
@@ -29,6 +39,13 @@
|
|||||||
&.Gate {
|
&.Gate {
|
||||||
stroke: #9aff40;
|
stroke: #9aff40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.Bridge {
|
||||||
|
stroke: #9aff40;
|
||||||
|
|
||||||
|
stroke-dasharray: 10 5;
|
||||||
|
stroke-linecap: round;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.EdgePathFront {
|
.EdgePathFront {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { PrimeIcons } from 'primereact/api';
|
|||||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||||
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||||
import { SHIP_SIZES_DESCRIPTION, SHIP_SIZES_NAMES_SHORT } from '@/hooks/Mapper/components/map/constants.ts';
|
import { SHIP_SIZES_DESCRIPTION, SHIP_SIZES_NAMES_SHORT } from '@/hooks/Mapper/components/map/constants.ts';
|
||||||
|
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
const MAP_TRANSLATES: Record<string, string> = {
|
const MAP_TRANSLATES: Record<string, string> = {
|
||||||
[Position.Top]: 'translate(-48%, 0%)',
|
[Position.Top]: 'translate(-48%, 0%)',
|
||||||
@@ -42,7 +43,9 @@ export const SHIP_SIZES_COLORS = {
|
|||||||
export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }: EdgeProps<SolarSystemConnection>) => {
|
export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }: EdgeProps<SolarSystemConnection>) => {
|
||||||
const sourceNode = useStore(useCallback(store => store.nodeInternals.get(source), [source]));
|
const sourceNode = useStore(useCallback(store => store.nodeInternals.get(source), [source]));
|
||||||
const targetNode = useStore(useCallback(store => store.nodeInternals.get(target), [target]));
|
const targetNode = useStore(useCallback(store => store.nodeInternals.get(target), [target]));
|
||||||
const isWormhole = data?.type !== ConnectionType.gate;
|
const isWormhole = data?.type === ConnectionType.wormhole;
|
||||||
|
const isGate = data?.type === ConnectionType.gate;
|
||||||
|
const isBridge = data?.type === ConnectionType.bridge;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { isThickConnections },
|
data: { isThickConnections },
|
||||||
@@ -55,9 +58,7 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
|||||||
|
|
||||||
const offset = isThickConnections ? MAP_OFFSETS_TICK[targetPos] : MAP_OFFSETS[targetPos];
|
const offset = isThickConnections ? MAP_OFFSETS_TICK[targetPos] : MAP_OFFSETS[targetPos];
|
||||||
|
|
||||||
const method = isWormhole ? getBezierPath : getBezierPath;
|
const [edgePath, labelX, labelY] = getBezierPath({
|
||||||
|
|
||||||
const [edgePath, labelX, labelY] = method({
|
|
||||||
sourceX: sx - offset.x,
|
sourceX: sx - offset.x,
|
||||||
sourceY: sy - offset.y,
|
sourceY: sy - offset.y,
|
||||||
sourcePosition: sourcePos,
|
sourcePosition: sourcePos,
|
||||||
@@ -67,7 +68,7 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
|||||||
});
|
});
|
||||||
|
|
||||||
return [edgePath, labelX, labelY, sx, sy, tx, ty, sourcePos, targetPos];
|
return [edgePath, labelX, labelY, sx, sy, tx, ty, sourcePos, targetPos];
|
||||||
}, [isThickConnections, sourceNode, targetNode, isWormhole]);
|
}, [isThickConnections, sourceNode, targetNode]);
|
||||||
|
|
||||||
if (!sourceNode || !targetNode || !data) {
|
if (!sourceNode || !targetNode || !data) {
|
||||||
return null;
|
return null;
|
||||||
@@ -79,9 +80,11 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
|||||||
id={`back_${id}`}
|
id={`back_${id}`}
|
||||||
className={clsx(classes.EdgePathBack, {
|
className={clsx(classes.EdgePathBack, {
|
||||||
[classes.Tick]: isThickConnections,
|
[classes.Tick]: isThickConnections,
|
||||||
[classes.TimeCrit]: isWormhole && data.time_status === TimeStatus.eol,
|
[classes.time1]: isWormhole && data.time_status === TimeStatus._1h,
|
||||||
|
[classes.time4]: isWormhole && data.time_status === TimeStatus._4h,
|
||||||
[classes.Hovered]: hovered,
|
[classes.Hovered]: hovered,
|
||||||
[classes.Gate]: !isWormhole,
|
[classes.Gate]: isGate,
|
||||||
|
[classes.Bridge]: isBridge,
|
||||||
})}
|
})}
|
||||||
d={path}
|
d={path}
|
||||||
markerEnd={markerEnd}
|
markerEnd={markerEnd}
|
||||||
@@ -95,7 +98,8 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
|||||||
[classes.MassVerge]: isWormhole && data.mass_status === MassState.verge,
|
[classes.MassVerge]: isWormhole && data.mass_status === MassState.verge,
|
||||||
[classes.MassHalf]: isWormhole && data.mass_status === MassState.half,
|
[classes.MassHalf]: isWormhole && data.mass_status === MassState.half,
|
||||||
[classes.Frigate]: isWormhole && data.ship_size_type === ShipSizeStatus.small,
|
[classes.Frigate]: isWormhole && data.ship_size_type === ShipSizeStatus.small,
|
||||||
[classes.Gate]: !isWormhole,
|
[classes.Gate]: isGate,
|
||||||
|
[classes.Bridge]: isBridge,
|
||||||
})}
|
})}
|
||||||
d={path}
|
d={path}
|
||||||
markerEnd={markerEnd}
|
markerEnd={markerEnd}
|
||||||
@@ -147,6 +151,19 @@ export const SolarSystemEdge = ({ id, source, target, markerEnd, style, data }:
|
|||||||
</WdTooltipWrapper>
|
</WdTooltipWrapper>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isBridge && (
|
||||||
|
<WdTooltipWrapper
|
||||||
|
content="Ansiblex Jump Bridge"
|
||||||
|
position={TooltipPosition.top}
|
||||||
|
className={clsx(
|
||||||
|
classes.LinkLabel,
|
||||||
|
'pointer-events-auto bg-lime-300 rounded opacity-100 cursor-auto text-neutral-900',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
B
|
||||||
|
</WdTooltipWrapper>
|
||||||
|
)}
|
||||||
|
|
||||||
{isWormhole && data.ship_size_type !== ShipSizeStatus.large && (
|
{isWormhole && data.ship_size_type !== ShipSizeStatus.large && (
|
||||||
<WdTooltipWrapper
|
<WdTooltipWrapper
|
||||||
content={SHIP_SIZES_DESCRIPTION[data.ship_size_type]}
|
content={SHIP_SIZES_DESCRIPTION[data.ship_size_type]}
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
@import '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
@use "sass:color";
|
||||||
|
@use '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
||||||
$pastel-blue: #5a7d9a;
|
@import '@/hooks/Mapper/components/map/styles/solar-system-node';
|
||||||
$pastel-pink: rgb(30, 161, 255);
|
|
||||||
$dark-bg: #2d2d2d;
|
|
||||||
$text-color: #ffffff;
|
|
||||||
$tooltip-bg: #202020;
|
|
||||||
|
|
||||||
$neon-color-1: rgb(27, 132, 236);
|
|
||||||
$neon-color-3: rgba(27, 132, 236, 0.40);
|
|
||||||
|
|
||||||
@keyframes move-stripes {
|
@keyframes move-stripes {
|
||||||
from {
|
from {
|
||||||
@@ -34,7 +27,7 @@ $neon-color-3: rgba(27, 132, 236, 0.40);
|
|||||||
color: var(--rf-text-color, #ffffff);
|
color: var(--rf-text-color, #ffffff);
|
||||||
|
|
||||||
box-shadow: 0 0 5px rgba($dark-bg, 0.5);
|
box-shadow: 0 0 5px rgba($dark-bg, 0.5);
|
||||||
border: 1px solid darken($pastel-blue, 10%);
|
border: 1px solid color.adjust($pastel-blue, $lightness: -10%);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Handle, NodeProps, Position } from 'reactflow';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import classes from './SolarSystemNodeDefault.module.scss';
|
import classes from './SolarSystemNodeDefault.module.scss';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { useLocalCounter, useNodeKillsCount, useSolarSystemNode } from '../../hooks';
|
import { useNodeKillsCount, useSolarSystemNode } from '../../hooks';
|
||||||
import {
|
import {
|
||||||
EFFECT_BACKGROUND_STYLES,
|
EFFECT_BACKGROUND_STYLES,
|
||||||
MARKER_BOOKMARK_BG_STYLES,
|
MARKER_BOOKMARK_BG_STYLES,
|
||||||
@@ -17,10 +17,12 @@ import { TooltipPosition, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-
|
|||||||
import { Tag } from 'primereact/tag';
|
import { Tag } from 'primereact/tag';
|
||||||
import { LocalCounter } from '@/hooks/Mapper/components/map/components/LocalCounter';
|
import { LocalCounter } from '@/hooks/Mapper/components/map/components/LocalCounter';
|
||||||
import { KillsCounter } from '@/hooks/Mapper/components/map/components/KillsCounter';
|
import { KillsCounter } from '@/hooks/Mapper/components/map/components/KillsCounter';
|
||||||
|
import { useLocalCounter } from '@/hooks/Mapper/components/hooks/useLocalCounter.ts';
|
||||||
|
|
||||||
// let render = 0;
|
// let render = 0;
|
||||||
export const SolarSystemNodeDefault = memo((props: NodeProps<MapSolarSystemType>) => {
|
export const SolarSystemNodeDefault = memo((props: NodeProps<MapSolarSystemType>) => {
|
||||||
const nodeVars = useSolarSystemNode(props);
|
const nodeVars = useSolarSystemNode(props);
|
||||||
|
|
||||||
const { localCounterCharacters } = useLocalCounter(nodeVars);
|
const { localCounterCharacters } = useLocalCounter(nodeVars);
|
||||||
const { killsCount: localKillsCount, killsActivityType: localKillsActivityType } = useNodeKillsCount(
|
const { killsCount: localKillsCount, killsActivityType: localKillsActivityType } = useNodeKillsCount(
|
||||||
nodeVars.solarSystemId,
|
nodeVars.solarSystemId,
|
||||||
@@ -139,12 +141,26 @@ export const SolarSystemNodeDefault = memo((props: NodeProps<MapSolarSystemType>
|
|||||||
|
|
||||||
{nodeVars.isWormhole && !nodeVars.customName && <div />}
|
{nodeVars.isWormhole && !nodeVars.customName && <div />}
|
||||||
|
|
||||||
<div className="flex items-center gap-1 justify-end">
|
<div className="flex items-center gap-0.5 justify-end">
|
||||||
<div className={clsx('flex items-center gap-1')}>
|
<div className={clsx('flex items-center gap-0.5')}>
|
||||||
{nodeVars.locked && <i className={clsx(PrimeIcons.LOCK, classes.lockIcon)} />}
|
{nodeVars.locked && <i className={clsx(PrimeIcons.LOCK, classes.lockIcon)} />}
|
||||||
{nodeVars.hubs.includes(nodeVars.solarSystemId) && (
|
{nodeVars.hubs.includes(nodeVars.solarSystemId) && (
|
||||||
<i className={clsx(PrimeIcons.MAP_MARKER, classes.mapMarker)} />
|
<i className={clsx(PrimeIcons.MAP_MARKER, classes.mapMarker)} />
|
||||||
)}
|
)}
|
||||||
|
{nodeVars.description != null && nodeVars.description !== '' && (
|
||||||
|
<WdTooltipWrapper
|
||||||
|
className="h-[15px] transform -translate-y-[6%]"
|
||||||
|
position={TooltipPosition.top}
|
||||||
|
content={`System have description`}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={clsx(
|
||||||
|
'pi hero-chat-bubble-bottom-center-text w-[10px] h-[10px]',
|
||||||
|
'text-[8px] relative top-[1px]',
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</WdTooltipWrapper>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LocalCounter
|
<LocalCounter
|
||||||
@@ -177,6 +193,17 @@ export const SolarSystemNodeDefault = memo((props: NodeProps<MapSolarSystemType>
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{nodeVars.systemHighlighted === nodeVars.solarSystemId && (
|
||||||
|
<div
|
||||||
|
className={clsx('absolute top-[-4px] left-[-4px]', 'w-[calc(100%+8px)] h-[calc(100%+8px)]', 'animate-pulse')}
|
||||||
|
>
|
||||||
|
<div className="absolute left-0 top-0 w-3 h-2 border-t-2 border-l-2 border-sky-300"></div>
|
||||||
|
<div className="absolute right-0 top-0 w-3 h-2 border-t-2 border-r-2 border-sky-300"></div>
|
||||||
|
<div className="absolute left-0 bottom-0 w-3 h-2 border-b-2 border-l-2 border-sky-300"></div>
|
||||||
|
<div className="absolute right-0 bottom-0 w-3 h-2 border-b-2 border-r-2 border-sky-300"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={classes.Handlers}>
|
<div className={classes.Handlers}>
|
||||||
<Handle
|
<Handle
|
||||||
type="source"
|
type="source"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import './SolarSystemNodeDefault.module.scss';
|
@use './SolarSystemNodeDefault.module.scss';
|
||||||
|
|
||||||
/* ---------------------------------------------
|
/* ---------------------------------------------
|
||||||
Only override what's different from the base
|
Only override what's different from the base
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Handle, NodeProps, Position } from 'reactflow';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import classes from './SolarSystemNodeTheme.module.scss';
|
import classes from './SolarSystemNodeTheme.module.scss';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { useLocalCounter, useNodeKillsCount, useSolarSystemNode } from '../../hooks';
|
import { useNodeKillsCount, useSolarSystemNode } from '../../hooks';
|
||||||
import {
|
import {
|
||||||
EFFECT_BACKGROUND_STYLES,
|
EFFECT_BACKGROUND_STYLES,
|
||||||
MARKER_BOOKMARK_BG_STYLES,
|
MARKER_BOOKMARK_BG_STYLES,
|
||||||
@@ -16,6 +16,7 @@ import { TooltipPosition, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-
|
|||||||
import { TooltipSize } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper/utils.ts';
|
import { TooltipSize } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper/utils.ts';
|
||||||
import { LocalCounter } from '@/hooks/Mapper/components/map/components/LocalCounter';
|
import { LocalCounter } from '@/hooks/Mapper/components/map/components/LocalCounter';
|
||||||
import { KillsCounter } from '@/hooks/Mapper/components/map/components/KillsCounter';
|
import { KillsCounter } from '@/hooks/Mapper/components/map/components/KillsCounter';
|
||||||
|
import { useLocalCounter } from '@/hooks/Mapper/components/hooks/useLocalCounter.ts';
|
||||||
|
|
||||||
// let render = 0;
|
// let render = 0;
|
||||||
export const SolarSystemNodeTheme = memo((props: NodeProps<MapSolarSystemType>) => {
|
export const SolarSystemNodeTheme = memo((props: NodeProps<MapSolarSystemType>) => {
|
||||||
@@ -172,6 +173,17 @@ export const SolarSystemNodeTheme = memo((props: NodeProps<MapSolarSystemType>)
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{nodeVars.systemHighlighted === nodeVars.solarSystemId && (
|
||||||
|
<div
|
||||||
|
className={clsx('absolute top-[-4px] left-[-4px]', 'w-[calc(100%+8px)] h-[calc(100%+8px)]', 'animate-pulse')}
|
||||||
|
>
|
||||||
|
<div className="absolute left-0 top-0 w-3 h-2 border-t-2 border-l-2 border-sky-300"></div>
|
||||||
|
<div className="absolute right-0 top-0 w-3 h-2 border-t-2 border-r-2 border-sky-300"></div>
|
||||||
|
<div className="absolute left-0 bottom-0 w-3 h-2 border-b-2 border-l-2 border-sky-300"></div>
|
||||||
|
<div className="absolute right-0 bottom-0 w-3 h-2 border-b-2 border-r-2 border-sky-300"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={classes.Handlers}>
|
<div className={classes.Handlers}>
|
||||||
<Handle
|
<Handle
|
||||||
type="source"
|
type="source"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
@use '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
||||||
|
|
||||||
.Signature {
|
.Signature {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
|
||||||
import { InfoDrawer } from '@/hooks/Mapper/components/ui-kit';
|
import { InfoDrawer } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||||
|
|
||||||
import classes from './UnsplashedSignature.module.scss';
|
|
||||||
import { SystemSignature } from '@/hooks/Mapper/types/signatures';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
import { WORMHOLE_CLASS_STYLES, WORMHOLES_ADDITIONAL_INFO } from '@/hooks/Mapper/components/map/constants.ts';
|
import { WORMHOLE_CLASS_STYLES, WORMHOLES_ADDITIONAL_INFO } from '@/hooks/Mapper/components/map/constants.ts';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { renderInfoColumn } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
import { renderInfoColumn } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
||||||
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
||||||
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo.ts';
|
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo.ts';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { TimeStatus } from '@/hooks/Mapper/types';
|
||||||
|
import { SystemSignature } from '@/hooks/Mapper/types/signatures';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import classes from './UnsplashedSignature.module.scss';
|
||||||
|
|
||||||
interface UnsplashedSignatureProps {
|
interface UnsplashedSignatureProps {
|
||||||
signature: SystemSignature;
|
signature: SystemSignature;
|
||||||
@@ -35,7 +36,7 @@ export const UnsplashedSignature = ({ signature }: UnsplashedSignatureProps) =>
|
|||||||
}, [customInfo]);
|
}, [customInfo]);
|
||||||
|
|
||||||
const isEOL = useMemo(() => {
|
const isEOL = useMemo(() => {
|
||||||
return customInfo?.isEOL;
|
return customInfo?.time_status === TimeStatus._1h;
|
||||||
}, [customInfo]);
|
}, [customInfo]);
|
||||||
|
|
||||||
const whClassStyle = useMemo(() => {
|
const whClassStyle = useMemo(() => {
|
||||||
@@ -58,6 +59,7 @@ export const UnsplashedSignature = ({ signature }: UnsplashedSignatureProps) =>
|
|||||||
</InfoDrawer>
|
</InfoDrawer>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
smallPaddings
|
||||||
>
|
>
|
||||||
<div className={clsx(classes.Box, whClassStyle)}>
|
<div className={clsx(classes.Box, whClassStyle)}>
|
||||||
<svg width="13" height="8" viewBox="0 0 13 8" xmlns="http://www.w3.org/2000/svg">
|
<svg width="13" height="8" viewBox="0 0 13 8" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
@@ -716,11 +716,12 @@ export const STATUS_CLASSES: Record<number, string> = {
|
|||||||
[STATUSES.dangerous]: 'eve-system-status-dangerous',
|
[STATUSES.dangerous]: 'eve-system-status-dangerous',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TYPE_NAMES_ORDER = [ConnectionType.wormhole, ConnectionType.gate];
|
export const TYPE_NAMES_ORDER = [ConnectionType.wormhole, ConnectionType.gate, ConnectionType.bridge];
|
||||||
|
|
||||||
export const TYPE_NAMES = {
|
export const TYPE_NAMES = {
|
||||||
[ConnectionType.wormhole]: 'Wormhole',
|
[ConnectionType.wormhole]: 'Wormhole',
|
||||||
[ConnectionType.gate]: 'Gate',
|
[ConnectionType.gate]: 'Gate',
|
||||||
|
[ConnectionType.bridge]: 'Jumpgate',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MASS_STATE_NAMES_ORDER = [MassState.verge, MassState.half, MassState.normal];
|
export const MASS_STATE_NAMES_ORDER = [MassState.verge, MassState.half, MassState.normal];
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { UserPermission, UserPermissions } from '@/hooks/Mapper/types';
|
||||||
|
|
||||||
|
export const checkPermissions = (permissions: Partial<UserPermissions>, targetPermission: UserPermission) => {
|
||||||
|
return targetPermission != null && permissions[targetPermission];
|
||||||
|
};
|
||||||
@@ -4,3 +4,4 @@ export * from './getSystemClassStyles';
|
|||||||
export * from './getShapeClass';
|
export * from './getShapeClass';
|
||||||
export * from './getBackgroundClass';
|
export * from './getBackgroundClass';
|
||||||
export * from './prepareUnsplashedChunks';
|
export * from './prepareUnsplashedChunks';
|
||||||
|
export * from './checkPermissions';
|
||||||
|
|||||||
@@ -15,3 +15,12 @@ export const isKnownSpace = (wormholeClassID: number) => {
|
|||||||
export const isPossibleSpace = (spaces: number[], wormholeClassID: number) => {
|
export const isPossibleSpace = (spaces: number[], wormholeClassID: number) => {
|
||||||
return spaces.includes(wormholeClassID);
|
return spaces.includes(wormholeClassID);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isNullsecSpace = (wormholeClassID: number) => {
|
||||||
|
switch (wormholeClassID) {
|
||||||
|
case SOLAR_SYSTEM_CLASS_IDS.ns:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ export * from './useCommandsCharacters';
|
|||||||
export * from './useCommandsConnections';
|
export * from './useCommandsConnections';
|
||||||
export * from './useCommandsConnections';
|
export * from './useCommandsConnections';
|
||||||
export * from './useCenterSystem';
|
export * from './useCenterSystem';
|
||||||
export * from './useSelectSystem';
|
export * from './useSelectSystems';
|
||||||
export * from './useMapCommands';
|
export * from './useMapCommands';
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { useReactFlow } from 'reactflow';
|
import { useReactFlow } from 'reactflow';
|
||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { CommandCenterSystem } from '@/hooks/Mapper/types';
|
import { CommandCenterSystem } from '@/hooks/Mapper/types';
|
||||||
|
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||||
|
import { SYSTEM_FOCUSED_LIFETIME } from '@/hooks/Mapper/constants.ts';
|
||||||
|
|
||||||
export const useCenterSystem = () => {
|
export const useCenterSystem = () => {
|
||||||
const rf = useReactFlow();
|
const rf = useReactFlow();
|
||||||
|
|
||||||
const ref = useRef({ rf });
|
const { update } = useMapState();
|
||||||
ref.current = { rf };
|
|
||||||
|
const ref = useRef({ rf, update });
|
||||||
|
ref.current = { rf, update };
|
||||||
|
|
||||||
|
const highlightTimeout = useRef<number>();
|
||||||
|
|
||||||
return useCallback((systemId: CommandCenterSystem) => {
|
return useCallback((systemId: CommandCenterSystem) => {
|
||||||
const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
|
const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
|
||||||
@@ -14,5 +20,16 @@ export const useCenterSystem = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
|
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
|
||||||
|
|
||||||
|
ref.current.update({ systemHighlighted: systemId });
|
||||||
|
|
||||||
|
if (highlightTimeout.current !== undefined) {
|
||||||
|
clearTimeout(highlightTimeout.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightTimeout.current = setTimeout(() => {
|
||||||
|
highlightTimeout.current = undefined;
|
||||||
|
ref.current.update({ systemHighlighted: undefined });
|
||||||
|
}, SYSTEM_FOCUSED_LIFETIME);
|
||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { MapData, useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
import { MapData, useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||||
|
import { useEventBuffer } from '@/hooks/Mapper/hooks';
|
||||||
|
import { SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
|
||||||
import { CommandInit } from '@/hooks/Mapper/types/mapHandlers.ts';
|
import { CommandInit } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { useReactFlow } from 'reactflow';
|
import { useReactFlow } from 'reactflow';
|
||||||
@@ -11,6 +13,20 @@ export const useMapInit = () => {
|
|||||||
const ref = useRef({ rf, data, update });
|
const ref = useRef({ rf, data, update });
|
||||||
ref.current = { update, data, rf };
|
ref.current = { update, data, rf };
|
||||||
|
|
||||||
|
const updateSystems = useCallback((systems: SolarSystemRawType[]) => {
|
||||||
|
const { rf } = ref.current;
|
||||||
|
rf.setNodes(systems.map(convertSystem2Node));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { handleEvent: handleUpdateSystems } = useEventBuffer<any>(updateSystems);
|
||||||
|
|
||||||
|
const updateEdges = useCallback((connections: SolarSystemConnection[]) => {
|
||||||
|
const { rf } = ref.current;
|
||||||
|
rf.setEdges(connections.map(convertConnection2Edge));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { handleEvent: handleUpdateConnections } = useEventBuffer<any>(updateEdges);
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
({
|
({
|
||||||
systems,
|
systems,
|
||||||
@@ -22,9 +38,10 @@ export const useMapInit = () => {
|
|||||||
user_characters,
|
user_characters,
|
||||||
present_characters,
|
present_characters,
|
||||||
hubs,
|
hubs,
|
||||||
|
options,
|
||||||
|
user_permissions,
|
||||||
}: CommandInit) => {
|
}: CommandInit) => {
|
||||||
const { update } = ref.current;
|
const { update } = ref.current;
|
||||||
const { rf } = ref.current;
|
|
||||||
|
|
||||||
const updateData: Partial<MapData> = {};
|
const updateData: Partial<MapData> = {};
|
||||||
|
|
||||||
@@ -48,6 +65,14 @@ export const useMapInit = () => {
|
|||||||
updateData.hubs = hubs;
|
updateData.hubs = hubs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
updateData.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
updateData.userPermissions = user_permissions;
|
||||||
|
}
|
||||||
|
|
||||||
if (systems) {
|
if (systems) {
|
||||||
updateData.systems = systems;
|
updateData.systems = systems;
|
||||||
}
|
}
|
||||||
@@ -63,11 +88,13 @@ export const useMapInit = () => {
|
|||||||
update(updateData);
|
update(updateData);
|
||||||
|
|
||||||
if (systems) {
|
if (systems) {
|
||||||
rf.setNodes(systems.map(convertSystem2Node));
|
handleUpdateSystems(systems);
|
||||||
|
// rf.setNodes(systems.map(convertSystem2Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connections) {
|
if (connections) {
|
||||||
rf.setEdges(connections.map(convertConnection2Edge));
|
handleUpdateConnections(connections);
|
||||||
|
// rf.setEdges(connections.map(convertConnection2Edge));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { useReactFlow } from 'reactflow';
|
|
||||||
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) => {
|
|
||||||
ref.current.rf.setNodes(nds =>
|
|
||||||
nds.map(node => {
|
|
||||||
return {
|
|
||||||
...node,
|
|
||||||
selected: node.id === systemId,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
|
||||||
|
import { CommandSelectSystems } from '@/hooks/Mapper/types';
|
||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
import { useReactFlow } from 'reactflow';
|
||||||
|
|
||||||
|
export const useSelectSystems = (onSelectionChange: OnMapSelectionChange) => {
|
||||||
|
const rf = useReactFlow();
|
||||||
|
|
||||||
|
const ref = useRef({ rf, onSelectionChange });
|
||||||
|
ref.current = { rf, onSelectionChange };
|
||||||
|
|
||||||
|
return useCallback(({ systems, delay }: CommandSelectSystems) => {
|
||||||
|
const run = () => {
|
||||||
|
ref.current.rf.setNodes(nds =>
|
||||||
|
nds.map(node => {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
selected: systems.includes(node.id),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (delay == null || delay === 0) {
|
||||||
|
run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(run, delay);
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ForwardedRef, useImperativeHandle, useRef } from 'react';
|
|
||||||
import {
|
import {
|
||||||
CommandAddConnections,
|
CommandAddConnections,
|
||||||
CommandAddSystems,
|
CommandAddSystems,
|
||||||
@@ -14,12 +13,16 @@ import {
|
|||||||
CommandRemoveSystems,
|
CommandRemoveSystems,
|
||||||
Commands,
|
Commands,
|
||||||
CommandSelectSystem,
|
CommandSelectSystem,
|
||||||
|
CommandSelectSystems,
|
||||||
CommandUpdateConnection,
|
CommandUpdateConnection,
|
||||||
CommandUpdateSystems,
|
CommandUpdateSystems,
|
||||||
MapHandlers,
|
MapHandlers,
|
||||||
} from '@/hooks/Mapper/types/mapHandlers.ts';
|
} from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||||
|
import { ForwardedRef, useImperativeHandle, useRef } from 'react';
|
||||||
|
|
||||||
|
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
|
||||||
import {
|
import {
|
||||||
|
useCenterSystem,
|
||||||
useCommandsCharacters,
|
useCommandsCharacters,
|
||||||
useCommandsConnections,
|
useCommandsConnections,
|
||||||
useMapAddSystems,
|
useMapAddSystems,
|
||||||
@@ -27,10 +30,8 @@ import {
|
|||||||
useMapInit,
|
useMapInit,
|
||||||
useMapRemoveSystems,
|
useMapRemoveSystems,
|
||||||
useMapUpdateSystems,
|
useMapUpdateSystems,
|
||||||
useCenterSystem,
|
useSelectSystems,
|
||||||
useSelectSystem,
|
|
||||||
} from './api';
|
} from './api';
|
||||||
import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
|
|
||||||
|
|
||||||
export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange: OnMapSelectionChange) => {
|
export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange: OnMapSelectionChange) => {
|
||||||
const mapInit = useMapInit();
|
const mapInit = useMapInit();
|
||||||
@@ -38,7 +39,7 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
|
|||||||
const mapUpdateSystems = useMapUpdateSystems();
|
const mapUpdateSystems = useMapUpdateSystems();
|
||||||
const removeSystems = useMapRemoveSystems(onSelectionChange);
|
const removeSystems = useMapRemoveSystems(onSelectionChange);
|
||||||
const centerSystem = useCenterSystem();
|
const centerSystem = useCenterSystem();
|
||||||
const selectSystem = useSelectSystem();
|
const selectSystems = useSelectSystems(onSelectionChange);
|
||||||
|
|
||||||
const selectRef = useRef({ onSelectionChange });
|
const selectRef = useRef({ onSelectionChange });
|
||||||
selectRef.current = { onSelectionChange };
|
selectRef.current = { onSelectionChange };
|
||||||
@@ -105,14 +106,11 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Commands.selectSystem:
|
case Commands.selectSystem:
|
||||||
setTimeout(() => {
|
selectSystems({ systems: [data as string], delay: 500 });
|
||||||
const systemId = `${data}`;
|
break;
|
||||||
selectRef.current.onSelectionChange({
|
|
||||||
systems: [systemId],
|
case Commands.selectSystems:
|
||||||
connections: [],
|
selectSystems(data as CommandSelectSystems);
|
||||||
});
|
|
||||||
selectSystem(systemId as CommandSelectSystem);
|
|
||||||
}, 500);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Commands.pingAdded:
|
case Commands.pingAdded:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|||||||
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||||
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider';
|
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider';
|
||||||
import { useDoubleClick } from '@/hooks/Mapper/hooks/useDoubleClick';
|
import { useDoubleClick } from '@/hooks/Mapper/hooks/useDoubleClick';
|
||||||
import { Regions, REGIONS_MAP, Spaces } from '@/hooks/Mapper/constants';
|
import { Regions, REGIONS_MAP, SPACE_TO_CLASS } from '@/hooks/Mapper/constants';
|
||||||
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace';
|
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace';
|
||||||
import { getSystemClassStyles } from '@/hooks/Mapper/components/map/helpers';
|
import { getSystemClassStyles } from '@/hooks/Mapper/components/map/helpers';
|
||||||
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
||||||
@@ -50,27 +50,9 @@ export interface SolarSystemNodeVars {
|
|||||||
isRally: boolean;
|
isRally: boolean;
|
||||||
classTitle: string | null;
|
classTitle: string | null;
|
||||||
temporaryName?: string | null;
|
temporaryName?: string | null;
|
||||||
}
|
description: string | null;
|
||||||
|
comments_count: number | null;
|
||||||
const SpaceToClass: Record<string, string> = {
|
systemHighlighted: string | undefined;
|
||||||
[Spaces.Caldari]: 'Caldaria',
|
|
||||||
[Spaces.Matar]: 'Mataria',
|
|
||||||
[Spaces.Amarr]: 'Amarria',
|
|
||||||
[Spaces.Gallente]: 'Gallente',
|
|
||||||
[Spaces.Pochven]: 'Pochven',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useLocalCounter(nodeVars: SolarSystemNodeVars) {
|
|
||||||
const localCounterCharacters = useMemo(() => {
|
|
||||||
return nodeVars.charactersInSystem
|
|
||||||
.map(char => ({
|
|
||||||
...char,
|
|
||||||
compact: true,
|
|
||||||
isOwn: nodeVars.userCharacters.includes(char.eve_id),
|
|
||||||
}))
|
|
||||||
.sort((a, b) => a.name.localeCompare(b.name));
|
|
||||||
}, [nodeVars.charactersInSystem, nodeVars.userCharacters]);
|
|
||||||
return { localCounterCharacters };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarSystemNodeVars => {
|
export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarSystemNodeVars => {
|
||||||
@@ -84,6 +66,8 @@ export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
labels,
|
labels,
|
||||||
temporary_name,
|
temporary_name,
|
||||||
linked_sig_eve_id: linkedSigEveId = '',
|
linked_sig_eve_id: linkedSigEveId = '',
|
||||||
|
description,
|
||||||
|
comments_count,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -125,6 +109,7 @@ export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
showKSpaceBG,
|
showKSpaceBG,
|
||||||
isThickConnections,
|
isThickConnections,
|
||||||
pings,
|
pings,
|
||||||
|
systemHighlighted,
|
||||||
},
|
},
|
||||||
outCommand,
|
outCommand,
|
||||||
} = useMapState();
|
} = useMapState();
|
||||||
@@ -169,7 +154,7 @@ export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
const showHandlers = isConnecting || hoverNodeId === id;
|
const showHandlers = isConnecting || hoverNodeId === id;
|
||||||
|
|
||||||
const space = showKSpaceBG ? REGIONS_MAP[region_id] : '';
|
const space = showKSpaceBG ? REGIONS_MAP[region_id] : '';
|
||||||
const regionClass = showKSpaceBG ? SpaceToClass[space] || null : null;
|
const regionClass = showKSpaceBG ? SPACE_TO_CLASS[space] || null : null;
|
||||||
|
|
||||||
const { systemName, computedTemporaryName, customName } = useSystemName({
|
const { systemName, computedTemporaryName, customName } = useSystemName({
|
||||||
isTempSystemNameEnabled,
|
isTempSystemNameEnabled,
|
||||||
@@ -232,6 +217,9 @@ export const useSolarSystemNode = (props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
regionName,
|
regionName,
|
||||||
solarSystemName: solar_system_name,
|
solarSystemName: solar_system_name,
|
||||||
isRally,
|
isRally,
|
||||||
|
description,
|
||||||
|
comments_count,
|
||||||
|
systemHighlighted,
|
||||||
};
|
};
|
||||||
|
|
||||||
return nodeVars;
|
return nodeVars;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useRef } from 'react';
|
|
||||||
import { Node, useOnViewportChange, useReactFlow } from 'reactflow';
|
|
||||||
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||||
import { SolarSystemRawType } from '@/hooks/Mapper/types';
|
import { SolarSystemRawType } from '@/hooks/Mapper/types';
|
||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
import { Node, useOnViewportChange, useReactFlow } from 'reactflow';
|
||||||
|
|
||||||
const useThrottle = () => {
|
const useThrottle = () => {
|
||||||
const throttleSeed = useRef<number | null>(null);
|
const throttleSeed = useRef<number | null>(null);
|
||||||
|
|||||||
@@ -10,3 +10,5 @@ export type OnMapSelectionChange = (event: {
|
|||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
export type OnMapAddSystemCallback = (props: { coordinates: XYPosition | null }) => void;
|
export type OnMapAddSystemCallback = (props: { coordinates: XYPosition | null }) => void;
|
||||||
|
|
||||||
|
export type MapViewport = { zoom: 1; x: 0; y: 0 };
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@import './eve-common-variables';
|
@use './eve-common-variables';
|
||||||
@import './eve-common';
|
@use './eve-common';
|
||||||
|
|
||||||
.default-theme {
|
.default-theme {
|
||||||
--rf-bg-color: #0C0A09;
|
--rf-bg-color: #0C0A09;
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
|
@use "sass:color";
|
||||||
|
|
||||||
$friendlyBase: #3bbd39;
|
$friendlyBase: #3bbd39;
|
||||||
$friendlyAlpha: #3bbd3952;
|
$friendlyAlpha: #3bbd3952;
|
||||||
$friendlyDark20: darken($friendlyBase, 20%);
|
$friendlyDark20: color.adjust($friendlyBase, $lightness: -20%);
|
||||||
$friendlyDark30: darken($friendlyBase, 30%);
|
$friendlyDark30: color.adjust($friendlyBase, $lightness: -30%);
|
||||||
$friendlyDark5: darken($friendlyBase, 5%);
|
$friendlyDark5: color.adjust($friendlyBase, $lightness: -5%);
|
||||||
|
|
||||||
$lookingForBase: #43c2fd;
|
$lookingForBase: #43c2fd;
|
||||||
$lookingForAlpha: rgba(67, 176, 253, 0.48);
|
$lookingForAlpha: rgba(67, 176, 253, 0.48);
|
||||||
$lookingForDark15: darken($lookingForBase, 15%);
|
$lookingForDark15: color.adjust($lookingForBase, $lightness: -15%);
|
||||||
|
|
||||||
$homeBase: rgb(179, 253, 67);
|
$homeBase: rgb(179, 253, 67);
|
||||||
$homeAlpha: rgba(186, 248, 48, 0.32);
|
$homeAlpha: rgba(186, 248, 48, 0.32);
|
||||||
$homeBackground: #a0fa5636;
|
$homeBackground: #a0fa5636;
|
||||||
$homeDark30: darken($homeBase, 30%);
|
$homeDark30: color.adjust($homeBase, $lightness: -30%);
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--pastel-blue: #5a7d9a;
|
--pastel-blue: #5a7d9a;
|
||||||
@@ -117,6 +118,7 @@ $homeDark30: darken($homeBase, 30%);
|
|||||||
|
|
||||||
--conn-time-eol: #7452c3e3;
|
--conn-time-eol: #7452c3e3;
|
||||||
--conn-frigate: #325d88;
|
--conn-frigate: #325d88;
|
||||||
|
--conn-bridge: rgba(135, 185, 93, 0.85);
|
||||||
--conn-save: rgba(155, 102, 45, 0.85);
|
--conn-save: rgba(155, 102, 45, 0.85);
|
||||||
--selected-item-bg: rgba(98, 98, 98, 0.33);
|
--selected-item-bg: rgba(98, 98, 98, 0.33);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import './eve-common-variables';
|
@use './eve-common-variables';
|
||||||
|
|
||||||
|
|
||||||
.eve-wh-effect-color-pulsar {
|
.eve-wh-effect-color-pulsar {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
@import './default-theme.scss';
|
@use './default-theme.scss';
|
||||||
@import './pathfinder-theme.scss';
|
@use './pathfinder-theme.scss';
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
@import './eve-common-variables';
|
@use "sass:color";
|
||||||
@import './eve-common';
|
@use './eve-common-variables';
|
||||||
|
@use './eve-common';
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Oxygen:wght@300;400;700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Oxygen:wght@300;400;700&display=swap');
|
||||||
|
|
||||||
$homeBase: rgb(197, 253, 67);
|
$homeBase: rgb(197, 253, 67);
|
||||||
$homeAlpha: rgba(197, 253, 67, 0.32);
|
$homeAlpha: rgba(197, 253, 67, 0.32);
|
||||||
$homeDark30: darken($homeBase, 30%);
|
$homeDark30: color.adjust($homeBase, $lightness: -30%);
|
||||||
|
|
||||||
.pathfinder-theme {
|
.pathfinder-theme {
|
||||||
/* -- Override values from the default theme -- */
|
/* -- Override values from the default theme -- */
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
$pastel-blue: #5a7d9a;
|
||||||
|
$pastel-pink: rgb(30, 161, 255);
|
||||||
|
$dark-bg: #2d2d2d;
|
||||||
|
$text-color: #ffffff;
|
||||||
|
$tooltip-bg: #202020;
|
||||||
|
|
||||||
|
$neon-color-1: rgb(27, 132, 236);
|
||||||
|
$neon-color-3: rgba(27, 132, 236, 0.40);
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import { Dialog } from 'primereact/dialog';
|
import { SystemViewStandalone, WdButton, WHClassView, WHEffectView } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { IconField } from 'primereact/iconfield';
|
|
||||||
import { AutoComplete } from 'primereact/autocomplete';
|
|
||||||
import { OutCommand, SearchSystemItem } from '@/hooks/Mapper/types';
|
import { OutCommand, SearchSystemItem } from '@/hooks/Mapper/types';
|
||||||
import { SystemViewStandalone, WHClassView, WHEffectView } from '@/hooks/Mapper/components/ui-kit';
|
import { AutoComplete } from 'primereact/autocomplete';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { IconField } from 'primereact/iconfield';
|
||||||
|
import { useCallback, useRef, useState } from 'react';
|
||||||
import classes from './AddSystemDialog.module.scss';
|
import classes from './AddSystemDialog.module.scss';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace.ts';
|
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace.ts';
|
||||||
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
export type SearchOnSubmitCallback = (item: SearchSystemItem) => void;
|
export type SearchOnSubmitCallback = (item: SearchSystemItem) => void;
|
||||||
|
|
||||||
@@ -34,6 +33,7 @@ export const AddSystemDialog = ({
|
|||||||
data: { wormholesData },
|
data: { wormholesData },
|
||||||
} = useMapRootState();
|
} = useMapRootState();
|
||||||
|
|
||||||
|
// TODO fix it
|
||||||
const inputRef = useRef<any>();
|
const inputRef = useRef<any>();
|
||||||
const onShow = useCallback(() => {
|
const onShow = useCallback(() => {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
@@ -62,6 +62,7 @@ export const AddSystemDialog = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO fix it
|
||||||
let prepared = (result.systems as SearchSystemItem[]).sort((a, b) => {
|
let prepared = (result.systems as SearchSystemItem[]).sort((a, b) => {
|
||||||
const amatch = a.label.indexOf(query);
|
const amatch = a.label.indexOf(query);
|
||||||
const bmatch = b.label.indexOf(query);
|
const bmatch = b.label.indexOf(query);
|
||||||
@@ -114,90 +115,93 @@ export const AddSystemDialog = ({
|
|||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-3 px-1.5">
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="flex flex-col gap-2 py-3.5">
|
<div className="flex flex-col gap-3 px-1.5">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-2 py-3.5">
|
||||||
<IconField>
|
<div className="flex flex-col gap-1">
|
||||||
<AutoComplete
|
<IconField>
|
||||||
ref={inputRef}
|
<AutoComplete
|
||||||
multiple
|
ref={inputRef}
|
||||||
showEmptyMessage
|
multiple
|
||||||
scrollHeight="300px"
|
showEmptyMessage
|
||||||
value={selectedItem}
|
scrollHeight="300px"
|
||||||
suggestions={filteredItems}
|
value={selectedItem}
|
||||||
completeMethod={searchItems}
|
suggestions={filteredItems}
|
||||||
onChange={e => {
|
completeMethod={searchItems}
|
||||||
setSelectedItem(e.value.length < 2 ? e.value : [e.value[e.value.length - 1]]);
|
onChange={e => {
|
||||||
}}
|
setSelectedItem(e.value.length < 2 ? e.value : [e.value[e.value.length - 1]]);
|
||||||
emptyMessage="Not found any system..."
|
}}
|
||||||
placeholder="Type here..."
|
emptyMessage="Not found any system..."
|
||||||
field="label"
|
placeholder="Type here..."
|
||||||
id="value"
|
field="label"
|
||||||
className="w-full"
|
id="value"
|
||||||
itemTemplate={(item: SearchSystemItem) => {
|
className="w-full"
|
||||||
const { security, system_class, effect_power, effect_name, statics } = item.system_static_info;
|
itemTemplate={(item: SearchSystemItem) => {
|
||||||
const sortedStatics = sortWHClasses(wormholesData, statics);
|
const { security, system_class, effect_power, effect_name, statics } = item.system_static_info;
|
||||||
const isWH = isWormholeSpace(system_class);
|
const sortedStatics = sortWHClasses(wormholesData, statics);
|
||||||
|
const isWH = isWormholeSpace(system_class);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex gap-1.5', classes.SearchItem)}>
|
<div className={clsx('flex gap-1.5', classes.SearchItem)}>
|
||||||
<SystemViewStandalone
|
<SystemViewStandalone
|
||||||
security={security}
|
security={security}
|
||||||
system_class={system_class}
|
system_class={system_class}
|
||||||
solar_system_id={item.value}
|
solar_system_id={item.value}
|
||||||
class_title={item.class_title}
|
class_title={item.class_title}
|
||||||
solar_system_name={item.label}
|
solar_system_name={item.label}
|
||||||
region_name={item.region_name}
|
region_name={item.region_name}
|
||||||
/>
|
|
||||||
|
|
||||||
{effect_name && isWH && (
|
|
||||||
<WHEffectView
|
|
||||||
effectName={effect_name}
|
|
||||||
effectPower={effect_power}
|
|
||||||
className={classes.SearchItemEffect}
|
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
{isWH && (
|
{effect_name && isWH && (
|
||||||
<div className="flex gap-1 grow justify-between">
|
<WHEffectView
|
||||||
<div></div>
|
effectName={effect_name}
|
||||||
<div className="flex gap-1">
|
effectPower={effect_power}
|
||||||
{sortedStatics.map(x => (
|
className={classes.SearchItemEffect}
|
||||||
<WHClassView key={x} whClassName={x} />
|
/>
|
||||||
))}
|
)}
|
||||||
|
|
||||||
|
{isWH && (
|
||||||
|
<div className="flex gap-1 grow justify-between">
|
||||||
|
<div></div>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
{sortedStatics.map(x => (
|
||||||
|
<WHClassView key={x} whClassName={x} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
}}
|
||||||
}}
|
selectedItemTemplate={(item: SearchSystemItem) => (
|
||||||
selectedItemTemplate={(item: SearchSystemItem) => (
|
<SystemViewStandalone
|
||||||
<SystemViewStandalone
|
security={item.system_static_info.security}
|
||||||
security={item.system_static_info.security}
|
system_class={item.system_static_info.system_class}
|
||||||
system_class={item.system_static_info.system_class}
|
solar_system_id={item.value}
|
||||||
solar_system_id={item.value}
|
class_title={item.class_title}
|
||||||
class_title={item.class_title}
|
solar_system_name={item.label}
|
||||||
solar_system_name={item.label}
|
region_name={item.region_name}
|
||||||
region_name={item.region_name}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
</IconField>
|
||||||
</IconField>
|
|
||||||
|
|
||||||
<span className="text-[12px] text-stone-400 ml-1">*to search type at least 2 symbols.</span>
|
<span className="text-[12px] text-stone-400 ml-1">*to search type at least 2 symbols.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-2 justify-end">
|
||||||
|
<WdButton
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
outlined
|
||||||
|
disabled={!selectedItem || selectedItem.length !== 1}
|
||||||
|
size="small"
|
||||||
|
label="Submit"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
<div className="flex gap-2 justify-end">
|
|
||||||
<Button
|
|
||||||
onClick={handleSubmit}
|
|
||||||
outlined
|
|
||||||
disabled={!selectedItem || selectedItem.length !== 1}
|
|
||||||
size="small"
|
|
||||||
label="Submit"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
SystemView,
|
SystemView,
|
||||||
TimeAgo,
|
TimeAgo,
|
||||||
TooltipPosition,
|
TooltipPosition,
|
||||||
|
WdButton,
|
||||||
WdImgButton,
|
WdImgButton,
|
||||||
WdImgButtonTooltip,
|
WdImgButtonTooltip,
|
||||||
} from '@/hooks/Mapper/components/ui-kit';
|
} from '@/hooks/Mapper/components/ui-kit';
|
||||||
@@ -13,7 +14,6 @@ import { PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
|||||||
import { Commands, OutCommand, PingType } from '@/hooks/Mapper/types';
|
import { Commands, OutCommand, PingType } from '@/hooks/Mapper/types';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
@@ -256,7 +256,7 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
|
|||||||
)}
|
)}
|
||||||
></Toast>
|
></Toast>
|
||||||
|
|
||||||
<Button
|
<WdButton
|
||||||
icon="pi pi-bell"
|
icon="pi pi-bell"
|
||||||
severity="warning"
|
severity="warning"
|
||||||
aria-label="Notification"
|
aria-label="Notification"
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { InputText } from 'primereact/inputtext';
|
import { TooltipPosition, WdButton, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { Dialog } from 'primereact/dialog';
|
|
||||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
import { IconField } from 'primereact/iconfield';
|
|
||||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||||
import { WdImageSize, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { IconField } from 'primereact/iconfield';
|
||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
interface SystemCustomLabelDialog {
|
interface SystemCustomLabelDialog {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
@@ -126,7 +125,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
<WdButton type="submit" onClick={handleSave} outlined size="small" label="Save"></WdButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import {
|
|||||||
} from '@/hooks/Mapper/components/map/constants.ts';
|
} from '@/hooks/Mapper/components/map/constants.ts';
|
||||||
import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent';
|
import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent';
|
||||||
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
||||||
import { getWhSize } from '@/hooks/Mapper/helpers/getWhSize';
|
import { SETTINGS_KEYS, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
||||||
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo';
|
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { CommandLinkSignatureToSystem, SignatureGroup, SystemSignature, TimeStatus } from '@/hooks/Mapper/types';
|
import { CommandLinkSignatureToSystem, SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
|
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||||
import { SETTINGS_KEYS, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
import { useSystemSignaturesData } from '../../widgets/SystemSignatures/hooks/useSystemSignaturesData';
|
||||||
|
|
||||||
const K162_SIGNATURE_TYPE = WORMHOLES_ADDITIONAL_INFO_BY_SHORT_NAME['K162'].shortName;
|
const K162_SIGNATURE_TYPE = WORMHOLES_ADDITIONAL_INFO_BY_SHORT_NAME['K162'].shortName;
|
||||||
|
|
||||||
@@ -116,14 +116,14 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSelect = useCallback(
|
const handleSelect = useCallback(
|
||||||
async (signature: SystemSignature) => {
|
(signature: SystemSignature) => {
|
||||||
if (!signature) {
|
if (!signature) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { outCommand } = ref.current;
|
const { outCommand } = ref.current;
|
||||||
|
|
||||||
await outCommand({
|
outCommand({
|
||||||
type: OutCommand.linkSignatureToSystem,
|
type: OutCommand.linkSignatureToSystem,
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
@@ -131,34 +131,16 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parseSignatureCustomInfo(signature.custom_info).isEOL === true) {
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateConnectionTimeStatus,
|
|
||||||
data: {
|
|
||||||
source: data.solar_system_source,
|
|
||||||
target: data.solar_system_target,
|
|
||||||
value: TimeStatus.eol,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const whShipSize = getWhSize(wormholes, signature.type);
|
|
||||||
if (whShipSize !== undefined && whShipSize !== null) {
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateConnectionShipSizeType,
|
|
||||||
data: {
|
|
||||||
source: data.solar_system_source,
|
|
||||||
target: data.solar_system_target,
|
|
||||||
value: whShipSize,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
},
|
},
|
||||||
[data, setVisible, wormholes],
|
[data, setVisible],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { signatures } = useSystemSignaturesData({
|
||||||
|
systemId: `${data.solar_system_source}`,
|
||||||
|
settings: LINK_SIGNTATURE_SETTINGS,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!targetSystemDynamicInfo) {
|
if (!targetSystemDynamicInfo) {
|
||||||
handleHide();
|
handleHide();
|
||||||
@@ -176,10 +158,12 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
|
|||||||
>
|
>
|
||||||
<SystemSignaturesContent
|
<SystemSignaturesContent
|
||||||
systemId={`${data.solar_system_source}`}
|
systemId={`${data.solar_system_source}`}
|
||||||
hideLinkedSignatures
|
signatures={signatures}
|
||||||
|
hasUnsupportedLanguage={false}
|
||||||
settings={LINK_SIGNTATURE_SETTINGS}
|
settings={LINK_SIGNTATURE_SETTINGS}
|
||||||
|
hideLinkedSignatures
|
||||||
|
selectable
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
selectable={true}
|
|
||||||
filterSignature={filterSignature}
|
filterSignature={filterSignature}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { InputTextarea } from 'primereact/inputtextarea';
|
import { SystemView, WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { Dialog } from 'primereact/dialog';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
import { PingType } from '@/hooks/Mapper/types/ping.ts';
|
import { PingType } from '@/hooks/Mapper/types/ping.ts';
|
||||||
import { SystemView } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { InputTextarea } from 'primereact/inputtextarea';
|
||||||
|
import { useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
const PING_TITLES = {
|
const PING_TITLES = {
|
||||||
[PingType.Rally]: 'RALLY',
|
[PingType.Rally]: 'RALLY',
|
||||||
@@ -63,7 +62,7 @@ export const SystemPingDialog = ({ systemId, type, visible, setVisible }: System
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
draggable={false}
|
draggable={true}
|
||||||
style={{ width: '450px' }}
|
style={{ width: '450px' }}
|
||||||
onShow={onShow}
|
onShow={onShow}
|
||||||
onHide={() => {
|
onHide={() => {
|
||||||
@@ -92,7 +91,7 @@ export const SystemPingDialog = ({ systemId, type, visible, setVisible }: System
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button onClick={handleSave} size="small" severity="danger" label="Ping!"></Button>
|
<WdButton type="submit" onClick={handleSave} size="small" severity="danger" label="Ping!" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { InputText } from 'primereact/inputtext';
|
import { TooltipPosition, WdButton, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { InputTextarea } from 'primereact/inputtextarea';
|
|
||||||
import { Dialog } from 'primereact/dialog';
|
|
||||||
import { getSystemById } from '@/hooks/Mapper/helpers';
|
import { getSystemById } from '@/hooks/Mapper/helpers';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
|
||||||
import { IconField } from 'primereact/iconfield';
|
|
||||||
import { TooltipPosition, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
|
||||||
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic';
|
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic';
|
||||||
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
|
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { IconField } from 'primereact/iconfield';
|
||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
import { InputTextarea } from 'primereact/inputtextarea';
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
interface SystemSettingsDialog {
|
interface SystemSettingsDialog {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
@@ -114,7 +113,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
|||||||
<Dialog
|
<Dialog
|
||||||
header="System settings"
|
header="System settings"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
draggable={false}
|
draggable={true}
|
||||||
style={{ width: '450px' }}
|
style={{ width: '450px' }}
|
||||||
onShow={onShow}
|
onShow={onShow}
|
||||||
onHide={() => {
|
onHide={() => {
|
||||||
@@ -126,7 +125,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<form onSubmit={handleSave}>
|
<form onSubmit={handleSave}>
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3 px-2">
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<label htmlFor="username">Custom name</label>
|
<label htmlFor="username">Custom name</label>
|
||||||
@@ -226,7 +225,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
<WdButton onClick={handleSave} outlined size="small" label="Save" type="submit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
import { useRouteProvider } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
|
||||||
|
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import { RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import {
|
|
||||||
RoutesType,
|
|
||||||
useRouteProvider,
|
|
||||||
} from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
|
|
||||||
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
|
||||||
|
|
||||||
interface RoutesSettingsDialog {
|
interface RoutesSettingsDialog {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -83,7 +81,7 @@ export const RoutesSettingsDialog = ({ visible, setVisible }: RoutesSettingsDial
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button onClick={handleSave} outlined size="small" label="Apply"></Button>
|
<WdButton onClick={handleSave} outlined size="small" label="Apply"></WdButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|||||||
import { RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
import { RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
import { LoadRoutesCommand } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/types.ts';
|
import { LoadRoutesCommand } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/types.ts';
|
||||||
import { RoutesList } from '@/hooks/Mapper/types/routes.ts';
|
import { RoutesList } from '@/hooks/Mapper/types/routes.ts';
|
||||||
|
import { flattenValues } from '@/hooks/Mapper/utils/flattenValues.ts';
|
||||||
|
|
||||||
function usePrevious<T>(value: T): T | undefined {
|
function usePrevious<T>(value: T): T | undefined {
|
||||||
const ref = useRef<T>();
|
const ref = useRef<T>();
|
||||||
@@ -64,12 +65,8 @@ export const useLoadRoutes = ({
|
|||||||
systems?.length,
|
systems?.length,
|
||||||
connections,
|
connections,
|
||||||
hubs,
|
hubs,
|
||||||
routesSettings,
|
// we need make it flat recursively
|
||||||
...Object.keys(routesSettings)
|
...flattenValues(routesSettings),
|
||||||
.sort()
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-expect-error
|
|
||||||
.map(x => routesSettings[x]),
|
|
||||||
...deps,
|
...deps,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { SystemSettingsDialog } from '@/hooks/Mapper/components/mapInterface/components/SystemSettingsDialog/SystemSettingsDialog.tsx';
|
||||||
import { LayoutEventBlocker, SystemView, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
import { LayoutEventBlocker, SystemView, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { SystemInfoContent } from './SystemInfoContent';
|
import { ANOIK_ICON, DOTLAN_ICON, ZKB_ICON } from '@/hooks/Mapper/icons';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { SystemSettingsDialog } from '@/hooks/Mapper/components/mapInterface/components/SystemSettingsDialog/SystemSettingsDialog.tsx';
|
import { SystemInfoContent } from './SystemInfoContent';
|
||||||
import { ANOIK_ICON, DOTLAN_ICON, ZKB_ICON } from '@/hooks/Mapper/icons';
|
|
||||||
import { getSystemStaticInfo } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic';
|
|
||||||
|
|
||||||
export const SystemInfo = () => {
|
export const SystemInfo = () => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
@@ -48,7 +48,7 @@ export const SystemInfo = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LayoutEventBlocker className="flex gap-1 items-center">
|
<LayoutEventBlocker className="flex gap-1 items-center">
|
||||||
<a href={`https://zkillboard.com/system/${systemId}`} rel="noreferrer" target="_blank">
|
<a href={`https://zkillboard.com/system/${systemId}/`} rel="noreferrer" target="_blank">
|
||||||
<img src={ZKB_ICON} width="14" height="14" className="external-icon" />
|
<img src={ZKB_ICON} width="14" height="14" className="external-icon" />
|
||||||
</a>
|
</a>
|
||||||
<a href={`http://anoik.is/systems/${solarSystemName}`} rel="noreferrer" target="_blank">
|
<a href={`http://anoik.is/systems/${solarSystemName}`} rel="noreferrer" target="_blank">
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { TabPanel, TabView } from 'primereact/tabview';
|
import { TabPanel, TabView } from 'primereact/tabview';
|
||||||
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/components';
|
||||||
import { Dropdown } from 'primereact/dropdown';
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
@@ -10,6 +9,7 @@ import {
|
|||||||
SIGNATURE_SETTINGS,
|
SIGNATURE_SETTINGS,
|
||||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
|
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
|
||||||
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
interface SystemSignatureSettingsDialogProps {
|
interface SystemSignatureSettingsDialogProps {
|
||||||
settings: SignatureSettingsType;
|
settings: SignatureSettingsType;
|
||||||
@@ -92,7 +92,7 @@ export const SystemSignatureSettingsDialog = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
<WdButton onClick={handleSave} outlined size="small" label="Save" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -1,123 +1,16 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
||||||
|
import { SETTINGS_KEYS, SIGNATURE_WINDOW_ID, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
||||||
|
import { useHotkey } from '@/hooks/Mapper/hooks/useHotkey';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import { useSignatureUndo } from './hooks/useSignatureUndo';
|
||||||
|
import { useSystemSignaturesData } from './hooks/useSystemSignaturesData';
|
||||||
|
import { SystemSignaturesHeader } from './SystemSignatureHeader';
|
||||||
import { SystemSignaturesContent } from './SystemSignaturesContent';
|
import { SystemSignaturesContent } from './SystemSignaturesContent';
|
||||||
import { SystemSignatureSettingsDialog } from './SystemSignatureSettingsDialog';
|
import { SystemSignatureSettingsDialog } from './SystemSignatureSettingsDialog';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
import { SystemSignaturesHeader } from './SystemSignatureHeader';
|
|
||||||
import { useHotkey } from '@/hooks/Mapper/hooks/useHotkey';
|
|
||||||
import { getDeletionTimeoutMs } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
|
|
||||||
import { OutCommand, OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers';
|
|
||||||
import { ExtendedSystemSignature } from '@/hooks/Mapper/types';
|
|
||||||
import { SETTINGS_KEYS, SIGNATURE_WINDOW_ID, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom hook for managing pending signature deletions and undo countdown.
|
|
||||||
*/
|
|
||||||
function useSignatureUndo(
|
|
||||||
systemId: string | undefined,
|
|
||||||
settings: SignatureSettingsType,
|
|
||||||
outCommand: OutCommandHandler,
|
|
||||||
) {
|
|
||||||
const [countdown, setCountdown] = useState<number>(0);
|
|
||||||
const [pendingIds, setPendingIds] = useState<Set<string>>(new Set());
|
|
||||||
const [deletedSignatures, setDeletedSignatures] = useState<ExtendedSystemSignature[]>([]);
|
|
||||||
const intervalRef = useRef<number | null>(null);
|
|
||||||
|
|
||||||
const addDeleted = useCallback((signatures: ExtendedSystemSignature[]) => {
|
|
||||||
const newIds = signatures.map(sig => sig.eve_id);
|
|
||||||
setPendingIds(prev => {
|
|
||||||
const next = new Set(prev);
|
|
||||||
newIds.forEach(id => next.add(id));
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
setDeletedSignatures(prev => [...prev, ...signatures]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Clear deleted signatures when system changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (systemId) {
|
|
||||||
setDeletedSignatures([]);
|
|
||||||
setPendingIds(new Set());
|
|
||||||
setCountdown(0);
|
|
||||||
if (intervalRef.current != null) {
|
|
||||||
clearInterval(intervalRef.current);
|
|
||||||
intervalRef.current = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [systemId]);
|
|
||||||
|
|
||||||
// kick off or clear countdown whenever pendingIds changes
|
|
||||||
useEffect(() => {
|
|
||||||
// clear any existing timer
|
|
||||||
if (intervalRef.current != null) {
|
|
||||||
clearInterval(intervalRef.current);
|
|
||||||
intervalRef.current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pendingIds.size === 0) {
|
|
||||||
setCountdown(0);
|
|
||||||
setDeletedSignatures([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine timeout from settings
|
|
||||||
const timeoutMs = getDeletionTimeoutMs(settings);
|
|
||||||
|
|
||||||
// Ensure a minimum of 1 second for immediate deletion so the UI shows
|
|
||||||
const effectiveTimeoutMs = timeoutMs === 0 ? 1000 : timeoutMs;
|
|
||||||
|
|
||||||
setCountdown(Math.ceil(effectiveTimeoutMs / 1000));
|
|
||||||
|
|
||||||
// start new interval
|
|
||||||
intervalRef.current = window.setInterval(() => {
|
|
||||||
setCountdown(prev => {
|
|
||||||
if (prev <= 1) {
|
|
||||||
clearInterval(intervalRef.current!);
|
|
||||||
intervalRef.current = null;
|
|
||||||
setPendingIds(new Set());
|
|
||||||
setDeletedSignatures([]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return prev - 1;
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (intervalRef.current != null) {
|
|
||||||
clearInterval(intervalRef.current);
|
|
||||||
intervalRef.current = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [pendingIds, settings]);
|
|
||||||
|
|
||||||
// undo handler
|
|
||||||
const handleUndo = useCallback(async () => {
|
|
||||||
if (!systemId || pendingIds.size === 0) return;
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.undoDeleteSignatures,
|
|
||||||
data: { system_id: systemId, eve_ids: Array.from(pendingIds) },
|
|
||||||
});
|
|
||||||
setPendingIds(new Set());
|
|
||||||
setDeletedSignatures([]);
|
|
||||||
setCountdown(0);
|
|
||||||
if (intervalRef.current != null) {
|
|
||||||
clearInterval(intervalRef.current);
|
|
||||||
intervalRef.current = null;
|
|
||||||
}
|
|
||||||
}, [systemId, pendingIds, outCommand]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
pendingIds,
|
|
||||||
countdown,
|
|
||||||
deletedSignatures,
|
|
||||||
addDeleted,
|
|
||||||
handleUndo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SystemSignatures = () => {
|
export const SystemSignatures = () => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
const [sigCount, setSigCount] = useState(0);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { selectedSystems },
|
data: { selectedSystems },
|
||||||
@@ -127,31 +20,6 @@ export const SystemSignatures = () => {
|
|||||||
|
|
||||||
const [systemId] = selectedSystems;
|
const [systemId] = selectedSystems;
|
||||||
const isSystemSelected = useMemo(() => selectedSystems.length === 1, [selectedSystems.length]);
|
const isSystemSelected = useMemo(() => selectedSystems.length === 1, [selectedSystems.length]);
|
||||||
const { pendingIds, countdown, deletedSignatures, addDeleted, handleUndo } = useSignatureUndo(
|
|
||||||
systemId,
|
|
||||||
settingsSignatures,
|
|
||||||
outCommand,
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkey(true, ['z', 'Z'], (event: KeyboardEvent) => {
|
|
||||||
if (pendingIds.size > 0 && countdown > 0) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
handleUndo();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCountChange = useCallback((count: number) => {
|
|
||||||
setSigCount(count);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSettingsSave = useCallback(
|
|
||||||
(newSettings: SignatureSettingsType) => {
|
|
||||||
settingsSignaturesUpdate(newSettings);
|
|
||||||
setVisible(false);
|
|
||||||
},
|
|
||||||
[settingsSignaturesUpdate],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleLazyDeleteToggle = useCallback(
|
const handleLazyDeleteToggle = useCallback(
|
||||||
(value: boolean) => {
|
(value: boolean) => {
|
||||||
@@ -163,7 +31,42 @@ export const SystemSignatures = () => {
|
|||||||
[settingsSignaturesUpdate],
|
[settingsSignaturesUpdate],
|
||||||
);
|
);
|
||||||
|
|
||||||
const openSettings = useCallback(() => setVisible(true), []);
|
const {
|
||||||
|
signatures,
|
||||||
|
selectedSignatures,
|
||||||
|
setSelectedSignatures,
|
||||||
|
handleDeleteSelected,
|
||||||
|
handleSelectAll,
|
||||||
|
handlePaste,
|
||||||
|
hasUnsupportedLanguage,
|
||||||
|
} = useSystemSignaturesData({
|
||||||
|
systemId,
|
||||||
|
settings: settingsSignatures,
|
||||||
|
onLazyDeleteChange: handleLazyDeleteToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sigCount = useMemo(() => signatures.length, [signatures]);
|
||||||
|
const deletedSignatures = useMemo(() => signatures.filter(s => s.deleted), [signatures]);
|
||||||
|
|
||||||
|
const { countdown, handleUndo } = useSignatureUndo(systemId, settingsSignatures, deletedSignatures, outCommand);
|
||||||
|
|
||||||
|
useHotkey(true, ['z', 'Z'], (event: KeyboardEvent) => {
|
||||||
|
if (deletedSignatures.length > 0 && countdown > 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
handleUndo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSettingsSave = useCallback(
|
||||||
|
(newSettings: SignatureSettingsType) => {
|
||||||
|
settingsSignaturesUpdate(newSettings);
|
||||||
|
setShowSettings(false);
|
||||||
|
},
|
||||||
|
[settingsSignaturesUpdate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const openSettings = useCallback(() => setShowSettings(true), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Widget
|
<Widget
|
||||||
@@ -171,7 +74,7 @@ export const SystemSignatures = () => {
|
|||||||
<SystemSignaturesHeader
|
<SystemSignaturesHeader
|
||||||
sigCount={sigCount}
|
sigCount={sigCount}
|
||||||
lazyDeleteValue={settingsSignatures[SETTINGS_KEYS.LAZY_DELETE_SIGNATURES] as boolean}
|
lazyDeleteValue={settingsSignatures[SETTINGS_KEYS.LAZY_DELETE_SIGNATURES] as boolean}
|
||||||
pendingCount={pendingIds.size}
|
pendingCount={deletedSignatures.length}
|
||||||
undoCountdown={countdown}
|
undoCountdown={countdown}
|
||||||
onLazyDeleteChange={handleLazyDeleteToggle}
|
onLazyDeleteChange={handleLazyDeleteToggle}
|
||||||
onUndoClick={handleUndo}
|
onUndoClick={handleUndo}
|
||||||
@@ -187,18 +90,21 @@ export const SystemSignatures = () => {
|
|||||||
) : (
|
) : (
|
||||||
<SystemSignaturesContent
|
<SystemSignaturesContent
|
||||||
systemId={systemId}
|
systemId={systemId}
|
||||||
|
signatures={signatures}
|
||||||
|
selectedSignatures={selectedSignatures}
|
||||||
|
onSelectSignatures={setSelectedSignatures}
|
||||||
|
onDeleteSelected={handleDeleteSelected}
|
||||||
|
onSelectAll={handleSelectAll}
|
||||||
|
onPaste={handlePaste}
|
||||||
|
hasUnsupportedLanguage={hasUnsupportedLanguage}
|
||||||
settings={settingsSignatures}
|
settings={settingsSignatures}
|
||||||
deletedSignatures={deletedSignatures}
|
|
||||||
onLazyDeleteChange={handleLazyDeleteToggle}
|
|
||||||
onCountChange={handleCountChange}
|
|
||||||
onSignatureDeleted={addDeleted}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{visible && (
|
{showSettings && (
|
||||||
<SystemSignatureSettingsDialog
|
<SystemSignatureSettingsDialog
|
||||||
settings={settingsSignatures}
|
settings={settingsSignatures}
|
||||||
onCancel={() => setVisible(false)}
|
onCancel={() => setShowSettings(false)}
|
||||||
onSave={handleSettingsSave}
|
onSave={handleSettingsSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -28,39 +28,44 @@ import {
|
|||||||
renderInfoColumn,
|
renderInfoColumn,
|
||||||
renderUpdatedTimeLeft,
|
renderUpdatedTimeLeft,
|
||||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
||||||
|
import { SETTINGS_KEYS, SIGNATURE_WINDOW_ID, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
||||||
import { useClipboard, useHotkey } from '@/hooks/Mapper/hooks';
|
import { useClipboard, useHotkey } from '@/hooks/Mapper/hooks';
|
||||||
import useMaxWidth from '@/hooks/Mapper/hooks/useMaxWidth';
|
import useMaxWidth from '@/hooks/Mapper/hooks/useMaxWidth';
|
||||||
import { getSignatureRowClass } from '../helpers/rowStyles';
|
|
||||||
import { useSystemSignaturesData } from '../hooks/useSystemSignaturesData';
|
|
||||||
import { SETTINGS_KEYS, SIGNATURE_WINDOW_ID, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { getSignatureRowClass } from '../helpers/rowStyles';
|
||||||
|
|
||||||
const renderColIcon = (sig: SystemSignature) => renderIcon(sig);
|
const renderColIcon = (sig: SystemSignature) => renderIcon(sig);
|
||||||
|
|
||||||
interface SystemSignaturesContentProps {
|
interface SystemSignaturesContentProps {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
|
signatures: ExtendedSystemSignature[];
|
||||||
|
selectedSignatures?: ExtendedSystemSignature[];
|
||||||
|
onSelectSignatures?: (s: ExtendedSystemSignature[]) => void;
|
||||||
|
onDeleteSelected?: () => Promise<void>;
|
||||||
|
onSelectAll?: () => void;
|
||||||
|
onPaste?: (clipboardString: string) => void;
|
||||||
settings: SignatureSettingsType;
|
settings: SignatureSettingsType;
|
||||||
hideLinkedSignatures?: boolean;
|
hideLinkedSignatures?: boolean;
|
||||||
|
hasUnsupportedLanguage?: boolean;
|
||||||
selectable?: boolean;
|
selectable?: boolean;
|
||||||
onSelect?: (signature: SystemSignature) => void;
|
onSelect?: (signature: SystemSignature) => void;
|
||||||
onLazyDeleteChange?: (value: boolean) => void;
|
|
||||||
onCountChange?: (count: number) => void;
|
|
||||||
filterSignature?: (signature: SystemSignature) => boolean;
|
filterSignature?: (signature: SystemSignature) => boolean;
|
||||||
onSignatureDeleted?: (deletedSignatures: ExtendedSystemSignature[]) => void;
|
|
||||||
deletedSignatures?: ExtendedSystemSignature[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SystemSignaturesContent = ({
|
export const SystemSignaturesContent = ({
|
||||||
systemId,
|
systemId,
|
||||||
|
signatures,
|
||||||
|
selectedSignatures,
|
||||||
|
onSelectSignatures,
|
||||||
|
onDeleteSelected,
|
||||||
|
onSelectAll,
|
||||||
|
onPaste,
|
||||||
settings,
|
settings,
|
||||||
hideLinkedSignatures,
|
hideLinkedSignatures,
|
||||||
|
hasUnsupportedLanguage,
|
||||||
selectable,
|
selectable,
|
||||||
onSelect,
|
onSelect,
|
||||||
onLazyDeleteChange,
|
|
||||||
onCountChange,
|
|
||||||
filterSignature,
|
filterSignature,
|
||||||
onSignatureDeleted,
|
|
||||||
deletedSignatures = [],
|
|
||||||
}: SystemSignaturesContentProps) => {
|
}: SystemSignaturesContentProps) => {
|
||||||
const [selectedSignatureForDialog, setSelectedSignatureForDialog] = useState<SystemSignature | null>(null);
|
const [selectedSignatureForDialog, setSelectedSignatureForDialog] = useState<SystemSignature | null>(null);
|
||||||
const [showSignatureSettings, setShowSignatureSettings] = useState(false);
|
const [showSignatureSettings, setShowSignatureSettings] = useState(false);
|
||||||
@@ -79,32 +84,18 @@ export const SystemSignaturesContent = ({
|
|||||||
|
|
||||||
const { clipboardContent, setClipboardContent } = useClipboard();
|
const { clipboardContent, setClipboardContent } = useClipboard();
|
||||||
|
|
||||||
const {
|
const deletedSignatures = useMemo(() => signatures.filter(s => s.deleted), [signatures]);
|
||||||
signatures,
|
|
||||||
selectedSignatures,
|
|
||||||
setSelectedSignatures,
|
|
||||||
handleDeleteSelected,
|
|
||||||
handleSelectAll,
|
|
||||||
handlePaste,
|
|
||||||
hasUnsupportedLanguage,
|
|
||||||
} = useSystemSignaturesData({
|
|
||||||
systemId,
|
|
||||||
settings,
|
|
||||||
onCountChange,
|
|
||||||
onLazyDeleteChange,
|
|
||||||
onSignatureDeleted,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectable) return;
|
if (selectable) return;
|
||||||
if (!clipboardContent?.text) return;
|
if (!clipboardContent?.text) return;
|
||||||
|
|
||||||
handlePaste(clipboardContent.text);
|
onPaste?.(clipboardContent.text);
|
||||||
|
|
||||||
setClipboardContent(null);
|
setClipboardContent(null);
|
||||||
}, [selectable, clipboardContent, handlePaste, setClipboardContent]);
|
}, [selectable, clipboardContent, onPaste, setClipboardContent]);
|
||||||
|
|
||||||
useHotkey(true, ['a'], handleSelectAll);
|
useHotkey(true, ['a'], () => onSelectAll?.());
|
||||||
|
|
||||||
useHotkey(false, ['Backspace', 'Delete'], (event: KeyboardEvent) => {
|
useHotkey(false, ['Backspace', 'Delete'], (event: KeyboardEvent) => {
|
||||||
const targetWindow = (event.target as HTMLHtmlElement)?.closest(`[data-window-id="${SIGNATURE_WINDOW_ID}"]`);
|
const targetWindow = (event.target as HTMLHtmlElement)?.closest(`[data-window-id="${SIGNATURE_WINDOW_ID}"]`);
|
||||||
@@ -117,7 +108,7 @@ export const SystemSignaturesContent = ({
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
// Delete key should always immediately delete, never show pending deletions
|
// Delete key should always immediately delete, never show pending deletions
|
||||||
handleDeleteSelected();
|
onDeleteSelected?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleResize = useCallback(() => {
|
const handleResize = useCallback(() => {
|
||||||
@@ -152,14 +143,23 @@ export const SystemSignaturesContent = ({
|
|||||||
|
|
||||||
selectable
|
selectable
|
||||||
? onSelect?.(selectableSignatures[0])
|
? onSelect?.(selectableSignatures[0])
|
||||||
: setSelectedSignatures(selectableSignatures as ExtendedSystemSignature[]);
|
: onSelectSignatures?.(selectableSignatures as ExtendedSystemSignature[]);
|
||||||
},
|
},
|
||||||
[onSelect, selectable, setSelectedSignatures, deletedSignatures],
|
[onSelect, selectable, onSelectSignatures, deletedSignatures],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { showDescriptionColumn, showUpdatedColumn, showCharacterColumn, showCharacterPortrait } = useMemo(
|
const {
|
||||||
|
showGroupColumn,
|
||||||
|
showDescriptionColumn,
|
||||||
|
showAddedColumn,
|
||||||
|
showUpdatedColumn,
|
||||||
|
showCharacterColumn,
|
||||||
|
showCharacterPortrait,
|
||||||
|
} = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
showGroupColumn: settings[SETTINGS_KEYS.SHOW_GROUP_COLUMN] as boolean,
|
||||||
showDescriptionColumn: settings[SETTINGS_KEYS.SHOW_DESCRIPTION_COLUMN] as boolean,
|
showDescriptionColumn: settings[SETTINGS_KEYS.SHOW_DESCRIPTION_COLUMN] as boolean,
|
||||||
|
showAddedColumn: settings[SETTINGS_KEYS.SHOW_ADDED_COLUMN] as boolean,
|
||||||
showUpdatedColumn: settings[SETTINGS_KEYS.SHOW_UPDATED_COLUMN] as boolean,
|
showUpdatedColumn: settings[SETTINGS_KEYS.SHOW_UPDATED_COLUMN] as boolean,
|
||||||
showCharacterColumn: settings[SETTINGS_KEYS.SHOW_CHARACTER_COLUMN] as boolean,
|
showCharacterColumn: settings[SETTINGS_KEYS.SHOW_CHARACTER_COLUMN] as boolean,
|
||||||
showCharacterPortrait: settings[SETTINGS_KEYS.SHOW_CHARACTER_PORTRAIT] as boolean,
|
showCharacterPortrait: settings[SETTINGS_KEYS.SHOW_CHARACTER_PORTRAIT] as boolean,
|
||||||
@@ -168,9 +168,6 @@ export const SystemSignaturesContent = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const filteredSignatures = useMemo<ExtendedSystemSignature[]>(() => {
|
const filteredSignatures = useMemo<ExtendedSystemSignature[]>(() => {
|
||||||
// Get the set of deleted signature IDs for quick lookup
|
|
||||||
const deletedIds = new Set(deletedSignatures.map(sig => sig.eve_id));
|
|
||||||
|
|
||||||
// Common filter function
|
// Common filter function
|
||||||
const shouldShowSignature = (sig: ExtendedSystemSignature): boolean => {
|
const shouldShowSignature = (sig: ExtendedSystemSignature): boolean => {
|
||||||
if (filterSignature && !filterSignature(sig)) {
|
if (filterSignature && !filterSignature(sig)) {
|
||||||
@@ -204,24 +201,8 @@ export const SystemSignaturesContent = ({
|
|||||||
return settings[sig.kind] as boolean;
|
return settings[sig.kind] as boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Filter active signatures, excluding any that are in the deleted list
|
return signatures.filter(sig => shouldShowSignature(sig));
|
||||||
const activeSignatures = signatures.filter(sig => {
|
}, [signatures, hideLinkedSignatures, settings, filterSignature]);
|
||||||
// Skip if this signature is in the deleted list
|
|
||||||
if (deletedIds.has(sig.eve_id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shouldShowSignature(sig);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add deleted signatures with pending deletion flag, applying the same filters
|
|
||||||
const deletedWithPendingFlag = deletedSignatures.filter(shouldShowSignature).map(sig => ({
|
|
||||||
...sig,
|
|
||||||
pendingDeletion: true,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return [...activeSignatures, ...deletedWithPendingFlag];
|
|
||||||
}, [signatures, hideLinkedSignatures, settings, filterSignature, deletedSignatures]);
|
|
||||||
|
|
||||||
const onRowMouseEnter = useCallback((e: DataTableRowMouseEvent) => {
|
const onRowMouseEnter = useCallback((e: DataTableRowMouseEvent) => {
|
||||||
setHoveredSignature(e.data as SystemSignature);
|
setHoveredSignature(e.data as SystemSignature);
|
||||||
@@ -244,20 +225,18 @@ export const SystemSignaturesContent = ({
|
|||||||
|
|
||||||
return getSignatureRowClass(
|
return getSignatureRowClass(
|
||||||
rowData as ExtendedSystemSignature,
|
rowData as ExtendedSystemSignature,
|
||||||
refVars.current.selectedSignatures,
|
refVars.current.selectedSignatures || [],
|
||||||
refVars.current.settings[SETTINGS_KEYS.COLOR_BY_TYPE] as boolean,
|
refVars.current.settings[SETTINGS_KEYS.COLOR_BY_TYPE] as boolean,
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSortSettings = useCallback(
|
const handleSortSettings = useCallback((e: DataTableStateEvent) => {
|
||||||
(e: DataTableStateEvent) =>
|
refVars.current.settingsSignaturesUpdate({
|
||||||
refVars.current.settingsSignaturesUpdate({
|
...refVars.current.settingsSignatures,
|
||||||
...refVars.current.settingsSignatures,
|
[SETTINGS_KEYS.SORT_FIELD]: e.sortField,
|
||||||
[SETTINGS_KEYS.SORT_FIELD]: e.sortField,
|
[SETTINGS_KEYS.SORT_ORDER]: e.sortOrder,
|
||||||
[SETTINGS_KEYS.SORT_ORDER]: e.sortOrder,
|
});
|
||||||
}),
|
}, []);
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={tableRef} className="h-full">
|
<div ref={tableRef} className="h-full">
|
||||||
@@ -278,7 +257,7 @@ export const SystemSignaturesContent = ({
|
|||||||
value={filteredSignatures}
|
value={filteredSignatures}
|
||||||
size="small"
|
size="small"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
selection={selectedSignatures}
|
selection={selectedSignatures || []}
|
||||||
metaKeySelection
|
metaKeySelection
|
||||||
onSelectionChange={handleSelectSignatures}
|
onSelectionChange={handleSelectSignatures}
|
||||||
dataKey="eve_id"
|
dataKey="eve_id"
|
||||||
@@ -309,15 +288,17 @@ export const SystemSignaturesContent = ({
|
|||||||
style={{ maxWidth: 72, minWidth: 72, width: 72 }}
|
style={{ maxWidth: 72, minWidth: 72, width: 72 }}
|
||||||
sortable
|
sortable
|
||||||
/>
|
/>
|
||||||
<Column
|
{showGroupColumn && (
|
||||||
field="group"
|
<Column
|
||||||
header="Group"
|
field="group"
|
||||||
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
|
header="Group"
|
||||||
style={{ maxWidth: 110, minWidth: 110, width: 110 }}
|
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
|
||||||
body={sig => sig.group ?? ''}
|
style={{ maxWidth: 110, minWidth: 110, width: 110 }}
|
||||||
hidden={isCompact}
|
body={sig => sig.group ?? ''}
|
||||||
sortable
|
hidden={isCompact}
|
||||||
/>
|
sortable
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Column
|
<Column
|
||||||
field="info"
|
field="info"
|
||||||
header="Info"
|
header="Info"
|
||||||
@@ -325,6 +306,8 @@ export const SystemSignaturesContent = ({
|
|||||||
style={{ maxWidth: nameColumnWidth }}
|
style={{ maxWidth: nameColumnWidth }}
|
||||||
hidden={isCompact || isMedium}
|
hidden={isCompact || isMedium}
|
||||||
body={renderInfoColumn}
|
body={renderInfoColumn}
|
||||||
|
sortable
|
||||||
|
sortField="name"
|
||||||
/>
|
/>
|
||||||
{showDescriptionColumn && (
|
{showDescriptionColumn && (
|
||||||
<Column
|
<Column
|
||||||
@@ -336,15 +319,17 @@ export const SystemSignaturesContent = ({
|
|||||||
sortable
|
sortable
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Column
|
{showAddedColumn && (
|
||||||
field="inserted_at"
|
<Column
|
||||||
header="Added"
|
field="inserted_at"
|
||||||
dataType="date"
|
header="Added"
|
||||||
body={renderAddedTimeLeft}
|
dataType="date"
|
||||||
style={{ minWidth: 70, maxWidth: 80 }}
|
body={renderAddedTimeLeft}
|
||||||
bodyClassName="ssc-header text-ellipsis overflow-hidden whitespace-nowrap"
|
style={{ minWidth: 70, maxWidth: 80 }}
|
||||||
sortable
|
bodyClassName="ssc-header text-ellipsis overflow-hidden whitespace-nowrap"
|
||||||
/>
|
sortable
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showUpdatedColumn && (
|
{showUpdatedColumn && (
|
||||||
<Column
|
<Column
|
||||||
field="updated_at"
|
field="updated_at"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { SETTINGS_KEYS, SIGNATURES_DELETION_TIMING, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
||||||
import {
|
import {
|
||||||
GroupType,
|
GroupType,
|
||||||
SignatureGroup,
|
SignatureGroup,
|
||||||
@@ -11,7 +12,6 @@ import {
|
|||||||
SignatureKindFR,
|
SignatureKindFR,
|
||||||
SignatureKindRU,
|
SignatureKindRU,
|
||||||
} from '@/hooks/Mapper/types';
|
} from '@/hooks/Mapper/types';
|
||||||
import { SETTINGS_KEYS, SIGNATURES_DELETION_TIMING, SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
|
||||||
|
|
||||||
export const TIME_ONE_MINUTE = 1000 * 60;
|
export const TIME_ONE_MINUTE = 1000 * 60;
|
||||||
export const TIME_TEN_MINUTES = TIME_ONE_MINUTE * 10;
|
export const TIME_TEN_MINUTES = TIME_ONE_MINUTE * 10;
|
||||||
@@ -130,6 +130,8 @@ export const SIGNATURE_SETTINGS = {
|
|||||||
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.COMBAT_SITE, name: 'Show Combat Sites' },
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.COMBAT_SITE, name: 'Show Combat Sites' },
|
||||||
],
|
],
|
||||||
uiFlags: [
|
uiFlags: [
|
||||||
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_GROUP_COLUMN, name: 'Show Group Column' },
|
||||||
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_ADDED_COLUMN, name: 'Show Added Column' },
|
||||||
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_UPDATED_COLUMN, name: 'Show Updated Column' },
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_UPDATED_COLUMN, name: 'Show Updated Column' },
|
||||||
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_DESCRIPTION_COLUMN, name: 'Show Description Column' },
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_DESCRIPTION_COLUMN, name: 'Show Description Column' },
|
||||||
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_CHARACTER_COLUMN, name: 'Show Character Column' },
|
{ type: SettingsTypes.flag, key: SETTINGS_KEYS.SHOW_CHARACTER_COLUMN, name: 'Show Character Column' },
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import clsx from 'clsx';
|
|
||||||
import { ExtendedSystemSignature, SignatureGroup } from '@/hooks/Mapper/types';
|
import { ExtendedSystemSignature, SignatureGroup } from '@/hooks/Mapper/types';
|
||||||
|
import clsx from 'clsx';
|
||||||
import { getRowBackgroundColor } from './getRowBackgroundColor';
|
import { getRowBackgroundColor } from './getRowBackgroundColor';
|
||||||
import classes from './rowStyles.module.scss';
|
import classes from './rowStyles.module.scss';
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ export function getSignatureRowClass(
|
|||||||
return clsx([...baseCls, 'bg-violet-400/40 hover:bg-violet-300/40']);
|
return clsx([...baseCls, 'bg-violet-400/40 hover:bg-violet-300/40']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.pendingDeletion) {
|
if (row.deleted) {
|
||||||
return clsx([...baseCls, 'bg-red-400/40 hover:bg-red-400/50']);
|
return clsx([...baseCls, 'bg-red-400/40 hover:bg-red-400/50']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
import { ExtendedSystemSignature } from '@/hooks/Mapper/types';
|
|
||||||
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures.ts';
|
||||||
|
import { ExtendedSystemSignature } from '@/hooks/Mapper/types';
|
||||||
|
|
||||||
export interface UseSystemSignaturesDataProps {
|
export interface UseSystemSignaturesDataProps {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
settings: SignatureSettingsType;
|
settings: SignatureSettingsType;
|
||||||
hideLinkedSignatures?: boolean;
|
hideLinkedSignatures?: boolean;
|
||||||
onCountChange?: (count: number) => void;
|
onCountChange?: (count: number) => void;
|
||||||
onPendingChange?: (
|
|
||||||
pending: React.MutableRefObject<Record<string, ExtendedSystemSignature>>,
|
|
||||||
undo: () => void,
|
|
||||||
) => void;
|
|
||||||
onLazyDeleteChange?: (value: boolean) => void;
|
onLazyDeleteChange?: (value: boolean) => void;
|
||||||
deletionTiming?: number;
|
deletionTiming?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseFetchingParams {
|
export interface UseFetchingParams {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
|
settings: SignatureSettingsType;
|
||||||
signaturesRef: React.MutableRefObject<ExtendedSystemSignature[]>;
|
signaturesRef: React.MutableRefObject<ExtendedSystemSignature[]>;
|
||||||
setSignatures: React.Dispatch<React.SetStateAction<ExtendedSystemSignature[]>>;
|
setSignatures: React.Dispatch<React.SetStateAction<ExtendedSystemSignature[]>>;
|
||||||
pendingDeletionMapRef: React.MutableRefObject<Record<string, ExtendedSystemSignature>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UsePendingDeletionParams {
|
export interface UsePendingDeletionParams {
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
|
||||||
import { prepareUpdatePayload } from '../helpers';
|
|
||||||
import { UsePendingDeletionParams } from './types';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
import { ExtendedSystemSignature } from '@/hooks/Mapper/types';
|
|
||||||
|
|
||||||
export function usePendingDeletions({
|
|
||||||
systemId,
|
|
||||||
setSignatures,
|
|
||||||
onPendingChange,
|
|
||||||
}: Omit<UsePendingDeletionParams, 'deletionTiming'>) {
|
|
||||||
const { outCommand } = useMapRootState();
|
|
||||||
const pendingDeletionMapRef = useRef<Record<string, ExtendedSystemSignature>>({});
|
|
||||||
|
|
||||||
const processRemovedSignatures = useCallback(
|
|
||||||
async (
|
|
||||||
removed: ExtendedSystemSignature[],
|
|
||||||
added: ExtendedSystemSignature[],
|
|
||||||
updated: ExtendedSystemSignature[],
|
|
||||||
) => {
|
|
||||||
if (!removed.length) return;
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateSignatures,
|
|
||||||
data: prepareUpdatePayload(systemId, added, updated, removed),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[systemId, outCommand],
|
|
||||||
);
|
|
||||||
|
|
||||||
const clearPendingDeletions = useCallback(() => {
|
|
||||||
pendingDeletionMapRef.current = {};
|
|
||||||
setSignatures(prev => prev.map(x => (x.pendingDeletion ? { ...x, pendingDeletion: false } : x)));
|
|
||||||
onPendingChange?.(pendingDeletionMapRef, clearPendingDeletions);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
pendingDeletionMapRef,
|
|
||||||
processRemovedSignatures,
|
|
||||||
clearPendingDeletions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
import { useCallback } from 'react';
|
import { SETTINGS_KEYS } from '@/hooks/Mapper/constants/signatures';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { ExtendedSystemSignature, SystemSignature } from '@/hooks/Mapper/types';
|
import { ExtendedSystemSignature, SystemSignature } from '@/hooks/Mapper/types';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
||||||
import { prepareUpdatePayload, getActualSigs, mergeLocalPending } from '../helpers';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { getDeletionTimeoutMs } from '../constants';
|
||||||
|
import { getActualSigs, prepareUpdatePayload } from '../helpers';
|
||||||
import { UseFetchingParams } from './types';
|
import { UseFetchingParams } from './types';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
|
|
||||||
export const useSignatureFetching = ({
|
export const useSignatureFetching = ({ systemId, settings, signaturesRef, setSignatures }: UseFetchingParams) => {
|
||||||
systemId,
|
|
||||||
signaturesRef,
|
|
||||||
setSignatures,
|
|
||||||
pendingDeletionMapRef,
|
|
||||||
}: UseFetchingParams) => {
|
|
||||||
const {
|
const {
|
||||||
data: { characters },
|
data: { characters },
|
||||||
outCommand,
|
outCommand,
|
||||||
} = useMapRootState();
|
} = useMapRootState();
|
||||||
|
|
||||||
|
const deleteTimeout = useMemo(() => {
|
||||||
|
const lazyDelete = settings[SETTINGS_KEYS.LAZY_DELETE_SIGNATURES] as boolean;
|
||||||
|
if (!lazyDelete) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDeletionTimeoutMs(settings);
|
||||||
|
}, [settings]);
|
||||||
|
|
||||||
const handleGetSignatures = useCallback(async () => {
|
const handleGetSignatures = useCallback(async () => {
|
||||||
if (!systemId) {
|
if (!systemId) {
|
||||||
setSignatures([]);
|
setSignatures([]);
|
||||||
@@ -32,24 +38,23 @@ export const useSignatureFetching = ({
|
|||||||
character_name: characters.find(c => c.eve_id === s.character_eve_id)?.name,
|
character_name: characters.find(c => c.eve_id === s.character_eve_id)?.name,
|
||||||
})) as ExtendedSystemSignature[];
|
})) as ExtendedSystemSignature[];
|
||||||
|
|
||||||
setSignatures(() => mergeLocalPending(pendingDeletionMapRef, extended));
|
setSignatures(() => extended);
|
||||||
}, [characters, systemId, outCommand]);
|
}, [characters, systemId, outCommand]);
|
||||||
|
|
||||||
const handleUpdateSignatures = useCallback(
|
const handleUpdateSignatures = useCallback(
|
||||||
async (newList: ExtendedSystemSignature[], updateOnly: boolean, skipUpdateUntouched?: boolean) => {
|
async (newList: ExtendedSystemSignature[], updateOnly: boolean, skipUpdateUntouched?: boolean) => {
|
||||||
const { added, updated, removed } = getActualSigs(
|
const actualSigs = getActualSigs(signaturesRef.current, newList, updateOnly, skipUpdateUntouched);
|
||||||
signaturesRef.current,
|
|
||||||
newList,
|
|
||||||
updateOnly,
|
|
||||||
skipUpdateUntouched,
|
|
||||||
);
|
|
||||||
|
|
||||||
await outCommand({
|
const { added, updated, removed } = actualSigs;
|
||||||
type: OutCommand.updateSignatures,
|
|
||||||
data: prepareUpdatePayload(systemId, added, updated, removed),
|
if (updated.length !== 0 || added.length !== 0 || removed.length !== 0) {
|
||||||
});
|
await outCommand({
|
||||||
|
type: OutCommand.updateSignatures,
|
||||||
|
data: { ...prepareUpdatePayload(systemId, added, updated, removed), deleteTimeout },
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[systemId, outCommand, signaturesRef],
|
[systemId, deleteTimeout, outCommand, signaturesRef],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { SignatureSettingsType } from '@/hooks/Mapper/constants/signatures';
|
||||||
|
import { ExtendedSystemSignature, OutCommandHandler } from '@/hooks/Mapper/types';
|
||||||
|
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { getDeletionTimeoutMs } from '../constants';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook for managing pending signature deletions and undo countdown.
|
||||||
|
*/
|
||||||
|
export function useSignatureUndo(
|
||||||
|
systemId: string | undefined,
|
||||||
|
settings: SignatureSettingsType,
|
||||||
|
deletedSignatures: ExtendedSystemSignature[],
|
||||||
|
outCommand: OutCommandHandler,
|
||||||
|
) {
|
||||||
|
const [countdown, setCountdown] = useState<number>(0);
|
||||||
|
const intervalRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
// Clear deleted signatures when system changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (systemId) {
|
||||||
|
setCountdown(0);
|
||||||
|
if (intervalRef.current != null) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [systemId]);
|
||||||
|
|
||||||
|
// kick off or clear countdown whenever pendingIds changes
|
||||||
|
useEffect(() => {
|
||||||
|
// clear any existing timer
|
||||||
|
if (intervalRef.current != null) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deletedSignatures.length === 0) {
|
||||||
|
setCountdown(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine timeout from settings
|
||||||
|
const timeoutMs = getDeletionTimeoutMs(settings);
|
||||||
|
|
||||||
|
// Ensure a minimum of 1 second for immediate deletion so the UI shows
|
||||||
|
const effectiveTimeoutMs = timeoutMs === 0 ? 1000 : timeoutMs;
|
||||||
|
|
||||||
|
setCountdown(Math.ceil(effectiveTimeoutMs / 1000));
|
||||||
|
|
||||||
|
// start new interval
|
||||||
|
intervalRef.current = window.setInterval(() => {
|
||||||
|
setCountdown(prev => {
|
||||||
|
if (prev <= 1) {
|
||||||
|
clearInterval(intervalRef.current!);
|
||||||
|
intervalRef.current = null;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return prev - 1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (intervalRef.current != null) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [deletedSignatures, settings]);
|
||||||
|
|
||||||
|
// undo handler
|
||||||
|
const handleUndo = useCallback(async () => {
|
||||||
|
if (!systemId || deletedSignatures.length === 0) return;
|
||||||
|
await outCommand({
|
||||||
|
type: OutCommand.undoDeleteSignatures,
|
||||||
|
data: { system_id: systemId, eve_ids: deletedSignatures.map(s => s.eve_id) },
|
||||||
|
});
|
||||||
|
setCountdown(0);
|
||||||
|
if (intervalRef.current != null) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
intervalRef.current = null;
|
||||||
|
}
|
||||||
|
}, [systemId, deletedSignatures, outCommand]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
countdown,
|
||||||
|
handleUndo,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,44 +1,29 @@
|
|||||||
import { useMapEventListener } from '@/hooks/Mapper/events';
|
import { useMapEventListener } from '@/hooks/Mapper/events';
|
||||||
import { parseSignatures } from '@/hooks/Mapper/helpers';
|
import { parseSignatures } from '@/hooks/Mapper/helpers';
|
||||||
import { Commands, ExtendedSystemSignature, SignatureKind } from '@/hooks/Mapper/types';
|
import { Commands, ExtendedSystemSignature, SignatureKind } from '@/hooks/Mapper/types';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import useRefState from 'react-usestateref';
|
import useRefState from 'react-usestateref';
|
||||||
|
|
||||||
import { getDeletionTimeoutMs } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants.ts';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
import { getActualSigs } from '../helpers';
|
|
||||||
import { UseSystemSignaturesDataProps } from './types';
|
|
||||||
import { usePendingDeletions } from './usePendingDeletions';
|
|
||||||
import { useSignatureFetching } from './useSignatureFetching';
|
|
||||||
import { SETTINGS_KEYS } from '@/hooks/Mapper/constants/signatures.ts';
|
import { SETTINGS_KEYS } from '@/hooks/Mapper/constants/signatures.ts';
|
||||||
|
import { UseSystemSignaturesDataProps } from './types';
|
||||||
|
import { useSignatureFetching } from './useSignatureFetching';
|
||||||
|
|
||||||
export const useSystemSignaturesData = ({
|
export const useSystemSignaturesData = ({
|
||||||
systemId,
|
systemId,
|
||||||
settings,
|
settings,
|
||||||
onCountChange,
|
|
||||||
onPendingChange,
|
|
||||||
onLazyDeleteChange,
|
onLazyDeleteChange,
|
||||||
onSignatureDeleted,
|
|
||||||
}: Omit<UseSystemSignaturesDataProps, 'deletionTiming'> & {
|
}: Omit<UseSystemSignaturesDataProps, 'deletionTiming'> & {
|
||||||
onSignatureDeleted?: (deletedSignatures: ExtendedSystemSignature[]) => void;
|
onSignatureDeleted?: (deletedSignatures: ExtendedSystemSignature[]) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { outCommand } = useMapRootState();
|
|
||||||
const [signatures, setSignatures, signaturesRef] = useRefState<ExtendedSystemSignature[]>([]);
|
const [signatures, setSignatures, signaturesRef] = useRefState<ExtendedSystemSignature[]>([]);
|
||||||
const [selectedSignatures, setSelectedSignatures] = useState<ExtendedSystemSignature[]>([]);
|
const [selectedSignatures, setSelectedSignatures] = useState<ExtendedSystemSignature[]>([]);
|
||||||
const [hasUnsupportedLanguage, setHasUnsupportedLanguage] = useState<boolean>(false);
|
const [hasUnsupportedLanguage, setHasUnsupportedLanguage] = useState<boolean>(false);
|
||||||
|
|
||||||
const { pendingDeletionMapRef, processRemovedSignatures, clearPendingDeletions } = usePendingDeletions({
|
|
||||||
systemId,
|
|
||||||
setSignatures,
|
|
||||||
onPendingChange,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { handleGetSignatures, handleUpdateSignatures } = useSignatureFetching({
|
const { handleGetSignatures, handleUpdateSignatures } = useSignatureFetching({
|
||||||
systemId,
|
systemId,
|
||||||
|
settings,
|
||||||
signaturesRef,
|
signaturesRef,
|
||||||
setSignatures,
|
setSignatures,
|
||||||
pendingDeletionMapRef,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handlePaste = useCallback(
|
const handlePaste = useCallback(
|
||||||
@@ -67,40 +52,14 @@ export const useSystemSignaturesData = ({
|
|||||||
setHasUnsupportedLanguage(false);
|
setHasUnsupportedLanguage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentNonPending = lazyDeleteValue
|
await handleUpdateSignatures(incomingSignatures, !lazyDeleteValue, false);
|
||||||
? signaturesRef.current.filter(sig => !sig.pendingDeletion)
|
|
||||||
: signaturesRef.current.filter(sig => !sig.pendingDeletion || !sig.pendingAddition);
|
|
||||||
|
|
||||||
const { added, updated, removed } = getActualSigs(currentNonPending, incomingSignatures, !lazyDeleteValue, false);
|
|
||||||
|
|
||||||
if (removed.length > 0) {
|
|
||||||
await processRemovedSignatures(removed, added, updated);
|
|
||||||
|
|
||||||
// Show pending deletions if lazy deletion is enabled
|
|
||||||
// The deletion timing controls how long the countdown lasts, not whether lazy delete is active
|
|
||||||
if (onSignatureDeleted && lazyDeleteValue) {
|
|
||||||
onSignatureDeleted(removed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updated.length !== 0 || added.length !== 0) {
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateSignatures,
|
|
||||||
data: {
|
|
||||||
system_id: systemId,
|
|
||||||
added,
|
|
||||||
updated,
|
|
||||||
removed: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const keepLazy = settings[SETTINGS_KEYS.KEEP_LAZY_DELETE] as boolean;
|
const keepLazy = settings[SETTINGS_KEYS.KEEP_LAZY_DELETE] as boolean;
|
||||||
if (lazyDeleteValue && !keepLazy) {
|
if (lazyDeleteValue && !keepLazy) {
|
||||||
onLazyDeleteChange?.(false);
|
onLazyDeleteChange?.(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[settings, signaturesRef, processRemovedSignatures, outCommand, systemId, onLazyDeleteChange, onSignatureDeleted],
|
[settings, handleUpdateSignatures, onLazyDeleteChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDeleteSelected = useCallback(async () => {
|
const handleDeleteSelected = useCallback(async () => {
|
||||||
@@ -109,23 +68,15 @@ export const useSystemSignaturesData = ({
|
|||||||
const selectedIds = selectedSignatures.map(s => s.eve_id);
|
const selectedIds = selectedSignatures.map(s => s.eve_id);
|
||||||
const finalList = signatures.filter(s => !selectedIds.includes(s.eve_id));
|
const finalList = signatures.filter(s => !selectedIds.includes(s.eve_id));
|
||||||
|
|
||||||
// IMPORTANT: Send deletion to server BEFORE updating local state
|
|
||||||
// Otherwise signaturesRef.current will be updated and getActualSigs won't detect removals
|
|
||||||
await handleUpdateSignatures(finalList, false, true);
|
|
||||||
|
|
||||||
// Update local state after server call
|
|
||||||
setSignatures(finalList);
|
|
||||||
setSelectedSignatures([]);
|
setSelectedSignatures([]);
|
||||||
}, [handleUpdateSignatures, selectedSignatures, signatures, setSignatures]);
|
|
||||||
|
await handleUpdateSignatures(finalList, false, true);
|
||||||
|
}, [handleUpdateSignatures, selectedSignatures, signatures]);
|
||||||
|
|
||||||
const handleSelectAll = useCallback(() => {
|
const handleSelectAll = useCallback(() => {
|
||||||
setSelectedSignatures(signatures);
|
setSelectedSignatures(signatures);
|
||||||
}, [signatures]);
|
}, [signatures]);
|
||||||
|
|
||||||
const undoPending = useCallback(() => {
|
|
||||||
clearPendingDeletions();
|
|
||||||
}, [clearPendingDeletions]);
|
|
||||||
|
|
||||||
useMapEventListener(event => {
|
useMapEventListener(event => {
|
||||||
if (event.name === Commands.signaturesUpdated && String(event.data) === String(systemId)) {
|
if (event.name === Commands.signaturesUpdated && String(event.data) === String(systemId)) {
|
||||||
handleGetSignatures();
|
handleGetSignatures();
|
||||||
@@ -136,18 +87,13 @@ export const useSystemSignaturesData = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!systemId) {
|
if (!systemId) {
|
||||||
setSignatures([]);
|
setSignatures([]);
|
||||||
undoPending();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleGetSignatures();
|
handleGetSignatures();
|
||||||
}, [systemId]);
|
}, [systemId]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onCountChange?.(signatures.length);
|
|
||||||
}, [signatures]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
signatures: signatures.filter(sig => !sig.deleted),
|
signatures,
|
||||||
selectedSignatures,
|
selectedSignatures,
|
||||||
setSelectedSignatures,
|
setSelectedSignatures,
|
||||||
handleDeleteSelected,
|
handleDeleteSelected,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { PrimeIcons } from 'primereact/api';
|
|
||||||
import { SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
|
|
||||||
import { SystemViewStandalone, TooltipPosition, WHClassView } from '@/hooks/Mapper/components/ui-kit';
|
import { SystemViewStandalone, TooltipPosition, WHClassView } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
import { SignatureGroup, SystemSignature, TimeStatus } from '@/hooks/Mapper/types';
|
||||||
|
import { PrimeIcons } from 'primereact/api';
|
||||||
|
|
||||||
import { renderK162Type } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
import { renderK162Type } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
||||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { renderName } from './renderName.tsx';
|
|
||||||
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
import { K162_TYPES_MAP } from '@/hooks/Mapper/constants.ts';
|
||||||
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo.ts';
|
import { parseSignatureCustomInfo } from '@/hooks/Mapper/helpers/parseSignatureCustomInfo.ts';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { renderName } from './renderName.tsx';
|
||||||
|
|
||||||
export const renderInfoColumn = (row: SystemSignature) => {
|
export const renderInfoColumn = (row: SystemSignature) => {
|
||||||
if (!row.group || row.group === SignatureGroup.Wormhole) {
|
if (!row.group || row.group === SignatureGroup.Wormhole) {
|
||||||
@@ -18,7 +18,9 @@ export const renderInfoColumn = (row: SystemSignature) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-start items-center gap-[4px]">
|
<div className="flex justify-start items-center gap-[4px]">
|
||||||
{customInfo.isEOL && (
|
{row.temporary_name && <span className={clsx('text-[12px]')}>{row.temporary_name}</span>}
|
||||||
|
|
||||||
|
{customInfo.time_status === TimeStatus._1h && (
|
||||||
<WdTooltipWrapper offset={5} position={TooltipPosition.top} content="Signature marked as EOL">
|
<WdTooltipWrapper offset={5} position={TooltipPosition.top} content="Signature marked as EOL">
|
||||||
<div className="pi pi-clock text-fuchsia-400 text-[11px] mr-[2px]"></div>
|
<div className="pi pi-clock text-fuchsia-400 text-[11px] mr-[2px]"></div>
|
||||||
</WdTooltipWrapper>
|
</WdTooltipWrapper>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { AutoComplete } from 'primereact/autocomplete';
|
import { AutoComplete } from 'primereact/autocomplete';
|
||||||
import { Calendar } from 'primereact/calendar';
|
import { Calendar } from 'primereact/calendar';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { StructureItem, StructureStatus, statusesRequiringTimer, formatToISO } from '../helpers';
|
import { formatToISO, statusesRequiringTimer, StructureItem, StructureStatus } from '../helpers';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
interface StructuresEditDialogProps {
|
interface StructuresEditDialogProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -54,14 +54,13 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
|
|
||||||
// If user typed more text but we have partial match in prevResults
|
// If user typed more text but we have partial match in prevResults
|
||||||
if (newQuery.startsWith(prevQuery) && prevResults.length > 0) {
|
if (newQuery.startsWith(prevQuery) && prevResults.length > 0) {
|
||||||
const filtered = prevResults.filter(item =>
|
const filtered = prevResults.filter(item => item.label.toLowerCase().includes(newQuery.toLowerCase()));
|
||||||
item.label.toLowerCase().includes(newQuery.toLowerCase()),
|
|
||||||
);
|
|
||||||
setOwnerSuggestions(filtered);
|
setOwnerSuggestions(filtered);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// TODO fix it
|
||||||
const { results = [] } = await outCommand({
|
const { results = [] } = await outCommand({
|
||||||
type: OutCommand.getCorporationNames,
|
type: OutCommand.getCorporationNames,
|
||||||
data: { search: newQuery },
|
data: { search: newQuery },
|
||||||
@@ -96,9 +95,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
// when user picks a corp from auto-complete
|
// when user picks a corp from auto-complete
|
||||||
const handleSelectOwner = (selected: { label: string; value: string }) => {
|
const handleSelectOwner = (selected: { label: string; value: string }) => {
|
||||||
setOwnerInput(selected.label);
|
setOwnerInput(selected.label);
|
||||||
setEditData(prev =>
|
setEditData(prev => (prev ? { ...prev, ownerName: selected.label, ownerId: selected.value } : null));
|
||||||
prev ? { ...prev, ownerName: selected.label, ownerId: selected.value } : null,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStatusChange = (val: string) => {
|
const handleStatusChange = (val: string) => {
|
||||||
@@ -125,6 +122,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
// fetch corporation ticker if we have an ownerId
|
// fetch corporation ticker if we have an ownerId
|
||||||
if (editData.ownerId) {
|
if (editData.ownerId) {
|
||||||
try {
|
try {
|
||||||
|
// TODO fix it
|
||||||
const { ticker } = await outCommand({
|
const { ticker } = await outCommand({
|
||||||
type: OutCommand.getCorporationTicker,
|
type: OutCommand.getCorporationTicker,
|
||||||
data: { corp_id: editData.ownerId },
|
data: { corp_id: editData.ownerId },
|
||||||
@@ -157,11 +155,7 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
<div className="flex flex-col gap-2 text-[14px]">
|
<div className="flex flex-col gap-2 text-[14px]">
|
||||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||||
<span>Type:</span>
|
<span>Type:</span>
|
||||||
<input
|
<input readOnly className="p-inputtext p-component cursor-not-allowed" value={editData.structureType ?? ''} />
|
||||||
readOnly
|
|
||||||
className="p-inputtext p-component cursor-not-allowed"
|
|
||||||
value={editData.structureType ?? ''}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||||
<span>Name:</span>
|
<span>Name:</span>
|
||||||
@@ -204,10 +198,12 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
|
|
||||||
{statusesRequiringTimer.includes(editData.status) && (
|
{statusesRequiringTimer.includes(editData.status) && (
|
||||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center">
|
||||||
<span>Timer <br /> (Eve Time):</span>
|
<span>
|
||||||
|
Timer <br /> (Eve Time):
|
||||||
|
</span>
|
||||||
<Calendar
|
<Calendar
|
||||||
value={editData.endTime ? new Date(editData.endTime) : undefined}
|
value={editData.endTime ? new Date(editData.endTime) : undefined}
|
||||||
onChange={(e) => handleChange('endTime', e.value ?? '')}
|
onChange={e => handleChange('endTime', e.value ?? '')}
|
||||||
showTime
|
showTime
|
||||||
hourFormat="24"
|
hourFormat="24"
|
||||||
dateFormat="yy-mm-dd"
|
dateFormat="yy-mm-dd"
|
||||||
@@ -227,8 +223,8 @@ export const SystemStructuresDialog: React.FC<StructuresEditDialogProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end items-center gap-2 mt-4">
|
<div className="flex justify-end items-center gap-2 mt-4">
|
||||||
<Button label="Delete" severity="danger" className="p-button-sm" onClick={handleDeleteClick} />
|
<WdButton label="Delete" severity="danger" className="p-button-sm" onClick={handleDeleteClick} />
|
||||||
<Button label="Save" className="p-button-sm" onClick={handleSaveClick} />
|
<WdButton label="Save" className="p-button-sm" onClick={handleSaveClick} />
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,8 +16,21 @@ const SystemKillsContent = () => {
|
|||||||
} = useMapRootState();
|
} = useMapRootState();
|
||||||
|
|
||||||
const [systemId] = selectedSystems || [];
|
const [systemId] = selectedSystems || [];
|
||||||
|
const whCacheRef = useMemo(() => new Map<number, boolean>(), []);
|
||||||
|
|
||||||
const systemStaticInfo = getSystemStaticInfo(systemId)!;
|
const isWormholeSystem = useCallback(
|
||||||
|
(systemId: number): boolean => {
|
||||||
|
const cached = whCacheRef.get(systemId);
|
||||||
|
if (cached !== undefined) return cached;
|
||||||
|
|
||||||
|
const info = getSystemStaticInfo(systemId);
|
||||||
|
const isWH = info?.system_class != null ? isWormholeSpace(Number(info.system_class)) : false;
|
||||||
|
|
||||||
|
whCacheRef.set(systemId, isWH);
|
||||||
|
return isWH;
|
||||||
|
},
|
||||||
|
[whCacheRef],
|
||||||
|
);
|
||||||
|
|
||||||
const { kills, isLoading, error } = useSystemKills({
|
const { kills, isLoading, error } = useSystemKills({
|
||||||
systemId,
|
systemId,
|
||||||
@@ -30,15 +43,9 @@ const SystemKillsContent = () => {
|
|||||||
const showLoading = isLoading && kills.length === 0;
|
const showLoading = isLoading && kills.length === 0;
|
||||||
|
|
||||||
const filteredKills = useMemo(() => {
|
const filteredKills = useMemo(() => {
|
||||||
if (!settingsKills.whOnly || !settingsKills.showAll) return kills;
|
if (!settingsKills.whOnly) return kills;
|
||||||
return kills.filter(kill => {
|
return kills.filter(kill => isWormholeSystem(Number(kill.solar_system_id)));
|
||||||
if (!systemStaticInfo) {
|
}, [kills, settingsKills.whOnly, isWormholeSystem]);
|
||||||
console.warn(`System with id ${kill.solar_system_id} not found.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isWormholeSpace(systemStaticInfo.system_class);
|
|
||||||
});
|
|
||||||
}, [kills, settingsKills.whOnly, systemStaticInfo, settingsKills.showAll]);
|
|
||||||
|
|
||||||
if (!isSubscriptionActive) {
|
if (!isSubscriptionActive) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { Button } from 'primereact/button';
|
import { SystemView, TooltipPosition, WdButton, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { WdImgButton } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import {
|
import {
|
||||||
AddSystemDialog,
|
AddSystemDialog,
|
||||||
SearchOnSubmitCallback,
|
SearchOnSubmitCallback,
|
||||||
} from '@/hooks/Mapper/components/mapInterface/components/AddSystemDialog';
|
} from '@/hooks/Mapper/components/mapInterface/components/AddSystemDialog';
|
||||||
import { SystemView, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
|
||||||
interface KillsSettingsDialogProps {
|
interface KillsSettingsDialogProps {
|
||||||
@@ -158,7 +156,7 @@ export const KillsSettingsDialog: React.FC<KillsSettingsDialogProps> = ({ visibl
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end mt-4">
|
<div className="flex gap-2 justify-end mt-4">
|
||||||
<Button onClick={handleApply} label="Apply" outlined size="small" />
|
<WdButton onClick={handleApply} label="Apply" outlined size="small" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useCallback, useMemo, useState, useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import debounce from 'lodash.debounce';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
||||||
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { useStableValue } from '@/hooks/Mapper/hooks';
|
||||||
|
|
||||||
interface UseSystemKillsProps {
|
interface UseSystemKillsProps {
|
||||||
systemId?: string;
|
systemId?: string;
|
||||||
@@ -30,9 +30,8 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
update,
|
update,
|
||||||
storedSettings: { settingsKills },
|
storedSettings: { settingsKills },
|
||||||
} = useMapRootState();
|
} = useMapRootState();
|
||||||
const { excludedSystems } = settingsKills;
|
|
||||||
|
|
||||||
const effectiveSinceHours = sinceHours;
|
const excludedSystems = useStableValue(settingsKills.excludedSystems);
|
||||||
|
|
||||||
const effectiveSystemIds = useMemo(() => {
|
const effectiveSystemIds = useMemo(() => {
|
||||||
if (showAllVisible) {
|
if (showAllVisible) {
|
||||||
@@ -76,13 +75,13 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
eventType = OutCommand.getSystemsKills;
|
eventType = OutCommand.getSystemsKills;
|
||||||
requestData = {
|
requestData = {
|
||||||
system_ids: effectiveSystemIds,
|
system_ids: effectiveSystemIds,
|
||||||
since_hours: effectiveSinceHours,
|
since_hours: sinceHours,
|
||||||
};
|
};
|
||||||
} else if (systemId) {
|
} else if (systemId) {
|
||||||
eventType = OutCommand.getSystemKills;
|
eventType = OutCommand.getSystemKills;
|
||||||
requestData = {
|
requestData = {
|
||||||
system_id: systemId,
|
system_id: systemId,
|
||||||
since_hours: effectiveSinceHours,
|
since_hours: sinceHours,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -110,16 +109,7 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[showAllVisible, systemId, outCommand, effectiveSystemIds, effectiveSinceHours, mergeKillsIntoGlobal],
|
[showAllVisible, systemId, outCommand, effectiveSystemIds, sinceHours, mergeKillsIntoGlobal],
|
||||||
);
|
|
||||||
|
|
||||||
const debouncedFetchKills = useMemo(
|
|
||||||
() =>
|
|
||||||
debounce(fetchKills, 500, {
|
|
||||||
leading: true,
|
|
||||||
trailing: false,
|
|
||||||
}),
|
|
||||||
[fetchKills],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const finalKills = useMemo(() => {
|
const finalKills = useMemo(() => {
|
||||||
@@ -141,27 +131,22 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!systemId && !showAllVisible && !didFallbackFetch.current) {
|
if (!systemId && !showAllVisible && !didFallbackFetch.current) {
|
||||||
didFallbackFetch.current = true;
|
didFallbackFetch.current = true;
|
||||||
debouncedFetchKills.cancel();
|
|
||||||
fetchKills(true);
|
fetchKills(true);
|
||||||
}
|
}
|
||||||
}, [systemId, showAllVisible, debouncedFetchKills, fetchKills]);
|
}, [systemId, showAllVisible, fetchKills]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (effectiveSystemIds.length === 0) return;
|
if (effectiveSystemIds.length === 0) return;
|
||||||
|
|
||||||
if (showAllVisible || systemId) {
|
if (showAllVisible || systemId) {
|
||||||
// Cancel any pending debounced fetch
|
|
||||||
debouncedFetchKills.cancel();
|
|
||||||
// Fetch kills immediately
|
|
||||||
fetchKills();
|
fetchKills();
|
||||||
return () => debouncedFetchKills.cancel();
|
return;
|
||||||
}
|
}
|
||||||
}, [showAllVisible, systemId, effectiveSystemIds, debouncedFetchKills, fetchKills]);
|
}, [showAllVisible, systemId, effectiveSystemIds, fetchKills]);
|
||||||
|
|
||||||
const refetch = useCallback(() => {
|
const refetch = useCallback(() => {
|
||||||
debouncedFetchKills.cancel();
|
|
||||||
fetchKills();
|
fetchKills();
|
||||||
}, [debouncedFetchKills, fetchKills]);
|
}, [fetchKills]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kills: finalKills,
|
kills: finalKills,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useMapEventListener } from '@/hooks/Mapper/events';
|
|||||||
import { Commands } from '@/hooks/Mapper/types';
|
import { Commands } from '@/hooks/Mapper/types';
|
||||||
import { PingsInterface } from '@/hooks/Mapper/components/mapInterface/components';
|
import { PingsInterface } from '@/hooks/Mapper/components/mapInterface/components';
|
||||||
import { OldSettingsDialog } from '@/hooks/Mapper/components/mapRootContent/components/OldSettingsDialog.tsx';
|
import { OldSettingsDialog } from '@/hooks/Mapper/components/mapRootContent/components/OldSettingsDialog.tsx';
|
||||||
|
import { TopSearch } from '@/hooks/Mapper/components/mapRootContent/components/TopSearch';
|
||||||
|
|
||||||
export interface MapRootContentProps {}
|
export interface MapRootContentProps {}
|
||||||
|
|
||||||
@@ -72,6 +73,7 @@ export const MapRootContent = ({}: MapRootContentProps) => {
|
|||||||
<div className="absolute top-0 left-14 w-[calc(100%-3.5rem)] h-[calc(100%-3.5rem)] pointer-events-none">
|
<div className="absolute top-0 left-14 w-[calc(100%-3.5rem)] h-[calc(100%-3.5rem)] pointer-events-none">
|
||||||
<Topbar>
|
<Topbar>
|
||||||
<div className="flex items-center ml-1">
|
<div className="flex items-center ml-1">
|
||||||
|
<TopSearch />
|
||||||
<PingsInterface />
|
<PingsInterface />
|
||||||
<MapContextMenu
|
<MapContextMenu
|
||||||
onShowOnTheMap={handleShowOnTheMap}
|
onShowOnTheMap={handleShowOnTheMap}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
import classes from './Connections.module.scss';
|
|
||||||
import { Sidebar } from 'primereact/sidebar';
|
|
||||||
import { useEffect, useMemo, useState, useCallback } from 'react';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import {
|
import {
|
||||||
ConnectionType,
|
|
||||||
ConnectionOutput,
|
|
||||||
ConnectionInfoOutput,
|
ConnectionInfoOutput,
|
||||||
|
ConnectionOutput,
|
||||||
|
ConnectionType,
|
||||||
OutCommand,
|
OutCommand,
|
||||||
Passage,
|
Passage,
|
||||||
SolarSystemConnection,
|
SolarSystemConnection,
|
||||||
} from '@/hooks/Mapper/types';
|
} from '@/hooks/Mapper/types';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Sidebar } from 'primereact/sidebar';
|
||||||
|
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import classes from './Connections.module.scss';
|
||||||
|
|
||||||
import { PassageCard } from './PassageCard';
|
import { InfoDrawer, SystemView, TimeAgo } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { InfoDrawer, SystemView } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import { kgToTons } from '@/hooks/Mapper/utils/kgToTons.ts';
|
import { kgToTons } from '@/hooks/Mapper/utils/kgToTons.ts';
|
||||||
import { TimeAgo } from '@/hooks/Mapper/components/ui-kit';
|
import { PassageCard } from './PassageCard';
|
||||||
|
|
||||||
const sortByDate = (a: string, b: string) => new Date(a).getTime() - new Date(b).getTime();
|
const sortByDate = (a: string, b: string) => new Date(a).getTime() - new Date(b).getTime();
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ export const Connections = ({ selectedConnection, onHide }: OnTheMapProps) => {
|
|||||||
}, [connections, selectedConnection]);
|
}, [connections, selectedConnection]);
|
||||||
|
|
||||||
const isWormhole = useMemo(() => {
|
const isWormhole = useMemo(() => {
|
||||||
return cnInfo?.type !== ConnectionType.gate;
|
return cnInfo?.type === ConnectionType.wormhole;
|
||||||
}, [cnInfo]);
|
}, [cnInfo]);
|
||||||
|
|
||||||
const [passages, setPassages] = useState<Passage[]>([]);
|
const [passages, setPassages] = useState<Passage[]>([]);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export const MapSettingsComp = ({ visible, onHide }: MapSettingsProps) => {
|
|||||||
header="Map user settings"
|
header="Map user settings"
|
||||||
visible
|
visible
|
||||||
draggable={false}
|
draggable={false}
|
||||||
style={{ width: '600px' }}
|
className="w-[600px] h-[400px]"
|
||||||
onShow={handleShow}
|
onShow={handleShow}
|
||||||
onHide={handleHide}
|
onHide={handleHide}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
@@ -10,6 +9,7 @@ import { MapUserSettings, RemoteAdminSettingsResponse } from '@/hooks/Mapper/map
|
|||||||
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
||||||
import fastDeepEqual from 'fast-deep-equal';
|
import fastDeepEqual from 'fast-deep-equal';
|
||||||
import { useDetectSettingsChanged } from '@/hooks/Mapper/components/hooks';
|
import { useDetectSettingsChanged } from '@/hooks/Mapper/components/hooks';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
export const AdminSettings = () => {
|
export const AdminSettings = () => {
|
||||||
const {
|
const {
|
||||||
@@ -92,7 +92,7 @@ export const AdminSettings = () => {
|
|||||||
<div className="w-full h-full flex flex-col gap-5">
|
<div className="w-full h-full flex flex-col gap-5">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<WdButton
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ref={cfRef}
|
ref={cfRef}
|
||||||
onClick={cfShow}
|
onClick={cfShow}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import {
|
|||||||
import { useMapSettings } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/MapSettingsProvider.tsx';
|
import { useMapSettings } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/MapSettingsProvider.tsx';
|
||||||
import { SettingsListItem } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/types.ts';
|
import { SettingsListItem } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/types.ts';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Button } from 'primereact/button';
|
import { TooltipPosition, WdButton, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { TooltipPosition, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit';
|
|
||||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ export const CommonSettings = () => {
|
|||||||
<div className="grid grid-cols-[1fr_auto]">
|
<div className="grid grid-cols-[1fr_auto]">
|
||||||
<div />
|
<div />
|
||||||
<WdTooltipWrapper content="This dangerous action. And can not be undone" position={TooltipPosition.top}>
|
<WdTooltipWrapper content="This dangerous action. And can not be undone" position={TooltipPosition.top}>
|
||||||
<Button
|
<WdButton
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ref={cfRef}
|
ref={cfRef}
|
||||||
className="py-[4px]"
|
className="py-[4px]"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
import { Divider } from 'primereact/divider';
|
import { Divider } from 'primereact/divider';
|
||||||
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
import { callToastError, callToastSuccess, callToastWarn } from '@/hooks/Mapper/helpers';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
type SaveDefaultSettingsReturn = { success: boolean; error: string };
|
type SaveDefaultSettingsReturn = { success: boolean; error: string };
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ export const DefaultSettings = () => {
|
|||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<WdButton
|
||||||
onClick={handleSaveAsDefault}
|
onClick={handleSaveAsDefault}
|
||||||
icon="pi pi-save"
|
icon="pi pi-save"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
|||||||
import { saveTextFile } from '@/hooks/Mapper/utils/saveToFile.ts';
|
import { saveTextFile } from '@/hooks/Mapper/utils/saveToFile.ts';
|
||||||
import { SplitButton } from 'primereact/splitbutton';
|
import { SplitButton } from 'primereact/splitbutton';
|
||||||
import { loadTextFile } from '@/hooks/Mapper/utils';
|
import { loadTextFile } from '@/hooks/Mapper/utils';
|
||||||
|
import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
|
||||||
|
import { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
|
||||||
|
|
||||||
export const ImportExport = () => {
|
export const ImportExport = () => {
|
||||||
const {
|
const {
|
||||||
@@ -22,8 +24,9 @@ export const ImportExport = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard
|
||||||
const parsed = parseMapUserSettings(text);
|
const parsed = parseMapUserSettings(text);
|
||||||
if (applySettings(parsed)) {
|
if (applySettings(applyMigrations(parsed) || createDefaultStoredSettings())) {
|
||||||
toast.current?.show({
|
toast.current?.show({
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
summary: 'Import',
|
summary: 'Import',
|
||||||
@@ -59,8 +62,9 @@ export const ImportExport = () => {
|
|||||||
try {
|
try {
|
||||||
const text = await loadTextFile();
|
const text = await loadTextFile();
|
||||||
|
|
||||||
|
// INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard
|
||||||
const parsed = parseMapUserSettings(text);
|
const parsed = parseMapUserSettings(text);
|
||||||
if (applySettings(parsed)) {
|
if (applySettings(applyMigrations(parsed) || createDefaultStoredSettings())) {
|
||||||
toast.current?.show({
|
toast.current?.show({
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
summary: 'Import',
|
summary: 'Import',
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { OutCommand } from '@/hooks/Mapper/types';
|
import { OutCommand } from '@/hooks/Mapper/types';
|
||||||
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts';
|
import { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
|
||||||
import { callToastSuccess } from '@/hooks/Mapper/helpers';
|
import { callToastSuccess } from '@/hooks/Mapper/helpers';
|
||||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
||||||
import { RemoteAdminSettingsResponse } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
import { RemoteAdminSettingsResponse } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
|
import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
export const ServerSettings = () => {
|
export const ServerSettings = () => {
|
||||||
const {
|
const {
|
||||||
@@ -29,15 +29,16 @@ export const ServerSettings = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res?.default_settings == null) {
|
if (res?.default_settings == null) {
|
||||||
applySettings(createDefaultWidgetSettings());
|
applySettings(createDefaultStoredSettings());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
applySettings(parseMapUserSettings(res.default_settings));
|
//INFO: INSTEAD CHECK WE WILL TRY TO APPLY MIGRATION
|
||||||
|
applySettings(applyMigrations(JSON.parse(res.default_settings)) || createDefaultStoredSettings());
|
||||||
callToastSuccess(toast.current, 'Settings synchronized successfully');
|
callToastSuccess(toast.current, 'Settings synchronized successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
applySettings(createDefaultWidgetSettings());
|
applySettings(createDefaultStoredSettings());
|
||||||
}
|
}
|
||||||
}, [applySettings, outCommand]);
|
}, [applySettings, outCommand]);
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ export const ServerSettings = () => {
|
|||||||
<div className="w-full h-full flex flex-col gap-5">
|
<div className="w-full h-full flex flex-col gap-5">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<WdButton
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ref={cfRef}
|
ref={cfRef}
|
||||||
onClick={cfShow}
|
onClick={cfShow}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { PrettySwitchbox } from '@/hooks/Mapper/components/mapRootContent/compon
|
|||||||
import { WIDGETS_CHECKBOXES_PROPS, WidgetsIds } from '@/hooks/Mapper/components/mapInterface/constants.tsx';
|
import { WIDGETS_CHECKBOXES_PROPS, WidgetsIds } from '@/hooks/Mapper/components/mapInterface/constants.tsx';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
|
|
||||||
export interface WidgetsSettingsProps {}
|
export interface WidgetsSettingsProps {}
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ export const WidgetsSettings = ({}: WidgetsSettingsProps) => {
|
|||||||
|
|
||||||
<div className="grid grid-cols-[1fr_auto]">
|
<div className="grid grid-cols-[1fr_auto]">
|
||||||
<div />
|
<div />
|
||||||
<Button className="py-[4px]" onClick={resetWidgets} outlined size="small" label="Reset Widgets"></Button>
|
<WdButton className="py-[4px]" onClick={resetWidgets} outlined size="small" label="Reset Widgets" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SettingsListItem, UserSettingsRemoteProps } from './types.ts';
|
|
||||||
import { InterfaceStoredSettingsProps } from '@/hooks/Mapper/mapRootProvider';
|
import { InterfaceStoredSettingsProps } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { AvailableThemes, MiniMapPlacement, PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
import { AvailableThemes, MiniMapPlacement, PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
|
import { SettingsListItem, UserSettingsRemoteProps } from './types.ts';
|
||||||
|
|
||||||
export const DEFAULT_REMOTE_SETTINGS = {
|
export const DEFAULT_REMOTE_SETTINGS = {
|
||||||
[UserSettingsRemoteProps.link_signature_on_splash]: false,
|
[UserSettingsRemoteProps.link_signature_on_splash]: false,
|
||||||
@@ -51,7 +51,7 @@ export const SIGNATURES_CHECKBOXES_PROPS: SettingsListItem[] = [
|
|||||||
export const CONNECTIONS_CHECKBOXES_PROPS: SettingsListItem[] = [
|
export const CONNECTIONS_CHECKBOXES_PROPS: SettingsListItem[] = [
|
||||||
{
|
{
|
||||||
prop: UserSettingsRemoteProps.delete_connection_with_sigs,
|
prop: UserSettingsRemoteProps.delete_connection_with_sigs,
|
||||||
label: 'Delete connections to linked signatures',
|
label: 'Delete connections with linked signatures',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,27 +1,15 @@
|
|||||||
import { Dialog } from 'primereact/dialog';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { ConfirmPopup } from 'primereact/confirmpopup';
|
|
||||||
import { useCallback, useRef } from 'react';
|
|
||||||
import { MapUserSettings } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
|
||||||
import {
|
|
||||||
DEFAULT_KILLS_WIDGET_SETTINGS,
|
|
||||||
DEFAULT_ON_THE_MAP_SETTINGS,
|
|
||||||
DEFAULT_ROUTES_SETTINGS,
|
|
||||||
DEFAULT_WIDGET_LOCAL_SETTINGS,
|
|
||||||
getDefaultWidgetProps,
|
|
||||||
STORED_INTERFACE_DEFAULT_VALUES,
|
|
||||||
} from '@/hooks/Mapper/mapRootProvider/constants.ts';
|
|
||||||
import { DEFAULT_SIGNATURE_SETTINGS } from '@/hooks/Mapper/constants/signatures.ts';
|
|
||||||
import { Toast } from 'primereact/toast';
|
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
|
||||||
import { saveTextFile } from '@/hooks/Mapper/utils';
|
|
||||||
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
import { useConfirmPopup } from '@/hooks/Mapper/hooks';
|
||||||
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
|
import { MapUserSettings } from '@/hooks/Mapper/mapRootProvider/types.ts';
|
||||||
|
import { saveTextFile } from '@/hooks/Mapper/utils';
|
||||||
|
import { ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { Toast } from 'primereact/toast';
|
||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
const createSettings = function <T>(lsSettings: string | null, defaultValues: T) {
|
const createSettings = function <T>(lsSettings: string | null, defaultValues: T) {
|
||||||
return {
|
return lsSettings ? JSON.parse(lsSettings) : defaultValues;
|
||||||
version: -1,
|
|
||||||
settings: lsSettings ? JSON.parse(lsSettings) : defaultValues,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OldSettingsDialog = () => {
|
export const OldSettingsDialog = () => {
|
||||||
@@ -41,16 +29,18 @@ export const OldSettingsDialog = () => {
|
|||||||
const widgetKills = localStorage.getItem('kills:widget:settings');
|
const widgetKills = localStorage.getItem('kills:widget:settings');
|
||||||
const onTheMapOld = localStorage.getItem('window:onTheMap:settings');
|
const onTheMapOld = localStorage.getItem('window:onTheMap:settings');
|
||||||
const widgetsOld = localStorage.getItem('windows:settings:v2');
|
const widgetsOld = localStorage.getItem('windows:settings:v2');
|
||||||
const signatures = localStorage.getItem('wanderer_system_signature_settings_v6_5');
|
const signatures = localStorage.getItem('wanderer_system_signature_settings_v6_6');
|
||||||
|
|
||||||
const out: MapUserSettings = {
|
const out: MapUserSettings = {
|
||||||
killsWidget: createSettings(widgetKills, DEFAULT_KILLS_WIDGET_SETTINGS),
|
version: 0,
|
||||||
localWidget: createSettings(widgetLocal, DEFAULT_WIDGET_LOCAL_SETTINGS),
|
migratedFromOld: false,
|
||||||
widgets: createSettings(widgetsOld, getDefaultWidgetProps()),
|
killsWidget: createSettings(widgetKills, {}),
|
||||||
routes: createSettings(widgetRoutes, DEFAULT_ROUTES_SETTINGS),
|
localWidget: createSettings(widgetLocal, {}),
|
||||||
onTheMap: createSettings(onTheMapOld, DEFAULT_ON_THE_MAP_SETTINGS),
|
widgets: createSettings(widgetsOld, {}),
|
||||||
signaturesWidget: createSettings(signatures, DEFAULT_SIGNATURE_SETTINGS),
|
routes: createSettings(widgetRoutes, {}),
|
||||||
interface: createSettings(interfaceSettings, STORED_INTERFACE_DEFAULT_VALUES),
|
onTheMap: createSettings(onTheMapOld, {}),
|
||||||
|
signaturesWidget: createSettings(signatures, {}),
|
||||||
|
interface: createSettings(interfaceSettings, {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (asFile) {
|
if (asFile) {
|
||||||
@@ -118,7 +108,7 @@ export const OldSettingsDialog = () => {
|
|||||||
localStorage.removeItem('kills:widget:settings');
|
localStorage.removeItem('kills:widget:settings');
|
||||||
localStorage.removeItem('window:onTheMap:settings');
|
localStorage.removeItem('window:onTheMap:settings');
|
||||||
localStorage.removeItem('windows:settings:v2');
|
localStorage.removeItem('windows:settings:v2');
|
||||||
localStorage.removeItem('wanderer_system_signature_settings_v6_5');
|
localStorage.removeItem('wanderer_system_signature_settings_v6_6');
|
||||||
|
|
||||||
checkOldSettings();
|
checkOldSettings();
|
||||||
}, [checkOldSettings]);
|
}, [checkOldSettings]);
|
||||||
@@ -139,7 +129,7 @@ export const OldSettingsDialog = () => {
|
|||||||
className="w-[640px] h-[400px] text-text-color min-h-0"
|
className="w-[640px] h-[400px] text-text-color min-h-0"
|
||||||
footer={
|
footer={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<Button
|
<WdButton
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ref={cfRef}
|
ref={cfRef}
|
||||||
onClick={cfShow}
|
onClick={cfShow}
|
||||||
@@ -168,7 +158,7 @@ export const OldSettingsDialog = () => {
|
|||||||
<div className="h-[30px]"></div>
|
<div className="h-[30px]"></div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Button
|
<WdButton
|
||||||
onClick={handleExportClipboard}
|
onClick={handleExportClipboard}
|
||||||
icon="pi pi-copy"
|
icon="pi pi-copy"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -176,7 +166,7 @@ export const OldSettingsDialog = () => {
|
|||||||
label="Export to Clipboard"
|
label="Export to Clipboard"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<WdButton
|
||||||
onClick={handleExportAsFile}
|
onClick={handleExportAsFile}
|
||||||
icon="pi pi-download"
|
icon="pi pi-download"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
|||||||
|
|
||||||
import { useMapCheckPermissions } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
import { useMapCheckPermissions } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||||
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
||||||
|
import { TopSearch } from '@/hooks/Mapper/components/mapRootContent/components/TopSearch';
|
||||||
// import { DebugComponent } from '@/hooks/Mapper/components/mapRootContent/components/RightBar/DebugComponent.tsx';
|
// import { DebugComponent } from '@/hooks/Mapper/components/mapRootContent/components/RightBar/DebugComponent.tsx';
|
||||||
|
|
||||||
interface RightBarProps {
|
interface RightBarProps {
|
||||||
@@ -48,7 +49,7 @@ export const RightBar = ({
|
|||||||
classes.RightBarRoot,
|
classes.RightBarRoot,
|
||||||
'w-full h-full',
|
'w-full h-full',
|
||||||
'text-gray-200 shadow-lg border-l border-zinc-800 border-opacity-70 bg-opacity-70 bg-neutral-900',
|
'text-gray-200 shadow-lg border-l border-zinc-800 border-opacity-70 bg-opacity-70 bg-neutral-900',
|
||||||
'flex flex-col items-center justify-between',
|
'flex flex-col items-center justify-between pt-1',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-2 items-center mt-1">
|
<div className="flex flex-col gap-2 items-center mt-1">
|
||||||
@@ -65,15 +66,31 @@ export const RightBar = ({
|
|||||||
</button>
|
</button>
|
||||||
</WdTooltipWrapper>
|
</WdTooltipWrapper>
|
||||||
|
|
||||||
<WdTooltipWrapper content="Show on the map" position={TooltipPosition.left}>
|
<div className="flex flex-col gap-1">
|
||||||
<button
|
<TopSearch
|
||||||
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
|
customBtn={open => (
|
||||||
type="button"
|
<WdTooltipWrapper content="Show on the map" position={TooltipPosition.left}>
|
||||||
onClick={onShowOnTheMap}
|
<button
|
||||||
>
|
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
|
||||||
<i className="pi pi-hashtag"></i>
|
type="button"
|
||||||
</button>
|
onClick={open}
|
||||||
</WdTooltipWrapper>
|
>
|
||||||
|
<i className="pi pi-search"></i>
|
||||||
|
</button>
|
||||||
|
</WdTooltipWrapper>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<WdTooltipWrapper content="Show on the map" 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={onShowOnTheMap}
|
||||||
|
>
|
||||||
|
<i className="pi pi-hashtag"></i>
|
||||||
|
</button>
|
||||||
|
</WdTooltipWrapper>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{additionalContent}
|
{additionalContent}
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
import { Dialog } from 'primereact/dialog';
|
|
||||||
import { useCallback, useEffect } from 'react';
|
|
||||||
import { OutCommand, SignatureGroup, SystemSignature, TimeStatus } from '@/hooks/Mapper/types';
|
|
||||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|
||||||
import {
|
import {
|
||||||
SignatureGroupContent,
|
SignatureGroupContent,
|
||||||
SignatureGroupSelect,
|
SignatureGroupSelect,
|
||||||
} from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components';
|
} from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components';
|
||||||
import { InputText } from 'primereact/inputtext';
|
|
||||||
import { SystemsSettingsProvider } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/Provider.tsx';
|
import { SystemsSettingsProvider } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/Provider.tsx';
|
||||||
import { Button } from 'primereact/button';
|
import { WdButton } from '@/hooks/Mapper/components/ui-kit';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { getWhSize } from '@/hooks/Mapper/helpers/getWhSize';
|
import { OutCommand, SignatureGroup, SystemSignature, TimeStatus } from '@/hooks/Mapper/types';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||||
|
|
||||||
type SystemSignaturePrepared = Omit<SystemSignature, 'linked_system'> & { linked_system: string };
|
type SystemSignaturePrepared = Omit<SystemSignature, 'linked_system'> & {
|
||||||
|
linked_system: string;
|
||||||
|
k162Type: string;
|
||||||
|
time_status: TimeStatus;
|
||||||
|
};
|
||||||
|
|
||||||
export interface MapSettingsProps {
|
export interface MapSettingsProps {
|
||||||
systemId: string;
|
systemId: string;
|
||||||
@@ -22,10 +25,7 @@ export interface MapSettingsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SignatureSettings = ({ systemId, show, onHide, signatureData }: MapSettingsProps) => {
|
export const SignatureSettings = ({ systemId, show, onHide, signatureData }: MapSettingsProps) => {
|
||||||
const {
|
const { outCommand } = useMapRootState();
|
||||||
outCommand,
|
|
||||||
data: { wormholes },
|
|
||||||
} = useMapRootState();
|
|
||||||
|
|
||||||
const handleShow = async () => {};
|
const handleShow = async () => {};
|
||||||
const signatureForm = useForm<Partial<SystemSignaturePrepared>>({});
|
const signatureForm = useForm<Partial<SystemSignaturePrepared>>({});
|
||||||
@@ -52,41 +52,13 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
solar_system_target: values.linked_system,
|
solar_system_target: values.linked_system,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: need fix
|
|
||||||
if (values.isEOL) {
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateConnectionTimeStatus,
|
|
||||||
data: {
|
|
||||||
source: systemId,
|
|
||||||
target: values.linked_system,
|
|
||||||
value: TimeStatus.eol,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.type) {
|
|
||||||
const whShipSize = getWhSize(wormholes, values.type);
|
|
||||||
if (whShipSize !== undefined && whShipSize !== null) {
|
|
||||||
await outCommand({
|
|
||||||
type: OutCommand.updateConnectionShipSizeType,
|
|
||||||
data: {
|
|
||||||
source: systemId,
|
|
||||||
target: values.linked_system,
|
|
||||||
value: whShipSize,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out = {
|
out = {
|
||||||
...out,
|
...out,
|
||||||
custom_info: JSON.stringify({
|
custom_info: JSON.stringify({
|
||||||
// TODO: need fix
|
|
||||||
k162Type: values.k162Type,
|
k162Type: values.k162Type,
|
||||||
// TODO: need fix
|
time_status: values.time_status,
|
||||||
isEOL: values.isEOL,
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,6 +66,10 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
out = { ...out, type: values.type };
|
out = { ...out, type: values.type };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (values.temporary_name != null) {
|
||||||
|
out = { ...out, temporary_name: values.temporary_name };
|
||||||
|
}
|
||||||
|
|
||||||
if (signatureData.group !== SignatureGroup.Wormhole) {
|
if (signatureData.group !== SignatureGroup.Wormhole) {
|
||||||
out = { ...out, name: '' };
|
out = { ...out, name: '' };
|
||||||
}
|
}
|
||||||
@@ -143,13 +119,14 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
added: [],
|
added: [],
|
||||||
updated: [out],
|
updated: [out],
|
||||||
removed: [],
|
removed: [],
|
||||||
|
deleteTimeout: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
signatureForm.reset();
|
signatureForm.reset();
|
||||||
onHide();
|
onHide();
|
||||||
},
|
},
|
||||||
[signatureData, signatureForm, outCommand, systemId, onHide, wormholes],
|
[signatureData, signatureForm, outCommand, systemId, onHide],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -161,18 +138,17 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
const { linked_system, custom_info, ...rest } = signatureData;
|
const { linked_system, custom_info, ...rest } = signatureData;
|
||||||
|
|
||||||
let k162Type = null;
|
let k162Type = null;
|
||||||
let isEOL = false;
|
let time_status = TimeStatus._24h;
|
||||||
if (custom_info) {
|
if (custom_info) {
|
||||||
const customInfo = JSON.parse(custom_info);
|
const customInfo = JSON.parse(custom_info);
|
||||||
k162Type = customInfo.k162Type;
|
k162Type = customInfo.k162Type;
|
||||||
isEOL = customInfo.isEOL;
|
time_status = customInfo.time_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
signatureForm.reset({
|
signatureForm.reset({
|
||||||
linked_system: linked_system?.solar_system_id.toString() ?? undefined,
|
linked_system: linked_system?.solar_system_id.toString() ?? undefined,
|
||||||
// TODO: need fix
|
|
||||||
k162Type: k162Type,
|
k162Type: k162Type,
|
||||||
isEOL: isEOL,
|
time_status: time_status,
|
||||||
...rest,
|
...rest,
|
||||||
});
|
});
|
||||||
}, [signatureForm, signatureData]);
|
}, [signatureForm, signatureData]);
|
||||||
@@ -181,7 +157,8 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
<Dialog
|
<Dialog
|
||||||
header={`Signature Edit [${signatureData?.eve_id}]`}
|
header={`Signature Edit [${signatureData?.eve_id}]`}
|
||||||
visible={show}
|
visible={show}
|
||||||
draggable={false}
|
draggable
|
||||||
|
resizable={false}
|
||||||
style={{ width: '390px' }}
|
style={{ width: '390px' }}
|
||||||
onShow={handleShow}
|
onShow={handleShow}
|
||||||
onHide={() => {
|
onHide={() => {
|
||||||
@@ -216,8 +193,8 @@ export const SignatureSettings = ({ systemId, show, onHide, signatureData }: Map
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 justify-end">
|
<div className="flex gap-2 justify-end px-[0.75rem] pb-[0.5rem]">
|
||||||
<Button onClick={handleSave} outlined size="small" label="Save"></Button>
|
<WdButton type="submit" outlined size="small" label="Save" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { InputSwitch } from 'primereact/inputswitch';
|
|
||||||
import { Controller, useFormContext } from 'react-hook-form';
|
|
||||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
|
||||||
|
|
||||||
export interface SignatureEOLCheckboxProps {
|
|
||||||
name: string;
|
|
||||||
defaultValue?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SignatureEOLCheckbox = ({ name, defaultValue = false }: SignatureEOLCheckboxProps) => {
|
|
||||||
const { control } = useFormContext<SystemSignature>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Controller
|
|
||||||
// @ts-ignore
|
|
||||||
name={name}
|
|
||||||
control={control}
|
|
||||||
defaultValue={defaultValue}
|
|
||||||
render={({ field }) => {
|
|
||||||
return <InputSwitch className="my-1" checked={!!field.value} onChange={e => field.onChange(e.value)} />;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './SignatureEOLCheckbox.tsx';
|
|
||||||
@@ -3,7 +3,8 @@ import { SystemSignature } from '@/hooks/Mapper/types';
|
|||||||
import { SignatureWormholeTypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureWormholeTypeSelect';
|
import { SignatureWormholeTypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureWormholeTypeSelect';
|
||||||
import { SignatureK162TypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
import { SignatureK162TypeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
||||||
import { SignatureLeadsToSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureLeadsToSelect';
|
import { SignatureLeadsToSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureLeadsToSelect';
|
||||||
import { SignatureEOLCheckbox } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureEOLCheckbox';
|
import { SignatureLifetimeSelect } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureLifetimeSelect.tsx';
|
||||||
|
import { SignatureTempName } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureTempName.tsx';
|
||||||
|
|
||||||
export const SignatureGroupContentWormholes = () => {
|
export const SignatureGroupContentWormholes = () => {
|
||||||
const { watch } = useFormContext<SystemSignature>();
|
const { watch } = useFormContext<SystemSignature>();
|
||||||
@@ -28,9 +29,14 @@ export const SignatureGroupContentWormholes = () => {
|
|||||||
<SignatureLeadsToSelect name="linked_system" />
|
<SignatureLeadsToSelect name="linked_system" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
||||||
|
<span>Lifetime:</span>
|
||||||
|
<SignatureLifetimeSelect name="time_status" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
<label className="grid grid-cols-[100px_250px_1fr] gap-2 items-center text-[14px]">
|
||||||
<span>EOL:</span>
|
<span>Temp. Name:</span>
|
||||||
<SignatureEOLCheckbox name="isEOL" />
|
<SignatureTempName />
|
||||||
</label>
|
</label>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
|
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||||
|
import { WdLifetimeSelector } from '@/hooks/Mapper/components/ui-kit/WdLifetimeSelector.tsx';
|
||||||
|
|
||||||
|
export interface SignatureEOLCheckboxProps {
|
||||||
|
name: string;
|
||||||
|
defaultValue?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SignatureLifetimeSelect = ({ name, defaultValue = false }: SignatureEOLCheckboxProps) => {
|
||||||
|
const { control } = useFormContext<SystemSignature>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="my-1">
|
||||||
|
<Controller
|
||||||
|
// @ts-ignore
|
||||||
|
name={name}
|
||||||
|
control={control}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
render={({ field }) => {
|
||||||
|
// @ts-ignore
|
||||||
|
return <WdLifetimeSelector lifetime={field.value} onChangeLifetime={e => field.onChange(e)} />;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||||
|
|
||||||
|
export const SignatureTempName = () => {
|
||||||
|
const { control } = useFormContext<SystemSignature>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Controller
|
||||||
|
name="temporary_name"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => <InputText placeholder="Temporary Name" value={field.value} onChange={field.onChange} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './SignatureGroupSelect';
|
export * from './SignatureGroupSelect';
|
||||||
export * from './SignatureGroupContent';
|
export * from './SignatureGroupContent';
|
||||||
export * from './SignatureK162TypeSelect';
|
export * from './SignatureK162TypeSelect';
|
||||||
|
export * from './SignatureLifetimeSelect';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user