From 2f86fc9f17b99467f5f4caa2cd1833c0dc9c3d4e Mon Sep 17 00:00:00 2001 From: Arkezar Date: Sat, 25 Apr 2026 18:21:29 +0200 Subject: [PATCH] feat: track Save Mass (locked) status on connections --- .../components/Connections/Connections.tsx | 44 ++++++++----- .../hooks/Mapper/types/connectionPassages.ts | 2 + lib/wanderer_app/api/map_connection.ex | 12 +++- .../map/server/map_server_connections_impl.ex | 63 +++++++++++++++++-- .../map_connections_event_handler.ex | 1 + ...425000000_add_map_connection_locked_by.exs | 21 +++++++ 6 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 priv/repo/migrations/20260425000000_add_map_connection_locked_by.exs diff --git a/assets/js/hooks/Mapper/components/mapRootContent/components/Connections/Connections.tsx b/assets/js/hooks/Mapper/components/mapRootContent/components/Connections/Connections.tsx index bb8e4385..5d322945 100644 --- a/assets/js/hooks/Mapper/components/mapRootContent/components/Connections/Connections.tsx +++ b/assets/js/hooks/Mapper/components/mapRootContent/components/Connections/Connections.tsx @@ -196,23 +196,35 @@ export const Connections = ({ selectedConnection, onHide }: OnTheMapProps) => { {/* Connection Info */}
{/* Connection Info Row */} - -
- - - +
+ {/*Left column*/} +
+ {isWormhole && info?.locked_at && ( + + + {info.locked_by_name && by {info.locked_by_name}} + + )}
- + {/*Right column*/} + +
+ + + +
+
+
{/*Left column*/} diff --git a/assets/js/hooks/Mapper/types/connectionPassages.ts b/assets/js/hooks/Mapper/types/connectionPassages.ts index 6cf06e1c..fb1770ab 100644 --- a/assets/js/hooks/Mapper/types/connectionPassages.ts +++ b/assets/js/hooks/Mapper/types/connectionPassages.ts @@ -21,6 +21,8 @@ export type PassageWithSourceTarget = { export type ConnectionInfoOutput = { marl_eol_time: string; + locked_at: string | null; + locked_by_name: string | null; }; export type ConnectionOutput = { diff --git a/lib/wanderer_app/api/map_connection.ex b/lib/wanderer_app/api/map_connection.ex index 7951113e..2e2ccf84 100644 --- a/lib/wanderer_app/api/map_connection.ex +++ b/lib/wanderer_app/api/map_connection.ex @@ -20,7 +20,7 @@ defmodule WandererApp.Api.MapConnection do json_api do type "map_connections" - includes([:map]) + includes([:map, :locked_by]) default_fields([ :solar_system_source, @@ -32,6 +32,7 @@ defmodule WandererApp.Api.MapConnection do :wormhole_type, :count_of_passage, :locked, + :locked_at, :custom_info ]) @@ -274,6 +275,11 @@ defmodule WandererApp.Api.MapConnection do public? true end + attribute :locked_at, :utc_datetime_usec do + public? true + allow_nil? true + end + attribute :custom_info, :string do public? true allow_nil? true @@ -288,5 +294,9 @@ defmodule WandererApp.Api.MapConnection do attribute_writable? true public? true end + + belongs_to :locked_by, WandererApp.Api.Character do + public? true + end end end diff --git a/lib/wanderer_app/map/server/map_server_connections_impl.ex b/lib/wanderer_app/map/server/map_server_connections_impl.ex index 80ce2540..bc6f423e 100644 --- a/lib/wanderer_app/map/server/map_server_connections_impl.ex +++ b/lib/wanderer_app/map/server/map_server_connections_impl.ex @@ -213,9 +213,34 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do solar_system_target_id ) |> case do - {:ok, %{id: connection_id}} -> + {:ok, %{id: connection_id} = connection} -> connection_mark_eol_time = get_connection_mark_eol_time(map_id, connection_id, nil) - {:ok, %{marl_eol_time: connection_mark_eol_time}} + locked_info = get_connection_locked_info(map_id, connection_id) + + locked_by_name = + case locked_info do + nil -> + nil + + %{locked_by_id: locked_by_id} -> + case WandererApp.Api.Character.by_id(locked_by_id) do + {:ok, character} -> character.name + _ -> nil + end + end + + locked_at = + case locked_info do + nil -> nil + %{locked_at: locked_at} -> locked_at + end + + {:ok, + %{ + marl_eol_time: connection_mark_eol_time, + locked_at: locked_at, + locked_by_name: locked_by_name + }} _ -> {:error, :not_found} @@ -293,8 +318,27 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do def update_connection_locked( map_id, connection_update - ), - do: update_connection(map_id, :update_locked, [:locked], connection_update) + ) do + update_connection(map_id, :update_locked, [:locked], connection_update, fn + %{locked: old_locked}, %{id: connection_id, locked: new_locked} = _ -> + case new_locked do + true -> + if not old_locked do + character_id = Map.get(connection_update, :character_id) + + WandererApp.Cache.put( + "map_#{map_id}:conn_#{connection_id}:locked_info", + %{locked_by_id: character_id, locked_at: DateTime.utc_now()} + ) + end + + _ -> + if old_locked do + WandererApp.Cache.delete("map_#{map_id}:conn_#{connection_id}:locked_info") + end + end + end) + end def update_connection_custom_info( map_id, @@ -954,6 +998,16 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do end end + def get_connection_locked_info(map_id, connection_id) do + case WandererApp.Cache.get("map_#{map_id}:conn_#{connection_id}:locked_info") do + nil -> + nil + + value -> + value + end + end + defp find_solar_system_jump(from_solar_system_id, to_solar_system_id) do case WandererApp.CachedInfo.get_solar_system_jump(from_solar_system_id, to_solar_system_id) do {:ok, jump} when not is_nil(jump) -> {:ok, [jump]} @@ -1033,6 +1087,7 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do }) WandererApp.Cache.delete("map_#{map_id}:conn_#{connection.id}:start_time") + WandererApp.Cache.delete("map_#{map_id}:conn_#{connection.id}:locked_info") # Clear linked_sig_eve_id on target system when connection is deleted # This ensures old signatures become orphaned and won't affect future connections diff --git a/lib/wanderer_app_web/live/map/event_handlers/map_connections_event_handler.ex b/lib/wanderer_app_web/live/map/event_handlers/map_connections_event_handler.ex index a0a61360..e02b5a4e 100644 --- a/lib/wanderer_app_web/live/map/event_handlers/map_connections_event_handler.ex +++ b/lib/wanderer_app_web/live/map/event_handlers/map_connections_event_handler.ex @@ -240,6 +240,7 @@ defmodule WandererAppWeb.MapConnectionsEventHandler do solar_system_target_id: solar_system_target_id_int } |> Map.put_new(key_atom, value) + |> Map.put(:character_id, main_character_id) ]) {:noreply, socket} diff --git a/priv/repo/migrations/20260425000000_add_map_connection_locked_by.exs b/priv/repo/migrations/20260425000000_add_map_connection_locked_by.exs new file mode 100644 index 00000000..0c4cf396 --- /dev/null +++ b/priv/repo/migrations/20260425000000_add_map_connection_locked_by.exs @@ -0,0 +1,21 @@ +defmodule WandererApp.Repo.Migrations.AddMapConnectionLockedBy do + @moduledoc """ + Add locked_by and locked_at tracking to map_chain_v1 connections + """ + + use Ecto.Migration + + def up do + alter table(:map_chain_v1) do + add :locked_by_id, :binary_id + add :locked_at, :utc_datetime_usec + end + end + + def down do + alter table(:map_chain_v1) do + remove :locked_by_id + remove :locked_at + end + end +end