easy_flow 0.4.8 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/easy_flow/manage/draws_canvas.rb +1 -1
- data/app/models/easy_flow/canvas.rb +3 -2
- data/lib/easy_flow/host.rb +5 -1
- data/lib/easy_flow/version.rb +1 -1
- data/the_local/agents/easy_flow-develop.md +10 -7
- data/the_local/agents/easy_flow-info.md +6 -4
- data/the_local/agents/easy_flow-install.md +6 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 310df5972d6ca11a6862e8c101b79f8802adbe620ee90e3c8764cda70feb9492
|
|
4
|
+
data.tar.gz: c43a02f417356eb7bf31e2e53fa220a4d32b7fefed055ed031dda114eccec951
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82e5b5eede06952c31b553577668d70499b828e576f5acc2e96964a30f8c897c6762d8e450674d5774d2c54034c0309019cf68138ddc45d9de48b165659bfe29
|
|
7
|
+
data.tar.gz: 0ad147aae3a60c96b225122d43d7f73e570c275b101b7c74db0bf00389ac01e927026ae5428925c3f9f8887d88a14f1266d82cd5299972b4f53dba7b75e32f9c
|
|
@@ -6,7 +6,7 @@ module EasyFlow
|
|
|
6
6
|
private
|
|
7
7
|
|
|
8
8
|
def canvas_payload(flow)
|
|
9
|
-
Canvas.new(canvas_document(flow)).to_h
|
|
9
|
+
Canvas.new(canvas_document(flow), host: flow_host).to_h
|
|
10
10
|
.merge("undoable" => flow.edit_history.undoable?, "redoable" => flow.edit_history.redoable?,
|
|
11
11
|
"changes" => listed_changes(flow), "flow" => flow_details(flow))
|
|
12
12
|
end
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
module EasyFlow
|
|
2
2
|
class Canvas
|
|
3
|
-
def initialize(document, registry: EasyFlow.registry)
|
|
3
|
+
def initialize(document, registry: EasyFlow.registry, host: nil)
|
|
4
4
|
@document = document
|
|
5
5
|
@registry = registry
|
|
6
|
+
@host = host
|
|
6
7
|
end
|
|
7
8
|
|
|
8
9
|
def to_h
|
|
@@ -81,7 +82,7 @@ module EasyFlow
|
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
def palette
|
|
84
|
-
@registry.step_types.reject(&:begins_here?).map do |step_type|
|
|
85
|
+
@registry.step_types.reject(&:begins_here?).select { |step_type| @host.nil? || step_type.ends_here? || @host.offers?(step_type.id) }.map do |step_type|
|
|
85
86
|
{ "type" => step_type.id.to_s, "label" => step_type.step_name,
|
|
86
87
|
"fields" => step_type.settings.fields.transform_keys(&:to_s).transform_values(&:to_s),
|
|
87
88
|
"labels" => step_type.settings.labels.transform_keys(&:to_s),
|
data/lib/easy_flow/host.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module EasyFlow
|
|
2
2
|
class Host
|
|
3
3
|
attr_reader :name
|
|
4
|
-
attr_writer :layout, :admin_layout
|
|
4
|
+
attr_writer :layout, :admin_layout, :offers
|
|
5
5
|
attr_accessor :admin_authentication_method, :visitor_authorization_method, :refusal_method
|
|
6
6
|
|
|
7
7
|
def initialize(name)
|
|
@@ -23,5 +23,9 @@ module EasyFlow
|
|
|
23
23
|
def set_up?
|
|
24
24
|
true
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
def offers?(step_type)
|
|
28
|
+
@offers.nil? || @offers.map(&:to_s).include?(step_type.to_s)
|
|
29
|
+
end
|
|
26
30
|
end
|
|
27
31
|
end
|
data/lib/easy_flow/version.rb
CHANGED
|
@@ -73,18 +73,19 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
A step whose type is not registered is neither shown nor run as that type.
|
|
76
|
-
4.
|
|
76
|
+
4. Ask the developer which hosts' admins should be able to add the type. A registered type is in a host's palette, the step types an admin can add on that host's canvas, only when the host names no list of offered step types or its list includes the type's id. A type that declares `ends_here` is in every host's palette, and a type that declares `begins_here` is in none. When a host that names a list should offer the new type, add the type's id to that host's list through `easy_flow-install`. Leaving a type off a host's list only keeps admins from adding it there, and a step of that type already in one of the host's flows is still drawn and run.
|
|
77
|
+
5. Use these words to declare the type. Each is called once at class level (or inside the `EasyFlow.step` block):
|
|
77
78
|
- `step_name "<label>"` — the name admins see on the canvas. Defaults to the id.
|
|
78
79
|
- `setting :name, type:, label:, options:, required:, limit:, check:, from:, outputs_of:` — a field the admin fills in on the canvas. `type` is one of `:string`, `:integer`, `:float`, `:boolean`, `:select`, `:multi_select`, `:previous_step`, `:from_step`, `:list`, or boot raises `EasyFlow::UnknownFieldType`. A `:select` or `:multi_select` must pass `options:`, or boot raises the same error. `options:` is either an array of strings, or a lambda taking no arguments that returns one; the lambda is called each time the canvas is opened and each time an admin saves the step's settings, so the options follow the app's data without a restart (`options: -> { Region.order(:name).pluck(:code) }`). A saved setting whose value is no longer among the options is refused the next time the admin saves that step. When the options come from the app's records, ask the developer which records, which column is stored as the value, and whether the list must differ by account or host, since the lambda is passed nothing and the same list is offered everywhere the type is used. A `:list` must take a block of `setting` calls describing one entry. `:previous_step` lets the admin pick an earlier step, and is always required. `outputs_of: :<setting>` offers the outputs of the step chosen in that setting, and `from: :<setting>` offers the values of the output chosen in that setting; either one makes the type `:from_step`. `limit:` is the most values a `:multi_select` takes. `check:` is a lambda given the value that returns an error message, or `nil` when the value is acceptable. `label:` defaults to the name humanized.
|
|
79
80
|
- `output :name, type:, label:, values:, from:` — a value the step records. `type` is one of `:string`, `:integer`, `:float`, `:boolean`, or boot raises `EasyFlow::UnknownOutputType`. `values:` is an array or a lambda taking the node, listing the values the output can take; the canvas offers these as the connections leaving the step, so a type that routes must declare them. `from: :<setting>` takes the values from the step chosen in that setting.
|
|
80
81
|
- `names_by :setting` or `names_by { |node| ... }` — what the step is called on the canvas, from a setting or computed.
|
|
81
82
|
- `awaits_input` — the visitor is shown this step and submits an answer to it.
|
|
82
|
-
- `waits_until { |node, state| ... }` — the run stops at this step until the block returns a truthy value. See step
|
|
83
|
+
- `waits_until { |node, state| ... }` — the run stops at this step until the block returns a truthy value. See step 8.
|
|
83
84
|
- `answer_check { |node, value| ... }` — checks a submitted answer before it is recorded. `value` is the submitted string, or `nil` when the input sent nothing. Return a message to refuse the answer, or `nil` to accept it. Without it every answer is accepted, including a blank one.
|
|
84
85
|
- `ends_here` / `begins_here` — marks the type as an end or a start of a flow.
|
|
85
86
|
- `displays_by { |node| ... }` — builds the object handed to the step's partial as the local `step`. Without it the partial receives the node itself.
|
|
86
87
|
- `drawn_by "<partial>"` — the partial that draws this type for a visitor. Without it the host's default drawing is used, which expects `step.id`, `step.text` and `step.choices`, so a type with its own display shape needs its own partial.
|
|
87
|
-
|
|
88
|
+
6. For a type that computes or routes, define instance methods on the class (or `process { |node, state| ... }` / `route { |node, state| ... }` in the block form):
|
|
88
89
|
|
|
89
90
|
```ruby
|
|
90
91
|
def process(node, state)
|
|
@@ -101,7 +102,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
101
102
|
- `process` returns the value recorded under this step's id. It runs as soon as a visitor reaches the step, before the next step is shown.
|
|
102
103
|
- A type that declares more than one `output` returns a hash from `process`, keyed by each output's name as a string. A later compare step reads the output the admin picks from that hash.
|
|
103
104
|
- `route` returns the value that picks the connection to follow; it is compared as a string with the value each leaving connection is labelled with, so `false` follows the connection labelled `false`. Returning `nil` follows the first connection. A route that returns `true` or `false` declares `output :result, type: :boolean, values: [true, false]`.
|
|
104
|
-
|
|
105
|
+
7. For a type that awaits input, write the partial named in `drawn_by`, for example `app/views/flow_steps/_rating.html.erb`. It receives the display object as `step`. It renders only the input, since the page supplies the form, the Next button and the Back button. The input must be named `answers[<step id>]`, or the answer is not recorded:
|
|
105
106
|
|
|
106
107
|
```erb
|
|
107
108
|
<%= label_tag "answers[#{step.id}]", step.text %>
|
|
@@ -118,7 +119,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
118
119
|
setting :required, type: :boolean
|
|
119
120
|
answer_check { |node, value| "Fill this in to go on." if node.config["required"] && value.blank? }
|
|
120
121
|
```
|
|
121
|
-
|
|
122
|
+
8. For a type that waits, declare `waits_until` with a block that says whether what the step waits for has happened:
|
|
122
123
|
|
|
123
124
|
```ruby
|
|
124
125
|
module FlowSteps
|
|
@@ -142,7 +143,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
142
143
|
- The page does not reload itself. Ask the developer how the run should move on when what it waits for happens:
|
|
143
144
|
- The visitor reloads the page. This needs nothing more, and works whether or not the flow keeps a stored run.
|
|
144
145
|
- The app calls `run.advance` where the event is handled, such as a webhook or a job. See "Read a run and its answers". This needs a stored run, so it only applies to a flow the admin set to save each step.
|
|
145
|
-
|
|
146
|
+
9. Restart the server, open a flow on the canvas of each host that should offer the type, and check the type is in the palette, its settings show, and a preview walks through it. On a host that names a list of offered step types without the type's id, check the type is not in the palette.
|
|
146
147
|
|
|
147
148
|
### Serve a host's flows from the app's own controller
|
|
148
149
|
|
|
@@ -208,6 +209,8 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
208
209
|
- A step type's id comes from its class name or the id passed to `EasyFlow.step`, and it is stored in flow documents, so renaming the class or id breaks every flow that uses it.
|
|
209
210
|
- Never give a step type one of the built-in ids: `start`, `terminal`, `question`, `condition`, `switch`, `compare`.
|
|
210
211
|
- Register class-based step types inside `to_prepare`. A type registered anywhere else is lost on code reload in development.
|
|
212
|
+
- Registering a type does not put it in the palette of a host that names a list of offered step types without the type's id. Which step types a host offers is set through `easy_flow-install`, not here.
|
|
213
|
+
- A type that declares `ends_here` is in every host's palette, and a type that declares `begins_here` is in no host's palette.
|
|
211
214
|
- An `options:` lambda is passed nothing, and one list is offered on every host's canvas, so it cannot narrow the options by admin, account or host.
|
|
212
215
|
- A type that routes declares the values its output takes, or the canvas offers no connections to label.
|
|
213
216
|
- Always read a run against `run.pinned_definition`, never the flow's live version, since a run keeps the version it started on after a new one is published.
|
|
@@ -218,4 +221,4 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
218
221
|
- A type that waits never also declares `awaits_input`.
|
|
219
222
|
- `run.advance` only moves a stored run, and never finishes it; the visitor's next page load does.
|
|
220
223
|
- A `FlowsController` subclass needs all four named routes for its prefix; a missing one raises when the visitor is linked or redirected to it.
|
|
221
|
-
- The engine installs, mounts and configures hosts, layouts, the default drawing and checks through `easy_flow-install`, not here.
|
|
224
|
+
- The engine installs, mounts and configures hosts, the step types each host offers, layouts, the default drawing and checks through `easy_flow-install`, not here.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: easy_flow-info
|
|
3
|
-
description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, hosts, runs, the built-in step types including questions that can require an answer and branching on an answer or comparing a number, step types the host app registers, the checks they make on an answer, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data.
|
|
3
|
+
description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, hosts and the step types each offers its admins, runs, the built-in step types including questions that can require an answer and branching on an answer or comparing a number, step types the host app registers, the checks they make on an answer, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data.
|
|
4
4
|
tools: Read
|
|
5
5
|
scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
|
|
6
6
|
---
|
|
@@ -17,12 +17,12 @@ Reach for it when an app needs a questionnaire, an intake form, or any decision
|
|
|
17
17
|
|
|
18
18
|
easy_flow declares no commands of its own for this local. Its surface is split between the other two:
|
|
19
19
|
|
|
20
|
-
- **easy_flow-install** owns putting the engine into an app: its migrations, mounting it, choosing the controller it inherits from, naming hosts, choosing the default step drawing, the flow checks, and the admin pages.
|
|
20
|
+
- **easy_flow-install** owns putting the engine into an app: its migrations, mounting it, choosing the controller it inherits from, naming hosts and the step types each one offers, choosing the default step drawing, the flow checks, and the admin pages.
|
|
21
21
|
- **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait, moving a run on once what it waits for has happened, serving a host's flows from the app's own controllers and routes, and reading a visitor's run and answers.
|
|
22
22
|
|
|
23
23
|
## How to use it
|
|
24
24
|
|
|
25
|
-
- To get easy_flow running in an app, or to change how it is configured, use **easy_flow-install**.
|
|
25
|
+
- To get easy_flow running in an app, or to change how it is configured, including which step types a host's admins can add, use **easy_flow-install**.
|
|
26
26
|
- To add a step type, give a step type its own rule for refusing an answer, hold a run until something outside the flow has happened, put a flow on the app's own pages, or act on what a visitor answered, use **easy_flow-develop**.
|
|
27
27
|
- To branch a flow on an answer or on a number the visitor gave, no code is needed: an admin places one of the built-in branching steps on the canvas.
|
|
28
28
|
- To make a visitor answer a question before going on, no code is needed: an admin marks that question step as required on the canvas.
|
|
@@ -48,7 +48,9 @@ easy_flow declares no commands of its own for this local. Its surface is split b
|
|
|
48
48
|
- **Compare** — a built-in branching step that reads an earlier step's answer as a number and checks it against an amount by more than, less than, at least or at most, then follows the true or the false connection. When the earlier step recorded several outputs, the admin picks which one. An answer that is missing or is not a number decides false.
|
|
49
49
|
- **Waiting step** — a step whose type carries a rule saying whether what it waits for has happened, such as a payment clearing or a document being signed. A run that reaches it stops there, and the visitor sees "Waiting for" followed by the step's name, with no form to submit. Once the rule says it has happened, the run moves past the step the next time the visitor's page is loaded or the app moves the run on, and the step is recorded as `true`.
|
|
50
50
|
- **Registry** — the list of step types the app has registered, alongside the built-in ones. A step whose type is not registered is not shown or run as that type, and its answers are not checked.
|
|
51
|
-
- **Host** — a named part of the app that owns a set of flows. A host sets the visitor layout and the admin layout, how admins are authenticated, how visitors are authorized,
|
|
51
|
+
- **Host** — a named part of the app that owns a set of flows. A host sets the visitor layout and the admin layout, how admins are authenticated, how visitors are authorized, how a refusal is answered, and optionally which step types it offers. Flows are always looked up through a host, so one host never sees another's flows.
|
|
52
|
+
- **Offered step types** — the list of step types a host names for its admins to add. A host that names no list offers every registered step type. The list only narrows the palette.
|
|
53
|
+
- **Palette** — the step types an admin can add on a host's canvas. It never holds the start step, always holds the end step, and otherwise holds the step types the host offers. A step already in a flow whose type the host does not offer is still drawn and run.
|
|
52
54
|
- **Run** — one visitor's pass through a flow. A run is pinned to the version that was live when it started, so publishing a new version does not change a run already under way. It records each answer by step id, and going back discards the last answer on the path.
|
|
53
55
|
- **Answers** — the recorded state of a run, keyed by step id. The next step is always worked out from these answers and the connections in the pinned version.
|
|
54
56
|
- **Refused answer** — an answer the step's answer check turned down. Nothing is recorded for that step, and the visitor is shown the same step again with the check's message. This works the same whether the flow keeps a stored run or carries its answers in the page.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: easy_flow-install
|
|
3
|
-
description: Use to hook easy_flow into a project — copying and running its migrations, mounting the engine for each host, setting the controller it inherits from, declaring hosts with their layouts and
|
|
3
|
+
description: Use to hook easy_flow into a project — copying and running its migrations, mounting the engine for each host, setting the controller it inherits from, declaring hosts with their layouts, access methods and the step types each offers, choosing the default step drawing, turning on optional checks, and reaching the admin pages.
|
|
4
4
|
tools: Bash, Read, Edit
|
|
5
5
|
scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
|
|
6
6
|
---
|
|
@@ -16,7 +16,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
16
16
|
- `bin/rails easy_flow:install:migrations` — copies the engine's migrations into the host's `db/migrate`, creating the flow, version and run tables.
|
|
17
17
|
- `mount EasyFlow::Engine` — the route that serves one host's visitor pages and admin pages under a path, with the host named in `defaults: { easy_flow_host: "<host>" }`.
|
|
18
18
|
- `EasyFlow.base_controller=` — the name, as a string, of the host controller every engine controller inherits from. Defaults to `"ActionController::Base"`.
|
|
19
|
-
- `EasyFlow.host` — declares a named host with its visitor layout, admin layout, admin authentication method, visitor authorization method and
|
|
19
|
+
- `EasyFlow.host` — declares a named host with its visitor layout, admin layout, admin authentication method, visitor authorization method, refusal method, and the step types its admins can add on the canvas.
|
|
20
20
|
- `EasyFlow.draws_with` — the partial that draws a visitor's step when the step's type names none. Defaults to the engine's own `easy_flow/steps/choosing`.
|
|
21
21
|
- `EasyFlow.check` — turns on an optional flow check: `:unrouted_value`, `:unfollowed_path` or `:dead_end`.
|
|
22
22
|
- `/manage/flows` — the admin pages, under each mount path, where flows are listed, created, drawn on the canvas, previewed and published.
|
|
@@ -42,6 +42,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
42
42
|
host.admin_authentication_method = :authenticate_admin!
|
|
43
43
|
host.visitor_authorization_method = :easy_flow_visitor_permitted?
|
|
44
44
|
host.refusal_method = :refuse_flow
|
|
45
|
+
host.offers = %i[question condition switch compare]
|
|
45
46
|
end
|
|
46
47
|
```
|
|
47
48
|
|
|
@@ -50,6 +51,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
50
51
|
- `admin_authentication_method` — a method on the base controller, called with no arguments before every admin page. With none set, the admin pages are open to anyone.
|
|
51
52
|
- `visitor_authorization_method` — a method on the base controller, called with the flow, returning true when the visitor may run it. With none set, every visitor is refused.
|
|
52
53
|
- `refusal_method` — a method on the base controller, called with the refusal error when a visitor is refused or a flow is unpublished or withdrawn. With none set, the response is `404 Not Found`.
|
|
54
|
+
- `offers` — the step types this host's admins can add from the canvas palette, as a list of step type names. With none set, every registered step type is offered. The engine's own names are `question`, `condition`, `switch` and `compare`, A step type the app declares is named by the id passed to `EasyFlow.step`, or after its class when it is a step class, so `Steps::Notify` is `notify`. The End step is offered whether it is listed or not, and the Start step is never offered. Ask the developer which step types each host should offer.
|
|
53
55
|
|
|
54
56
|
Each method named here must exist on the base controller. Ask the developer to point at it or write it. Do not invent its logic.
|
|
55
57
|
7. Mount the engine in `config/routes.rb`, once per host. The host name in `defaults` must match a name declared in step 6. When there is more than one mount, give each an `as:` name:
|
|
@@ -74,5 +76,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
74
76
|
- After install, check that `<mount path>/manage/flows` shows the flow list and that a new flow opens on the canvas. If the canvas is blank, check that the admin layout calls `yield :head`.
|
|
75
77
|
- After publishing a flow, check that `<mount path>/<slug>` shows it to a visitor who passes the host's visitor authorization method.
|
|
76
78
|
- After upgrading easy_flow, run `bin/rails easy_flow:install:migrations` again and then `bin/rails db:migrate`. Only migrations the app does not already have are copied.
|
|
79
|
+
- After setting a host's `offers`, check that the canvas palette on that host's `<mount path>/manage/flows` lists only those step types and End.
|
|
80
|
+
- Taking a step type off a host's `offers` removes it from the palette only. Steps of that type already in the host's flows stay in them and keep running.
|
|
77
81
|
- The initializer runs once at boot, so a change to it needs a server restart.
|
|
78
82
|
- Declaring step types, serving a host's flows from the app's own controllers and routes, and reading runs and answers are out of scope here. They belong to the `easy_flow-develop` local.
|