Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,16 @@ body:has(#diagram-page[data-immersive="true"]) {
background-color: transparent !important;
}
}

/* Station journal rail.
When the docked journal is open, `.journal-open` is set on #diagram-page and
the page reserves the right 24rem (pr-96). The slide-in edit drawers + their
overlay are `fixed right-0`, so shift them left by the rail width (w-96 =
24rem) — node/pathway editing then opens *beside* the journal, not under it.
Two-class specificity beats the drawers' own `right-0`/`inset-0` utility. */
.journal-open .app-drawer {
right: 24rem;
}
.journal-open .app-drawer-overlay {
right: 24rem;
}
8 changes: 8 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ window.addEventListener("phx:scroll_to_error", (e) => {
})
})

// Scroll the focused journal entry into view within the rail (map → journal).
window.addEventListener("phx:journal_focus", (e) => {
requestAnimationFrame(() => {
const el = document.getElementById(`journal-entry-${e.detail.id}`)
if (el) el.scrollIntoView({ behavior: "smooth", block: "center" })
})
})

// connect if there are any LiveViews on the page
liveSocket.connect()

Expand Down
18 changes: 18 additions & 0 deletions assets/js/diagram_canvas_hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,24 @@ const DiagramCanvasHook = {
marker.setAttribute("stroke-width", `${OVERLAY_BASE.rectStroke / iconScale}`);
});

// Journal markers (pin markers + node/pathway "has an open entry" indicators)
// are drawn at full size in diagram space; counter-scale each about its center
// so it stays a fixed on-screen size as the diagram zooms, like node markers.
overlay.querySelectorAll("[data-journal-scale]").forEach((group) => {
const cx = parseFloat(group.getAttribute("data-center-x"));
const cy = parseFloat(group.getAttribute("data-center-y"));

if (!Number.isFinite(cx) || !Number.isFinite(cy)) {
return;
}

const k = 1 / iconScale;
group.setAttribute(
"transform",
`translate(${cx} ${cy}) scale(${k}) translate(${-cx} ${-cy})`,
);
});

overlay.querySelectorAll("[data-stop-label]").forEach((label) => {
const cx = parseFloat(label.getAttribute("data-center-x"));
const cy = parseFloat(label.getAttribute("data-center-y"));
Expand Down
35 changes: 35 additions & 0 deletions lib/gtfs_planner/gtfs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2282,6 +2282,41 @@ defmodule GtfsPlanner.Gtfs do
|> Repo.all()
end

@doc """
Fetch a single journal entry scoped to its (org, version), or nil. Used by the
desktop review surface to act on one entry.
"""
def get_journal_entry(organization_id, gtfs_version_id, id) do
Repo.get_by(JournalEntry,
id: id,
organization_id: organization_id,
gtfs_version_id: gtfs_version_id
)
end

@doc """
Close a journal entry — a desk/Studio action that stamps `closed_at` = now and
`closed_by` = the acting user. Closing changes an entry's review state; it never
hides the entry from the journal. Re-closing simply restamps. Distinct from the
companion sync path (`sync_journal_entries/2`), which ignores client closure
fields; this touches only the workflow fields and skips target re-validation.
"""
def close_journal_entry(%JournalEntry{} = entry, closed_by_user_id) do
entry
|> Ecto.Changeset.change(closed_at: DateTime.utc_now(), closed_by: closed_by_user_id)
|> Repo.update()
end

@doc """
Reopen a closed journal entry: clears `closed_at`/`closed_by` so it returns to the
open queue. No-op-safe on an already-open entry.
"""
def reopen_journal_entry(%JournalEntry{} = entry) do
entry
|> Ecto.Changeset.change(closed_at: nil, closed_by: nil)
|> Repo.update()
end

defp descendant_stop_ids_query(organization_id, gtfs_version_id, station_stop_id) do
direct_child_ids =
from(s in Stop,
Expand Down
4 changes: 2 additions & 2 deletions lib/gtfs_planner_web/components/core_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ defmodule GtfsPlannerWeb.CoreComponents do
<%!-- Overlay --%>
<div
class={[
"fixed inset-0 bg-black/30 z-40 transition-opacity duration-300",
"app-drawer-overlay fixed inset-0 bg-black/30 z-40 transition-opacity duration-300",
@open && "opacity-100",
!@open && "opacity-0 pointer-events-none"
]}
Expand All @@ -724,7 +724,7 @@ defmodule GtfsPlannerWeb.CoreComponents do
<aside
id={@id}
class={[
"fixed top-0 right-0 h-full w-screen min-w-[320px] bg-base-100 shadow-xl border-l border-base-200 z-50 transition-transform duration-300 overflow-x-hidden",
"app-drawer fixed top-0 right-0 h-full w-screen min-w-[320px] bg-base-100 shadow-xl border-l border-base-200 z-50 transition-transform duration-300 overflow-x-hidden",
@open && "translate-x-0",
!@open && "translate-x-full",
@class
Expand Down
Loading