diff --git a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 b/assets/javascripts/discourse/components/wizard-custom-step.js.es6
index ff3d4ee6..a18743dd 100644
--- a/assets/javascripts/discourse/components/wizard-custom-step.js.es6
+++ b/assets/javascripts/discourse/components/wizard-custom-step.js.es6
@@ -1,8 +1,15 @@
import Component from "@ember/component";
+import { default as discourseComputed } from 'discourse-common/utils/decorators';
+import { wizardFieldList } from '../lib/wizard';
export default Component.extend({
classNames: 'wizard-custom-step',
+ @discourseComputed('wizard.steps', 'step.id')
+ descriptionWizardFields(steps, stepId) {
+ return wizardFieldList(steps, { upTo: stepId });
+ },
+
actions: {
bannerUploadDone(upload) {
this.set("step.banner", upload.url);
diff --git a/assets/javascripts/discourse/components/wizard-text-editor.js.es6 b/assets/javascripts/discourse/components/wizard-text-editor.js.es6
index 5c95f179..4cbb7efb 100644
--- a/assets/javascripts/discourse/components/wizard-text-editor.js.es6
+++ b/assets/javascripts/discourse/components/wizard-text-editor.js.es6
@@ -1,4 +1,5 @@
import { default as discourseComputed, on } from 'discourse-common/utils/decorators';
+import { notEmpty } from "@ember/object/computed";
import { userProperties } from '../lib/wizard';
import { scheduleOnce } from "@ember/runloop";
import Component from "@ember/component";
@@ -8,9 +9,11 @@ export default Component.extend({
barEnabled: true,
previewEnabled: true,
fieldsEnabled: true,
+ hasWizardFields: notEmpty('wizardFieldList'),
didReceiveAttrs() {
this._super(...arguments);
+
if (!this.barEnabled) {
scheduleOnce('afterRender', () => {
$(this.element).find('.d-editor-button-bar').addClass('hidden');
diff --git a/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs
new file mode 100644
index 00000000..503ee113
--- /dev/null
+++ b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs
@@ -0,0 +1,7 @@
+{{#each site.complete_custom_wizard as |wizard|}}
+
+{{/each}}
\ No newline at end of file
diff --git a/assets/javascripts/discourse/connectors/top-notices/prompt-completion.js.es6 b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.js.es6
new file mode 100644
index 00000000..8d097475
--- /dev/null
+++ b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.js.es6
@@ -0,0 +1,6 @@
+export default {
+ shouldRender(_, ctx) {
+ return ctx.siteSettings.custom_wizard_enabled &&
+ ctx.site.complete_custom_wizard;
+ }
+}
\ No newline at end of file
diff --git a/assets/javascripts/discourse/controllers/admin-wizards-wizard-show.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-wizard-show.js.es6
index e2aaec10..5f10283e 100644
--- a/assets/javascripts/discourse/controllers/admin-wizards-wizard-show.js.es6
+++ b/assets/javascripts/discourse/controllers/admin-wizards-wizard-show.js.es6
@@ -1,7 +1,7 @@
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
import { notEmpty, alias } from "@ember/object/computed";
import showModal from 'discourse/lib/show-modal';
-import { generateId } from '../lib/wizard';
+import { generateId, wizardFieldList } from '../lib/wizard';
import { buildProperties } from '../lib/wizard-json';
import { dasherize } from "@ember/string";
import EmberObject from "@ember/object";
@@ -47,29 +47,11 @@ export default Controller.extend({
@discourseComputed('currentStep.id', 'wizard.save_submissions', 'wizard.steps.@each.fields[]')
wizardFields(currentStepId, saveSubmissions) {
- const allSteps = this.get('wizard.steps');
- let steps = allSteps;
- let fields = [];
-
+ let steps = this.wizard.steps;
if (!saveSubmissions) {
- steps = [allSteps.findBy('id', currentStepId)];
+ steps = [steps.findBy('id', currentStepId)];
}
-
- steps.forEach((s) => {
- if (s.fields && s.fields.length > 0) {
- let stepFields = s.fields.map((f) => {
- return EmberObject.create({
- id: f.id,
- label: `${f.label} (${s.id}, ${f.id})`,
- type: f.type
- });
- });
-
- fields.push(...stepFields);
- }
- });
-
- return fields;
+ return wizardFieldList(steps);
},
actions: {
diff --git a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
index 1e4436cb..cd2d9558 100644
--- a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
+++ b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
@@ -7,25 +7,6 @@ export default {
const siteSettings = container.lookup('site-settings:main');
if (!siteSettings.custom_wizard_enabled) return;
-
- withPluginApi('0.8.12', api => {
- api.modifyClass('component:global-notice', {
- buildBuffer(buffer) {
- this._super(...arguments);
- const wizards = this.site.get('complete_custom_wizard');
- if (wizards) {
- wizards.forEach((w) => {
- const text = I18n.t('wizard.complete_custom', {
- wizard_url: w.url,
- wizard_name: w.name,
- site_name: this.siteSettings.title
- });
- buffer.push(``);
- });
- }
- }
- });
- });
const existing = DiscourseURL.routeTo;
DiscourseURL.routeTo = function(path, opts) {
diff --git a/assets/javascripts/discourse/lib/wizard-json.js.es6 b/assets/javascripts/discourse/lib/wizard-json.js.es6
index 3ef519b1..670fcee7 100644
--- a/assets/javascripts/discourse/lib/wizard-json.js.es6
+++ b/assets/javascripts/discourse/lib/wizard-json.js.es6
@@ -137,7 +137,7 @@ function buildProperties(json) {
steps: A(),
actions: A()
};
-
+
if (present(json)) {
props.existingId = true;
props = buildBasicProperties(json, 'wizard', props);
diff --git a/assets/javascripts/discourse/lib/wizard.js.es6 b/assets/javascripts/discourse/lib/wizard.js.es6
index 2f252fbe..188e6ed4 100644
--- a/assets/javascripts/discourse/lib/wizard.js.es6
+++ b/assets/javascripts/discourse/lib/wizard.js.es6
@@ -1,3 +1,5 @@
+import EmberObject from "@ember/object";
+
function selectKitContent(content) {
return content.map(i => ({id: i, name: i}));
}
@@ -177,9 +179,8 @@ const fieldProperties = {
'content'
],
advanced: [
- 'prefill',
- 'content',
- 'property'
+ 'property',
+ 'key'
],
required: [
'id',
@@ -290,6 +291,33 @@ function listProperties(type, objectType = null) {
return properties;
}
+function wizardFieldList(steps = [], opts = {}) {
+ let upToIndex = null;
+
+ if (opts.upTo) {
+ upToIndex = steps.map((s) => (s.id)).indexOf(opts.upTo);
+ }
+
+ return steps.reduce((result, step, index) => {
+ let fields = step.fields;
+
+ if (fields && fields.length > 0) {
+
+ if (upToIndex === null || index < upToIndex) {
+ result.push(...fields.map((field) => {
+ return EmberObject.create({
+ id: field.id,
+ label: `${field.label} (${step.id}, ${field.id})`,
+ type: field.type
+ });
+ }));
+ }
+ }
+
+ return result;
+ }, []);
+}
+
export {
selectKitContent,
generateName,
@@ -298,5 +326,6 @@ export {
snakeCase,
schema,
userProperties,
- listProperties
+ listProperties,
+ wizardFieldList
};
\ No newline at end of file
diff --git a/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6
index 1384a252..d2e7ff2f 100644
--- a/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6
+++ b/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6
@@ -21,7 +21,7 @@ export default DiscourseRoute.extend({
setupController(controller, model) {
const parentModel = this.modelFor('adminWizardsWizard');
const wizard = CustomWizard.create((!model || model.create) ? {} : model);
-
+
controller.setProperties({
wizardList: parentModel.wizard_list,
fieldTypes: selectKitContent(parentModel.field_types),
diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
index b7711339..23a745b3 100644
--- a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
@@ -97,6 +97,34 @@
{{/if}}
+{{#if showPrefill}}
+
+
+
+
+
+
+ {{wizard-mapper
+ inputs=field.prefill
+ options=prefillOptions}}
+
+
+{{/if}}
+
+{{#if showContent}}
+
+
+
+
+
+
+ {{wizard-mapper
+ inputs=field.content
+ options=contentOptions}}
+
+
+{{/if}}
+
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
{{#if field.showAdvanced}}
@@ -120,34 +148,6 @@
{{/if}}
- {{#if showPrefill}}
-
-
-
-
-
-
- {{wizard-mapper
- inputs=field.prefill
- options=prefillOptions}}
-
-
- {{/if}}
-
- {{#if showContent}}
-
-
-
-
-
-
- {{wizard-mapper
- inputs=field.content
- options=contentOptions}}
-
-
- {{/if}}
-
diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs
index c2f0b073..6c4b359a 100644
--- a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs
@@ -30,7 +30,7 @@
{{wizard-text-editor
value=step.raw_description
- fieldsEnabled=false}}
+ wizardFields=descriptionWizardFields}}
diff --git a/assets/javascripts/discourse/templates/components/wizard-text-editor.hbs b/assets/javascripts/discourse/templates/components/wizard-text-editor.hbs
index b306aee6..5638ac70 100644
--- a/assets/javascripts/discourse/templates/components/wizard-text-editor.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-text-editor.hbs
@@ -21,10 +21,13 @@
{{i18n 'admin.wizard.action.post_builder.user_fields'}}
{{userFieldList}}
-
+
+ {{#if hasWizardFields}}
+
+ {{/if}}
{{/if}}
{{/if}}
diff --git a/assets/javascripts/wizard/initializers/custom.js.es6 b/assets/javascripts/wizard/initializers/custom.js.es6
index d879e14e..d74e25b1 100644
--- a/assets/javascripts/wizard/initializers/custom.js.es6
+++ b/assets/javascripts/wizard/initializers/custom.js.es6
@@ -89,7 +89,13 @@ export default {
animateInvalidFields() {
Ember.run.scheduleOnce('afterRender', () => {
- $('.invalid input[type=text], .invalid textarea, .invalid input[type=checkbox], .invalid .select-kit').wiggle(2, 100);
+ let query = '.invalid input[type=text], .invalid textarea, .invalid input[type=checkbox], .invalid .select-kit';
+
+ $([document.documentElement, document.body]).animate({
+ scrollTop: $(query).offset().top - 200
+ }, 400, function() {
+ $(query).wiggle(2, 100);
+ });
});
},
@@ -185,6 +191,7 @@ export default {
if (wizardErrors.length) {
this.handleWizardError(wizardErrors.join('\n'));
}
+ this.animateInvalidFields();
throw response;
}
diff --git a/assets/javascripts/wizard/templates/custom.index.hbs b/assets/javascripts/wizard/templates/custom.index.hbs
index c8e8966c..6040d9b5 100644
--- a/assets/javascripts/wizard/templates/custom.index.hbs
+++ b/assets/javascripts/wizard/templates/custom.index.hbs
@@ -2,13 +2,13 @@
{{wizard-no-access text=(i18n 'wizard.none') wizardId=wizardId}}
{{else}}
{{#if requiresLogin}}
- {{wizard-no-access text=(i18n 'wizard.requires_login' name=name) wizardId=wizardId}}
+ {{wizard-no-access text=(i18n 'wizard.requires_login') wizardId=wizardId}}
{{else}}
{{#if notPermitted}}
- {{wizard-no-access text=(i18n 'wizard.not_permitted' name=name) wizardId=wizardId}}
+ {{wizard-no-access text=(i18n 'wizard.not_permitted') wizardId=wizardId}}
{{else}}
{{#if completed}}
- {{wizard-no-access text=(i18n 'wizard.completed' name=name) wizardId=wizardId}}
+ {{wizard-no-access text=(i18n 'wizard.completed') wizardId=wizardId}}
{{/if}}
{{/if}}
{{/if}}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 4ce6d571..463ef8c6 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1,7 +1,7 @@
en:
js:
wizard:
- complete_custom: "Welcome to %{site_name}! Get started with the %{wizard_name} wizard ✨"
+ complete_custom: "Complete the {{name}}"
admin_js:
admin:
@@ -337,11 +337,11 @@ en:
other: "Select at least {{count}} items."
wizard:
- completed: "You have completed the {{name}} wizard."
- not_permitted: "You are not permitted to access the {{name}} wizard."
+ completed: "You have completed this wizard."
+ not_permitted: "You are not permitted to access this wizard."
none: "There is no wizard here."
return_to_site: "Return to {{siteName}}"
- requires_login: "You need to be logged in to access the {{name}} wizard."
+ requires_login: "You need to be logged in to access this wizard."
reset: "Reset this wizard."
step_not_permitted: "You're not permitted to view this step."
diff --git a/jobs/set_after_time_wizard.rb b/jobs/set_after_time_wizard.rb
index e94d2d92..7aa528ba 100644
--- a/jobs/set_after_time_wizard.rb
+++ b/jobs/set_after_time_wizard.rb
@@ -1,16 +1,20 @@
module Jobs
class SetAfterTimeWizard < ::Jobs::Base
def execute(args)
- if CustomWizard::Wizard.find(args[:wizard_id])
- user_ids = []
+ if SiteSetting.custom_wizard_enabled
+ wizard = CustomWizard::Wizard.find(args[:wizard_id])
+
+ if wizard && wizard.after_time
+ user_ids = []
- User.human_users.each do |user|
- if CustomWizard::Wizard.set_wizard_redirect(args[:wizard_id], user)
- user_ids.push(user.id)
+ User.human_users.each do |user|
+ if CustomWizard::Wizard.set_wizard_redirect(wizard.id, user)
+ user_ids.push(user.id)
+ end
end
- end
- MessageBus.publish "/redirect_to_wizard", args[:wizard_id], user_ids: user_ids
+ MessageBus.publish "/redirect_to_wizard", wizard.id, user_ids: user_ids
+ end
end
end
end
diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb
index b8f9b7dd..fba34f48 100644
--- a/lib/custom_wizard/builder.rb
+++ b/lib/custom_wizard/builder.rb
@@ -36,6 +36,13 @@ class CustomWizard::Builder
sorted_field_validators << { priority: priority, type: type, block: block }
@sorted_field_validators.sort_by! { |h| -h[:priority] }
end
+
+ def mapper
+ CustomWizard::Mapper.new(
+ user: @wizard.user,
+ data: @submissions.last
+ )
+ end
def build(build_opts = {}, params = {})
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
@@ -46,8 +53,12 @@ class CustomWizard::Builder
@steps.each do |step_template|
@wizard.append_step(step_template['id']) do |step|
step.title = step_template['title'] if step_template['title']
- step.description = step_template['description'] if step_template['description']
step.banner = step_template['banner'] if step_template['banner']
+
+ if step_template['description']
+ step.description = mapper.interpolate(step_template['description'])
+ end
+
step.key = step_template['key'] if step_template['key']
step.permitted = true
@@ -87,10 +98,7 @@ class CustomWizard::Builder
p['key'] = @submissions.last[p['key']]
end
- unless CustomWizard::Mapper.new(
- user: @wizard.user,
- data: @submissions.last
- ).validate_pairs(pairs)
+ unless mapper.validate_pairs(pairs)
step.permitted = false
end
end
diff --git a/lib/custom_wizard/step_updater.rb b/lib/custom_wizard/step_updater.rb
index aa6523d5..caeb37ef 100644
--- a/lib/custom_wizard/step_updater.rb
+++ b/lib/custom_wizard/step_updater.rb
@@ -13,17 +13,23 @@ class CustomWizard::StepUpdater
end
def update
- return false if !SiteSetting.custom_wizard_enabled
-
- @step.updater.call(self) if @step.present? && @step.updater.present?
+ byebug
- if success?
+ if SiteSetting.custom_wizard_enabled &&
+ @step.present? &&
+ @step.updater.present? &&
+ success?
+
+ @step.updater.call(self)
+
UserHistory.create(
action: UserHistory.actions[:custom_wizard_step],
acting_user_id: @current_user.id,
context: @wizard.id,
subject: @step.id
)
+ else
+ false
end
end
diff --git a/lib/custom_wizard/validator.rb b/lib/custom_wizard/validator.rb
index b14fe22f..5b377584 100644
--- a/lib/custom_wizard/validator.rb
+++ b/lib/custom_wizard/validator.rb
@@ -107,11 +107,14 @@ class CustomWizard::Validator
wizard = CustomWizard::Wizard.create(@params[:id]) if !@opts[:create]
current_time = wizard.present? ? wizard.after_time_scheduled : nil
new_time = @params[:after_time_scheduled]
+
+ begin
+ active_time = Time.parse(new_time.present? ? new_time : current_time).utc
+ rescue ArgumentError
+ invalid_time = true
+ end
- if (new_time.blank? && current_time.blank?) ||
- (new_time !~ /^([01]?[0-9]|2[0-3])\:[0-5][0-9]$/) ||
- (Time.parse(new_time).utc < Time.now.utc)
-
+ if invalid_time || active_time.blank? || active_time < Time.now.utc
@error = { type: 'after_time' }
end
end
diff --git a/lib/custom_wizard/wizard.rb b/lib/custom_wizard/wizard.rb
index 9d2383cf..71371554 100644
--- a/lib/custom_wizard/wizard.rb
+++ b/lib/custom_wizard/wizard.rb
@@ -172,9 +172,7 @@ class CustomWizard::Wizard
def can_access?
return true if user.admin
- return false if multiple_submissions && completed?
- return false if !permitted?
- return true
+ return permitted? && (multiple_submissions || !completed?)
end
def reset
@@ -230,7 +228,11 @@ class CustomWizard::Wizard
if (records = filter_records('prompt_completion')).any?
records.reduce([]) do |result, record|
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
- result.push(id: wizard.id, name: wizard.name) if !wizard.completed?
+
+ if wizard.permitted? && !wizard.completed?
+ result.push(id: wizard.id, name: wizard.name)
+ end
+
result
end
else
diff --git a/serializers/site_serializer.rb b/serializers/site_serializer.rb
index f899ae6e..8a25e032 100644
--- a/serializers/site_serializer.rb
+++ b/serializers/site_serializer.rb
@@ -15,7 +15,7 @@ module CustomWizardSiteSerializerExtension
def complete_custom_wizard
if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user)
- requires_completion.map {|w| {name: w[:name], url: "/w/#{w[:id]}"}}
+ requires_completion.map {|w| { name: w[:name], url: "/w/#{w[:id]}"} }
end
end