mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-11-29 04:23:22 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42e706e1c2 | ||
|
|
025dd06053 | ||
|
|
bcb421d879 | ||
|
|
66056ab54b | ||
|
|
bb92f76ceb | ||
|
|
84076b340b | ||
|
|
48caae5c0e | ||
|
|
77dd23795a | ||
|
|
2771d6304e | ||
|
|
9946edffa4 | ||
|
|
50bf2fd9d3 | ||
|
|
bdcde168aa | ||
|
|
5807142e20 | ||
|
|
ec2d9565b9 | ||
|
|
a18a71c73d | ||
|
|
93a6bd1156 | ||
|
|
581a410aef | ||
|
|
ab02fe988c | ||
|
|
b8d20fb21b | ||
|
|
12fa1a0be8 | ||
|
|
85a84f7507 | ||
|
|
2385313013 | ||
|
|
c7ce727571 | ||
|
|
8b165ff478 | ||
|
|
6d7d0cc72d | ||
|
|
f7eba5d4fd | ||
|
|
73ef6dae73 | ||
|
|
7fa6df1e5e | ||
|
|
e1a2ffb151 | ||
|
|
6d7727a32d | ||
|
|
6d7a94bd5a | ||
|
|
ecc3fb17e1 | ||
|
|
209e2bf0a5 | ||
|
|
b1947e57a4 | ||
|
|
74507501a5 | ||
|
|
c73481fd58 | ||
|
|
7795ad0b0c | ||
|
|
aff768f413 | ||
|
|
310b60f5b6 | ||
|
|
100f0be86a |
118
CHANGELOG.md
118
CHANGELOG.md
@@ -2,6 +2,124 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.29.3](https://github.com/wanderer-industries/wanderer/compare/v1.29.2...v1.29.3) (2024-12-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Increased eve DB data download timeout
|
||||
|
||||
## [v1.29.2](https://github.com/wanderer-industries/wanderer/compare/v1.29.1...v1.29.2) (2024-12-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fix unpkg CDN issues, fix Abyssals sites adding as systems on map
|
||||
|
||||
## [v1.29.1](https://github.com/wanderer-industries/wanderer/compare/v1.29.0...v1.29.1) (2024-12-05)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.29.0](https://github.com/wanderer-industries/wanderer/compare/v1.28.1...v1.29.0) (2024-12-05)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Signatures: Show 'Unsplashed' signatures on the map (optionally)
|
||||
|
||||
## [v1.28.1](https://github.com/wanderer-industries/wanderer/compare/v1.28.0...v1.28.1) (2024-12-04)
|
||||
|
||||
|
||||
|
||||
|
||||
## [v1.28.0](https://github.com/wanderer-industries/wanderer/compare/v1.27.1...v1.28.0) (2024-12-04)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Map: Added an option to show 'Offline characters' to map admins & managers only
|
||||
|
||||
## [v1.27.1](https://github.com/wanderer-industries/wanderer/compare/v1.27.0...v1.27.1) (2024-12-04)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Map: Fix 'On the map' visibility
|
||||
|
||||
## [v1.27.0](https://github.com/wanderer-industries/wanderer/compare/v1.26.1...v1.27.0) (2024-12-03)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Map: Hide 'On the map' list for 'Viewer' role
|
||||
|
||||
## [v1.26.1](https://github.com/wanderer-industries/wanderer/compare/v1.26.0...v1.26.1) (2024-12-03)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Signatures: Fix error on splash wh
|
||||
|
||||
## [v1.26.0](https://github.com/wanderer-industries/wanderer/compare/v1.25.2...v1.26.0) (2024-12-03)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Signatures: Keep 'Lazy delete' enabled setting
|
||||
|
||||
## [v1.25.2](https://github.com/wanderer-industries/wanderer/compare/v1.25.1...v1.25.2) (2024-12-01)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Signatures: Fix lazy delete on system switch
|
||||
|
||||
## [v1.25.1](https://github.com/wanderer-industries/wanderer/compare/v1.25.0...v1.25.1) (2024-11-28)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Signatures: Fix colors & add 'Backspace' hotkey to delete signatures
|
||||
|
||||
## [v1.25.0](https://github.com/wanderer-industries/wanderer/compare/v1.24.2...v1.25.0) (2024-11-28)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Signatures: Automatically remove signature if linked system removed
|
||||
|
||||
## [v1.24.2](https://github.com/wanderer-industries/wanderer/compare/v1.24.1...v1.24.2) (2024-11-27)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Signatures: Fix paste signatures
|
||||
|
||||
## [v1.24.1](https://github.com/wanderer-industries/wanderer/compare/v1.24.0...v1.24.1) (2024-11-27)
|
||||
|
||||
|
||||
|
||||
@@ -870,3 +870,63 @@ body {
|
||||
}
|
||||
}
|
||||
/* Map refresh END */
|
||||
|
||||
.inputContainer {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
}
|
||||
.inputContainer > span:nth-child(1),
|
||||
.inputContainer > label:nth-child(1) {
|
||||
color: var(--gray-200);
|
||||
font-size: 13px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.inputContainer > :nth-child(2) {
|
||||
border-bottom: 2px dotted #3f3f3f;
|
||||
height: 1px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.smallInputSwitch {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.smallInputSwitch .p-inputswitch {
|
||||
height: 1rem;
|
||||
width: 2rem;
|
||||
}
|
||||
.smallInputSwitch .p-inputswitch.p-inputswitch-checked .p-inputswitch-slider::before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
.smallInputSwitch .p-inputswitch.p-highlight .p-inputswitch-slider:before {
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
.smallInputSwitch .p-inputswitch .p-inputswitch-slider::before {
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
margin-top: -0.4rem;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
.checkboxRoot.sizeXS {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
.checkboxRoot.sizeXS .p-checkbox-box,
|
||||
.checkboxRoot.sizeXS .p-checkbox-input {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
.checkboxRoot.sizeM {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.checkboxRoot.sizeM .p-checkbox-box,
|
||||
.checkboxRoot.sizeM .p-checkbox-input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ $pastel-green: #88b04b;
|
||||
$pastel-yellow: #ffdd59;
|
||||
$dark-bg: #2d2d2d;
|
||||
$text-color: #ffffff;
|
||||
$tooltip-bg: #202020; // Темный фон для подсказок
|
||||
$tooltip-bg: #202020; // Dark background for tooltips
|
||||
|
||||
.RootCustomNode {
|
||||
display: flex;
|
||||
@@ -136,7 +136,7 @@ $tooltip-bg: #202020; // Темный фон для подсказок
|
||||
.Bookmarks {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
left: 4px;
|
||||
|
||||
@@ -182,6 +182,42 @@ $tooltip-bg: #202020; // Темный фон для подсказок
|
||||
}
|
||||
}
|
||||
|
||||
.Unsplashed {
|
||||
position: absolute;
|
||||
width: calc(50% - 4px);
|
||||
z-index: -1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2px;
|
||||
left: 2px;
|
||||
|
||||
&--right {
|
||||
left: calc(50% + 6px);
|
||||
}
|
||||
|
||||
& > .Signature {
|
||||
width: 13px;
|
||||
height: 4px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
border-radius: 5px;
|
||||
color: #ffffff;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
padding-top: 2px;
|
||||
font-weight: bolder;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
display: block;
|
||||
|
||||
background-color: #833ca4;
|
||||
|
||||
&:not(:first-child) {
|
||||
box-shadow: inset 4px -3px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
@@ -276,7 +312,6 @@ $tooltip-bg: #202020; // Темный фон для подсказок
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.Handlers {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Handle, Position, WrapNodeProps } from 'reactflow';
|
||||
import { MapSolarSystemType } from '../../map.types';
|
||||
import classes from './SolarSystemNode.module.scss';
|
||||
import clsx from 'clsx';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
|
||||
import {
|
||||
EFFECT_BACKGROUND_STYLES,
|
||||
LABELS_INFO,
|
||||
@@ -12,8 +14,9 @@ import {
|
||||
} from '@/hooks/Mapper/components/map/constants.ts';
|
||||
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace.ts';
|
||||
import { WormholeClassComp } from '@/hooks/Mapper/components/map/components/WormholeClassComp';
|
||||
import { UnsplashedSignature } from '@/hooks/Mapper/components/map/components/UnsplashedSignature';
|
||||
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx';
|
||||
import { getSystemClassStyles } from '@/hooks/Mapper/components/map/helpers';
|
||||
import { getSystemClassStyles, prepareUnsplashedChunks } from '@/hooks/Mapper/components/map/helpers';
|
||||
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
||||
import { PrimeIcons } from 'primereact/api';
|
||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
|
||||
@@ -50,6 +53,9 @@ export const getActivityType = (count: number) => {
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
export const SolarSystemNode = memo(({ data, selected }: WrapNodeProps<MapSolarSystemType>) => {
|
||||
const { interfaceSettings } = useMapRootState();
|
||||
const { isShowUnsplashedSignatures } = interfaceSettings;
|
||||
|
||||
const {
|
||||
system_class,
|
||||
security,
|
||||
@@ -63,6 +69,8 @@ export const SolarSystemNode = memo(({ data, selected }: WrapNodeProps<MapSolarS
|
||||
solar_system_name,
|
||||
} = data.system_static_info;
|
||||
|
||||
const signatures = data.system_signatures;
|
||||
|
||||
const { locked, name, tag, status, labels, id } = data || {};
|
||||
|
||||
const customName = solar_system_name !== name ? name : undefined;
|
||||
@@ -128,6 +136,22 @@ export const SolarSystemNode = memo(({ data, selected }: WrapNodeProps<MapSolarS
|
||||
const space = showKSpaceBG ? REGIONS_MAP[region_id] : '';
|
||||
const regionClass = showKSpaceBG ? SpaceToClass[space] : null;
|
||||
|
||||
const [unsplashedLeft, unsplashedRight] = useMemo(() => {
|
||||
if (!isShowUnsplashedSignatures) {
|
||||
return [[], []];
|
||||
}
|
||||
|
||||
return prepareUnsplashedChunks(
|
||||
signatures
|
||||
.filter(s => s.group === 'Wormhole' && !s.linked_system)
|
||||
.map(s => ({
|
||||
eve_id: s.eve_id,
|
||||
type: s.type,
|
||||
custom_info: s.custom_info,
|
||||
})),
|
||||
);
|
||||
}, [isShowUnsplashedSignatures, signatures]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{visible && (
|
||||
@@ -237,6 +261,22 @@ export const SolarSystemNode = memo(({ data, selected }: WrapNodeProps<MapSolarS
|
||||
)}
|
||||
</div>
|
||||
|
||||
{visible && isShowUnsplashedSignatures && (
|
||||
<div className={classes.Unsplashed}>
|
||||
{unsplashedLeft.map(x => (
|
||||
<UnsplashedSignature key={x.sig_id} signature={x} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{visible && isShowUnsplashedSignatures && (
|
||||
<div className={clsx([classes.Unsplashed, classes['Unsplashed--right']])}>
|
||||
{unsplashedRight.map(x => (
|
||||
<UnsplashedSignature key={x.sig_id} signature={x} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div onMouseDownCapture={dbClick} className={classes.Handlers}>
|
||||
<Handle
|
||||
type="source"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
@import '@/hooks/Mapper/components/map/styles/eve-common-variables';
|
||||
|
||||
.Signature {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
display: block;
|
||||
|
||||
& > .Box {
|
||||
width: 13px;
|
||||
height: 4px;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||
import { InfoDrawer } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
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 { useMemo } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { renderInfoColumn } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders';
|
||||
|
||||
import { k162Types } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings/components/SignatureK162TypeSelect';
|
||||
|
||||
interface UnsplashedSignatureProps {
|
||||
signature: SystemSignature;
|
||||
}
|
||||
export const UnsplashedSignature = ({ signature }: UnsplashedSignatureProps) => {
|
||||
const {
|
||||
data: { wormholesData },
|
||||
} = useMapRootState();
|
||||
|
||||
const whData = useMemo(() => wormholesData[signature.type], [signature.type, wormholesData]);
|
||||
const whClass = useMemo(() => (whData ? WORMHOLES_ADDITIONAL_INFO[whData.dest] : null), [whData]);
|
||||
|
||||
const k162TypeOption = useMemo(() => {
|
||||
if (!signature.custom_info) {
|
||||
return null;
|
||||
}
|
||||
const customInfo = JSON.parse(signature.custom_info);
|
||||
if (!customInfo.k162Type) {
|
||||
return null;
|
||||
}
|
||||
return k162Types.find(x => x.value === customInfo.k162Type);
|
||||
}, [signature]);
|
||||
|
||||
const whClassStyle = useMemo(() => {
|
||||
if (signature.type === 'K162' && k162TypeOption) {
|
||||
const k162Data = wormholesData[k162TypeOption.whClassName];
|
||||
const k162Class = k162Data ? WORMHOLES_ADDITIONAL_INFO[k162Data.dest] : null;
|
||||
return k162Class ? WORMHOLE_CLASS_STYLES[k162Class.wormholeClassID] : '';
|
||||
}
|
||||
return whClass ? WORMHOLE_CLASS_STYLES[whClass.wormholeClassID] : '';
|
||||
}, [signature, whClass, k162TypeOption, wormholesData]);
|
||||
|
||||
return (
|
||||
<WdTooltipWrapper
|
||||
className={clsx(classes.Signature)}
|
||||
content={
|
||||
(
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title={<b className="text-slate-50">{signature.eve_id}</b>}>
|
||||
{renderInfoColumn(signature)}
|
||||
</InfoDrawer>
|
||||
</div>
|
||||
) as React.ReactNode
|
||||
}
|
||||
>
|
||||
<div className={clsx(classes.Box, whClassStyle)}>
|
||||
<svg width="13" height="4" viewBox="0 0 13 4" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="13" height="4" rx="2" className={whClassStyle} fill="currentColor" />
|
||||
</svg>
|
||||
</div>
|
||||
</WdTooltipWrapper>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './UnsplashedSignature.tsx';
|
||||
@@ -3,3 +3,4 @@ export * from './convertSystem2Node';
|
||||
export * from './getSystemClassStyles';
|
||||
export * from './getShapeClass';
|
||||
export * from './getBackgroundClass';
|
||||
export * from './prepareUnsplashedChunks';
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Helper function to split an array into chunks of size
|
||||
const chunkArray = (array: any[], size: number) => {
|
||||
const chunks = [];
|
||||
for (let i = 0; i < array.length; i += size) {
|
||||
chunks.push(array.slice(i, i + size));
|
||||
}
|
||||
return chunks;
|
||||
};
|
||||
|
||||
export const prepareUnsplashedChunks = (items: any[]) => {
|
||||
// Split the items into chunks of 4
|
||||
const chunks = chunkArray(items, 4);
|
||||
|
||||
// Get the column elements
|
||||
const leftColumn: any[] = [];
|
||||
const rightColumn: any[] = [];
|
||||
|
||||
chunks.forEach((chunk, index) => {
|
||||
const column = index % 2 === 0 ? leftColumn : rightColumn;
|
||||
|
||||
chunk.forEach(item => {
|
||||
column.push(item);
|
||||
});
|
||||
});
|
||||
|
||||
return [leftColumn, rightColumn];
|
||||
};
|
||||
@@ -26,8 +26,8 @@ $eve-effect-republicStellarObservatory: #6991ce;
|
||||
$eve-effect-federalStellarObservatory: #6991ce;
|
||||
|
||||
$eve-wh-type-color-high: #5dffd2;
|
||||
$eve-wh-type-color-low: #d96c07;
|
||||
$eve-wh-type-color-null: #8b3263;
|
||||
$eve-wh-type-color-low: #f79400;
|
||||
$eve-wh-type-color-null: #fc3c3c;
|
||||
$eve-wh-type-color-c1: #69bfce;
|
||||
$eve-wh-type-color-c2: #6991ce;
|
||||
$eve-wh-type-color-c3: #a8cb70;
|
||||
|
||||
@@ -8,6 +8,8 @@ import { CharacterTypeRaw, WithIsOwnCharacter } from '@/hooks/Mapper/types';
|
||||
import { CharacterCard, LayoutEventBlocker, WdCheckbox } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { sortCharacters } from '@/hooks/Mapper/components/mapInterface/helpers/sortCharacters.ts';
|
||||
import useLocalStorageState from 'use-local-storage-state';
|
||||
import { useMapCheckPermissions, useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
||||
|
||||
type CharItemProps = {
|
||||
compact: boolean;
|
||||
@@ -62,6 +64,14 @@ export const LocalCharacters = () => {
|
||||
|
||||
const [systemId] = selectedSystems;
|
||||
|
||||
const restrictOfflineShowing = useMapGetOption('restrict_offline_showing');
|
||||
const isAdminOrManager = useMapCheckPermissions([UserPermission.MANAGE_MAP]);
|
||||
|
||||
const showOffline = useMemo(
|
||||
() => !restrictOfflineShowing || isAdminOrManager,
|
||||
[isAdminOrManager, restrictOfflineShowing],
|
||||
);
|
||||
|
||||
const itemTemplate = useItemTemplate();
|
||||
|
||||
const sorted = useMemo(() => {
|
||||
@@ -70,13 +80,13 @@ export const LocalCharacters = () => {
|
||||
.map(x => ({ ...x, isOwn: userCharacters.includes(x.eve_id), compact: settings.compact }))
|
||||
.sort(sortCharacters);
|
||||
|
||||
if (!settings.showOffline) {
|
||||
if (!showOffline || !settings.showOffline) {
|
||||
return sorted.filter(c => c.online);
|
||||
}
|
||||
|
||||
return sorted;
|
||||
// eslint-disable-next-line
|
||||
}, [characters, settings.showOffline, settings.compact, systemId, userCharacters, presentCharacters]);
|
||||
}, [showOffline, characters, settings.showOffline, settings.compact, systemId, userCharacters, presentCharacters]);
|
||||
|
||||
const isNobodyHere = sorted.length === 0;
|
||||
const isNotSelectedSystem = selectedSystems.length !== 1;
|
||||
@@ -88,14 +98,16 @@ export const LocalCharacters = () => {
|
||||
<div className="flex justify-between items-center text-xs w-full">
|
||||
<span className="select-none">Local{showList ? ` [${sorted.length}]` : ''}</span>
|
||||
<LayoutEventBlocker className="flex items-center gap-2">
|
||||
<WdCheckbox
|
||||
size="xs"
|
||||
labelSide="left"
|
||||
label={'Show offline'}
|
||||
value={settings.showOffline}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
|
||||
onChange={() => setSettings(() => ({ ...settings, showOffline: !settings.showOffline }))}
|
||||
/>
|
||||
{showOffline && (
|
||||
<WdCheckbox
|
||||
size="xs"
|
||||
labelSide="left"
|
||||
label={'Show offline'}
|
||||
value={settings.showOffline}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
|
||||
onChange={() => setSettings(() => ({ ...settings, showOffline: !settings.showOffline }))}
|
||||
/>
|
||||
)}
|
||||
|
||||
<span
|
||||
className={clsx('w-4 h-4 cursor-pointer', {
|
||||
@@ -115,7 +127,9 @@ export const LocalCharacters = () => {
|
||||
)}
|
||||
|
||||
{isNobodyHere && !isNotSelectedSystem && (
|
||||
<div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm">Nobody here</div>
|
||||
<div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm">
|
||||
Nobody here
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showList && (
|
||||
|
||||
@@ -27,15 +27,17 @@ import { PrimeIcons } from 'primereact/api';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { CheckboxChangeEvent } from 'primereact/checkbox';
|
||||
|
||||
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v5';
|
||||
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v5_2';
|
||||
export const SHOW_DESCRIPTION_COLUMN_SETTING = 'show_description_column_setting';
|
||||
export const SHOW_UPDATED_COLUMN_SETTING = 'SHOW_UPDATED_COLUMN_SETTING';
|
||||
export const LAZY_DELETE_SIGNATURES_SETTING = 'LAZY_DELETE_SIGNATURES_SETTING';
|
||||
export const KEEP_LAZY_DELETE_SETTING = 'KEEP_LAZY_DELETE_ENABLED_SETTING';
|
||||
|
||||
const settings: Setting[] = [
|
||||
{ key: SHOW_UPDATED_COLUMN_SETTING, name: 'Show Updated Column', value: false, isFilter: false },
|
||||
{ key: SHOW_DESCRIPTION_COLUMN_SETTING, name: 'Show Description Column', value: false, isFilter: false },
|
||||
{ key: LAZY_DELETE_SIGNATURES_SETTING, name: 'Lazy Delete Signatures', value: false, isFilter: false },
|
||||
{ key: KEEP_LAZY_DELETE_SETTING, name: 'Keep "Lazy Delete" Enabled', value: false, isFilter: false },
|
||||
{ key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true, isFilter: true },
|
||||
{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true, isFilter: true },
|
||||
{ key: DEPLOYABLE, name: 'Show Deployables', value: true, isFilter: true },
|
||||
@@ -77,10 +79,10 @@ export const SystemSignatures = () => {
|
||||
setVisible(false);
|
||||
}, []);
|
||||
|
||||
const handleLazyDeleteChange = useCallback((event: CheckboxChangeEvent) => {
|
||||
const handleLazyDeleteChange = useCallback((value: boolean) => {
|
||||
setSettings(settings => {
|
||||
const lazyDelete = settings.find(setting => setting.key === LAZY_DELETE_SIGNATURES_SETTING)!;
|
||||
lazyDelete.value = !!event.checked;
|
||||
lazyDelete.value = value;
|
||||
localStorage.setItem(SIGNATURE_SETTINGS_KEY, JSON.stringify(settings));
|
||||
return [...settings];
|
||||
});
|
||||
@@ -107,7 +109,7 @@ export const SystemSignatures = () => {
|
||||
label={'Lazy delete'}
|
||||
value={lazyDeleteValue}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
|
||||
onChange={handleLazyDeleteChange}
|
||||
onChange={(event: CheckboxChangeEvent) => handleLazyDeleteChange(!!event.checked)}
|
||||
/>
|
||||
|
||||
<WdImgButton
|
||||
@@ -149,7 +151,7 @@ export const SystemSignatures = () => {
|
||||
System is not selected
|
||||
</div>
|
||||
) : (
|
||||
<SystemSignaturesContent systemId={systemId} settings={settings} />
|
||||
<SystemSignaturesContent systemId={systemId} settings={settings} onLazyDeleteChange={handleLazyDeleteChange} />
|
||||
)}
|
||||
{visible && (
|
||||
<SystemSignatureSettingsDialog
|
||||
|
||||
@@ -11,6 +11,7 @@ import useRefState from 'react-usestateref';
|
||||
import { Setting } from '../SystemSignatureSettingsDialog';
|
||||
import { useHotkey } from '@/hooks/Mapper/hooks';
|
||||
import useMaxWidth from '@/hooks/Mapper/hooks/useMaxWidth.ts';
|
||||
import { useClipboard } from '@/hooks/Mapper/hooks/useClipboard';
|
||||
|
||||
import classes from './SystemSignaturesContent.module.scss';
|
||||
import clsx from 'clsx';
|
||||
@@ -37,6 +38,7 @@ import {
|
||||
SHOW_DESCRIPTION_COLUMN_SETTING,
|
||||
SHOW_UPDATED_COLUMN_SETTING,
|
||||
LAZY_DELETE_SIGNATURES_SETTING,
|
||||
KEEP_LAZY_DELETE_SETTING,
|
||||
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures';
|
||||
type SystemSignaturesSortSettings = {
|
||||
sortField: string;
|
||||
@@ -54,6 +56,7 @@ interface SystemSignaturesContentProps {
|
||||
hideLinkedSignatures?: boolean;
|
||||
selectable?: boolean;
|
||||
onSelect?: (signature: SystemSignature) => void;
|
||||
onLazyDeleteChange?: (value: boolean) => void;
|
||||
}
|
||||
export const SystemSignaturesContent = ({
|
||||
systemId,
|
||||
@@ -61,6 +64,7 @@ export const SystemSignaturesContent = ({
|
||||
hideLinkedSignatures,
|
||||
selectable,
|
||||
onSelect,
|
||||
onLazyDeleteChange,
|
||||
}: SystemSignaturesContentProps) => {
|
||||
const { outCommand } = useMapRootState();
|
||||
|
||||
@@ -83,10 +87,16 @@ export const SystemSignaturesContent = ({
|
||||
|
||||
const tooltipRef = useRef<WdTooltipHandlers>(null);
|
||||
|
||||
const { clipboardContent, setClipboardContent } = useClipboard();
|
||||
|
||||
const lazyDeleteValue = useMemo(() => {
|
||||
return settings.find(setting => setting.key === LAZY_DELETE_SIGNATURES_SETTING)?.value ?? false;
|
||||
}, [settings]);
|
||||
|
||||
const keepLazyDeleteValue = useMemo(() => {
|
||||
return settings.find(setting => setting.key === KEEP_LAZY_DELETE_SETTING)?.value ?? false;
|
||||
}, [settings]);
|
||||
|
||||
const handleResize = useCallback(() => {
|
||||
if (tableRef.current) {
|
||||
const tableWidth = tableRef.current.offsetWidth;
|
||||
@@ -202,28 +212,47 @@ export const SystemSignaturesContent = ({
|
||||
[onSelect, selectable],
|
||||
);
|
||||
|
||||
const handlePaste = async () => {
|
||||
const clipboardContent = await navigator.clipboard.readText();
|
||||
if (refData.current.selectable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clipboardContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handlePaste = async (clipboardContent: string) => {
|
||||
const newSignatures = parseSignatures(
|
||||
clipboardContent,
|
||||
settings.map(x => x.key),
|
||||
);
|
||||
|
||||
handleUpdateSignatures(newSignatures, !lazyDeleteValue);
|
||||
|
||||
if (lazyDeleteValue && !keepLazyDeleteValue) {
|
||||
onLazyDeleteChange?.(false);
|
||||
}
|
||||
};
|
||||
|
||||
useHotkey(true, ['a'], handleSelectAll);
|
||||
useHotkey(true, ['v'], handlePaste);
|
||||
const handleEnterRow = useCallback(
|
||||
(e: DataTableRowMouseEvent) => {
|
||||
setHoveredSig(filteredSignatures[e.index]);
|
||||
tooltipRef.current?.show(e.originalEvent);
|
||||
},
|
||||
[filteredSignatures],
|
||||
);
|
||||
|
||||
useHotkey(false, ['Delete'], handleDeleteSelected);
|
||||
const handleLeaveRow = useCallback((e: DataTableRowMouseEvent) => {
|
||||
tooltipRef.current?.hide(e.originalEvent);
|
||||
setHoveredSig(null);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (refData.current.selectable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clipboardContent?.text) {
|
||||
return;
|
||||
}
|
||||
|
||||
handlePaste(clipboardContent.text);
|
||||
setClipboardContent(null);
|
||||
}, [clipboardContent, selectable, lazyDeleteValue, keepLazyDeleteValue]);
|
||||
|
||||
useHotkey(true, ['a'], handleSelectAll);
|
||||
useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected);
|
||||
|
||||
useEffect(() => {
|
||||
if (!systemId) {
|
||||
@@ -261,19 +290,6 @@ export const SystemSignaturesContent = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleEnterRow = useCallback(
|
||||
(e: DataTableRowMouseEvent) => {
|
||||
setHoveredSig(filteredSignatures[e.index]);
|
||||
tooltipRef.current?.show(e.originalEvent);
|
||||
},
|
||||
[filteredSignatures],
|
||||
);
|
||||
|
||||
const handleLeaveRow = useCallback((e: DataTableRowMouseEvent) => {
|
||||
tooltipRef.current?.hide(e.originalEvent);
|
||||
setHoveredSig(null);
|
||||
}, []);
|
||||
|
||||
const renderToolbar = (/*row: SystemSignature*/) => {
|
||||
return (
|
||||
<div className="flex justify-end items-center gap-2 mr-[4px]">
|
||||
@@ -357,7 +373,6 @@ export const SystemSignaturesContent = ({
|
||||
></Column>
|
||||
<Column
|
||||
field="info"
|
||||
// header="Info"
|
||||
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
body={renderInfoColumn}
|
||||
style={{ maxWidth: nameColumnWidth }}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.whFontSize {
|
||||
font-size: 11px !important;
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrap
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { renderName } from './renderName.tsx';
|
||||
import classes from './renderInfoColumn.module.scss';
|
||||
|
||||
export const renderInfoColumn = (row: SystemSignature) => {
|
||||
if (!row.group || row.group === SignatureGroup.Wormhole) {
|
||||
@@ -23,12 +22,11 @@ export const renderInfoColumn = (row: SystemSignature) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-start items-center gap-[6px]">
|
||||
<div className="flex justify-start items-center gap-[4px]">
|
||||
{row.type && (
|
||||
<WHClassView
|
||||
className="text-[11px]"
|
||||
classNameWh={classes.whFontSize}
|
||||
highlightName
|
||||
classNameWh="!text-[11px] !font-bold"
|
||||
hideWhClass={!!row.linked_system}
|
||||
whClassName={row.type}
|
||||
noOffset
|
||||
@@ -36,11 +34,10 @@ export const renderInfoColumn = (row: SystemSignature) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{!row.linked_system && !!k162TypeOption && <>{renderK162Type(k162TypeOption, 'text-[11px]')}</>}
|
||||
{!row.linked_system && row.type === 'K162' && !!k162TypeOption && <>{renderK162Type(k162TypeOption)}</>}
|
||||
|
||||
{row.linked_system && (
|
||||
<>
|
||||
{/*<span className="w-4 h-4 hero-arrow-long-right"></span>*/}
|
||||
<span title={row.linked_system?.solar_system_name}>
|
||||
<SystemViewStandalone
|
||||
className={clsx('select-none text-center cursor-context-menu')}
|
||||
|
||||
@@ -5,6 +5,8 @@ import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrap
|
||||
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { OutCommand } from '@/hooks/Mapper/types';
|
||||
import { MenuItem } from 'primereact/menuitem';
|
||||
import { useMapCheckPermissions } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
||||
|
||||
export interface MapContextMenuProps {
|
||||
onShowOnTheMap?: () => void;
|
||||
@@ -14,6 +16,8 @@ export interface MapContextMenuProps {
|
||||
export const MapContextMenu = ({ onShowOnTheMap, onShowMapSettings }: MapContextMenuProps) => {
|
||||
const { outCommand, setInterfaceSettings } = useMapRootState();
|
||||
|
||||
const canTrackCharacters = useMapCheckPermissions([UserPermission.TRACK_CHARACTER]);
|
||||
|
||||
const menuRight = useRef<Menu>(null);
|
||||
|
||||
const handleAddCharacter = useCallback(() => {
|
||||
@@ -24,34 +28,40 @@ export const MapContextMenu = ({ onShowOnTheMap, onShowMapSettings }: MapContext
|
||||
}, [outCommand]);
|
||||
|
||||
const items = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Tracking',
|
||||
icon: 'pi pi-user-plus',
|
||||
command: handleAddCharacter,
|
||||
},
|
||||
{
|
||||
label: 'On the map',
|
||||
icon: 'pi pi-hashtag',
|
||||
command: onShowOnTheMap,
|
||||
},
|
||||
{ separator: true },
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: `pi pi-cog`,
|
||||
command: onShowMapSettings,
|
||||
},
|
||||
{
|
||||
label: 'Dock menu',
|
||||
icon: 'pi pi-window-maximize',
|
||||
command: () =>
|
||||
setInterfaceSettings(x => ({
|
||||
...x,
|
||||
isShowMenu: !x.isShowMenu,
|
||||
})),
|
||||
},
|
||||
] as MenuItem[];
|
||||
}, [handleAddCharacter, onShowMapSettings, onShowOnTheMap, setInterfaceSettings]);
|
||||
return (
|
||||
[
|
||||
{
|
||||
label: 'Tracking',
|
||||
icon: 'pi pi-user-plus',
|
||||
command: handleAddCharacter,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
label: 'On the map',
|
||||
icon: 'pi pi-hashtag',
|
||||
command: onShowOnTheMap,
|
||||
visible: canTrackCharacters,
|
||||
},
|
||||
{ separator: true, visible: true },
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: `pi pi-cog`,
|
||||
command: onShowMapSettings,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
label: 'Dock menu',
|
||||
icon: 'pi pi-window-maximize',
|
||||
command: () =>
|
||||
setInterfaceSettings(x => ({
|
||||
...x,
|
||||
isShowMenu: !x.isShowMenu,
|
||||
})),
|
||||
visible: true,
|
||||
},
|
||||
] as MenuItem[]
|
||||
).filter(item => item.visible);
|
||||
}, [canTrackCharacters, handleAddCharacter, onShowMapSettings, onShowOnTheMap, setInterfaceSettings]);
|
||||
|
||||
return (
|
||||
<div className="ml-1">
|
||||
|
||||
@@ -53,6 +53,7 @@ const SYSTEMS_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
|
||||
const SIGNATURES_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
{ prop: UserSettingsRemoteProps.link_signature_on_splash, label: 'Link signature on splash' },
|
||||
{ prop: InterfaceStoredSettingsProps.isShowUnsplashedSignatures, label: 'Show unsplashed signatures' },
|
||||
];
|
||||
|
||||
const CONNECTIONS_CHECKBOXES_PROPS: CheckboxesList = [
|
||||
@@ -128,7 +129,7 @@ export const MapSettings = ({ show, onHide }: MapSettingsProps) => {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
header="Map settings"
|
||||
header="Map user settings"
|
||||
visible={show}
|
||||
draggable={false}
|
||||
style={{ width: '550px' }}
|
||||
|
||||
@@ -8,6 +8,8 @@ import clsx from 'clsx';
|
||||
import { CharacterTypeRaw, WithIsOwnCharacter } from '@/hooks/Mapper/types';
|
||||
import { CharacterCard, WdCheckbox } from '@/hooks/Mapper/components/ui-kit';
|
||||
import useLocalStorageState from 'use-local-storage-state';
|
||||
import { useMapCheckPermissions, useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
||||
|
||||
type WindowLocalSettingsType = {
|
||||
compact: boolean;
|
||||
@@ -50,14 +52,22 @@ export const OnTheMap = ({ show, onHide }: OnTheMapProps) => {
|
||||
defaultValue: STORED_DEFAULT_VALUES,
|
||||
});
|
||||
|
||||
const restrictOfflineShowing = useMapGetOption('restrict_offline_showing');
|
||||
const isAdminOrManager = useMapCheckPermissions([UserPermission.MANAGE_MAP]);
|
||||
|
||||
const showOffline = useMemo(
|
||||
() => !restrictOfflineShowing || isAdminOrManager,
|
||||
[isAdminOrManager, restrictOfflineShowing],
|
||||
);
|
||||
|
||||
const sorted = useMemo(() => {
|
||||
const out = characters.map(x => ({ ...x, isOwn: userCharacters.includes(x.eve_id) })).sort(sortCharacters);
|
||||
if (!settings.hideOffline) {
|
||||
if (showOffline && !settings.hideOffline) {
|
||||
return out;
|
||||
}
|
||||
|
||||
return out.filter(x => x.online);
|
||||
}, [characters, settings.hideOffline, userCharacters]);
|
||||
}, [showOffline, characters, settings.hideOffline, userCharacters]);
|
||||
|
||||
return (
|
||||
<Sidebar
|
||||
@@ -70,14 +80,16 @@ export const OnTheMap = ({ show, onHide }: OnTheMapProps) => {
|
||||
>
|
||||
<div className={clsx(classes.SidebarContent, '')}>
|
||||
<div className={'flex justify-end items-center gap-2 px-3'}>
|
||||
<WdCheckbox
|
||||
size="m"
|
||||
labelSide="left"
|
||||
label={'Hide offline'}
|
||||
value={settings.hideOffline}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
|
||||
onChange={() => setSettings(() => ({ ...settings, hideOffline: !settings.hideOffline }))}
|
||||
/>
|
||||
{showOffline && (
|
||||
<WdCheckbox
|
||||
size="m"
|
||||
labelSide="left"
|
||||
label={'Hide offline'}
|
||||
value={settings.hideOffline}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
|
||||
onChange={() => setSettings(() => ({ ...settings, hideOffline: !settings.hideOffline }))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<VirtualScroller
|
||||
|
||||
@@ -6,6 +6,9 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
import { useMapCheckPermissions } from '@/hooks/Mapper/mapRootProvider/hooks/api';
|
||||
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
|
||||
|
||||
interface RightBarProps {
|
||||
onShowOnTheMap?: () => void;
|
||||
onShowMapSettings?: () => void;
|
||||
@@ -14,6 +17,8 @@ interface RightBarProps {
|
||||
export const RightBar = ({ onShowOnTheMap, onShowMapSettings }: RightBarProps) => {
|
||||
const { outCommand, interfaceSettings, setInterfaceSettings } = useMapRootState();
|
||||
|
||||
const canTrackCharacters = useMapCheckPermissions([UserPermission.TRACK_CHARACTER]);
|
||||
|
||||
const isShowMinimap = interfaceSettings.isShowMinimap === undefined ? true : interfaceSettings.isShowMinimap;
|
||||
|
||||
const handleAddCharacter = useCallback(() => {
|
||||
@@ -64,19 +69,21 @@ export const RightBar = ({ onShowOnTheMap, onShowMapSettings }: RightBarProps) =
|
||||
</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>
|
||||
{canTrackCharacters && (
|
||||
<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>
|
||||
|
||||
<div className="flex flex-col items-center mb-2 gap-1">
|
||||
<WdTooltipWrapper content="User settings" position={TooltipPosition.left}>
|
||||
<WdTooltipWrapper content="Map user settings" position={TooltipPosition.left}>
|
||||
<button
|
||||
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
|
||||
type="button"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.SystemView {
|
||||
font-size: 14px;
|
||||
}
|
||||
@@ -2,126 +2,102 @@ import { Dropdown } from 'primereact/dropdown';
|
||||
import clsx from 'clsx';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { useMemo } from 'react';
|
||||
import { SystemView } from '@/hooks/Mapper/components/ui-kit';
|
||||
import classes from './SignatureK162TypeSelect.module.scss';
|
||||
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { SOLAR_SYSTEM_CLASS_IDS } from '@/hooks/Mapper/components/map/constants.ts';
|
||||
import { WHClassView } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export const k162Types = [
|
||||
{
|
||||
label: 'Hi-Sec',
|
||||
value: 'hs',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.hs,
|
||||
security: '0.8',
|
||||
whClassName: 'A641',
|
||||
},
|
||||
{
|
||||
label: 'Low-Sec',
|
||||
value: 'ls',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.ls,
|
||||
security: '0.4',
|
||||
whClassName: 'J377',
|
||||
},
|
||||
{
|
||||
label: 'Null-Sec',
|
||||
value: 'ns',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.ns,
|
||||
security: '-0.5',
|
||||
whClassName: 'C248',
|
||||
},
|
||||
{
|
||||
label: 'C1',
|
||||
value: 'c1',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c1,
|
||||
whClassName: 'E004',
|
||||
},
|
||||
{
|
||||
label: 'C2',
|
||||
value: 'c2',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c2,
|
||||
whClassName: 'D382',
|
||||
},
|
||||
{
|
||||
label: 'C3',
|
||||
value: 'c3',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c3,
|
||||
whClassName: 'L477',
|
||||
},
|
||||
{
|
||||
label: 'C4',
|
||||
value: 'c4',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c4,
|
||||
whClassName: 'M001',
|
||||
},
|
||||
{
|
||||
label: 'C5',
|
||||
value: 'c5',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c5,
|
||||
whClassName: 'L614',
|
||||
},
|
||||
{
|
||||
label: 'C6',
|
||||
value: 'c6',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.c6,
|
||||
whClassName: 'G008',
|
||||
},
|
||||
{
|
||||
label: 'C13',
|
||||
value: 'c13',
|
||||
whClassName: 'A009',
|
||||
},
|
||||
{
|
||||
label: 'Thera',
|
||||
value: 'thera',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.thera,
|
||||
whClassName: 'F353',
|
||||
},
|
||||
{
|
||||
label: 'Pochven',
|
||||
value: 'pochven',
|
||||
system_class: SOLAR_SYSTEM_CLASS_IDS.pochven,
|
||||
whClassName: 'F216',
|
||||
},
|
||||
];
|
||||
|
||||
import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types';
|
||||
|
||||
const renderNoValue = () => <div className="flex gap-2 items-center">-Unknown-</div>;
|
||||
|
||||
// @ts-ignore
|
||||
export const renderK162Type = (
|
||||
option: {
|
||||
label?: string;
|
||||
value: string;
|
||||
security?: string;
|
||||
system_class?: number;
|
||||
},
|
||||
className?: string,
|
||||
) => {
|
||||
export const renderK162Type = (option: {
|
||||
label?: string;
|
||||
value: string;
|
||||
security?: string;
|
||||
system_class?: number;
|
||||
whClassName?: string;
|
||||
}) => {
|
||||
if (!option) {
|
||||
return renderNoValue();
|
||||
}
|
||||
const { value, label = '', system_class = 0, security = '1.0' } = option;
|
||||
const { value, whClassName = '' } = option;
|
||||
if (value == null) {
|
||||
return renderNoValue();
|
||||
}
|
||||
|
||||
const systemInfo: SolarSystemStaticInfoRaw = {
|
||||
region_id: 0,
|
||||
constellation_id: 0,
|
||||
solar_system_id: 0,
|
||||
constellation_name: '',
|
||||
region_name: '',
|
||||
system_class: system_class,
|
||||
security: security,
|
||||
type_description: '',
|
||||
class_title: label,
|
||||
is_shattered: false,
|
||||
effect_name: '',
|
||||
effect_power: 0,
|
||||
statics: [],
|
||||
wandering: [],
|
||||
triglavian_invasion_status: '',
|
||||
sun_type_id: 0,
|
||||
solar_system_name: '',
|
||||
solar_system_name_lc: '',
|
||||
};
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<SystemView systemId="" className={className} showCustomName hideRegion systemInfo={systemInfo} />
|
||||
</div>
|
||||
<WHClassView
|
||||
classNameWh="!text-[11px] !font-bold"
|
||||
hideWhClassName
|
||||
hideTooltip
|
||||
whClassName={whClassName}
|
||||
noOffset
|
||||
useShortTitle
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
export const renderK162TypeOption = option => {
|
||||
return renderK162Type(option, classes.SystemView);
|
||||
};
|
||||
|
||||
export interface SignatureK162TypeSelectProps {
|
||||
name: string;
|
||||
defaultValue?: string;
|
||||
@@ -150,8 +126,8 @@ export const SignatureK162TypeSelect = ({ name, defaultValue = '' }: SignatureK1
|
||||
placeholder="Select K162 type"
|
||||
className={clsx('w-full')}
|
||||
scrollHeight="240px"
|
||||
itemTemplate={renderK162TypeOption}
|
||||
valueTemplate={renderK162TypeOption}
|
||||
itemTemplate={renderK162Type}
|
||||
valueTemplate={renderK162Type}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.WHClassViewRoot {
|
||||
|
||||
}
|
||||
|
||||
.WHClassViewContent {
|
||||
|
||||
@@ -18,7 +18,9 @@ export interface WHClassViewProps {
|
||||
whClassName: string;
|
||||
noOffset?: boolean;
|
||||
useShortTitle?: boolean;
|
||||
hideTooltip?: boolean;
|
||||
hideWhClass?: boolean;
|
||||
hideWhClassName?: boolean;
|
||||
highlightName?: boolean;
|
||||
className?: string;
|
||||
classNameWh?: string;
|
||||
@@ -28,7 +30,9 @@ export const WHClassView = ({
|
||||
whClassName,
|
||||
noOffset,
|
||||
useShortTitle,
|
||||
hideTooltip,
|
||||
hideWhClass,
|
||||
hideWhClassName,
|
||||
highlightName,
|
||||
className,
|
||||
classNameWh,
|
||||
@@ -45,25 +49,27 @@ export const WHClassView = ({
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.WHClassViewRoot, className)}>
|
||||
<Tooltip
|
||||
target={`.wh-name${whClassName}${uid}`}
|
||||
position="right"
|
||||
mouseTrack
|
||||
mouseTrackLeft={20}
|
||||
mouseTrackTop={30}
|
||||
className="border border-green-300 rounded border-opacity-10 bg-stone-900 bg-opacity-90 "
|
||||
>
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title="Total mass">{prepareMass(whData.total_mass)}</InfoDrawer>
|
||||
<InfoDrawer title="Jump mass">{prepareMass(whData.max_mass_per_jump)}</InfoDrawer>
|
||||
{!hideTooltip && (
|
||||
<Tooltip
|
||||
target={`.wh-name${whClassName}${uid}`}
|
||||
position="right"
|
||||
mouseTrack
|
||||
mouseTrackLeft={20}
|
||||
mouseTrackTop={30}
|
||||
className="border border-green-300 rounded border-opacity-10 bg-stone-900 bg-opacity-90 "
|
||||
>
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title="Total mass">{prepareMass(whData.total_mass)}</InfoDrawer>
|
||||
<InfoDrawer title="Jump mass">{prepareMass(whData.max_mass_per_jump)}</InfoDrawer>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title="Lifetime">{whData.lifetime}h</InfoDrawer>
|
||||
<InfoDrawer title="Mass regen">{prepareMass(whData.mass_regen)}</InfoDrawer>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title="Lifetime">{whData.lifetime}h</InfoDrawer>
|
||||
<InfoDrawer title="Mass regen">{prepareMass(whData.mass_regen)}</InfoDrawer>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -73,7 +79,7 @@ export const WHClassView = ({
|
||||
`wh-name${whClassName}${uid}`,
|
||||
)}
|
||||
>
|
||||
<span className={clsx({ [whClassStyle]: highlightName })}>{whClassName}</span>
|
||||
{!hideWhClassName && <span className={clsx({ [whClassStyle]: highlightName })}>{whClassName}</span>}
|
||||
{!hideWhClass && whClass && (
|
||||
<span className={clsx(classes.WHClassName, whClassStyle, classNameWh)}>
|
||||
{useShortTitle ? whClass.shortTitle : whClass.shortName}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
|
||||
export const useClipboard = () => {
|
||||
const [clipboardContent, setClipboardContent] = useState<string | null>(null);
|
||||
const [clipboardContent, setClipboardContent] = useState<{ text: string } | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const getClipboardContent = useCallback(async () => {
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
setClipboardContent(text);
|
||||
setClipboardContent({ text });
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError('Failed to read clipboard content.');
|
||||
@@ -18,7 +18,7 @@ export const useClipboard = () => {
|
||||
const handlePaste = (event: ClipboardEvent) => {
|
||||
const text = event.clipboardData?.getData('text');
|
||||
if (text) {
|
||||
setClipboardContent(text);
|
||||
setClipboardContent({ text });
|
||||
setError(null);
|
||||
}
|
||||
};
|
||||
@@ -30,5 +30,5 @@ export const useClipboard = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { clipboardContent, error, getClipboardContent };
|
||||
return { clipboardContent, error, getClipboardContent, setClipboardContent };
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ const INITIAL_DATA: MapRootData = {
|
||||
selectedSystems: [],
|
||||
selectedConnections: [],
|
||||
userPermissions: {},
|
||||
options: {},
|
||||
};
|
||||
|
||||
export enum InterfaceStoredSettingsProps {
|
||||
@@ -33,6 +34,7 @@ export enum InterfaceStoredSettingsProps {
|
||||
isShowMinimap = 'isShowMinimap',
|
||||
isShowKSpace = 'isShowKSpace',
|
||||
isThickConnections = 'isThickConnections',
|
||||
isShowUnsplashedSignatures = 'isShowUnsplashedSignatures',
|
||||
}
|
||||
|
||||
export type InterfaceStoredSettings = {
|
||||
@@ -40,6 +42,7 @@ export type InterfaceStoredSettings = {
|
||||
isShowMinimap: boolean;
|
||||
isShowKSpace: boolean;
|
||||
isThickConnections: boolean;
|
||||
isShowUnsplashedSignatures: boolean;
|
||||
};
|
||||
|
||||
export const STORED_INTERFACE_DEFAULT_VALUES: InterfaceStoredSettings = {
|
||||
@@ -47,6 +50,7 @@ export const STORED_INTERFACE_DEFAULT_VALUES: InterfaceStoredSettings = {
|
||||
isShowMinimap: true,
|
||||
isShowKSpace: false,
|
||||
isThickConnections: false,
|
||||
isShowUnsplashedSignatures: false,
|
||||
};
|
||||
|
||||
export interface MapRootContextProps {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './useMapInit';
|
||||
export * from './useMapUpdated';
|
||||
export * from './useMapCheckPermissions';
|
||||
export * from './useMapGetOption';
|
||||
export * from './useRoutes';
|
||||
export * from './useCommandsConnections';
|
||||
export * from './useCommandsSystems';
|
||||
|
||||
@@ -2,11 +2,14 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { CommandAddSystems, CommandRemoveSystems, CommandUpdateSystems } from '@/hooks/Mapper/types';
|
||||
import { useLoadSystemStatic } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic.ts';
|
||||
|
||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||
import { emitMapEvent } from '@/hooks/Mapper/events';
|
||||
import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts';
|
||||
export const useCommandsSystems = () => {
|
||||
const {
|
||||
update,
|
||||
data: { systems },
|
||||
outCommand,
|
||||
} = useMapRootState();
|
||||
|
||||
const { addSystemStatic } = useLoadSystemStatic({ systems: [] });
|
||||
@@ -56,5 +59,29 @@ export const useCommandsSystems = () => {
|
||||
update({ systems: out }, true);
|
||||
}, []);
|
||||
|
||||
return { addSystems, removeSystems, updateSystems };
|
||||
const updateSystemSignatures = useCallback(
|
||||
async (systemId: string) => {
|
||||
const { update, systems } = ref.current;
|
||||
|
||||
const { signatures } = await outCommand({
|
||||
type: OutCommand.getSignatures,
|
||||
data: { system_id: `${systemId}` },
|
||||
});
|
||||
|
||||
const out = systems.map(current => {
|
||||
if (current.id === `${systemId}`) {
|
||||
return { ...current, system_signatures: signatures };
|
||||
}
|
||||
|
||||
return current;
|
||||
});
|
||||
|
||||
update({ systems: out }, true);
|
||||
|
||||
emitMapEvent({ name: Commands.updateSystems, data: out });
|
||||
},
|
||||
[outCommand],
|
||||
);
|
||||
|
||||
return { addSystems, removeSystems, updateSystems, updateSystemSignatures };
|
||||
};
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
|
||||
export const useMapGetOption = (option: string) => {
|
||||
const {
|
||||
data: { options },
|
||||
} = useMapRootState();
|
||||
|
||||
return useMemo(() => options[option], [option, options]);
|
||||
};
|
||||
@@ -20,6 +20,7 @@ export const useMapInit = () => {
|
||||
present_characters,
|
||||
hubs,
|
||||
user_permissions,
|
||||
options,
|
||||
}: CommandInit) => {
|
||||
const updateData: Partial<MapRootData> = {};
|
||||
|
||||
@@ -60,6 +61,10 @@ export const useMapInit = () => {
|
||||
updateData.hubs = hubs;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
updateData.options = options;
|
||||
}
|
||||
|
||||
if (system_static_infos) {
|
||||
system_static_infos.forEach(static_info => {
|
||||
addSystemStatic(static_info);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
CommandRemoveSystems,
|
||||
CommandRoutes,
|
||||
Commands,
|
||||
CommandSignaturesUpdated,
|
||||
CommandUpdateConnection,
|
||||
CommandUpdateSystems,
|
||||
MapHandlers,
|
||||
@@ -31,7 +32,7 @@ import { emitMapEvent } from '@/hooks/Mapper/events';
|
||||
|
||||
export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
|
||||
const mapInit = useMapInit();
|
||||
const { addSystems, removeSystems, updateSystems } = useCommandsSystems();
|
||||
const { addSystems, removeSystems, updateSystems, updateSystemSignatures } = useCommandsSystems();
|
||||
const { addConnections, removeConnections, updateConnection } = useCommandsConnections();
|
||||
const { charactersUpdated, characterAdded, characterRemoved, characterUpdated, presentCharacters } =
|
||||
useCommandsCharacters();
|
||||
@@ -88,7 +89,7 @@ export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
|
||||
break;
|
||||
|
||||
case Commands.signaturesUpdated: // USED
|
||||
// do nothing here
|
||||
updateSystemSignatures(data as CommandSignaturesUpdated);
|
||||
break;
|
||||
|
||||
case Commands.linkSignatureToSystem: // USED
|
||||
|
||||
@@ -62,6 +62,7 @@ export type CommandInit = {
|
||||
user_permissions: UserPermissions;
|
||||
hubs: string[];
|
||||
routes: RoutesList;
|
||||
options: Record<string, string | boolean>;
|
||||
reset?: boolean;
|
||||
};
|
||||
export type CommandAddSystems = SolarSystemRawType[];
|
||||
|
||||
@@ -19,4 +19,5 @@ export type MapUnionTypes = {
|
||||
kills: Record<number, number>;
|
||||
connections: SolarSystemConnection[];
|
||||
userPermissions: Partial<UserPermissions>;
|
||||
options: Record<string, string | boolean>;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { XYPosition } from 'reactflow';
|
||||
|
||||
import { SystemSignature } from '@/hooks/Mapper/types/signatures';
|
||||
|
||||
export enum SolarSystemStaticInfoRawNames {
|
||||
regionId = 'region_id',
|
||||
constellationId = 'constellation_id',
|
||||
@@ -116,4 +118,5 @@ export type SolarSystemRawType = {
|
||||
name: string | null;
|
||||
|
||||
system_static_info: SolarSystemStaticInfoRaw;
|
||||
system_signatures: SystemSignature[];
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
)
|
||||
|
||||
define(:by_system_id, action: :by_system_id, args: [:system_id])
|
||||
define(:by_linked_system_id, action: :by_linked_system_id, args: [:linked_system_id])
|
||||
end
|
||||
|
||||
actions do
|
||||
@@ -55,7 +56,8 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
:description,
|
||||
:kind,
|
||||
:group,
|
||||
:type
|
||||
:type,
|
||||
:custom_info
|
||||
]
|
||||
|
||||
argument :system_id, :uuid, allow_nil?: false
|
||||
@@ -98,6 +100,12 @@ defmodule WandererApp.Api.MapSystemSignature do
|
||||
|
||||
filter(expr(system_id == ^arg(:system_id)))
|
||||
end
|
||||
|
||||
read :by_linked_system_id do
|
||||
argument(:linked_system_id, :integer, allow_nil?: false)
|
||||
|
||||
filter(expr(linked_system_id == ^arg(:linked_system_id)))
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
|
||||
@@ -49,7 +49,7 @@ defmodule WandererApp.EveDataService do
|
||||
end)
|
||||
end)
|
||||
|
||||
Task.await_many(tasks, :timer.minutes(1))
|
||||
Task.await_many(tasks, :timer.minutes(30))
|
||||
end
|
||||
|
||||
def download_file(file_name) do
|
||||
|
||||
@@ -14,6 +14,7 @@ defmodule WandererApp.Map do
|
||||
hubs: [],
|
||||
connections: Map.new(),
|
||||
acls: [],
|
||||
options: Map.new(),
|
||||
characters_limit: nil,
|
||||
hubs_limit: nil
|
||||
|
||||
@@ -69,6 +70,9 @@ defmodule WandererApp.Map do
|
||||
def get_characters_limit(map_id),
|
||||
do: {:ok, map_id |> get_map!() |> Map.get(:characters_limit, 100)}
|
||||
|
||||
def get_options(map_id),
|
||||
do: {:ok, map_id |> get_map!() |> Map.get(:options, Map.new())}
|
||||
|
||||
@doc """
|
||||
Returns a full list of characters in the map
|
||||
"""
|
||||
@@ -251,6 +255,13 @@ defmodule WandererApp.Map do
|
||||
map
|
||||
end
|
||||
|
||||
def update_options!(%{map_id: map_id} = map, options) do
|
||||
map_id
|
||||
|> update_map(%{options: options})
|
||||
|
||||
map
|
||||
end
|
||||
|
||||
def add_systems!(map, []), do: map
|
||||
|
||||
def add_systems!(%{map_id: map_id} = map, [system | rest]) do
|
||||
|
||||
@@ -277,15 +277,11 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
}
|
||||
end
|
||||
|
||||
def handle_event({:options_updated, options}, state),
|
||||
do: %{
|
||||
state
|
||||
| map_opts: [
|
||||
layout: options |> Map.get("layout", "left_to_right"),
|
||||
store_custom_labels:
|
||||
options |> Map.get("store_custom_labels", "false") |> String.to_existing_atom()
|
||||
]
|
||||
}
|
||||
def handle_event({:options_updated, options}, %{map: map} = state) do
|
||||
map |> WandererApp.Map.update_options!(options)
|
||||
|
||||
%{state | map_opts: map_options(options)}
|
||||
end
|
||||
|
||||
def handle_event({ref, _result}, %{map_id: _map_id} = state) do
|
||||
Process.demonitor(ref, [:flush])
|
||||
@@ -319,6 +315,16 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
map |> Map.put_new(attribute, get_in(update, [Access.key(attribute)]))
|
||||
end)}
|
||||
|
||||
defp map_options(options) do
|
||||
[
|
||||
layout: options |> Map.get("layout", "left_to_right"),
|
||||
store_custom_labels:
|
||||
options |> Map.get("store_custom_labels", "false") |> String.to_existing_atom(),
|
||||
restrict_offline_showing:
|
||||
options |> Map.get("restrict_offline_showing", "false") |> String.to_existing_atom()
|
||||
]
|
||||
end
|
||||
|
||||
defp save_map_state(%{map_id: map_id} = _state) do
|
||||
systems_last_activity =
|
||||
map_id
|
||||
@@ -389,22 +395,17 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
systems,
|
||||
connections
|
||||
) do
|
||||
{:ok, options} = WandererApp.MapRepo.options_to_form_data(initial_map)
|
||||
|
||||
map =
|
||||
initial_map
|
||||
|> WandererApp.Map.new()
|
||||
|> WandererApp.Map.update_options!(options)
|
||||
|> WandererApp.Map.update_subscription_settings!(subscription_settings)
|
||||
|> WandererApp.Map.add_systems!(systems)
|
||||
|> WandererApp.Map.add_connections!(connections)
|
||||
|> WandererApp.Map.add_characters!(characters)
|
||||
|
||||
{:ok, map_options} = WandererApp.MapRepo.options_to_form_data(initial_map)
|
||||
|
||||
map_opts = [
|
||||
layout: map_options |> Map.get("layout", "left_to_right"),
|
||||
store_custom_labels:
|
||||
map_options |> Map.get("store_custom_labels", "false") |> String.to_existing_atom()
|
||||
]
|
||||
|
||||
character_ids =
|
||||
map_id
|
||||
|> WandererApp.Map.get_map!()
|
||||
@@ -412,7 +413,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
|
||||
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", character_ids)
|
||||
|
||||
%{state | map: map, map_opts: map_opts}
|
||||
%{state | map: map, map_opts: map_options(options)}
|
||||
end
|
||||
|
||||
def maybe_import_systems(state, %{"systems" => systems} = _settings, user_id, character_id) do
|
||||
|
||||
@@ -356,8 +356,6 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
|
||||
def can_add_location(_scope, nil), do: false
|
||||
|
||||
def can_add_location(:all, _solar_system_id), do: true
|
||||
|
||||
def can_add_location(:none, _solar_system_id), do: false
|
||||
|
||||
def can_add_location(scope, solar_system_id) do
|
||||
@@ -380,6 +378,9 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
not (@prohibited_system_classes |> Enum.member?(system_static_info.system_class)) and
|
||||
@known_space |> Enum.member?(system_static_info.system_class)
|
||||
|
||||
:all ->
|
||||
not (@prohibited_system_classes |> Enum.member?(system_static_info.system_class))
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
|
||||
@@ -224,6 +224,19 @@ defmodule WandererApp.Map.Server.SystemsImpl do
|
||||
WandererApp.MapConnectionRepo.destroy(map_id, connection)
|
||||
end)
|
||||
|
||||
removed_ids
|
||||
|> Enum.map(fn solar_system_id ->
|
||||
WandererApp.Api.MapSystemSignature.by_linked_system_id!(solar_system_id)
|
||||
end)
|
||||
|> List.flatten()
|
||||
|> Enum.uniq_by(& &1.system_id)
|
||||
|> Enum.each(fn s ->
|
||||
{:ok, %{system: system}} = s |> Ash.load([:system])
|
||||
Ash.destroy!(s)
|
||||
|
||||
Impl.broadcast!(map_id, :signatures_updated, system.solar_system_id)
|
||||
end)
|
||||
|
||||
@ddrt.delete(removed_ids, rtree_name)
|
||||
|
||||
Impl.broadcast!(map_id, :remove_connections, connections_to_remove)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
defmodule WandererApp.MapRepo do
|
||||
use WandererApp, :repository
|
||||
|
||||
@default_map_options %{"layout" => "left_to_right", "store_custom_labels" => "false"}
|
||||
@default_map_options %{
|
||||
"layout" => "left_to_right",
|
||||
"store_custom_labels" => "false",
|
||||
"restrict_offline_showing" => "false"
|
||||
}
|
||||
|
||||
def get(map_id, relationships \\ []) do
|
||||
map_id
|
||||
|
||||
@@ -143,15 +143,10 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
def server_status(assigns) do
|
||||
~H"""
|
||||
<div
|
||||
class="flex flex-col p-4 items-center absolute bottom-16 left-1 gap-2 tooltip tooltip-right"
|
||||
class="flex flex-col p-4 items-center absolute bottom-16 left-2 gap-2 tooltip tooltip-right"
|
||||
data-tip="server: Tranquility"
|
||||
>
|
||||
<div
|
||||
:if={@online}
|
||||
class="absolute block w-4 h-4 rounded-full shadow-inner bg-green-500 animate-ping"
|
||||
>
|
||||
</div>
|
||||
<div class={"block w-4 h-4 rounded-full shadow-inner #{if @online, do: " bg-green-500", else: "bg-red-500"}"}>
|
||||
<div class={"block w-2 h-2 rounded-full shadow-inner #{if @online, do: " bg-green-500", else: "bg-red-500"}"}>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@@ -336,6 +331,7 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
"""
|
||||
attr(:id, :any, default: nil)
|
||||
attr(:class, :string, default: nil)
|
||||
attr(:wrapper_class, :string, default: nil)
|
||||
attr(:name, :any)
|
||||
attr(:label, :string, default: nil)
|
||||
attr(:prefix, :string, default: nil)
|
||||
@@ -381,21 +377,62 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
end)
|
||||
|
||||
~H"""
|
||||
<div phx-feedback-for={@name} class="form-control mt-8">
|
||||
<label class="label cursor-pointer gap-2">
|
||||
<span class="label-text"><%= @label %></span>
|
||||
<input type="hidden" name={@name} value="false" />
|
||||
<input
|
||||
type="checkbox"
|
||||
id={@id}
|
||||
name={@name}
|
||||
value="true"
|
||||
checked={@checked}
|
||||
class="checkbox"
|
||||
{@rest}
|
||||
/>
|
||||
<div phx-feedback-for={@name} class="form-control mt-2">
|
||||
<label class="inputContainer" for={@name}>
|
||||
<span><%= @label %></span>
|
||||
<div></div>
|
||||
<div class="smallInputSwitch">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
class={[
|
||||
"checkboxRoot sizeM p-checkbox p-component",
|
||||
classes("p-highlight": @checked)
|
||||
]}
|
||||
data-p-highlight={@checked}
|
||||
data-p-disabled="false"
|
||||
data-pc-name="checkbox"
|
||||
data-pc-section="root"
|
||||
>
|
||||
<input
|
||||
id={@id}
|
||||
name={@name}
|
||||
type="checkbox"
|
||||
class="p-checkbox-input"
|
||||
aria-invalid="false"
|
||||
data-pc-section="input"
|
||||
value="true"
|
||||
checked={@checked}
|
||||
{@rest}
|
||||
/>
|
||||
<div
|
||||
class="p-checkbox-box"
|
||||
data-p-highlight={@checked}
|
||||
data-p-disabled="false"
|
||||
data-pc-section="box"
|
||||
>
|
||||
<svg
|
||||
:if={@checked}
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="p-icon p-checkbox-icon"
|
||||
aria-hidden="true"
|
||||
data-pc-section="icon"
|
||||
>
|
||||
<path
|
||||
d="M4.86199 11.5948C4.78717 11.5923 4.71366 11.5745 4.64596 11.5426C4.57826 11.5107 4.51779 11.4652 4.46827 11.4091L0.753985 7.69483C0.683167 7.64891 0.623706 7.58751 0.580092 7.51525C0.536478 7.44299 0.509851 7.36177 0.502221 7.27771C0.49459 7.19366 0.506156 7.10897 0.536046 7.03004C0.565935 6.95111 0.613367 6.88 0.674759 6.82208C0.736151 6.76416 0.8099 6.72095 0.890436 6.69571C0.970973 6.67046 1.05619 6.66385 1.13966 6.67635C1.22313 6.68886 1.30266 6.72017 1.37226 6.76792C1.44186 6.81567 1.4997 6.8786 1.54141 6.95197L4.86199 10.2503L12.6397 2.49483C12.7444 2.42694 12.8689 2.39617 12.9932 2.40745C13.1174 2.41873 13.2343 2.47141 13.3251 2.55705C13.4159 2.64268 13.4753 2.75632 13.4938 2.87973C13.5123 3.00315 13.4888 3.1292 13.4271 3.23768L5.2557 11.4091C5.20618 11.4652 5.14571 11.5107 5.07801 11.5426C5.01031 11.5745 4.9368 11.5923 4.86199 11.5948Z"
|
||||
fill="currentColor"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<label for={@name} class="select-none ml-1.5"></label>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
@@ -403,24 +440,28 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
def input(%{type: "range"} = assigns) do
|
||||
~H"""
|
||||
<div phx-feedback-for={@name}>
|
||||
<label class="form-control w-full">
|
||||
<div class="form-control w-full">
|
||||
<.label for={@id}>
|
||||
<span class="label-text"><%= @label %></span>
|
||||
<span class="label-value"><%= @value %></span>
|
||||
<span><%= @label %></span>
|
||||
<div></div>
|
||||
<%= @value %>
|
||||
</.label>
|
||||
<input
|
||||
type="range"
|
||||
id={@id}
|
||||
name={@name}
|
||||
value={@value}
|
||||
class={[
|
||||
"p-component w-full",
|
||||
@class,
|
||||
@errors != [] && "border-rose-400 focus:border-rose-400"
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<input
|
||||
type="range"
|
||||
id={@id}
|
||||
name={@name}
|
||||
value={@value}
|
||||
class={[
|
||||
"p-component w-full",
|
||||
@class,
|
||||
@errors != [] && "border-rose-400 focus:border-rose-400"
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
@@ -428,13 +469,20 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
|
||||
def input(%{type: "select"} = assigns) do
|
||||
~H"""
|
||||
<div phx-feedback-for={@name}>
|
||||
<div
|
||||
phx-feedback-for={@name}
|
||||
class={[
|
||||
"inputContainer",
|
||||
@wrapper_class
|
||||
]}
|
||||
>
|
||||
<.label :if={@label} for={@id}><%= @label %></.label>
|
||||
<div :if={@label}></div>
|
||||
<select
|
||||
id={@id}
|
||||
name={@name}
|
||||
class={[
|
||||
"w-full",
|
||||
"p-component",
|
||||
@class
|
||||
]}
|
||||
multiple={@multiple}
|
||||
@@ -503,9 +551,9 @@ defmodule WandererAppWeb.CoreComponents do
|
||||
|
||||
def label(assigns) do
|
||||
~H"""
|
||||
<div for={@for} class="label">
|
||||
<label for={@for} class="inputContainer">
|
||||
<%= render_slot(@inner_block) %>
|
||||
</div>
|
||||
</label>
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -32,14 +32,22 @@
|
||||
/>
|
||||
<script
|
||||
crossorigin="anonymous"
|
||||
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
||||
integrity={integrity_hash("https://unpkg.com/react@18/umd/react.production.min.js")}
|
||||
src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"
|
||||
integrity={
|
||||
integrity_hash(
|
||||
"https://cdn.jsdelivr.net/npm/react-dom@16/umd/react-dom.development.js https://unpkg.com/react@18/umd/react.production.min.js"
|
||||
)
|
||||
}
|
||||
>
|
||||
</script>
|
||||
<script
|
||||
crossorigin="anonymous"
|
||||
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
||||
integrity={integrity_hash("https://unpkg.com/react-dom@18/umd/react-dom.production.min.js")}
|
||||
src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"
|
||||
integrity={
|
||||
integrity_hash(
|
||||
"https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"
|
||||
)
|
||||
}
|
||||
>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ defmodule WandererAppWeb.MapPicker do
|
||||
:if={maps}
|
||||
type="select"
|
||||
field={f[:map_slug]}
|
||||
class="select h-8 min-h-[0px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
placeholder="Select a map..."
|
||||
options={Enum.map(@maps.result, fn map -> {map.label, map.value} end)}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,8 @@ defmodule WandererAppWeb.UserActivity do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def update(assigns,
|
||||
def update(
|
||||
assigns,
|
||||
socket
|
||||
) do
|
||||
{:ok,
|
||||
@@ -116,7 +117,6 @@ defmodule WandererAppWeb.UserActivity do
|
||||
<h6 class="text-base leading-[150%] font-semibold dark:text-white">
|
||||
<%= _get_event_data(@event_type, Jason.decode!(@event_data) |> Map.drop(["character_id"])) %>
|
||||
</h6>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@@ -125,7 +125,6 @@ defmodule WandererAppWeb.UserActivity do
|
||||
@impl true
|
||||
def handle_event("undo", %{"event-data" => event_data} = _params, socket) do
|
||||
# notify_to(socket.assigns.notify_to, socket.assigns.event_name, map_slug)
|
||||
IO.inspect(event_data)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@@ -136,8 +136,10 @@
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:owner_id]}
|
||||
class="p-dropdown p-component p-inputwrapper mt-8"
|
||||
placeholder="Select a map owner"
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
wrapper_class="mt-2"
|
||||
label="Owner"
|
||||
placeholder="Select an owner"
|
||||
options={Enum.map(@characters, fn character -> {character.label, character.id} end)}
|
||||
/>
|
||||
<div class="modal-action">
|
||||
|
||||
@@ -39,7 +39,8 @@ defmodule WandererAppWeb.AclMember do
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:role]}
|
||||
class="select h-8 min-h-[0px] !pt-1 !pb-1 text-sm bg-neutral-900 w-[70px]"
|
||||
class="select h-8 min-h-[0px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
wrapper_class="w-[60px] mr-16"
|
||||
placeholder="Select a role..."
|
||||
options={Enum.map(@roles, fn role -> {role.label, role.value} end)}
|
||||
/>
|
||||
|
||||
@@ -434,7 +434,19 @@ defmodule WandererAppWeb.MapCoreEventHandler do
|
||||
socket
|
||||
|> handle_map_start_events(map_id, events)
|
||||
|
||||
map_characters = map_id |> WandererApp.Map.list_characters()
|
||||
{:ok, options} =
|
||||
map_id
|
||||
|> WandererApp.Map.get_options()
|
||||
|
||||
user_permissions =
|
||||
initial_data
|
||||
|> Map.get(:user_permissions)
|
||||
|
||||
map_characters =
|
||||
map_id
|
||||
|> WandererApp.Map.list_characters()
|
||||
|> filter_map_characters(user_character_eve_ids, user_permissions, options)
|
||||
|> Enum.map(&MapCharactersEventHandler.map_ui_character/1)
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
@@ -447,10 +459,7 @@ defmodule WandererAppWeb.MapCoreEventHandler do
|
||||
|> MapEventHandler.push_map_event(
|
||||
"init",
|
||||
initial_data
|
||||
|> Map.put(
|
||||
:characters,
|
||||
map_characters |> Enum.map(&MapCharactersEventHandler.map_ui_character/1)
|
||||
)
|
||||
|> Map.put(:characters, map_characters)
|
||||
)
|
||||
|> push_event("js-exec", %{
|
||||
to: "#map-loader",
|
||||
@@ -500,13 +509,15 @@ defmodule WandererAppWeb.MapCoreEventHandler do
|
||||
{:ok, hubs} = map_id |> WandererApp.Map.list_hubs()
|
||||
{:ok, connections} = map_id |> WandererApp.Map.list_connections()
|
||||
{:ok, systems} = map_id |> WandererApp.Map.list_systems()
|
||||
{:ok, options} = map_id |> WandererApp.Map.get_options()
|
||||
|
||||
%{
|
||||
systems:
|
||||
systems
|
||||
|> Enum.map(fn system -> MapEventHandler.map_ui_system(system, include_static_data?) end),
|
||||
hubs: hubs,
|
||||
connections: connections |> Enum.map(&MapEventHandler.map_ui_connection/1)
|
||||
connections: connections |> Enum.map(&MapEventHandler.map_ui_connection/1),
|
||||
options: options
|
||||
}
|
||||
end
|
||||
|
||||
@@ -525,6 +536,26 @@ defmodule WandererAppWeb.MapCoreEventHandler do
|
||||
end
|
||||
end
|
||||
|
||||
defp filter_map_characters(
|
||||
characters,
|
||||
user_character_eve_ids,
|
||||
%{
|
||||
manage_map: manage_map_permission
|
||||
} = _user_permissions,
|
||||
options
|
||||
) do
|
||||
restrict_offline_showing =
|
||||
options |> Map.get("restrict_offline_showing", "false") |> String.to_existing_atom()
|
||||
|
||||
show_offline? = not restrict_offline_showing or manage_map_permission
|
||||
|
||||
characters
|
||||
|> Enum.filter(fn character ->
|
||||
show_offline? || character.online ||
|
||||
user_character_eve_ids |> Enum.member?(character.eve_id)
|
||||
end)
|
||||
end
|
||||
|
||||
defp map_system(
|
||||
%{
|
||||
solar_system_name: solar_system_name,
|
||||
|
||||
@@ -312,7 +312,7 @@ defmodule WandererAppWeb.MapSignaturesEventHandler do
|
||||
def handle_ui_event(event, body, socket),
|
||||
do: MapCoreEventHandler.handle_ui_event(event, body, socket)
|
||||
|
||||
defp get_system_signatures(system_id),
|
||||
def get_system_signatures(system_id),
|
||||
do:
|
||||
system_id
|
||||
|> WandererApp.Api.MapSystemSignature.by_system_id!()
|
||||
|
||||
@@ -234,6 +234,7 @@ defmodule WandererAppWeb.MapEventHandler do
|
||||
|
||||
def map_ui_system(
|
||||
%{
|
||||
id: system_id,
|
||||
solar_system_id: solar_system_id,
|
||||
name: name,
|
||||
description: description,
|
||||
@@ -249,12 +250,20 @@ defmodule WandererAppWeb.MapEventHandler do
|
||||
) do
|
||||
system_static_info = get_system_static_info(solar_system_id)
|
||||
|
||||
system_signatures =
|
||||
system_id
|
||||
|> WandererAppWeb.MapSignaturesEventHandler.get_system_signatures()
|
||||
|> Enum.filter(fn signature ->
|
||||
is_nil(signature.linked_system) && signature.group == "Wormhole"
|
||||
end)
|
||||
|
||||
%{
|
||||
id: "#{solar_system_id}",
|
||||
position: %{x: position_x, y: position_y},
|
||||
description: description,
|
||||
name: name,
|
||||
system_static_info: system_static_info,
|
||||
system_signatures: system_signatures,
|
||||
labels: labels,
|
||||
locked: locked,
|
||||
status: status,
|
||||
|
||||
@@ -280,14 +280,17 @@ defmodule WandererAppWeb.MapsLive do
|
||||
do:
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:amounts, [
|
||||
%{label: "150M", value: 150_000_000},
|
||||
%{label: "300M", value: 300_000_000},
|
||||
%{label: "600M", value: 600_000_000},
|
||||
%{label: "1.2B", value: 1_200_000_000},
|
||||
%{label: "2.4B", value: 2_400_000_000},
|
||||
%{label: "5B", value: 5_000_000_000}
|
||||
])
|
||||
|> assign(
|
||||
:amounts,
|
||||
[
|
||||
{"150M", 150_000_000},
|
||||
{"300M", 300_000_000},
|
||||
{"600M", 600_000_000},
|
||||
{"1.2B", 1_200_000_000},
|
||||
{"2.4B", 2_400_000_000},
|
||||
{"5B", 5_000_000_000}
|
||||
]
|
||||
)
|
||||
|> assign(is_topping_up?: true)}
|
||||
|
||||
@impl true
|
||||
@@ -654,7 +657,7 @@ defmodule WandererAppWeb.MapsLive do
|
||||
) do
|
||||
options =
|
||||
options_form
|
||||
|> Map.take(["layout", "store_custom_labels"])
|
||||
|> Map.take(["layout", "store_custom_labels", "restrict_offline_showing"])
|
||||
|
||||
{:ok, updated_map} = WandererApp.MapRepo.update_options(map, options)
|
||||
|
||||
|
||||
@@ -139,14 +139,18 @@
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:owner_id]}
|
||||
class="p-dropdown p-component p-inputwrapper mt-8"
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
wrapper_class="mt-2"
|
||||
label="Map owner"
|
||||
placeholder="Select a map owner"
|
||||
options={Enum.map(@characters, fn character -> {character.label, character.id} end)}
|
||||
/>
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:scope]}
|
||||
class="p-dropdown p-component p-inputwrapper mt-8"
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
wrapper_class="mt-2"
|
||||
label="Map scope"
|
||||
placeholder="Select a map scope"
|
||||
options={Enum.map(@scopes, fn scope -> {scope, scope} end)}
|
||||
/>
|
||||
@@ -182,203 +186,411 @@
|
||||
<.modal
|
||||
:if={@live_action in [:settings]}
|
||||
title="Map Settings"
|
||||
class="!w-[800px]"
|
||||
class="!min-w-[700px]"
|
||||
id="map-settings-modal"
|
||||
show
|
||||
on_cancel={JS.patch(~p"/maps")}
|
||||
>
|
||||
<div role="tablist" class="tabs tabs-bordered">
|
||||
<a
|
||||
role="tab"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="general"
|
||||
class={[
|
||||
"tab",
|
||||
classes("tab-active": @active_settings_tab == "general")
|
||||
]}
|
||||
>
|
||||
<.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" /> General
|
||||
</a>
|
||||
<a
|
||||
role="tab"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="import"
|
||||
class={[
|
||||
"tab",
|
||||
classes("tab-active": @active_settings_tab == "import")
|
||||
]}
|
||||
>
|
||||
<.icon name="hero-document-arrow-down-solid" class="w-4 h-4" /> Import/Export
|
||||
</a>
|
||||
<a
|
||||
:if={@map_subscriptions_enabled?}
|
||||
role="tab"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="balance"
|
||||
class={[
|
||||
"tab",
|
||||
classes("tab-active": @active_settings_tab == "balance")
|
||||
]}
|
||||
>
|
||||
<.icon name="hero-banknotes-solid" class="w-4 h-4" /> Balance
|
||||
</a>
|
||||
<a
|
||||
:if={@map_subscriptions_enabled?}
|
||||
role="tab"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="subscription"
|
||||
class={[
|
||||
"tab",
|
||||
classes("tab-active": @active_settings_tab == "subscription")
|
||||
]}
|
||||
>
|
||||
<.icon name="hero-check-badge-solid" class="w-4 h-4" /> Subscription
|
||||
</a>
|
||||
</div>
|
||||
<.header :if={@active_settings_tab == "general"} class="bordered border-1 border-zinc-800">
|
||||
<:actions>
|
||||
<.form
|
||||
:let={f}
|
||||
:if={assigns |> Map.get(:options_form, false)}
|
||||
for={@options_form}
|
||||
phx-change="update_options"
|
||||
>
|
||||
<div>
|
||||
<div class="stat-title">Map systems layout</div>
|
||||
<div class="stat-value text-white">
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:layout]}
|
||||
class="p-dropdown p-component p-inputwrapper"
|
||||
placeholder="Map default layout"
|
||||
options={@layout_options}
|
||||
/>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="_verticalTabsContainer_1o01l_2">
|
||||
<div class="p-tabview p-component" data-pc-name="tabview" data-pc-section="root">
|
||||
<div class="p-tabview-nav-container" data-pc-section="navcontainer">
|
||||
<div class="p-tabview-nav-content" data-pc-section="navcontent">
|
||||
<ul class="p-tabview-nav" role="tablist" data-pc-section="nav">
|
||||
<li
|
||||
class={[
|
||||
"p-unselectable-text",
|
||||
classes("p-tabview-selected p-highlight": @active_settings_tab == "general")
|
||||
]}
|
||||
role="presentation"
|
||||
data-pc-name=""
|
||||
data-pc-section="header"
|
||||
>
|
||||
<a
|
||||
role="tab"
|
||||
class="p-tabview-nav-link flex p-[10px]"
|
||||
tabindex="0"
|
||||
aria-controls="pr_id_330_content"
|
||||
aria-selected="true"
|
||||
aria-disabled="false"
|
||||
data-pc-section="headeraction"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="general"
|
||||
>
|
||||
<span class="p-tabview-title" data-pc-section="headertitle">
|
||||
<.icon name="hero-wrench-screwdriver-solid" class="w-4 h-4" /> General
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
:if={@map_subscriptions_enabled?}
|
||||
class={[
|
||||
"p-unselectable-text",
|
||||
classes("p-tabview-selected p-highlight": @active_settings_tab == "balance")
|
||||
]}
|
||||
role="presentation"
|
||||
data-pc-name=""
|
||||
data-pc-section="header"
|
||||
>
|
||||
<a
|
||||
role="tab"
|
||||
class="p-tabview-nav-link flex p-[10px]"
|
||||
tabindex="-1"
|
||||
aria-controls="pr_id_332_content"
|
||||
aria-selected="false"
|
||||
aria-disabled="false"
|
||||
data-pc-section="headeraction"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="balance"
|
||||
>
|
||||
<span class="p-tabview-title" data-pc-section="headertitle">
|
||||
<.icon name="hero-banknotes-solid" class="w-4 h-4" /> Balance
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
:if={@map_subscriptions_enabled?}
|
||||
class={[
|
||||
"p-unselectable-text",
|
||||
classes(
|
||||
"p-tabview-selected p-highlight": @active_settings_tab == "subscription"
|
||||
)
|
||||
]}
|
||||
role="presentation"
|
||||
data-pc-name=""
|
||||
data-pc-section="header"
|
||||
>
|
||||
<a
|
||||
role="tab"
|
||||
class="p-tabview-nav-link flex p-[10px]"
|
||||
tabindex="-1"
|
||||
aria-controls="pr_id_334_content"
|
||||
aria-selected="false"
|
||||
aria-disabled="false"
|
||||
data-pc-section="headeraction"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="subscription"
|
||||
>
|
||||
<span class="p-tabview-title" data-pc-section="headertitle">
|
||||
<.icon name="hero-check-badge-solid" class="w-4 h-4" /> Subscription
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class={[
|
||||
"p-unselectable-text",
|
||||
classes("p-tabview-selected p-highlight": @active_settings_tab == "import")
|
||||
]}
|
||||
role="presentation"
|
||||
data-pc-name=""
|
||||
data-pc-section="header"
|
||||
>
|
||||
<a
|
||||
role="tab"
|
||||
class="p-tabview-nav-link flex p-[10px]"
|
||||
tabindex="-1"
|
||||
aria-controls="pr_id_331_content"
|
||||
aria-selected="false"
|
||||
aria-disabled="false"
|
||||
data-pc-section="headeraction"
|
||||
phx-click="change_settings_tab"
|
||||
phx-value-tab="import"
|
||||
>
|
||||
<span class="p-tabview-title" data-pc-section="headertitle">
|
||||
<.icon name="hero-document-arrow-down-solid" class="w-4 h-4" /> Import/Export
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
aria-hidden="true"
|
||||
role="presentation"
|
||||
class="p-tabview-ink-bar"
|
||||
data-pc-section="inkbar"
|
||||
style="width: 146px; left: 0px;"
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-tabview-panels" data-pc-section="panelcontainer">
|
||||
<div
|
||||
id="pr_id_330_content"
|
||||
class="p-tabview-panel"
|
||||
role="tabpanel"
|
||||
aria-labelledby="pr_id_33_header_0"
|
||||
data-pc-name=""
|
||||
data-pc-section="content"
|
||||
>
|
||||
<div :if={@active_settings_tab == "general"}>
|
||||
<.form
|
||||
:let={f}
|
||||
:if={assigns |> Map.get(:options_form, false)}
|
||||
for={@options_form}
|
||||
phx-change="update_options"
|
||||
>
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:layout]}
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
label="Map systems layout"
|
||||
placeholder="Map default layout"
|
||||
options={@layout_options}
|
||||
/>
|
||||
<.input
|
||||
type="checkbox"
|
||||
field={f[:store_custom_labels]}
|
||||
label="Store system custom labels"
|
||||
/>
|
||||
<.input
|
||||
type="checkbox"
|
||||
field={f[:restrict_offline_showing]}
|
||||
label="Show offline characters to admins & managers only"
|
||||
/>
|
||||
</.form>
|
||||
</div>
|
||||
|
||||
<div :if={@active_settings_tab == "import"}>
|
||||
<.form
|
||||
:if={assigns |> Map.get(:import_form, false)}
|
||||
for={@import_form}
|
||||
phx-change="import"
|
||||
>
|
||||
<div phx-drop-target="{@uploads.settings.ref}">
|
||||
<.live_file_input upload={@uploads.settings} />
|
||||
</div>
|
||||
</.form>
|
||||
<progress :if={@importing} class="progress w-56"></progress>
|
||||
<.button
|
||||
id="export-settings-btn"
|
||||
class="mt-8"
|
||||
type="button"
|
||||
disabled={@importing}
|
||||
phx-hook="DownloadJson"
|
||||
data-name={@map_slug}
|
||||
data-content={Jason.encode!(assigns[:export_settings] || %{})}
|
||||
>
|
||||
<.icon name="hero-document-arrow-down-solid" class="w-4 h-4" /> Export Settings
|
||||
</.button>
|
||||
</div>
|
||||
|
||||
<div :if={@active_settings_tab == "balance"}>
|
||||
<div class="stats w-full bg-primary text-primary-content">
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button
|
||||
:if={not @is_topping_up?}
|
||||
class="mt-2"
|
||||
type="button"
|
||||
phx-click="show_topup"
|
||||
>
|
||||
<.icon name="hero-banknotes-solid" class="w-4 h-4" /> Top Up
|
||||
</.button>
|
||||
</div>
|
||||
<div class="stat-title">Map balance</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= @map_balance
|
||||
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
<div class="stat-actions text-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.form
|
||||
:let={f}
|
||||
:if={@is_topping_up?}
|
||||
for={@topup_form}
|
||||
class="mt-2"
|
||||
phx-change="validate_topup"
|
||||
phx-submit="topup"
|
||||
>
|
||||
<.input
|
||||
type="select"
|
||||
field={f[:amount]}
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
label="Topup amount"
|
||||
placeholder="Select topup amount"
|
||||
options={@amounts}
|
||||
/>
|
||||
<div class="modal-action">
|
||||
<.button class="mt-2" type="button" phx-click="hide_topup">
|
||||
Cancel
|
||||
</.button>
|
||||
<.button class="mt-2" type="submit">
|
||||
Top Up
|
||||
</.button>
|
||||
</div>
|
||||
</.form>
|
||||
</div>
|
||||
|
||||
<.table
|
||||
:if={@active_settings_tab == "subscription"}
|
||||
class="!max-h-[300px] !overflow-y-auto"
|
||||
empty_label="No active subscriptions, using alpha plan by default."
|
||||
id="active-subscriptions-tbl"
|
||||
rows={@map_subscriptions}
|
||||
>
|
||||
<:col :let={subscription} label="Subscription Plan">
|
||||
<%= subscription.plan %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Status">
|
||||
<%= subscription.status %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Characters Limit">
|
||||
<%= subscription.characters_limit %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Hubs Limit">
|
||||
<%= subscription.hubs_limit %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Active Till">
|
||||
<.local_time
|
||||
:if={subscription.active_till}
|
||||
id={"subscription-active-till-#{subscription.id}"}
|
||||
at={subscription.active_till}
|
||||
>
|
||||
<%= subscription.active_till %>
|
||||
</.local_time>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Auto Renew">
|
||||
<%= if subscription.auto_renew?, do: "Yes", else: "No" %>
|
||||
</:col>
|
||||
<:action :let={subscription}>
|
||||
<div class="tooltip tooltip-left" data-tip="Edit subscription">
|
||||
<button
|
||||
:if={subscription.status == :active && subscription.plan != :alpha}
|
||||
phx-click="edit-subscription"
|
||||
phx-value-id={subscription.id}
|
||||
>
|
||||
<.icon name="hero-pencil-square-solid" class="w-4 h-4 hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</:action>
|
||||
<:action :let={subscription}>
|
||||
<div class="tooltip tooltip-left" data-tip="Cancel subscription">
|
||||
<button
|
||||
:if={subscription.status == :active && subscription.plan != :alpha}
|
||||
phx-click="cancel-subscription"
|
||||
phx-value-id={subscription.id}
|
||||
data={[confirm: "Please confirm to cancel subscription!"]}
|
||||
>
|
||||
<.icon name="hero-trash-solid" class="w-4 h-4 hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</:action>
|
||||
</.table>
|
||||
|
||||
<.header
|
||||
:if={@active_settings_tab == "subscription" && @is_adding_subscription?}
|
||||
class="bordered border-1 flex flex-col gap-4"
|
||||
>
|
||||
<div :if={is_nil(@selected_subscription)}>
|
||||
Add subscription
|
||||
<div class="badge badge-secondary">Limited time offer: 50%</div>
|
||||
</div>
|
||||
<div :if={not is_nil(@selected_subscription)}>
|
||||
Edit subscription
|
||||
<div class="badge badge-secondary">Limited time offer: 50%</div>
|
||||
</div>
|
||||
<.form
|
||||
:let={f}
|
||||
for={@subscription_form}
|
||||
phx-change="validate_subscription"
|
||||
phx-submit={
|
||||
if is_nil(@selected_subscription),
|
||||
do: "subscribe",
|
||||
else: "update_subscription"
|
||||
}
|
||||
>
|
||||
<.input
|
||||
:if={is_nil(@selected_subscription)}
|
||||
type="select"
|
||||
field={f[:period]}
|
||||
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
|
||||
label="Subscription period"
|
||||
options={@subscription_periods}
|
||||
/>
|
||||
<.input
|
||||
field={f[:characters_limit]}
|
||||
label="Characters limit"
|
||||
show_value={true}
|
||||
type="range"
|
||||
min="300"
|
||||
max="5000"
|
||||
step="100"
|
||||
class="range range-xs"
|
||||
/>
|
||||
<.input
|
||||
field={f[:hubs_limit]}
|
||||
label="Hubs limit"
|
||||
show_value={true}
|
||||
type="range"
|
||||
min="20"
|
||||
max="50"
|
||||
step="10"
|
||||
class="range range-xs"
|
||||
/>
|
||||
<.input field={f[:auto_renew?]} label="Auto Renew" type="checkbox" />
|
||||
<div
|
||||
:if={is_nil(@selected_subscription)}
|
||||
class="stats w-full bg-primary text-primary-content mt-2"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button type="submit">
|
||||
Subscribe
|
||||
</.button>
|
||||
</div>
|
||||
<div class="flex gap-8">
|
||||
<div>
|
||||
<div class="stat-title">Estimated price</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= (@estimated_price - @discount)
|
||||
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="stat-title">Discount</div>
|
||||
<div class="stat-value text-white relative">
|
||||
ISK <%= @discount
|
||||
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
<span class="absolute top-0 right-0 text-xs text-white discount" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:if={not is_nil(@selected_subscription)}
|
||||
class="stats w-full bg-primary text-primary-content"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button type="button" phx-click="cancel_edit_subscription">
|
||||
Cancel
|
||||
</.button>
|
||||
<.button type="submit">
|
||||
Update
|
||||
</.button>
|
||||
</div>
|
||||
<div class="stat-title">Additional price (mounthly)</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= @additional_price
|
||||
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
<div class="stat-actions text-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
</.form>
|
||||
</.header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
type="checkbox"
|
||||
field={f[:store_custom_labels]}
|
||||
label="Store system custom labels"
|
||||
/>
|
||||
</.form>
|
||||
</:actions>
|
||||
</.header>
|
||||
<.header :if={@active_settings_tab == "import"} class="bordered border-1 border-zinc-800">
|
||||
Import/Export Map Settings
|
||||
<:actions>
|
||||
<.form :if={assigns |> Map.get(:import_form, false)} for={@import_form} phx-change="import">
|
||||
<div phx-drop-target="{@uploads.settings.ref}">
|
||||
<.live_file_input upload={@uploads.settings} />
|
||||
</div>
|
||||
</.form>
|
||||
<progress :if={@importing} class="progress w-56"></progress>
|
||||
<.button
|
||||
id="export-settings-btn"
|
||||
class="mt-8"
|
||||
type="button"
|
||||
disabled={@importing}
|
||||
phx-hook="DownloadJson"
|
||||
data-name={@map_slug}
|
||||
data-content={Jason.encode!(assigns[:export_settings] || %{})}
|
||||
>
|
||||
<.icon name="hero-document-arrow-down-solid" class="w-4 h-4" /> Export Settings
|
||||
</.button>
|
||||
</:actions>
|
||||
</.header>
|
||||
<.header :if={@active_settings_tab == "balance"} class="bordered border-1 border-zinc-800">
|
||||
<div class="stats w-full bg-primary text-primary-content">
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button :if={not @is_topping_up?} class="mt-2" type="button" phx-click="show_topup">
|
||||
<.icon name="hero-banknotes-solid" class="w-4 h-4" /> Top Up
|
||||
</.button>
|
||||
</div>
|
||||
<div class="stat-title">Map balance</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= @map_balance |> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
<div class="stat-actions text-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.form
|
||||
:let={f}
|
||||
:if={@is_topping_up?}
|
||||
for={@topup_form}
|
||||
phx-change="validate_topup"
|
||||
phx-submit="topup"
|
||||
>
|
||||
<.live_select
|
||||
field={f[:amount]}
|
||||
update_min_len={0}
|
||||
options={@amounts}
|
||||
placeholder="Select topup amount"
|
||||
/>
|
||||
<div class="modal-action">
|
||||
<.button class="mt-2" type="button" phx-click="hide_topup">
|
||||
Cancel
|
||||
</.button>
|
||||
<.button class="mt-2" type="submit">
|
||||
Top Up
|
||||
</.button>
|
||||
</div>
|
||||
</.form>
|
||||
</.header>
|
||||
<.table
|
||||
:if={@active_settings_tab == "subscription"}
|
||||
class="!max-h-[20vh] !overflow-y-auto"
|
||||
empty_label="No active subscriptions, using alpha plan by default."
|
||||
id="active-subscriptions-tbl"
|
||||
rows={@map_subscriptions}
|
||||
>
|
||||
<:col :let={subscription} label="Subscription Plan">
|
||||
<%= subscription.plan %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Status">
|
||||
<%= subscription.status %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Characters Limit">
|
||||
<%= subscription.characters_limit %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Hubs Limit">
|
||||
<%= subscription.hubs_limit %>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Active Till">
|
||||
<.local_time
|
||||
:if={subscription.active_till}
|
||||
id={"subscription-active-till-#{subscription.id}"}
|
||||
at={subscription.active_till}
|
||||
>
|
||||
<%= subscription.active_till %>
|
||||
</.local_time>
|
||||
</:col>
|
||||
<:col :let={subscription} label="Auto Renew">
|
||||
<%= if subscription.auto_renew?, do: "Yes", else: "No" %>
|
||||
</:col>
|
||||
<:action :let={subscription}>
|
||||
<div class="tooltip tooltip-left" data-tip="Edit subscription">
|
||||
<button
|
||||
:if={subscription.status == :active && subscription.plan != :alpha}
|
||||
phx-click="edit-subscription"
|
||||
phx-value-id={subscription.id}
|
||||
>
|
||||
<.icon name="hero-pencil-square-solid" class="w-4 h-4 hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</:action>
|
||||
<:action :let={subscription}>
|
||||
<div class="tooltip tooltip-left" data-tip="Cancel subscription">
|
||||
<button
|
||||
:if={subscription.status == :active && subscription.plan != :alpha}
|
||||
phx-click="cancel-subscription"
|
||||
phx-value-id={subscription.id}
|
||||
data={[confirm: "Please confirm to cancel subscription!"]}
|
||||
>
|
||||
<.icon name="hero-trash-solid" class="w-4 h-4 hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</:action>
|
||||
</.table>
|
||||
</div>
|
||||
|
||||
<div class="modal-action">
|
||||
<div
|
||||
@@ -402,102 +614,4 @@
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.header
|
||||
:if={@active_settings_tab == "subscription" && @is_adding_subscription?}
|
||||
class="bordered border-1 flex flex-col gap-4"
|
||||
>
|
||||
<div :if={is_nil(@selected_subscription)}>
|
||||
Add subscription
|
||||
<div class="badge badge-secondary">Limited time offer: 50%</div>
|
||||
</div>
|
||||
<div :if={not is_nil(@selected_subscription)}>
|
||||
Edit subscription
|
||||
<div class="badge badge-secondary">Limited time offer: 50%</div>
|
||||
</div>
|
||||
<.form
|
||||
:let={f}
|
||||
for={@subscription_form}
|
||||
phx-change="validate_subscription"
|
||||
phx-submit={if is_nil(@selected_subscription), do: "subscribe", else: "update_subscription"}
|
||||
>
|
||||
<.input
|
||||
:if={is_nil(@selected_subscription)}
|
||||
type="select"
|
||||
field={f[:period]}
|
||||
class="p-dropdown p-component p-inputwrapper"
|
||||
placeholder="Subscription period"
|
||||
options={@subscription_periods}
|
||||
/>
|
||||
<.input
|
||||
field={f[:characters_limit]}
|
||||
label="Characters limit"
|
||||
show_value={true}
|
||||
type="range"
|
||||
min="300"
|
||||
max="5000"
|
||||
step="100"
|
||||
class="range range-xs"
|
||||
/>
|
||||
<.input
|
||||
field={f[:hubs_limit]}
|
||||
label="Hubs limit"
|
||||
show_value={true}
|
||||
type="range"
|
||||
min="20"
|
||||
max="50"
|
||||
step="10"
|
||||
class="range range-xs"
|
||||
/>
|
||||
<.input field={f[:auto_renew?]} label="Auto Renew" type="checkbox" />
|
||||
<div
|
||||
:if={is_nil(@selected_subscription)}
|
||||
class="stats w-full bg-primary text-primary-content"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button type="submit">
|
||||
Subscribe
|
||||
</.button>
|
||||
</div>
|
||||
<div class="flex gap-8">
|
||||
<div>
|
||||
<div class="stat-title">Estimated price</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= (@estimated_price - @discount)
|
||||
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="stat-title">Discount</div>
|
||||
<div class="stat-value text-white relative">
|
||||
ISK <%= @discount |> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
<span class="absolute top-0 right-0 text-xs text-white discount" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:if={not is_nil(@selected_subscription)}
|
||||
class="stats w-full bg-primary text-primary-content"
|
||||
>
|
||||
<div class="stat">
|
||||
<div class="stat-figure text-primary">
|
||||
<.button type="button" phx-click="cancel_edit_subscription">
|
||||
Cancel
|
||||
</.button>
|
||||
<.button type="submit">
|
||||
Update
|
||||
</.button>
|
||||
</div>
|
||||
<div class="stat-title">Additional price (mounthly)</div>
|
||||
<div class="stat-value text-white">
|
||||
ISK <%= @additional_price |> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
|
||||
</div>
|
||||
<div class="stat-actions text-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
</.form>
|
||||
</.header>
|
||||
</.modal>
|
||||
|
||||
@@ -57,6 +57,7 @@ defmodule WandererAppWeb.Router do
|
||||
@script_src,
|
||||
~w('unsafe-inline'),
|
||||
~w(https://unpkg.com),
|
||||
~w(https://cdn.jsdelivr.net),
|
||||
~w(https://w.appzi.io),
|
||||
~w(https://www.googletagmanager.com),
|
||||
~w(https://cdnjs.cloudflare.com)
|
||||
|
||||
6
mix.exs
6
mix.exs
@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
@version "1.24.1"
|
||||
@version "1.29.3"
|
||||
|
||||
def project do
|
||||
[
|
||||
@@ -124,12 +124,12 @@ defmodule WandererApp.MixProject do
|
||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
|
||||
"assets.setup": [
|
||||
"cmd npm install --prefix assets"
|
||||
"cmd yarn install --cwd assets"
|
||||
],
|
||||
"assets.build": [],
|
||||
"assets.deploy": [
|
||||
"assets.setup",
|
||||
"cmd --cd assets npm run build",
|
||||
"cmd --cd assets yarn run build",
|
||||
"phx.digest"
|
||||
]
|
||||
]
|
||||
|
||||
@@ -31,10 +31,10 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
31,6,Shuttle,0,0,0,0,0,1
|
||||
32,1,Alliance,None,0,0,0,0,0
|
||||
38,7,Shield Extender,82,0,0,0,0,1
|
||||
39,7,Shield Recharger,83,0,0,0,0,1
|
||||
39,7,Shield Recharger,26451,0,0,0,0,1
|
||||
40,7,Shield Booster,84,0,0,0,0,1
|
||||
41,7,Remote Shield Booster,86,0,0,0,0,1
|
||||
43,7,Capacitor Recharger,90,0,0,0,0,1
|
||||
43,7,Capacitor Recharger,26457,0,0,0,0,1
|
||||
46,7,Propulsion Module,96,0,0,0,0,1
|
||||
47,7,Cargo Scanner,106,0,0,0,0,1
|
||||
48,7,Ship Scanner,107,0,0,0,0,1
|
||||
@@ -44,8 +44,8 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
54,7,Mining Laser,138,0,0,0,0,1
|
||||
55,7,Projectile Weapon,384,0,0,0,0,1
|
||||
56,7,Missile Launcher,168,0,0,0,0,0
|
||||
57,7,Shield Power Relay,0,0,0,0,0,1
|
||||
59,7,Gyrostabilizer,0,0,0,0,0,1
|
||||
57,7,Shield Power Relay,26450,0,0,0,0,1
|
||||
59,7,Gyrostabilizer,26452,0,0,0,0,1
|
||||
60,7,Damage Control,0,0,0,0,0,1
|
||||
61,7,Capacitor Battery,0,0,0,0,0,1
|
||||
62,7,Armor Repair Unit,0,1,0,0,0,1
|
||||
@@ -86,10 +86,10 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
110,9,Titan Blueprint,None,1,0,0,0,1
|
||||
111,9,Shuttle Blueprint,0,1,0,0,0,1
|
||||
118,9,Shield Extender Blueprint,82,1,0,0,0,1
|
||||
119,9,Shield Recharger Blueprint,83,1,0,0,0,1
|
||||
119,9,Shield Recharger Blueprint,26451,1,0,0,0,1
|
||||
120,9,Shield Booster Blueprint,84,1,0,0,0,1
|
||||
121,9,Remote Shield Booster Blueprint,86,1,0,0,0,1
|
||||
123,9,Capacitor Recharger Blueprint,90,1,0,0,0,1
|
||||
123,9,Capacitor Recharger Blueprint,26457,1,0,0,0,1
|
||||
126,9,Propulsion Module Blueprint,96,1,0,0,0,1
|
||||
127,9,Cargo Scanner Blueprint,106,1,0,0,0,1
|
||||
128,9,Ship Scanner Blueprint,107,1,0,0,0,1
|
||||
@@ -149,14 +149,14 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
201,7,ECM,0,0,0,0,0,1
|
||||
202,7,ECCM,0,0,0,0,0,1
|
||||
203,7,Sensor Backup Array,0,0,0,0,0,1
|
||||
205,7,Heat Sink,0,0,0,0,0,1
|
||||
205,7,Heat Sink,26453,0,0,0,0,1
|
||||
208,7,Sensor Dampener,105,0,0,0,0,1
|
||||
209,7,Remote Tracking Computer,3346,0,0,0,0,1
|
||||
210,7,Signal Amplifier,0,0,0,0,0,1
|
||||
211,7,Tracking Enhancer,0,0,0,0,0,1
|
||||
212,7,Sensor Booster,74,0,0,0,0,1
|
||||
213,7,Tracking Computer,3346,0,0,0,0,1
|
||||
218,9,Heat Sink Blueprint,0,1,0,0,0,1
|
||||
218,9,Heat Sink Blueprint,26453,1,0,0,0,1
|
||||
223,9,Sensor Booster Blueprint,0,1,0,0,0,1
|
||||
224,9,Tracking Computer Blueprint,0,1,0,0,0,1
|
||||
225,7,Cheat Module Group,0,0,0,0,0,0
|
||||
@@ -197,7 +197,7 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
299,18,Repair Drone,0,0,0,0,0,0
|
||||
300,20,Cyberimplant,0,1,0,0,0,1
|
||||
301,11,Concord Drone,0,0,0,0,0,0
|
||||
302,7,Magnetic Field Stabilizer,0,0,0,0,0,1
|
||||
302,7,Magnetic Field Stabilizer,26454,0,0,0,0,1
|
||||
303,20,Booster,0,0,0,0,0,1
|
||||
304,20,DNA Mutator,0,0,0,0,0,0
|
||||
305,2,Comet,0,0,0,0,0,0
|
||||
@@ -595,10 +595,10 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
764,7,Overdrive Injector System,0,0,0,0,0,1
|
||||
765,7,Expanded Cargohold,0,0,0,0,0,1
|
||||
766,7,Power Diagnostic System,0,0,0,0,0,1
|
||||
767,7,Capacitor Power Relay,0,0,0,0,0,1
|
||||
768,7,Capacitor Flux Coil,0,0,0,0,0,1
|
||||
767,7,Capacitor Power Relay,26455,0,0,0,0,1
|
||||
768,7,Capacitor Flux Coil,26456,0,0,0,0,1
|
||||
769,7,Reactor Control Unit,0,0,0,0,0,1
|
||||
770,7,Shield Flux Coil,0,0,0,0,0,1
|
||||
770,7,Shield Flux Coil,26449,0,0,0,0,1
|
||||
771,7,Missile Launcher Heavy Assault,3241,0,0,0,0,1
|
||||
772,8,Heavy Assault Missile,3237,0,0,0,1,1
|
||||
773,7,Rig Armor,0,0,0,0,0,1
|
||||
@@ -1322,7 +1322,7 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
1962,66,Structure QA Modules,None,0,0,0,0,0
|
||||
1964,17,Mutaplasmids,None,0,0,0,0,1
|
||||
1966,66,Structure Capacitor Battery,None,0,0,0,0,1
|
||||
1967,66,Structure Capacitor Power Relay,None,0,0,0,0,1
|
||||
1967,66,Structure Capacitor Power Relay,26455,0,0,0,0,1
|
||||
1968,66,Structure Armor Reinforcer,None,0,0,0,0,1
|
||||
1969,7,Abyssal Modules,None,0,0,0,0,0
|
||||
1971,2,Abyssal Hazards,None,0,0,0,0,0
|
||||
@@ -1523,6 +1523,12 @@ groupID,categoryID,groupName,iconID,useBasePrice,anchored,anchorable,fittableNon
|
||||
4802,11,Asteroid Sansha's Nation Officer Frigate,None,0,0,0,0,0
|
||||
4803,11,Asteroid Serpentis Officer Cruiser,None,0,0,0,0,0
|
||||
4804,11,Asteroid Serpentis Officer Frigate,None,0,0,0,0,0
|
||||
4807,7,Breacher Pod Launchers,None,0,0,0,0,1
|
||||
4808,8,SCARAB Breacher Pods,None,0,0,0,1,1
|
||||
4810,22,Mercenary Den,None,0,0,0,0,1
|
||||
4811,9,Mercenary Den Blueprint,None,1,0,0,0,1
|
||||
4820,9,Mutaplasmid Blueprint,None,1,0,0,0,1
|
||||
4821,17,Atavum,None,1,0,0,0,1
|
||||
350858,350001,Infantry Weapons,None,1,0,0,0,0
|
||||
351064,350001,Infantry Dropsuits,None,1,0,0,0,0
|
||||
351121,350001,Infantry Modules,None,1,0,0,0,0
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user