0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 01:10:28 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2020-04-14 15:46:06 +10:00
Ursprung 92e61f3f51
Commit d128565979
21 geänderte Dateien mit 161 neuen und 113 gelöschten Zeilen

Datei anzeigen

@ -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);

Datei anzeigen

@ -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');

Datei anzeigen

@ -0,0 +1,7 @@
{{#each site.complete_custom_wizard as |wizard|}}
<div class='row'>
<div class='alert alert-info alert-wizard'>
<a href="{{wizard.url}}">{{i18n 'wizard.complete_custom' name=wizard.name}}</a>
</div>
</div>
{{/each}}

Datei anzeigen

@ -0,0 +1,6 @@
export default {
shouldRender(_, ctx) {
return ctx.siteSettings.custom_wizard_enabled &&
ctx.site.complete_custom_wizard;
}
}

Datei anzeigen

@ -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: {

Datei anzeigen

@ -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(`<div class='row'><div class='alert alert-info alert-wizard'>${text}</div></div>`);
});
}
}
});
});
const existing = DiscourseURL.routeTo;
DiscourseURL.routeTo = function(path, opts) {

Datei anzeigen

@ -137,7 +137,7 @@ function buildProperties(json) {
steps: A(),
actions: A()
};
if (present(json)) {
props.existingId = true;
props = buildBasicProperties(json, 'wizard', props);

Datei anzeigen

@ -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
};

Datei anzeigen

@ -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),

Datei anzeigen

@ -97,6 +97,34 @@
</div>
{{/if}}
{{#if showPrefill}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.prefill'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=field.prefill
options=prefillOptions}}
</div>
</div>
{{/if}}
{{#if showContent}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.content'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=field.content
options=contentOptions}}
</div>
</div>
{{/if}}
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
{{#if field.showAdvanced}}
@ -120,34 +148,6 @@
</div>
{{/if}}
{{#if showPrefill}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.prefill'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=field.prefill
options=prefillOptions}}
</div>
</div>
{{/if}}
{{#if showContent}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.content'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=field.content
options=contentOptions}}
</div>
</div>
{{/if}}
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.translation'}}</label>

Datei anzeigen

@ -30,7 +30,7 @@
<div class="setting-value">
{{wizard-text-editor
value=step.raw_description
fieldsEnabled=false}}
wizardFields=descriptionWizardFields}}
</div>
</div>

Datei anzeigen

@ -21,10 +21,13 @@
{{i18n 'admin.wizard.action.post_builder.user_fields'}}
{{userFieldList}}
</label>
<label>
{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}
{{wizardFieldList}}
</label>
{{#if hasWizardFields}}
<label>
{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}
{{wizardFieldList}}
</label>
{{/if}}
</div>
{{/if}}
{{/if}}

Datei anzeigen

@ -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;
}

Datei anzeigen

@ -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}}

Datei anzeigen

@ -1,7 +1,7 @@
en:
js:
wizard:
complete_custom: "Welcome to %{site_name}! Get started with <a href='%{wizard_url}' data-auto-route='true'>the %{wizard_name} wizard</a> ✨"
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."

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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