fix: issue #19 opening post editor on blogmark
This commit is contained in:
@@ -186,6 +186,9 @@ export const AppShell = {
|
|||||||
this.el.addEventListener("change", this.handleChange);
|
this.el.addEventListener("change", this.handleChange);
|
||||||
syncMediaThumbnailState(this.el);
|
syncMediaThumbnailState(this.el);
|
||||||
this.restoreStoredWorkbenchSession();
|
this.restoreStoredWorkbenchSession();
|
||||||
|
// Rehydration is done (any stored-session push is ordered before this):
|
||||||
|
// tell the server it may now deliver queued deep links.
|
||||||
|
this.pushEvent("shell_ready", {});
|
||||||
},
|
},
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
|
|||||||
@@ -152,7 +152,6 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|
|
||||||
if connected do
|
if connected do
|
||||||
Phoenix.PubSub.subscribe(BDS.PubSub, Watcher.topic())
|
Phoenix.PubSub.subscribe(BDS.PubSub, Watcher.topic())
|
||||||
attach_deep_link()
|
|
||||||
Process.send_after(self(), :refresh_task_status, @refresh_interval)
|
Process.send_after(self(), :refresh_task_status, @refresh_interval)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -546,7 +545,20 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|
|
||||||
def handle_event("restore_workbench_session", %{"session" => session_payload}, socket)
|
def handle_event("restore_workbench_session", %{"session" => session_payload}, socket)
|
||||||
when is_map(session_payload) do
|
when is_map(session_payload) do
|
||||||
{:noreply, reload_shell(socket, SessionUtil.restore_workbench_session(session_payload))}
|
restored =
|
||||||
|
session_payload
|
||||||
|
|> SessionUtil.restore_workbench_session()
|
||||||
|
|> preserve_active_tab(socket.assigns.workbench)
|
||||||
|
|
||||||
|
{:noreply, reload_shell(socket, restored)}
|
||||||
|
end
|
||||||
|
|
||||||
|
# The client signals readiness after mounting its hooks and pushing any
|
||||||
|
# stored workbench session. Deep links attach only now, so cold-start
|
||||||
|
# blogmark links run after rehydration and the editor they open survives.
|
||||||
|
def handle_event("shell_ready", _params, socket) do
|
||||||
|
attach_deep_link()
|
||||||
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event(event, params, socket) when event in @native_menu_events do
|
def handle_event(event, params, socket) when event in @native_menu_events do
|
||||||
@@ -923,6 +935,21 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|> UrlState.push()
|
|> UrlState.push()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A tab opened before the client's stored session arrives (e.g. a blogmark
|
||||||
|
# deep link that switched projects) must survive the restore, so re-open it
|
||||||
|
# on the restored workbench with its original transient/pinned intent.
|
||||||
|
defp preserve_active_tab(restored, %{active_tab: nil}), do: restored
|
||||||
|
|
||||||
|
defp preserve_active_tab(restored, %{active_tab: {type, id}} = previous) do
|
||||||
|
intent =
|
||||||
|
case Enum.find(previous.tabs, &(&1.type == type and &1.id == id)) do
|
||||||
|
%{is_transient: true} -> :preview
|
||||||
|
_ -> :pin
|
||||||
|
end
|
||||||
|
|
||||||
|
Workbench.open_tab(restored, type, id, intent)
|
||||||
|
end
|
||||||
|
|
||||||
defp current_project_id(socket), do: (socket.assigns[:projects] || %{})[:active_project_id]
|
defp current_project_id(socket), do: (socket.assigns[:projects] || %{})[:active_project_id]
|
||||||
|
|
||||||
# Register this shell with the deep-link router and drain any links queued
|
# Register this shell with the deep-link router and drain any links queued
|
||||||
|
|||||||
@@ -271,9 +271,13 @@ rule ExecuteTransform {
|
|||||||
-- project_id and no active project the import is refused with a warning.
|
-- project_id and no active project the import is refused with a warning.
|
||||||
|
|
||||||
@guarantee BlogmarkColdStartDelivery
|
@guarantee BlogmarkColdStartDelivery
|
||||||
-- A deep link that arrives before the shell is connected (e.g. the
|
-- A deep link that arrives before the shell is ready (e.g. the
|
||||||
-- bookmarklet launching the app) is queued and replayed once a shell
|
-- bookmarklet launching the app) is queued and replayed only after the
|
||||||
-- attaches, so launching via a bookmarklet still creates the post.
|
-- client has finished initialising and rehydrating its stored
|
||||||
|
-- workbench session, so the post is created and the editor it opens is
|
||||||
|
-- not overwritten by the session restore. A session restore arriving
|
||||||
|
-- after a deep link (e.g. when the link switched projects) preserves
|
||||||
|
-- the newly opened editor tab as the active tab.
|
||||||
|
|
||||||
@guarantee TransformTrigger
|
@guarantee TransformTrigger
|
||||||
-- Transform scripts are triggered automatically by blogmark import.
|
-- Transform scripts are triggered automatically by blogmark import.
|
||||||
|
|||||||
@@ -960,6 +960,73 @@ defmodule BDS.Desktop.ShellLiveTest do
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "cold-start deep links replay only after the client signals shell_ready", %{
|
||||||
|
project: project
|
||||||
|
} do
|
||||||
|
start_supervised!({BDS.Desktop.DeepLink, []})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||||
|
|
||||||
|
url =
|
||||||
|
"bds2://new-post?title=" <>
|
||||||
|
URI.encode_www_form("Cold Start Post") <>
|
||||||
|
"&url=" <> URI.encode_www_form("https://example.com/cold")
|
||||||
|
|
||||||
|
send(BDS.Desktop.DeepLink, {:open_url, String.to_charlist(url)})
|
||||||
|
|
||||||
|
# The link stays queued while the client is still rehydrating.
|
||||||
|
_html = render(view)
|
||||||
|
refute Repo.get_by(Post, title: "Cold Start Post")
|
||||||
|
|
||||||
|
# The client restores its stored session, then signals readiness.
|
||||||
|
session_payload =
|
||||||
|
Workbench.new()
|
||||||
|
|> Workbench.open_tab(:post, "stored-post", :pin)
|
||||||
|
|> Session.serialize()
|
||||||
|
|
||||||
|
_html = render_hook(view, "restore_workbench_session", %{"session" => session_payload})
|
||||||
|
_html = render_hook(view, "shell_ready", %{})
|
||||||
|
html = render(view)
|
||||||
|
|
||||||
|
created_post = Repo.get_by!(Post, title: "Cold Start Post")
|
||||||
|
assert created_post.project_id == project.id
|
||||||
|
|
||||||
|
# The blogmark post is open and active; the restored tab survived.
|
||||||
|
assert html =~ ~s(data-tab-id="#{created_post.id}")
|
||||||
|
assert html =~ ~s(data-tab-id="stored-post")
|
||||||
|
|
||||||
|
assert :sys.get_state(view.pid).socket.assigns.workbench.active_tab ==
|
||||||
|
{:post, created_post.id}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "workbench session restore preserves a blogmark tab opened before the restore arrives" do
|
||||||
|
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||||
|
|
||||||
|
url =
|
||||||
|
"bds2://new-post?title=" <>
|
||||||
|
URI.encode_www_form("Survives Restore") <>
|
||||||
|
"&url=" <> URI.encode_www_form("https://example.com/survives")
|
||||||
|
|
||||||
|
send(view.pid, {:blogmark_deep_link, url})
|
||||||
|
_html = render(view)
|
||||||
|
created_post = Repo.get_by!(Post, title: "Survives Restore")
|
||||||
|
|
||||||
|
# A late session restore (e.g. after the blogmark switched projects) must
|
||||||
|
# not discard the editor tab the blogmark just opened.
|
||||||
|
session_payload =
|
||||||
|
Workbench.new()
|
||||||
|
|> Workbench.open_tab(:post, "stored-post", :pin)
|
||||||
|
|> Session.serialize()
|
||||||
|
|
||||||
|
html = render_hook(view, "restore_workbench_session", %{"session" => session_payload})
|
||||||
|
|
||||||
|
assert html =~ ~s(data-tab-id="#{created_post.id}")
|
||||||
|
assert html =~ ~s(data-tab-id="stored-post")
|
||||||
|
|
||||||
|
assert :sys.get_state(view.pid).socket.assigns.workbench.active_tab ==
|
||||||
|
{:post, created_post.id}
|
||||||
|
end
|
||||||
|
|
||||||
test "settings sidebar selections expose a scroll target for the preferences editor" do
|
test "settings sidebar selections expose a scroll target for the preferences editor" do
|
||||||
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user