0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 17:30:29 +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 Component from "@ember/component";
import { default as discourseComputed } from 'discourse-common/utils/decorators';
import { wizardFieldList } from '../lib/wizard';
export default Component.extend({ export default Component.extend({
classNames: 'wizard-custom-step', classNames: 'wizard-custom-step',
@discourseComputed('wizard.steps', 'step.id')
descriptionWizardFields(steps, stepId) {
return wizardFieldList(steps, { upTo: stepId });
},
actions: { actions: {
bannerUploadDone(upload) { bannerUploadDone(upload) {
this.set("step.banner", upload.url); this.set("step.banner", upload.url);

Datei anzeigen

@ -1,4 +1,5 @@
import { default as discourseComputed, on } from 'discourse-common/utils/decorators'; import { default as discourseComputed, on } from 'discourse-common/utils/decorators';
import { notEmpty } from "@ember/object/computed";
import { userProperties } from '../lib/wizard'; import { userProperties } from '../lib/wizard';
import { scheduleOnce } from "@ember/runloop"; import { scheduleOnce } from "@ember/runloop";
import Component from "@ember/component"; import Component from "@ember/component";
@ -8,9 +9,11 @@ export default Component.extend({
barEnabled: true, barEnabled: true,
previewEnabled: true, previewEnabled: true,
fieldsEnabled: true, fieldsEnabled: true,
hasWizardFields: notEmpty('wizardFieldList'),
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); this._super(...arguments);
if (!this.barEnabled) { if (!this.barEnabled) {
scheduleOnce('afterRender', () => { scheduleOnce('afterRender', () => {
$(this.element).find('.d-editor-button-bar').addClass('hidden'); $(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 { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
import { notEmpty, alias } from "@ember/object/computed"; import { notEmpty, alias } from "@ember/object/computed";
import showModal from 'discourse/lib/show-modal'; 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 { buildProperties } from '../lib/wizard-json';
import { dasherize } from "@ember/string"; import { dasherize } from "@ember/string";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
@ -47,29 +47,11 @@ export default Controller.extend({
@discourseComputed('currentStep.id', 'wizard.save_submissions', 'wizard.steps.@each.fields[]') @discourseComputed('currentStep.id', 'wizard.save_submissions', 'wizard.steps.@each.fields[]')
wizardFields(currentStepId, saveSubmissions) { wizardFields(currentStepId, saveSubmissions) {
const allSteps = this.get('wizard.steps'); let steps = this.wizard.steps;
let steps = allSteps;
let fields = [];
if (!saveSubmissions) { if (!saveSubmissions) {
steps = [allSteps.findBy('id', currentStepId)]; steps = [steps.findBy('id', currentStepId)];
} }
return wizardFieldList(steps);
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;
}, },
actions: { actions: {

Datei anzeigen

@ -8,25 +8,6 @@ export default {
if (!siteSettings.custom_wizard_enabled) return; 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; const existing = DiscourseURL.routeTo;
DiscourseURL.routeTo = function(path, opts) { DiscourseURL.routeTo = function(path, opts) {
if (path && path.indexOf('/w/') > -1) { if (path && path.indexOf('/w/') > -1) {

Datei anzeigen

@ -1,3 +1,5 @@
import EmberObject from "@ember/object";
function selectKitContent(content) { function selectKitContent(content) {
return content.map(i => ({id: i, name: i})); return content.map(i => ({id: i, name: i}));
} }
@ -177,9 +179,8 @@ const fieldProperties = {
'content' 'content'
], ],
advanced: [ advanced: [
'prefill', 'property',
'content', 'key'
'property'
], ],
required: [ required: [
'id', 'id',
@ -290,6 +291,33 @@ function listProperties(type, objectType = null) {
return properties; 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 { export {
selectKitContent, selectKitContent,
generateName, generateName,
@ -298,5 +326,6 @@ export {
snakeCase, snakeCase,
schema, schema,
userProperties, userProperties,
listProperties listProperties,
wizardFieldList
}; };

Datei anzeigen

@ -97,29 +97,6 @@
</div> </div>
{{/if}} {{/if}}
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
{{#if field.showAdvanced}}
<div class="advanced-settings">
{{#if isCategory}}
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.property'}}</label>
</div>
<div class="setting-value">
{{combo-box
value=field.property
content=categoryPropertyTypes
onChange=(action (mut field.property))
options=(hash
none='admin.wizard.selector.placeholder.property'
)}}
</div>
</div>
{{/if}}
{{#if showPrefill}} {{#if showPrefill}}
<div class="setting full field-mapper-setting"> <div class="setting full field-mapper-setting">
<div class="setting-label"> <div class="setting-label">
@ -148,6 +125,29 @@
</div> </div>
{{/if}} {{/if}}
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
{{#if field.showAdvanced}}
<div class="advanced-settings">
{{#if isCategory}}
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.property'}}</label>
</div>
<div class="setting-value">
{{combo-box
value=field.property
content=categoryPropertyTypes
onChange=(action (mut field.property))
options=(hash
none='admin.wizard.selector.placeholder.property'
)}}
</div>
</div>
{{/if}}
<div class="setting"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n 'admin.wizard.translation'}}</label> <label>{{i18n 'admin.wizard.translation'}}</label>

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -89,7 +89,13 @@ export default {
animateInvalidFields() { animateInvalidFields() {
Ember.run.scheduleOnce('afterRender', () => { 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) { if (wizardErrors.length) {
this.handleWizardError(wizardErrors.join('\n')); this.handleWizardError(wizardErrors.join('\n'));
} }
this.animateInvalidFields();
throw response; throw response;
} }

Datei anzeigen

@ -2,13 +2,13 @@
{{wizard-no-access text=(i18n 'wizard.none') wizardId=wizardId}} {{wizard-no-access text=(i18n 'wizard.none') wizardId=wizardId}}
{{else}} {{else}}
{{#if requiresLogin}} {{#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}} {{else}}
{{#if notPermitted}} {{#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}} {{else}}
{{#if completed}} {{#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}} {{/if}}
{{/if}} {{/if}}

Datei anzeigen

@ -1,7 +1,7 @@
en: en:
js: js:
wizard: 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_js:
admin: admin:
@ -337,11 +337,11 @@ en:
other: "Select at least {{count}} items." other: "Select at least {{count}} items."
wizard: wizard:
completed: "You have completed the {{name}} wizard." completed: "You have completed this wizard."
not_permitted: "You are not permitted to access the {{name}} wizard." not_permitted: "You are not permitted to access this wizard."
none: "There is no wizard here." none: "There is no wizard here."
return_to_site: "Return to {{siteName}}" 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." reset: "Reset this wizard."
step_not_permitted: "You're not permitted to view this step." step_not_permitted: "You're not permitted to view this step."

Datei anzeigen

@ -1,16 +1,20 @@
module Jobs module Jobs
class SetAfterTimeWizard < ::Jobs::Base class SetAfterTimeWizard < ::Jobs::Base
def execute(args) def execute(args)
if CustomWizard::Wizard.find(args[:wizard_id]) if SiteSetting.custom_wizard_enabled
wizard = CustomWizard::Wizard.find(args[:wizard_id])
if wizard && wizard.after_time
user_ids = [] user_ids = []
User.human_users.each do |user| User.human_users.each do |user|
if CustomWizard::Wizard.set_wizard_redirect(args[:wizard_id], user) if CustomWizard::Wizard.set_wizard_redirect(wizard.id, user)
user_ids.push(user.id) user_ids.push(user.id)
end 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 end
end end

Datei anzeigen

@ -37,6 +37,13 @@ class CustomWizard::Builder
@sorted_field_validators.sort_by! { |h| -h[:priority] } @sorted_field_validators.sort_by! { |h| -h[:priority] }
end end
def mapper
CustomWizard::Mapper.new(
user: @wizard.user,
data: @submissions.last
)
end
def build(build_opts = {}, params = {}) def build(build_opts = {}, params = {})
return nil if !SiteSetting.custom_wizard_enabled || !@wizard return nil if !SiteSetting.custom_wizard_enabled || !@wizard
return @wizard if !@wizard.can_access? return @wizard if !@wizard.can_access?
@ -46,8 +53,12 @@ class CustomWizard::Builder
@steps.each do |step_template| @steps.each do |step_template|
@wizard.append_step(step_template['id']) do |step| @wizard.append_step(step_template['id']) do |step|
step.title = step_template['title'] if step_template['title'] 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'] 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.key = step_template['key'] if step_template['key']
step.permitted = true step.permitted = true
@ -87,10 +98,7 @@ class CustomWizard::Builder
p['key'] = @submissions.last[p['key']] p['key'] = @submissions.last[p['key']]
end end
unless CustomWizard::Mapper.new( unless mapper.validate_pairs(pairs)
user: @wizard.user,
data: @submissions.last
).validate_pairs(pairs)
step.permitted = false step.permitted = false
end end
end end

Datei anzeigen

@ -13,17 +13,23 @@ class CustomWizard::StepUpdater
end end
def update def update
return false if !SiteSetting.custom_wizard_enabled byebug
@step.updater.call(self) if @step.present? && @step.updater.present? if SiteSetting.custom_wizard_enabled &&
@step.present? &&
@step.updater.present? &&
success?
@step.updater.call(self)
if success?
UserHistory.create( UserHistory.create(
action: UserHistory.actions[:custom_wizard_step], action: UserHistory.actions[:custom_wizard_step],
acting_user_id: @current_user.id, acting_user_id: @current_user.id,
context: @wizard.id, context: @wizard.id,
subject: @step.id subject: @step.id
) )
else
false
end end
end end

Datei anzeigen

@ -108,10 +108,13 @@ class CustomWizard::Validator
current_time = wizard.present? ? wizard.after_time_scheduled : nil current_time = wizard.present? ? wizard.after_time_scheduled : nil
new_time = @params[:after_time_scheduled] new_time = @params[:after_time_scheduled]
if (new_time.blank? && current_time.blank?) || begin
(new_time !~ /^([01]?[0-9]|2[0-3])\:[0-5][0-9]$/) || active_time = Time.parse(new_time.present? ? new_time : current_time).utc
(Time.parse(new_time).utc < Time.now.utc) rescue ArgumentError
invalid_time = true
end
if invalid_time || active_time.blank? || active_time < Time.now.utc
@error = { type: 'after_time' } @error = { type: 'after_time' }
end end
end end

Datei anzeigen

@ -172,9 +172,7 @@ class CustomWizard::Wizard
def can_access? def can_access?
return true if user.admin return true if user.admin
return false if multiple_submissions && completed? return permitted? && (multiple_submissions || !completed?)
return false if !permitted?
return true
end end
def reset def reset
@ -230,7 +228,11 @@ class CustomWizard::Wizard
if (records = filter_records('prompt_completion')).any? if (records = filter_records('prompt_completion')).any?
records.reduce([]) do |result, record| records.reduce([]) do |result, record|
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user) 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 result
end end
else else