alembic 0.1.0 → 0.3.0
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/README.md +36 -22
- data/app/assets/builds/alembic/page_builder.css +1 -1
- data/app/assets/builds/alembic/page_builder.js +3 -3
- data/app/controllers/alembic/application_controller.rb +1 -16
- data/app/controllers/alembic/flows_controller.rb +6 -90
- data/app/controllers/alembic/manage/base_controller.rb +2 -0
- data/app/controllers/alembic/manage/flows_controller.rb +12 -44
- data/app/controllers/alembic/manage/pages_controller.rb +8 -1
- data/app/controllers/alembic/manage/previews_controller.rb +4 -19
- data/app/controllers/alembic/pages_controller.rb +19 -0
- data/app/controllers/concerns/alembic/summarizes.rb +59 -0
- data/app/helpers/alembic/application_helper.rb +2 -2
- data/app/helpers/alembic/pages_helper.rb +40 -0
- data/app/helpers/alembic/result_blocks_helper.rb +45 -0
- data/app/models/alembic/flow/definition_summary.rb +10 -0
- data/app/models/alembic/flow/run_summary.rb +10 -0
- data/app/models/alembic/flow/summaries.rb +44 -5
- data/app/models/alembic/flow/summary_version.rb +1 -1
- data/app/models/alembic/outputs/band.rb +1 -1
- data/app/models/alembic/outputs/grouped.rb +1 -1
- data/app/models/alembic/outputs/lowest.rb +5 -3
- data/app/models/alembic/outputs/percentage.rb +1 -1
- data/app/models/alembic/outputs/weighted_sum.rb +1 -1
- data/app/models/alembic/page/drawing.rb +17 -0
- data/app/models/alembic/page/options.rb +53 -0
- data/app/models/alembic/page/version.rb +13 -0
- data/app/models/alembic/page.rb +32 -0
- data/app/models/alembic/result_blocks.rb +29 -0
- data/app/models/alembic/summary/report.rb +1 -1
- data/app/models/alembic/summary/result.rb +1 -1
- data/app/views/alembic/blocks/_answers.html.erb +11 -0
- data/app/views/alembic/blocks/_band.html.erb +6 -0
- data/app/views/alembic/blocks/_categories.html.erb +11 -0
- data/app/views/alembic/blocks/_lead.html.erb +15 -0
- data/app/views/alembic/blocks/_score.html.erb +7 -0
- data/app/views/alembic/blocks/_weakest.html.erb +12 -0
- data/app/views/alembic/flows/complete.html.erb +12 -6
- data/app/views/alembic/flows/show.html.erb +6 -6
- data/app/views/alembic/flows/summary_page.html.erb +5 -0
- data/app/views/alembic/manage/flows/edit.html.erb +16 -10
- data/app/views/alembic/manage/pages/_block_content.html.erb +1 -1
- data/app/views/alembic/manage/pages/index.html.erb +4 -1
- data/app/views/alembic/manage/pages/show.html.erb +7 -1
- data/app/views/alembic/pages/show.html.erb +5 -0
- data/config/routes.rb +8 -19
- data/db/migrate/20260825224538_remove_published_version_from_alembic_diagnostics.rb +21 -1
- data/db/migrate/20260922120000_add_slug_to_alembic_pages.rb +6 -0
- data/db/migrate/20260922130000_create_alembic_page_versions.rb +16 -0
- data/db/migrate/20260924220000_move_flows_onto_easy_flow.rb +166 -0
- data/db/migrate/20260930120000_add_summary_page_to_alembic_flow_definition_summaries.rb +6 -0
- data/lib/alembic/engine.rb +6 -11
- data/lib/alembic/version.rb +1 -1
- data/lib/alembic.rb +34 -6
- metadata +45 -71
- data/app/assets/builds/alembic/canvas.js +0 -1
- data/app/controllers/alembic/manage/canvas_controller.rb +0 -183
- data/app/controllers/alembic/manage/definitions_controller.rb +0 -15
- data/app/controllers/alembic/manage/versions_controller.rb +0 -22
- data/app/controllers/concerns/alembic/manage/draws_canvas.rb +0 -35
- data/app/javascript/alembic/canvas/Canvas.jsx +0 -197
- data/app/javascript/alembic/canvas/Connector.jsx +0 -30
- data/app/javascript/alembic/canvas/ConnectorLayer.jsx +0 -31
- data/app/javascript/alembic/canvas/Control.jsx +0 -42
- data/app/javascript/alembic/canvas/Inspector.jsx +0 -44
- data/app/javascript/alembic/canvas/Panel.jsx +0 -67
- data/app/javascript/alembic/canvas/Placeholder.jsx +0 -24
- data/app/javascript/alembic/canvas/Port.jsx +0 -16
- data/app/javascript/alembic/canvas/Records.jsx +0 -34
- data/app/javascript/alembic/canvas/StepCard.jsx +0 -57
- data/app/javascript/alembic/canvas/Toolbar.jsx +0 -19
- data/app/javascript/alembic/canvas/TypePicker.jsx +0 -21
- data/app/javascript/alembic/canvas/changes.js +0 -5
- data/app/javascript/alembic/canvas/choices.js +0 -4
- data/app/javascript/alembic/canvas/flow.js +0 -7
- data/app/javascript/alembic/canvas/flowSender.js +0 -22
- data/app/javascript/alembic/canvas/ids.js +0 -7
- data/app/javascript/alembic/canvas/rows.js +0 -2
- data/app/javascript/alembic/canvas/styles.js +0 -3
- data/app/javascript/alembic/canvas/useConnectors.js +0 -75
- data/app/javascript/alembic/canvas/useFlow.js +0 -17
- data/app/javascript/alembic/canvas.jsx +0 -13
- data/app/models/alembic/asked.rb +0 -3
- data/app/models/alembic/choice.rb +0 -7
- data/app/models/alembic/flow/admission.rb +0 -19
- data/app/models/alembic/flow/canvas.rb +0 -167
- data/app/models/alembic/flow/change.rb +0 -18
- data/app/models/alembic/flow/condition.rb +0 -24
- data/app/models/alembic/flow/definition.rb +0 -132
- data/app/models/alembic/flow/digest.rb +0 -116
- data/app/models/alembic/flow/document.rb +0 -131
- data/app/models/alembic/flow/drawing.rb +0 -15
- data/app/models/alembic/flow/edge.rb +0 -9
- data/app/models/alembic/flow/edit_history.rb +0 -75
- data/app/models/alembic/flow/layout.rb +0 -88
- data/app/models/alembic/flow/name.rb +0 -15
- data/app/models/alembic/flow/node.rb +0 -5
- data/app/models/alembic/flow/output.rb +0 -23
- data/app/models/alembic/flow/progress/kept.rb +0 -38
- data/app/models/alembic/flow/progress/loose.rb +0 -43
- data/app/models/alembic/flow/progress.rb +0 -11
- data/app/models/alembic/flow/registry.rb +0 -25
- data/app/models/alembic/flow/run.rb +0 -54
- data/app/models/alembic/flow/runner.rb +0 -65
- data/app/models/alembic/flow/settings.rb +0 -80
- data/app/models/alembic/flow/start.rb +0 -13
- data/app/models/alembic/flow/step.rb +0 -42
- data/app/models/alembic/flow/step_type/declaration.rb +0 -118
- data/app/models/alembic/flow/step_type.rb +0 -69
- data/app/models/alembic/flow/switch.rb +0 -17
- data/app/models/alembic/flow/terminal.rb +0 -13
- data/app/models/alembic/flow/validator.rb +0 -171
- data/app/models/alembic/flow/version.rb +0 -26
- data/app/models/alembic/flow/violation.rb +0 -9
- data/app/models/alembic/flow.rb +0 -44
- data/app/models/alembic/runner.rb +0 -13
- data/app/models/alembic/steps/question.rb +0 -52
- data/app/views/alembic/flow/steps/_choosing.html.erb +0 -9
- data/app/views/alembic/flows/step.html.erb +0 -27
- data/app/views/alembic/manage/definitions/edit.html.erb +0 -13
- data/app/views/alembic/manage/flows/index.html.erb +0 -32
- data/app/views/alembic/manage/flows/show.html.erb +0 -26
- data/app/views/alembic/manage/versions/index.html.erb +0 -41
|
@@ -1,34 +1,14 @@
|
|
|
1
1
|
module Alembic
|
|
2
|
-
class FlowsController <
|
|
3
|
-
|
|
2
|
+
class FlowsController < EasyFlow::FlowsController
|
|
3
|
+
hosted_by FLOW_HOST
|
|
4
|
+
include Summarizes
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
@diagnostic = flow
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def start
|
|
10
|
-
redirect_to alembic.run_path(Flow::Run.start(flow))
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def step
|
|
14
|
-
@guide = Runner.new(running_definition)
|
|
15
|
-
@progress = progress
|
|
16
|
-
@guide.run(@progress)
|
|
17
|
-
@answers = @progress.recorded
|
|
18
|
-
@question = @guide.next_step(@answers)
|
|
19
|
-
@drawing = @guide.drawing_at(@answers)
|
|
20
|
-
return render :step if @question
|
|
21
|
-
|
|
22
|
-
render_completion
|
|
23
|
-
end
|
|
6
|
+
private
|
|
24
7
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
redirect_to alembic.run_path(run)
|
|
8
|
+
def run_location(run)
|
|
9
|
+
alembic.run_path(run)
|
|
28
10
|
end
|
|
29
11
|
|
|
30
|
-
private
|
|
31
|
-
|
|
32
12
|
def flow_start_path(slug)
|
|
33
13
|
alembic.flow_path(slug)
|
|
34
14
|
end
|
|
@@ -36,69 +16,5 @@ module Alembic
|
|
|
36
16
|
def flow_step_path(slug)
|
|
37
17
|
alembic.flow_step_path(slug)
|
|
38
18
|
end
|
|
39
|
-
|
|
40
|
-
def previewing?
|
|
41
|
-
false
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def step_form
|
|
45
|
-
return { url: alembic.run_path(run), method: :patch } if run
|
|
46
|
-
|
|
47
|
-
{ url: flow_step_path(@guide.slug), method: :get }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def carries_answers?
|
|
51
|
-
run.nil?
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def render_completion
|
|
55
|
-
@answered = @guide.state_on_path(@answers)
|
|
56
|
-
@progress.finish(@answered)
|
|
57
|
-
@outputs = @progress.summary_of(@answered.transform_keys(&:to_s))
|
|
58
|
-
render :complete
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def progress
|
|
62
|
-
return @progress ||= Flow::Progress.for(run.flow, run: run) if run
|
|
63
|
-
|
|
64
|
-
@progress ||= Flow::Progress.for(flow, answers: submitted_answers, definition: running_definition)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def running_definition
|
|
68
|
-
@running_definition ||= run ? run.pinned_definition : flowing_definition(flow)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def run
|
|
72
|
-
return unless params[:id]
|
|
73
|
-
|
|
74
|
-
@run ||= admitted_run
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def admitted_run
|
|
78
|
-
found = Flow::Run.find(params[:id])
|
|
79
|
-
|
|
80
|
-
Flow::Admission.of_run(found, permitted: permitted?(found.flow))
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def flow
|
|
84
|
-
@stored_flow ||= admit(Flow::Definition.find_by(slug: params[:slug]))
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def flowing_definition(diagnostic)
|
|
88
|
-
diagnostic.live_definition
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def submitted_answers
|
|
92
|
-
params.fetch(:answers, {}).permit(*@guide.steps.map(&:id)).to_h.symbolize_keys
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def record_submitted
|
|
96
|
-
id, value = params.fetch(:answers, {}).permit(*asked).to_h.first
|
|
97
|
-
progress.record(id, value)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def asked
|
|
101
|
-
Runner.new(run.pinned_definition).steps.map(&:id)
|
|
102
|
-
end
|
|
103
19
|
end
|
|
104
20
|
end
|
|
@@ -1,54 +1,22 @@
|
|
|
1
1
|
module Alembic
|
|
2
2
|
module Manage
|
|
3
|
-
class FlowsController <
|
|
4
|
-
|
|
5
|
-
def index
|
|
6
|
-
@diagnostics = ordered_diagnostics
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def create
|
|
10
|
-
@diagnostic = Flow::Definition.new(create_params)
|
|
11
|
-
|
|
12
|
-
if @diagnostic.save
|
|
13
|
-
redirect_to manage_flow_path(@diagnostic), notice: "Flow created."
|
|
14
|
-
else
|
|
15
|
-
@diagnostics = ordered_diagnostics
|
|
16
|
-
render :index, status: :unprocessable_entity
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def show
|
|
21
|
-
@diagnostic = Flow::Definition.find(params[:id])
|
|
22
|
-
@canvas = canvas_payload(@diagnostic)
|
|
23
|
-
end
|
|
24
|
-
|
|
3
|
+
class FlowsController < EasyFlow::Manage::FlowsController
|
|
4
|
+
hosted_by FLOW_HOST
|
|
25
5
|
def edit
|
|
26
|
-
|
|
6
|
+
super
|
|
7
|
+
summaries = Flow::Summaries.new(@flow)
|
|
8
|
+
@summary = summaries.text
|
|
9
|
+
@summary_page = summaries.summary_page
|
|
10
|
+
@published_pages = Page.where(id: Page::Version.live.select(:page_id)).order(:name)
|
|
27
11
|
end
|
|
28
12
|
|
|
29
13
|
def update
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def destroy
|
|
36
|
-
Flow::Definition.find(params[:id]).destroy!
|
|
37
|
-
redirect_to manage_flows_path, notice: "Flow removed."
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def ordered_diagnostics
|
|
43
|
-
Flow::Definition.order(:slug)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def create_params
|
|
47
|
-
params.require(:flow).permit(:slug, :kind)
|
|
48
|
-
end
|
|
14
|
+
details = params.require(:flow)
|
|
15
|
+
summaries = Flow::Summaries.new(flow_host.flows.find(params[:id]))
|
|
16
|
+
summaries.describe(details[:summary]) unless details[:summary].nil?
|
|
17
|
+
summaries.finish_on(Page.find_by(id: details[:summary_page_id])) unless details[:summary_page_id].nil?
|
|
49
18
|
|
|
50
|
-
|
|
51
|
-
params.require(:flow).permit(:title, :summary, :start_label, :persists)
|
|
19
|
+
super
|
|
52
20
|
end
|
|
53
21
|
end
|
|
54
22
|
end
|
|
@@ -20,6 +20,13 @@ module Alembic
|
|
|
20
20
|
redirect_to manage_page_path(page)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def publish
|
|
24
|
+
page = Page.find(params[:id])
|
|
25
|
+
page.publish
|
|
26
|
+
|
|
27
|
+
redirect_to manage_page_path(page)
|
|
28
|
+
end
|
|
29
|
+
|
|
23
30
|
private
|
|
24
31
|
|
|
25
32
|
def payload(page)
|
|
@@ -31,7 +38,7 @@ module Alembic
|
|
|
31
38
|
end
|
|
32
39
|
|
|
33
40
|
def page_params
|
|
34
|
-
params.require(:page).permit(:name)
|
|
41
|
+
params.require(:page).permit(:name, :slug)
|
|
35
42
|
end
|
|
36
43
|
end
|
|
37
44
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module Alembic
|
|
2
2
|
module Manage
|
|
3
|
-
class PreviewsController < ::
|
|
4
|
-
|
|
3
|
+
class PreviewsController < EasyFlow::Manage::PreviewsController
|
|
4
|
+
hosted_by FLOW_HOST
|
|
5
|
+
include Summarizes
|
|
5
6
|
|
|
6
7
|
def show
|
|
7
|
-
@
|
|
8
|
+
@flow = previewed
|
|
8
9
|
render template: "alembic/flows/show"
|
|
9
10
|
end
|
|
10
11
|
|
|
@@ -17,22 +18,6 @@ module Alembic
|
|
|
17
18
|
def flow_step_path(_slug)
|
|
18
19
|
alembic.step_manage_flow_preview_path(previewed)
|
|
19
20
|
end
|
|
20
|
-
|
|
21
|
-
def previewing?
|
|
22
|
-
true
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def flowing_definition(diagnostic)
|
|
26
|
-
diagnostic.document
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def previewed
|
|
30
|
-
@previewed ||= Flow::Definition.find(params[:flow_id])
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def admit(_diagnostic)
|
|
34
|
-
previewed
|
|
35
|
-
end
|
|
36
21
|
end
|
|
37
22
|
end
|
|
38
23
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
class PagesController < ApplicationController
|
|
3
|
+
helper PagesHelper
|
|
4
|
+
helper KsBlocks::LayoutHelper
|
|
5
|
+
|
|
6
|
+
def show
|
|
7
|
+
@page = shown_page
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def shown_page
|
|
13
|
+
page = Page.find_by(slug: params[:slug])
|
|
14
|
+
raise NotPublished if page.nil? || page.live_version.nil?
|
|
15
|
+
|
|
16
|
+
page
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
module Summarizes
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
layout -> { Alembic.layout }
|
|
7
|
+
helper ApplicationHelper
|
|
8
|
+
helper PagesHelper
|
|
9
|
+
helper ResultBlocksHelper
|
|
10
|
+
helper KsBlocks::LayoutHelper
|
|
11
|
+
helper_method :flow_summary, :first_step_path, :summary_values
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def flow_summary(flow)
|
|
17
|
+
Flow::Summaries.new(flow).text
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def first_step_path(slug)
|
|
21
|
+
flow_step_path(slug)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def start_run(flow)
|
|
25
|
+
super.tap { |run| Flow::Summaries.new(flow).pin(run) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def finished(answers, finished_run)
|
|
29
|
+
@outputs = outputs_of(answers.transform_keys(&:to_s))
|
|
30
|
+
Flow::Summaries.new(flow).pin(finished_run) if finished_run && run.nil?
|
|
31
|
+
@summary_page = Flow::Summaries.new(run&.flow || flow).summary_page
|
|
32
|
+
render template: @summary_page&.live_version ? "alembic/flows/summary_page" : "alembic/flows/complete"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def summary_values
|
|
36
|
+
@outputs.to_h { |output| [ output.id, output.value ] }
|
|
37
|
+
.merge("slug" => @guide.slug, "note" => result_note, "answers" => answers_given)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def answers_given
|
|
41
|
+
@answered.map { |step, value| [ @guide.question_text(step), @guide.choice_label(step, value) ] }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def result_note
|
|
45
|
+
finished_flow = run&.flow || flow
|
|
46
|
+
return Alembic.lead_note.call(finished_flow.title, @outputs.to_h { |output| [ output.id, output.value ] }) if Alembic.lead_note
|
|
47
|
+
|
|
48
|
+
[ finished_flow.title, *@outputs.map { |output| "#{output.label}: #{helpers.alembic_output_lines(output.value).join(', ')}" } ]
|
|
49
|
+
.compact_blank.join(". ")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def outputs_of(state)
|
|
53
|
+
return Flow::Summaries.new(run.flow).of_run(run, state) if run
|
|
54
|
+
|
|
55
|
+
summaries = Flow::Summaries.new(flow)
|
|
56
|
+
summaries.any? ? summaries.of(state) : []
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -2,8 +2,8 @@ module Alembic
|
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
def alembic_output_lines(value)
|
|
4
4
|
case value
|
|
5
|
-
when Hash then value.map { |name, share| "#{name}: #{share}" }
|
|
6
|
-
when Array then value
|
|
5
|
+
when Hash then value.key?("name") ? [ value["name"] ] : value.map { |name, share| "#{name}: #{share}" }
|
|
6
|
+
when Array then value.map { |item| item.is_a?(Hash) ? item["name"] : item }
|
|
7
7
|
else [ value ]
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "ks_blocks/layout_helper"
|
|
2
|
+
|
|
3
|
+
module Alembic
|
|
4
|
+
module PagesHelper
|
|
5
|
+
UNDRAWABLE = "This block cannot be drawn until its fields are filled in.".freeze
|
|
6
|
+
|
|
7
|
+
def drawn_page(page, being_edited: false, values: {})
|
|
8
|
+
blocks = being_edited ? page.blocks : page.live_version&.blocks.to_a
|
|
9
|
+
drawn = blocks.to_h { |block| [ block["id"], drawn_block(block, values: values) ] }.compact
|
|
10
|
+
|
|
11
|
+
block_layout(blocks.select { |block| drawn.key?(block["id"]) }, kind: :pages) do |block|
|
|
12
|
+
drawn.fetch(block["id"])
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def drawn_block(block, values: {})
|
|
17
|
+
component = Page::Drawing.of(block["type"])
|
|
18
|
+
return unless component
|
|
19
|
+
|
|
20
|
+
options = Page::Options.for(block, values: values)
|
|
21
|
+
body = Page::Options.body_for(block)
|
|
22
|
+
body.nil? ? send(component, **options) : send(component, **options) { body }
|
|
23
|
+
rescue StandardError => undrawable
|
|
24
|
+
Rails.logger.error("Alembic could not draw the #{block['type']} block: #{undrawable.message}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def shown_block(block)
|
|
29
|
+
drawn_block(block) || undrawn_block(block)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def undrawn_block(block)
|
|
35
|
+
return UNDRAWABLE if Page::Drawing.of(block["type"])
|
|
36
|
+
|
|
37
|
+
KsBlocks.registry.block_types(kind: :pages).find { |type| type.key.to_s == block["type"] }&.name
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
module ResultBlocksHelper
|
|
3
|
+
def alembic_score_block(value: nil, caption: nil, kicker: "Your result")
|
|
4
|
+
render "alembic/blocks/score", value: value, caption: caption, kicker: kicker
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def alembic_band_block(value: nil, score: nil)
|
|
8
|
+
render "alembic/blocks/band", band: value.to_h, tone: alembic_tone(score)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def alembic_categories_block(value: nil, heading: "Where you stand, area by area")
|
|
12
|
+
render "alembic/blocks/categories", shares: value.to_h, heading: heading
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def alembic_weakest_block(value: nil, heading: "Your biggest blind spots", cost_label: "What it likely costs you:")
|
|
16
|
+
render "alembic/blocks/weakest", categories: Array(value), heading: heading, cost_label: cost_label
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def alembic_answers_block(value: nil, heading: "What you told us")
|
|
20
|
+
render "alembic/blocks/answers", answers: Array(value), heading: heading
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def alembic_lead_block(slug:, note: nil, heading: "The next step", blurb: nil, button: "Send", placeholder: "you@example.com")
|
|
24
|
+
render "alembic/blocks/lead", address: Alembic.lead_address.call(slug), slug: slug, note: note,
|
|
25
|
+
heading: heading, blurb: blurb, button: button, placeholder: placeholder
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def alembic_default_result(output, outputs = [])
|
|
29
|
+
case output.type
|
|
30
|
+
when "percentage" then alembic_score_block(value: output.value, caption: output.label)
|
|
31
|
+
when "band" then alembic_band_block(value: output.value, score: outputs.find { |other| other.type == "percentage" }&.value)
|
|
32
|
+
when "grouped" then alembic_categories_block(value: output.value)
|
|
33
|
+
when "lowest" then alembic_weakest_block(value: output.value)
|
|
34
|
+
else ui_stat_card(label: output.label, value: alembic_output_lines(output.value).join(" · "))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def alembic_tone(percentage)
|
|
39
|
+
return "bg-red-500" if percentage.to_i < 40
|
|
40
|
+
return "bg-amber-500" if percentage.to_i < 70
|
|
41
|
+
|
|
42
|
+
"bg-emerald-500"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
module Flow
|
|
3
|
+
class DefinitionSummary < ApplicationRecord
|
|
4
|
+
self.table_name = "alembic_flow_definition_summaries"
|
|
5
|
+
|
|
6
|
+
belongs_to :flow, class_name: "EasyFlow::Definition"
|
|
7
|
+
belongs_to :summary_page, class_name: "Alembic::Page", optional: true
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -10,12 +10,12 @@ module Alembic
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def current_version
|
|
13
|
-
|
|
13
|
+
versions.find_by(number: cursor)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def record(payload)
|
|
17
|
-
|
|
18
|
-
.tap { |version|
|
|
17
|
+
versions.create!(number: next_number, summary: payload)
|
|
18
|
+
.tap { |version| details.update!(summary_cursor: version.number) }
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def any?
|
|
@@ -26,18 +26,57 @@ module Alembic
|
|
|
26
26
|
Summary::Report.new(document).results(Summary::Run.new(state: state, steps: steps_by_id))
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def text
|
|
30
|
+
details.summary
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def describe(text)
|
|
34
|
+
details.update!(summary: text)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def summary_page
|
|
38
|
+
details.summary_page
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def finish_on(page)
|
|
42
|
+
details.update!(summary_page: page)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def pin(run)
|
|
46
|
+
RunSummary.create!(run: run, summary_version: current_version) if current_version
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def pinned_to(run)
|
|
50
|
+
RunSummary.find_by(run: run)&.summary_version
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def of_run(run, state)
|
|
54
|
+
pinned = pinned_to(run)&.summary
|
|
55
|
+
return [] if pinned.blank?
|
|
56
|
+
|
|
57
|
+
Summary::Report.new(pinned).results(Summary::Run.new(state: state, steps: run.pinned_steps))
|
|
58
|
+
end
|
|
59
|
+
|
|
29
60
|
private
|
|
30
61
|
|
|
62
|
+
def versions
|
|
63
|
+
SummaryVersion.where(flow: @flow)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def details
|
|
67
|
+
@details ||= DefinitionSummary.find_or_initialize_by(flow: @flow)
|
|
68
|
+
end
|
|
69
|
+
|
|
31
70
|
def steps_by_id
|
|
32
71
|
Array(@flow.definition.to_h["nodes"]).index_by { |node| node["id"] }
|
|
33
72
|
end
|
|
34
73
|
|
|
35
74
|
def cursor
|
|
36
|
-
|
|
75
|
+
details.summary_cursor || versions.maximum(:number)
|
|
37
76
|
end
|
|
38
77
|
|
|
39
78
|
def next_number
|
|
40
|
-
(
|
|
79
|
+
(versions.maximum(:number) || 0) + 1
|
|
41
80
|
end
|
|
42
81
|
end
|
|
43
82
|
end
|
|
@@ -3,7 +3,7 @@ module Alembic
|
|
|
3
3
|
class SummaryVersion < ApplicationRecord
|
|
4
4
|
self.table_name = "alembic_flow_summaries"
|
|
5
5
|
|
|
6
|
-
belongs_to :flow, class_name: "
|
|
6
|
+
belongs_to :flow, class_name: "EasyFlow::Definition"
|
|
7
7
|
|
|
8
8
|
validates :number, uniqueness: { scope: :flow_id }
|
|
9
9
|
|
|
@@ -15,7 +15,7 @@ module Alembic
|
|
|
15
15
|
def self.covering(config, number)
|
|
16
16
|
ordered = Array(config["bands"]).sort_by { |band| band["ceiling"] || Float::INFINITY }
|
|
17
17
|
|
|
18
|
-
ordered.find { |band| band["ceiling"].nil? || number < band["ceiling"] }&.
|
|
18
|
+
ordered.find { |band| band["ceiling"].nil? || number < band["ceiling"] }&.slice("name", "description")
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -4,7 +4,7 @@ module Alembic
|
|
|
4
4
|
def self.output_type
|
|
5
5
|
Summary::OutputType.define(:lowest) do
|
|
6
6
|
label "Weakest"
|
|
7
|
-
compute { |config, _run, so_far| Lowest.of(so_far[config["of"]], config["count"]) }
|
|
7
|
+
compute { |config, _run, so_far| Lowest.of(so_far[config["of"]], config["count"], config["copy"]) }
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -12,8 +12,10 @@ module Alembic
|
|
|
12
12
|
registry.register(output_type)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def self.of(shares, count)
|
|
16
|
-
shares.to_h.sort_by { |_name, share| share }.first(count.presence&.to_i || 1).map(&:first)
|
|
15
|
+
def self.of(shares, count, copy = nil)
|
|
16
|
+
weakest = shares.to_h.sort_by { |_name, share| share }.first(count.presence&.to_i || 1).map(&:first)
|
|
17
|
+
|
|
18
|
+
weakest.map { |name| { "name" => name, **copy.to_h.fetch(name, {}).slice("miss", "cost") } }
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
end
|
|
@@ -24,7 +24,7 @@ module Alembic
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def self.most(step)
|
|
27
|
-
Steps::Question.answers_of(step).filter_map { |option| option["weight"].to_i if option.is_a?(Hash) }.max.to_i
|
|
27
|
+
EasyFlow::Steps::Question.answers_of(step).filter_map { |option| option["weight"].to_i if option.is_a?(Hash) }.max.to_i
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -17,7 +17,7 @@ module Alembic
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def self.weight_of(step, value)
|
|
20
|
-
chosen = Steps::Question.answers_of(step).find { |option| option.is_a?(Hash) && option["value"] == value }
|
|
20
|
+
chosen = EasyFlow::Steps::Question.answers_of(step).find { |option| option.is_a?(Hash) && option["value"] == value }
|
|
21
21
|
|
|
22
22
|
chosen&.fetch("weight", nil).to_i
|
|
23
23
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
class Page < ApplicationRecord
|
|
3
|
+
module Drawing
|
|
4
|
+
def self.record(key, component)
|
|
5
|
+
components[key.to_sym] = component
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.of(key)
|
|
9
|
+
components[key.to_sym]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.components
|
|
13
|
+
@components ||= {}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Alembic
|
|
2
|
+
class Page < ApplicationRecord
|
|
3
|
+
module Options
|
|
4
|
+
def self.declare(key, options, body: nil)
|
|
5
|
+
declared[key.to_sym] = options
|
|
6
|
+
bodies[key.to_sym] = body
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.for(block, values: {})
|
|
10
|
+
named(filled(block).except(bodies[block["type"].to_sym]), declared.fetch(block["type"].to_sym, {}), values)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.body_for(block)
|
|
14
|
+
field = bodies[block["type"].to_sym]
|
|
15
|
+
|
|
16
|
+
filled(block)[field] if field
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.bodies
|
|
20
|
+
@bodies ||= {}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.declared
|
|
24
|
+
@declared ||= {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.filled(block)
|
|
28
|
+
block.fetch("content", {}).reject { |_key, value| value == "" }.symbolize_keys
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.named(filled, options, values)
|
|
32
|
+
options.each_with_object(filled) do |(option, spec), built|
|
|
33
|
+
spec.is_a?(Hash) ? fill(built, option, spec, values) : built[option] = spec
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.fill(built, option, spec, values)
|
|
38
|
+
value = handed(built, option, spec, values)
|
|
39
|
+
built[option] = value.nil? ? spec[:default] : value
|
|
40
|
+
built.delete(option) if built[option].nil?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.handed(built, option, spec, values)
|
|
44
|
+
return values[spec[:value]] if spec.key?(:value)
|
|
45
|
+
return values[built.delete(spec[:value_of]).to_s] if spec.key?(:value_of)
|
|
46
|
+
|
|
47
|
+
built.delete(spec.fetch(:from, option))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private_class_method :filled, :named, :fill, :handed
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|