DEV: Allow plugins to add wizard steps after specific steps (#9315)

DEV: Allow plugins to add wizard steps after specific steps (#9315)

diff --git a/app/assets/javascripts/wizard/components/wizard-step.js b/app/assets/javascripts/wizard/components/wizard-step.js
index 7884a27..dd36c58 100644
--- a/app/assets/javascripts/wizard/components/wizard-step.js
+++ b/app/assets/javascripts/wizard/components/wizard-step.js
@@ -61,6 +61,11 @@ export default Component.extend({
     return getUrl(`/images/wizard/${src}`);
   },
 
+  @discourseComputed("step.id")
+  bannerAndDescriptionClass(id) {
+    return `wizard-banner-and-description wizard-banner-and-description-${id}`;
+  },
+
   @observes("step.id")
   _stepChanged() {
     this.set("saving", false);
diff --git a/app/assets/javascripts/wizard/templates/components/wizard-step.hbs b/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
index 4f0686a..67f9b50 100644
--- a/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
+++ b/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
@@ -3,13 +3,15 @@
     <h1 class='wizard-step-title'>{{step.title}}</h1>
   {{/if}}
 
-  {{#if bannerImage}}
-    <img src={{bannerImage}} class="wizard-step-banner">
-  {{/if}}
+  <div class={{bannerAndDescriptionClass}}>
+    {{#if bannerImage}}
+      <img src={{bannerImage}} class="wizard-step-banner">
+    {{/if}}
 
-  {{#if step.description}}
-    <p class='wizard-step-description'>{{html-safe step.description}}</p>
-  {{/if}}
+    {{#if step.description}}
+      <p class='wizard-step-description'>{{html-safe step.description}}</p>
+    {{/if}}
+  </div>
 
   {{#wizard-step-form step=step}}
     {{#each step.fields as |field|}}
diff --git a/lib/wizard.rb b/lib/wizard.rb
index f334081..c58d652 100644
--- a/lib/wizard.rb
+++ b/lib/wizard.rb
@@ -18,15 +18,30 @@ class Wizard
     Step.new(step_name)
   end
 
-  def append_step(step)
+  def append_step(step, after: nil)
     return if @@excluded_steps.include?(step)
 
     step = create_step(step) if step.is_a?(String)
-
     yield step if block_given?
 
-    last_step = @steps.last
+    if after
+      before_step = @steps.detect { |s| s.id == after }
+
+      if before_step
+        step.previous = before_step
+        step.index = before_step.index + 1
+        if before_step.next
+          step.next = before_step.next
+          before_step.next.previous = step
+        end
+        before_step.next = step
+        @steps.insert(before_step.index + 1, step)
+        step.index += 1 while (step = step.next)
+        return
+      end
+    end
 
+    last_step = @steps.last
     @steps << step
 
     # If it's the first step
diff --git a/spec/components/wizard/wizard_spec.rb b/spec/components/wizard/wizard_spec.rb
index 0faef40..74fddb1 100644
--- a/spec/components/wizard/wizard_spec.rb
+++ b/spec/components/wizard/wizard_spec.rb
@@ -81,6 +81,56 @@ describe Wizard do
     end
   end
 
+  describe "#append_step with after specified" do
+    let(:user) { Fabricate.build(:moderator) }
+    let(:wizard) { Wizard.new(user) }
+
+    it 'inserts steps after the proper step' do
+      wizard.append_step('first') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('second') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('actually-second', after: 'first') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+
+      expect(wizard.steps.sort_by(&:index).map(&:id)).to eq(["first", "actually-second", "second"])
+      expect(wizard.steps.map(&:index).sort).to eq([0, 1, 2])
+    end
+
+    it 'inserts steps at the end if the after value does not match an existing step' do
+      wizard.append_step('first') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('second') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('should_be_last', after: 'abcdefghi') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+
+      expect(wizard.steps.sort_by(&:index).map(&:id)).to eq(["first", "second", "should_be_last"])
+      expect(wizard.steps.map(&:index).sort).to eq([0, 1, 2])
+    end
+
+    it 'inserts steps at the end' do
+      wizard.append_step('first') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('second') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+      wizard.append_step('last', after: 'second') do |step|
+        step.add_field(id: 'another_element', type: 'text')
+      end
+
+      expect(wizard.steps.sort_by(&:index).map(&:id)).to eq(["first", "second", "last"])
+      expect(wizard.steps.map(&:index).sort).to eq([0, 1, 2])
+    end
+  end
+
   describe "completed?" do
     let(:user) { Fabricate.build(:moderator) }
     let(:wizard) { Wizard.new(user) }

GitHub sha: 689c61b4

This commit appears in #9315 which was merged by markvanlan.