Module: Plutonium::Wizard::Resume
- Defined in:
- lib/plutonium/wizard/resume.rb
Overview
Builds the "continue where you left off" listing (§4.5): for every
in-progress Session row owned by a user (optionally narrowed to a tenant
scope), an enriched Entry carrying the wizard's label/icon, the current
step (+ its label), updated_at, and a resolved resume_url.
A host renders this on a dashboard:
Plutonium::Wizard.in_progress_for(view_context)
Resume URLs are built in the CURRENT portal (the one whose view_context is
passed), so a run is only ever linked from the portal it belongs to:
- A
register_wizard(portal/public) wizard draws a NAMED route carrying awizard_classroute default; we find it and build the URL from its helper, threading the tenant scope segment and (for tokened runs) the:token. - A
wizard-macro (resource-mounted) ANCHORED wizard's member URL is built by the sameresource_url_for(record, wizard:, step:)machinery the launch button uses — portal- and scope-correct by construction — from the row's anchor + the registering definition's wizard name.
When a row's mount can't be resolved in this portal (e.g. a non-anchored
resource-mounted wizard, whose resource identity isn't on the row, or a wizard
not mounted here), the entry is returned with resume_url: nil and a
resume_unresolved_reason, rather than guessing or raising.
Defined Under Namespace
Class Method Summary collapse
-
.entries_for(view_context, anchor: nil, wizard: nil) ⇒ Array<Entry>
In-progress entries for the run owner and tenant scope derived from the current portal's
view_context(the same object interactions take). -
.entry_for(row, view_context) ⇒ Entry?
Nil when the wizard class can't be loaded.
- .resolve_step(wizard_class, key) ⇒ Object
Class Method Details
.entries_for(view_context, anchor: nil, wizard: nil) ⇒ Array<Entry>
In-progress entries for the run owner and tenant scope derived from the
current portal's view_context (the same object interactions take). A run
belongs to exactly one portal context, so the scope MATCHES it: a scoped
portal narrows to its tenant; a non-scoped portal narrows to runs with no
scope (never another portal's entity-scoped runs). Resume URLs are built
through that same view_context, so they land in THIS portal. Newest first.
Optional +anchor:+/+wizard:+ filters narrow IN THE QUERY (before enrichment)
so discarded rows are never URL-resolved or anchor-loaded — cheaper than
filtering the returned array. Both compose; the wizard + anchor pair is
index-covered by [:wizard, :anchor_type, :anchor_id, :status].
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/plutonium/wizard/resume.rb', line 61 def entries_for(view_context, anchor: nil, wizard: nil) controller = view_context.controller owner = controller.helpers.current_user # A guest has no owner-tracked runs — anonymous runs are session-keyed and # ownerless (§4.5). The public surface stubs `current_user` to "Guest", so # bail rather than query `where(owner: "Guest")` (a non-record). And never # normalize "Guest" to nil: `where(owner: nil)` would match EVERY guest's # ownerless run — a cross-guest leak. return [] unless owner.present? && owner != "Guest" # `current_scoped_entity` is a helper_method — read it off the view context. scope = controller.scoped_to_entity? ? view_context.current_scoped_entity : nil # The portal pins the listing: a run is only shown by the portal it was # launched in. `scope` still isolates the tenant WITHIN a scoped portal — # `engine` alone can't (one engine serves every tenant via path scoping). engine = view_context.current_engine.name relation = Session.status_in_progress.where(owner: owner, engine: engine, scope: scope) relation = relation.where(anchor: anchor) if anchor relation = relation.where(wizard: wizard.name) if wizard relation .order(updated_at: :desc) .filter_map { |row| entry_for(row, view_context) } end |
.entry_for(row, view_context) ⇒ Entry?
Returns nil when the wizard class can't be loaded.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/plutonium/wizard/resume.rb', line 88 def entry_for(row, view_context) wizard_class = row.wizard.to_s.safe_constantize return nil unless wizard_class step = resolve_step(wizard_class, row.current_step) resolved = ResumeUrl.new(row, wizard_class, view_context).resolve Entry.new( wizard_class: wizard_class, label: wizard_class.label, icon: wizard_class.icon, current_step: row.current_step, current_step_label: step&.label, updated_at: row.updated_at, resume_url: resolved[:url], resume_unresolved_reason: resolved[:reason], session: row ) end |
.resolve_step(wizard_class, key) ⇒ Object
108 109 110 111 112 |
# File 'lib/plutonium/wizard/resume.rb', line 108 def resolve_step(wizard_class, key) return nil if key.blank? wizard_class.steps.find { |s| s.key.to_s == key.to_s } end |