diff --git a/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts b/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts index 52161f67..c4f35c92 100644 --- a/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts +++ b/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts @@ -118,6 +118,10 @@ export const useMapHandlers = (ref: ForwardedRef, onSelectionChange // do nothing here break; + case Commands.linkSignatureToSystem: + // do nothing here + break; + default: console.warn(`Map handlers: Unknown command: ${type}`, data); break; diff --git a/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/SystemLinkSignatureDialog.tsx b/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/SystemLinkSignatureDialog.tsx new file mode 100644 index 00000000..343ec69f --- /dev/null +++ b/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/SystemLinkSignatureDialog.tsx @@ -0,0 +1,70 @@ +import { useCallback, useRef } from 'react'; +import { Dialog } from 'primereact/dialog'; + +import { OutCommand } from '@/hooks/Mapper/types/mapHandlers.ts'; +import { SystemSignature } from '@/hooks/Mapper/types'; +import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; +import { CommandLinkSignatureToSystem } from '@/hooks/Mapper/types'; +import { SystemSignaturesContent } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent'; +import { + Setting, + COSMIC_SIGNATURE, +} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog'; + +interface SystemLinkSignatureDialogProps { + data: CommandLinkSignatureToSystem; + setVisible: (visible: boolean) => void; +} + +const signatureSettings: Setting[] = [{ key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }]; + +export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignatureDialogProps) => { + const { outCommand } = useMapRootState(); + + console.log(data); + + const ref = useRef({ outCommand }); + ref.current = { outCommand }; + + const handleHide = useCallback(() => { + setVisible(false); + }, [setVisible]); + + const handleSelect = useCallback( + (signatures: SystemSignature[]) => { + if (!signatures.length) { + return; + } + + const { outCommand } = ref.current; + + outCommand({ + type: OutCommand.linkSignatureToSystem, + data: { + ...data, + signature_eve_id: signatures[0].eve_id, + }, + }); + setVisible(false); + }, + [setVisible], + ); + + return ( + + + + ); +}; diff --git a/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/index.ts b/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/index.ts new file mode 100644 index 00000000..9d1abef9 --- /dev/null +++ b/assets/js/hooks/Mapper/components/mapInterface/components/SystemLinkSignatureDialog/index.ts @@ -0,0 +1 @@ +export * from './SystemLinkSignatureDialog'; diff --git a/assets/js/hooks/Mapper/components/mapInterface/components/index.ts b/assets/js/hooks/Mapper/components/mapInterface/components/index.ts index abcc6f99..02eb1eaf 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/components/index.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/components/index.ts @@ -2,3 +2,4 @@ export * from './Widget'; export * from './WidgetsGrid'; export * from './SystemSettingsDialog'; export * from './SystemCustomLabelDialog'; +export * from './SystemLinkSignatureDialog'; diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog/SystemSignatureSettingsDialog.tsx b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog/SystemSignatureSettingsDialog.tsx index 70ab50ac..90593002 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog/SystemSignatureSettingsDialog.tsx +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog/SystemSignatureSettingsDialog.tsx @@ -5,6 +5,14 @@ import { Checkbox } from 'primereact/checkbox'; export type Setting = { key: string; name: string; value: boolean }; +export const COSMIC_SIGNATURE = 'Cosmic Signature'; +export const COSMIC_ANOMALY = 'Cosmic Anomaly'; +export const DEPLOYABLE = 'Deployable'; +export const STRUCTURE = 'Structure'; +export const STARBASE = 'Starbase'; +export const SHIP = 'Ship'; +export const DRONE = 'Drone'; + interface SystemSignatureSettingsDialogProps { settings: Setting[]; onSave: (settings: Setting[]) => void; diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatures.tsx b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatures.tsx index 6c9fbed2..da4c645c 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatures.tsx +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatures.tsx @@ -1,7 +1,17 @@ import { Widget } from '@/hooks/Mapper/components/mapInterface/components'; import { InfoDrawer, LayoutEventBlocker, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit'; import { SystemSignaturesContent } from './SystemSignaturesContent'; -import { Setting, SystemSignatureSettingsDialog } from './SystemSignatureSettingsDialog'; +import { + Setting, + SystemSignatureSettingsDialog, + COSMIC_SIGNATURE, + COSMIC_ANOMALY, + DEPLOYABLE, + STRUCTURE, + STARBASE, + SHIP, + DRONE, +} from './SystemSignatureSettingsDialog'; import React, { useCallback, useEffect, useState } from 'react'; @@ -9,14 +19,6 @@ import { PrimeIcons } from 'primereact/api'; import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; -export const COSMIC_SIGNATURE = 'Cosmic Signature'; -export const COSMIC_ANOMALY = 'Cosmic Anomaly'; -export const DEPLOYABLE = 'Deployable'; -export const STRUCTURE = 'Structure'; -export const STARBASE = 'Starbase'; -export const SHIP = 'Ship'; -export const DRONE = 'Drone'; - const settings: Setting[] = [ { key: COSMIC_ANOMALY, name: 'Show Anomalies', value: true }, { key: COSMIC_SIGNATURE, name: 'Show Cosmic Signatures', value: true }, diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent/SystemSignaturesContent.tsx b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent/SystemSignaturesContent.tsx index 075b5b8f..86552455 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent/SystemSignaturesContent.tsx +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignaturesContent/SystemSignaturesContent.tsx @@ -24,6 +24,7 @@ import { renderIcon, renderName, renderTimeLeft, + renderLinkedSystem, } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/renders'; // import { PrimeIcons } from 'primereact/api'; import useLocalStorageState from 'use-local-storage-state'; @@ -41,8 +42,10 @@ const SORT_DEFAULT_VALUES: SystemSignaturesSortSettings = { interface SystemSignaturesContentProps { systemId: string; settings: Setting[]; + selectable?: boolean; + onSelect?: (signatures: SystemSignature[]) => void; } -export const SystemSignaturesContent = ({ systemId, settings }: SystemSignaturesContentProps) => { +export const SystemSignaturesContent = ({ systemId, settings, selectable, onSelect }: SystemSignaturesContentProps) => { const { outCommand } = useMapRootState(); const [signatures, setSignatures, signaturesRef] = useRefState([]); @@ -92,25 +95,25 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures setSignatures(signatures); }, [outCommand, systemId]); - const updateSignatures = useCallback( - async (newSignatures: SystemSignature[], updateOnly: boolean) => { - const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly); + // const updateSignatures = useCallback( + // async (newSignatures: SystemSignature[], updateOnly: boolean) => { + // const { added, updated, removed } = getActualSigs(signaturesRef.current, newSignatures, updateOnly); - const { signatures: updatedSignatures } = await outCommand({ - type: OutCommand.updateSignatures, - data: { - system_id: systemId, - added, - updated, - removed, - }, - }); + // const { signatures: updatedSignatures } = await outCommand({ + // type: OutCommand.updateSignatures, + // data: { + // system_id: systemId, + // added, + // updated, + // removed, + // }, + // }); - setSignatures(() => updatedSignatures); - setSelectedSignatures([]); - }, - [outCommand, systemId], - ); + // setSignatures(() => updatedSignatures); + // setSelectedSignatures([]); + // }, + // [outCommand, systemId], + // ); const handleUpdateSignatures = useCallback( async (newSignatures: SystemSignature[], updateOnly: boolean) => { @@ -133,6 +136,9 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures ); const handleDeleteSelected = useCallback(async () => { + if (selectable) { + return; + } if (selectedSignatures.length === 0) { return; } @@ -141,7 +147,7 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures signatures.filter(x => !selectedSignaturesEveIds.includes(x.eve_id)), false, ); - }, [handleUpdateSignatures, signatures, selectedSignatures]); + }, [handleUpdateSignatures, selectable, signatures, selectedSignatures]); const handleSelectAll = useCallback(() => { setSelectedSignatures(signatures); @@ -157,11 +163,20 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures setAskUser(false); }, [parsedSignatures, handleUpdateSignatures]); + const handleSelectSignatures = useCallback(e => { + setSelectedSignatures(e.value); + onSelect?.(e.value); + }, []); + useHotkey(true, ['a'], handleSelectAll); useHotkey(false, ['Backspace', 'Delete'], handleDeleteSelected); useEffect(() => { + if (selectable) { + return; + } + if (!clipboardContent) { return; } @@ -179,7 +194,7 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures setParsedSignatures(newSignatures); setAskUser(true); } - }, [clipboardContent]); + }, [clipboardContent, selectable]); useEffect(() => { if (!systemId) { @@ -240,10 +255,10 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures className={classes.Table} value={filteredSignatures} size="small" - selectionMode="multiple" + // selectionMode={selectable ? 'multiple' : 'single'} selection={selectedSignatures} metaKeySelection - onSelectionChange={e => setSelectedSignatures(e.value)} + onSelectionChange={handleSelectSignatures} dataKey="eve_id" tableClassName="w-full select-none" resizableColumns={false} @@ -297,6 +312,18 @@ export const SystemSignaturesContent = ({ systemId, settings }: SystemSignatures hidden={compact || medium} sortable > + {!selectable && ( + + )} + { + if (!row.linked_system) { + return null; + } + + return ( + + + + ); +}; diff --git a/assets/js/hooks/Mapper/components/mapWrapper/MapWrapper.tsx b/assets/js/hooks/Mapper/components/mapWrapper/MapWrapper.tsx index 528c06a3..ac02d057 100644 --- a/assets/js/hooks/Mapper/components/mapWrapper/MapWrapper.tsx +++ b/assets/js/hooks/Mapper/components/mapWrapper/MapWrapper.tsx @@ -5,13 +5,20 @@ import { MapRootData, useMapRootState } from '@/hooks/Mapper/mapRootProvider'; import { OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts'; import isEqual from 'lodash.isequal'; import { ContextMenuSystem, useContextMenuSystemHandlers } from '@/hooks/Mapper/components/contexts'; -import { SystemCustomLabelDialog, SystemSettingsDialog } from '@/hooks/Mapper/components/mapInterface/components'; +import { + SystemCustomLabelDialog, + SystemSettingsDialog, + SystemLinkSignatureDialog, +} from '@/hooks/Mapper/components/mapInterface/components'; import classes from './MapWrapper.module.scss'; import { Connections } from '@/hooks/Mapper/components/mapRootContent/components/Connections'; import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple'; import { getSystemById } from '@/hooks/Mapper/helpers'; import { Node } from 'reactflow'; +import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts'; +import { useMapEventListener } from '@/hooks/Mapper/events'; + import { STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/MapRootProvider'; interface MapWrapperProps { @@ -53,6 +60,7 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => { ); const [openSettings, setOpenSettings] = useState(null); + const [openLinkSignatures, setOpenLinkSignatures] = useState(null); const [openCustomLabel, setOpenCustomLabel] = useState(null); const handleCommand: OutCommandHandler = useCallback( event => { @@ -60,6 +68,9 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => { case OutCommand.openSettings: setOpenSettings(event.data.system_id); break; + case OutCommand.linkSignatureToSystem: + setOpenLinkSignatures(event.data); + break; default: return outCommand(event); } @@ -88,6 +99,14 @@ export const MapWrapper = ({ refn }: MapWrapperProps) => { const handleConnectionDbClick = useCallback((e: SolarSystemConnection) => setSelectedConnection(e), []); + useMapEventListener(event => { + switch (event.name) { + case Commands.linkSignatureToSystem: + setOpenLinkSignatures(event.data); + return true; + } + }); + return ( <> { /> {openSettings != null && ( - setOpenSettings(null)} - /> + setOpenSettings(null)} /> )} {openCustomLabel != null && ( - setOpenCustomLabel(null)} - /> + setOpenCustomLabel(null)} /> + )} + + {openLinkSignatures != null && ( + setOpenLinkSignatures(null)} /> )} setSelectedConnection(null)} /> diff --git a/assets/js/hooks/Mapper/events/index.ts b/assets/js/hooks/Mapper/events/index.ts new file mode 100644 index 00000000..c9aef7ae --- /dev/null +++ b/assets/js/hooks/Mapper/events/index.ts @@ -0,0 +1,13 @@ +import { createEvent } from 'react-event-hook'; + +export interface MapEvent { + name: string; + data: { + solar_system_source: number; + solar_system_target: number; + }; +} + +const { useMapEventListener, emitMapEvent } = createEvent('map-event')(); + +export { useMapEventListener, emitMapEvent }; diff --git a/assets/js/hooks/Mapper/helpers/parseSignatures.ts b/assets/js/hooks/Mapper/helpers/parseSignatures.ts index c218e81f..c4ee49d7 100644 --- a/assets/js/hooks/Mapper/helpers/parseSignatures.ts +++ b/assets/js/hooks/Mapper/helpers/parseSignatures.ts @@ -1,4 +1,4 @@ -import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures'; +import { COSMIC_SIGNATURE } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/SystemSignatureSettingsDialog'; import { SystemSignature } from '@/hooks/Mapper/types'; export const parseSignatures = (value: string, availableKeys: string[]): SystemSignature[] => { diff --git a/assets/js/hooks/Mapper/mapRootProvider/hooks/useMapRootHandlers.ts b/assets/js/hooks/Mapper/mapRootProvider/hooks/useMapRootHandlers.ts index 4bc2eb57..67368813 100644 --- a/assets/js/hooks/Mapper/mapRootProvider/hooks/useMapRootHandlers.ts +++ b/assets/js/hooks/Mapper/mapRootProvider/hooks/useMapRootHandlers.ts @@ -27,6 +27,8 @@ import { useRoutes, } from './api'; +import { emitMapEvent } from '@/hooks/Mapper/events'; + export const useMapRootHandlers = (ref: ForwardedRef) => { const mapInit = useMapInit(); const { addSystems, removeSystems, updateSystems } = useCommandsSystems(); @@ -93,6 +95,10 @@ export const useMapRootHandlers = (ref: ForwardedRef) => { // do nothing here break; + case Commands.linkSignatureToSystem: + emitMapEvent({ name: Commands.linkSignatureToSystem, data }); + break; + case Commands.killsUpdated: // do nothing here break; diff --git a/assets/js/hooks/Mapper/types/mapHandlers.ts b/assets/js/hooks/Mapper/types/mapHandlers.ts index 20cda539..4fb4d535 100644 --- a/assets/js/hooks/Mapper/types/mapHandlers.ts +++ b/assets/js/hooks/Mapper/types/mapHandlers.ts @@ -23,6 +23,7 @@ export enum Commands { routes = 'routes', centerSystem = 'center_system', selectSystem = 'select_system', + linkSignatureToSystem = 'link_signature_to_system', } export type Command = @@ -42,7 +43,8 @@ export type Command = | Commands.killsUpdated | Commands.routes | Commands.selectSystem - | Commands.centerSystem; + | Commands.centerSystem + | Commands.linkSignatureToSystem; export type CommandInit = { systems: SolarSystemRawType[]; @@ -75,6 +77,11 @@ export type CommandRoutes = RoutesList; export type CommandKillsUpdated = Kill[]; export type CommandSelectSystem = string | undefined; export type CommandCenterSystem = string | undefined; +export type CommandLinkSignatureToSystem = { + solar_system_source: number; + solar_system_target: number; + signatures: any[]; +}; export interface CommandData { [Commands.init]: CommandInit; @@ -94,6 +101,7 @@ export interface CommandData { [Commands.killsUpdated]: CommandKillsUpdated; [Commands.selectSystem]: CommandSelectSystem; [Commands.centerSystem]: CommandCenterSystem; + [Commands.linkSignatureToSystem]: CommandLinkSignatureToSystem; } export interface MapHandlers { @@ -129,6 +137,7 @@ export enum OutCommand { addCharacter = 'add_character', openUserSettings = 'open_user_settings', getPassages = 'get_passages', + linkSignatureToSystem = 'link_signature_to_system', // Only UI commands openSettings = 'open_settings', diff --git a/assets/js/hooks/Mapper/types/signatures.ts b/assets/js/hooks/Mapper/types/signatures.ts index 3f7c7b45..0ea3b028 100644 --- a/assets/js/hooks/Mapper/types/signatures.ts +++ b/assets/js/hooks/Mapper/types/signatures.ts @@ -1,9 +1,12 @@ +import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types'; + export type SystemSignature = { eve_id: string; kind: string; name: string; description?: string; group: string; + linked_system?: SolarSystemStaticInfoRaw; updated_at?: string; }; diff --git a/assets/package.json b/assets/package.json index 9d0adb24..00ca6c12 100644 --- a/assets/package.json +++ b/assets/package.json @@ -28,6 +28,7 @@ "primeicons": "^7.0.0", "primereact": "^10.6.5", "react-error-boundary": "^4.0.13", + "react-event-hook": "^3.1.2", "react-flow-renderer": "^10.3.17", "react-grid-layout": "^1.3.4", "react-usestateref": "^1.0.9", diff --git a/assets/yarn.lock b/assets/yarn.lock index f0849760..a3cf423f 100644 --- a/assets/yarn.lock +++ b/assets/yarn.lock @@ -3199,6 +3199,11 @@ react-error-boundary@^4.0.13: dependencies: "@babel/runtime" "^7.12.5" +react-event-hook@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/react-event-hook/-/react-event-hook-3.1.2.tgz#445e8f3b751f6abe4ef199f31bff47593c4c13d4" + integrity sha512-qQ9LXLdxmWRRZPlnqVjqlw7jovSvDosQEOyQ9cjPHhtDv8JIszjj0td1PuHJHrVW0LS8a1XeJhLe6i7S5u9SbQ== + react-flow-renderer@^10.3.17: version "10.3.17" resolved "https://registry.npmjs.org/react-flow-renderer/-/react-flow-renderer-10.3.17.tgz" diff --git a/lib/wanderer_app/api/map_system_signature.ex b/lib/wanderer_app/api/map_system_signature.ex index 6eace61f..2843043d 100644 --- a/lib/wanderer_app/api/map_system_signature.ex +++ b/lib/wanderer_app/api/map_system_signature.ex @@ -14,6 +14,7 @@ defmodule WandererApp.Api.MapSystemSignature do define(:all_active, action: :all_active) define(:create, action: :create) define(:update, action: :update) + define(:update_linked_system, action: :update_linked_system) define(:by_id, get_by: [:id], @@ -66,13 +67,18 @@ defmodule WandererApp.Api.MapSystemSignature do :name, :description, :kind, - :group + :group, + :linked_system_id ] primary? true require_atomic? false end + update :update_linked_system do + accept [:linked_system_id] + end + read :by_system_id do argument(:system_id, :string, allow_nil?: false) @@ -99,6 +105,10 @@ defmodule WandererApp.Api.MapSystemSignature do allow_nil? true end + attribute :linked_system_id, :integer do + allow_nil? true + end + attribute :kind, :string attribute :group, :string diff --git a/lib/wanderer_app/map/map_server_impl.ex b/lib/wanderer_app/map/map_server_impl.ex index 312458d9..b4e5feb0 100644 --- a/lib/wanderer_app/map/map_server_impl.ex +++ b/lib/wanderer_app/map/map_server_impl.ex @@ -1627,9 +1627,17 @@ defmodule WandererApp.Map.Server.Impl do solar_system_target: location.solar_system_id }) - broadcast!(map_id, :add_connection, connection) WandererApp.Map.add_connection(map_id, connection) + broadcast!(map_id, :add_connection, connection) + broadcast!(map_id, :maybe_link_signature, %{ + character_id: character_id, + solar_system_source: old_location.solar_system_id, + solar_system_target: location.solar_system_id, + }) + + :ok + {:error, error} -> @logger.debug(fn -> "Failed to add connection: #{inspect(error, pretty: true)}" end) :ok diff --git a/lib/wanderer_app/repositories/map_user_settings_repo.ex b/lib/wanderer_app/repositories/map_user_settings_repo.ex index 4bb80ec5..c7adcb52 100644 --- a/lib/wanderer_app/repositories/map_user_settings_repo.ex +++ b/lib/wanderer_app/repositories/map_user_settings_repo.ex @@ -1,7 +1,7 @@ defmodule WandererApp.MapUserSettingsRepo do use WandererApp, :repository - @default_form_data %{"select_on_spash" => "false"} + @default_form_data %{"select_on_spash" => "false", "link_signature_on_splash" => "false"} def get(map_id, user_id) do map_id diff --git a/lib/wanderer_app_web/components/layouts/app.html.heex b/lib/wanderer_app_web/components/layouts/app.html.heex index 597cfbb2..6c461a88 100644 --- a/lib/wanderer_app_web/components/layouts/app.html.heex +++ b/lib/wanderer_app_web/components/layouts/app.html.heex @@ -1,3 +1,3 @@ -
+
<%= @inner_content %>
diff --git a/lib/wanderer_app_web/components/layouts/blog.html.heex b/lib/wanderer_app_web/components/layouts/blog.html.heex index 1822f674..85ad4e46 100644 --- a/lib/wanderer_app_web/components/layouts/blog.html.heex +++ b/lib/wanderer_app_web/components/layouts/blog.html.heex @@ -1,5 +1,5 @@
diff --git a/lib/wanderer_app_web/components/layouts/landing.html.heex b/lib/wanderer_app_web/components/layouts/landing.html.heex index 8eecd4bd..4c600df4 100644 --- a/lib/wanderer_app_web/components/layouts/landing.html.heex +++ b/lib/wanderer_app_web/components/layouts/landing.html.heex @@ -5,7 +5,7 @@
<%= @inner_content %> diff --git a/lib/wanderer_app_web/components/layouts/live.html.heex b/lib/wanderer_app_web/components/layouts/live.html.heex index 57cd93b0..f458de80 100644 --- a/lib/wanderer_app_web/components/layouts/live.html.heex +++ b/lib/wanderer_app_web/components/layouts/live.html.heex @@ -1,4 +1,4 @@ -
+
<.connection_status> Re-establishing connection... diff --git a/lib/wanderer_app_web/live/maps/map_live.ex b/lib/wanderer_app_web/live/maps/map_live.ex index 1ee9043d..dfeda08a 100644 --- a/lib/wanderer_app_web/live/maps/map_live.ex +++ b/lib/wanderer_app_web/live/maps/map_live.ex @@ -211,6 +211,67 @@ defmodule WandererAppWeb.MapLive do {:noreply, socket} end + @impl true + def handle_info( + %{ + event: :maybe_link_signature, + payload: %{ + character_id: character_id, + solar_system_source: solar_system_source, + solar_system_target: solar_system_target, + } + }, + %{assigns: %{current_user: current_user, map_id: map_id, map_user_settings: map_user_settings}} = socket + ) do + is_user_character? = + current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id) + + link_signature_on_splash? = + map_user_settings + |> WandererApp.MapUserSettingsRepo.to_form_data!() + |> Map.get("link_signature_on_splash", "false") + |> String.to_existing_atom() + + {:ok, signatures} = + WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{ + map_id: map_id, + solar_system_id: solar_system_source + }) + |> case do + {:ok, system} -> + {:ok, get_system_signatures(system.id)} + _ -> + {:ok, []} + end + + # signatures + # : + # (4) [{…}, {…}, {…}, {…}] + # solar_system_source + # : + # 31000526 + # solar_system_target + # : + # 31001819 + # + socket = + (is_user_character? && link_signature_on_splash? && not(signatures |> Enum.empty?())) + |> case do + true -> + socket + |> push_map_event("link_signature_to_system", %{ + solar_system_source: solar_system_source, + solar_system_target: solar_system_target, + signatures: signatures + }) + + false -> + socket + end + + {:noreply, socket} + end + @impl true def handle_info(%{event: :update_map, payload: map_diff}, socket) do {:noreply, @@ -1048,7 +1109,7 @@ defmodule WandererAppWeb.MapLive do s |> WandererApp.Api.MapSystemSignature.create!() end) - {:reply, %{signatures: _get_system_signatures(system.id)}, socket} + {:reply, %{signatures: get_system_signatures(system.id)}, socket} _ -> {:reply, %{signatures: []}, @@ -1079,7 +1140,7 @@ defmodule WandererAppWeb.MapLive do solar_system_id: solar_system_id |> String.to_integer() }) do {:ok, system} -> - {:reply, %{signatures: _get_system_signatures(system.id)}, socket} + {:reply, %{signatures: get_system_signatures(system.id)}, socket} _ -> {:reply, %{signatures: []}, socket} @@ -1530,7 +1591,7 @@ defmodule WandererAppWeb.MapLive do user_settings_form, %{assigns: %{map_id: map_id, current_user: current_user}} = socket ) do - settings = user_settings_form |> Map.take(["select_on_spash"]) |> Jason.encode!() + settings = user_settings_form |> Map.take(["select_on_spash", "link_signature_on_splash"]) |> Jason.encode!() {:ok, user_settings} = WandererApp.MapUserSettingsRepo.create_or_update(map_id, current_user.id, settings) @@ -1540,7 +1601,56 @@ defmodule WandererAppWeb.MapLive do end @impl true - def handle_event("noop", _, socket), do: {:noreply, socket} + def handle_event( + "link_signature_to_system", + %{ + "signature_eve_id" => signature_eve_id, + "solar_system_source" => solar_system_source, + "solar_system_target" => solar_system_target + }, + socket + ) do + + socket + |> _check_user_permissions(:update_system) + |> case do + true -> + case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{ + map_id: socket.assigns.map_id, + solar_system_id: solar_system_source + }) do + {:ok, system} -> + first_character_eve_id = + Map.get(socket.assigns, :user_characters, []) |> List.first() + + case not is_nil(first_character_eve_id) do + true -> + WandererApp.Api.MapSystemSignature.by_system_id!(system.id) + |> Enum.filter(fn s -> s.eve_id == signature_eve_id end) + |> Enum.each(fn s -> + s + |> WandererApp.Api.MapSystemSignature.update_linked_system(%{linked_system_id: solar_system_target}) + end) + + {:noreply, socket} + + _ -> + {:noreply, + socket + |> put_flash( + :error, + "You should enable tracking for at least one character to work with signatures." + )} + end + + _ -> + {:noreply, socket} + end + + _ -> + {:noreply, socket} + end + end @impl true def handle_event("show_activity", _, socket) do @@ -1585,6 +1695,9 @@ defmodule WandererAppWeb.MapLive do })} end + @impl true + def handle_event("noop", _, socket), do: {:noreply, socket} + @impl true def handle_event(event, body, socket) do Logger.warning(fn -> "unhandled event: #{event} #{inspect(body)}" end) @@ -1816,11 +1929,11 @@ defmodule WandererAppWeb.MapLive do end end - defp _get_system_signatures(system_id), + defp get_system_signatures(system_id), do: system_id |> WandererApp.Api.MapSystemSignature.by_system_id!() - |> Enum.map(fn %{updated_at: updated_at} = s -> + |> Enum.map(fn %{updated_at: updated_at, linked_system_id: linked_system_id} = s -> s |> Map.take([ :system_id, @@ -1832,6 +1945,7 @@ defmodule WandererAppWeb.MapLive do :group, :updated_at ]) + |> Map.put(:linked_system, get_system_static_info(linked_system_id)) |> Map.put(:updated_at, updated_at |> Calendar.strftime("%Y/%m/%d %H:%M:%S")) end) @@ -1897,14 +2011,7 @@ defmodule WandererAppWeb.MapLive do } = _system, _include_static_data? \\ true ) do - system_static_info = - case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do - {:ok, system_static_info} -> - map_ui_system_static_info(system_static_info) - - _ -> - %{} - end + system_static_info = get_system_static_info(solar_system_id) %{ id: "#{solar_system_id}", @@ -1920,6 +2027,18 @@ defmodule WandererAppWeb.MapLive do } end + defp get_system_static_info(nil), do: nil + + defp get_system_static_info(solar_system_id) do + case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do + {:ok, system_static_info} -> + map_ui_system_static_info(system_static_info) + + _ -> + %{} + end + end + defp map_ui_system_static_info(nil), do: %{} defp map_ui_system_static_info(system_static_info), diff --git a/lib/wanderer_app_web/live/maps/map_live.html.heex b/lib/wanderer_app_web/live/maps/map_live.html.heex index acaf791d..0632ea20 100644 --- a/lib/wanderer_app_web/live/maps/map_live.html.heex +++ b/lib/wanderer_app_web/live/maps/map_live.html.heex @@ -164,5 +164,10 @@ phx-change="update_user_settings" > <.input type="checkbox" field={f[:select_on_spash]} label="Auto select splashed systems" /> + <.input + type="checkbox" + field={f[:link_signature_on_splash]} + label="Link splashed systems to signatures" + /> diff --git a/priv/repo/migrations/20241012105645_add_signature_linked_system.exs b/priv/repo/migrations/20241012105645_add_signature_linked_system.exs new file mode 100644 index 00000000..8fddad1b --- /dev/null +++ b/priv/repo/migrations/20241012105645_add_signature_linked_system.exs @@ -0,0 +1,21 @@ +defmodule WandererApp.Repo.Migrations.AddSignatureLinkedSystem do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:map_system_signatures_v1) do + add :linked_system_id, :bigint + end + end + + def down do + alter table(:map_system_signatures_v1) do + remove :linked_system_id + end + end +end diff --git a/priv/resource_snapshots/repo/map_system_signatures_v1/20241012105645.json b/priv/resource_snapshots/repo/map_system_signatures_v1/20241012105645.json new file mode 100644 index 00000000..810b4edd --- /dev/null +++ b/priv/resource_snapshots/repo/map_system_signatures_v1/20241012105645.json @@ -0,0 +1,167 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "eve_id", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "character_eve_id", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "description", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "linked_system_id", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "kind", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "group", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "map_system_signatures_v1_system_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "map_system_v1" + }, + "size": null, + "source": "system_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "B437BC9E9F4607EBD235CBB39B814710E223D532CE09B952C9371257159008F4", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "map_system_signatures_v1_uniq_system_eve_id_index", + "keys": [ + { + "type": "atom", + "value": "system_id" + }, + { + "type": "atom", + "value": "eve_id" + } + ], + "name": "uniq_system_eve_id", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.WandererApp.Repo", + "schema": null, + "table": "map_system_signatures_v1" +} \ No newline at end of file