1
0
Fork 0

Merge branch 'master' into pro-features

Dieser Commit ist enthalten in:
angusmcleod 2021-08-17 19:35:10 +08:00
Commit eff1d2c7d2
10 geänderte Dateien mit 139 neuen und 35 gelöschten Zeilen

Datei anzeigen

@ -1,15 +1,10 @@
import { import discourseComputed from "discourse-common/utils/decorators";
default as discourseComputed,
observes,
on,
} from "discourse-common/utils/decorators";
import { generateName } from "../lib/wizard"; import { generateName } from "../lib/wizard";
import { import {
setWizardDefaults, setWizardDefaults,
default as wizardSchema, default as wizardSchema,
} from "../lib/wizard-schema"; } from "../lib/wizard-schema";
import { notEmpty } from "@ember/object/computed"; import { notEmpty } from "@ember/object/computed";
import { scheduleOnce } from "@ember/runloop";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import Component from "@ember/component"; import Component from "@ember/component";
import { A } from "@ember/array"; import { A } from "@ember/array";
@ -19,28 +14,12 @@ export default Component.extend({
items: A(), items: A(),
anyLinks: notEmpty("links"), anyLinks: notEmpty("links"),
@on("didInsertElement")
@observes("links.[]")
setupSortable() {
scheduleOnce("afterRender", () => this.applySortable());
},
applySortable() {
$(this.element)
.find(".link-list")
.sortable({ tolerance: "pointer" })
.on("sortupdate", (e, ui) => {
this.updateItemOrder(ui.item.data("id"), ui.item.index());
});
},
updateItemOrder(itemId, newIndex) { updateItemOrder(itemId, newIndex) {
const items = this.items; const items = this.items;
const item = items.findBy("id", itemId); const item = items.findBy("id", itemId);
items.removeObject(item); items.removeObject(item);
item.set("index", newIndex); item.set("index", newIndex);
items.insertAt(newIndex, item); items.insertAt(newIndex, item);
scheduleOnce("afterRender", this, () => this.applySortable());
}, },
@discourseComputed("itemType") @discourseComputed("itemType")
@ -58,7 +37,7 @@ export default Component.extend({
return; return;
} }
return items.map((item) => { return items.map((item, index) => {
if (item) { if (item) {
let link = { let link = {
id: item.id, id: item.id,
@ -77,6 +56,15 @@ export default Component.extend({
} }
link.classes = classes; link.classes = classes;
link.index = index;
if (index === 0) {
link.first = true;
}
if (index === items.length - 1) {
link.last = true;
}
return link; return link;
} }
@ -118,6 +106,14 @@ export default Component.extend({
this.set("current", newItem); this.set("current", newItem);
}, },
back(item) {
this.updateItemOrder(item.id, item.index - 1);
},
forward(item) {
this.updateItemOrder(item.id, item.index + 1);
},
change(itemId) { change(itemId) {
this.set("current", this.items.findBy("id", itemId)); this.set("current", this.items.findBy("id", itemId));
}, },

Datei anzeigen

@ -2,10 +2,16 @@
<div class="link-list"> <div class="link-list">
{{#if anyLinks}} {{#if anyLinks}}
{{#each links as |l|}} {{#each links as |link|}}
<div data-id={{l.id}}> <div data-id={{link.id}}>
{{d-button action="change" actionParam=l.id translatedLabel=l.label class=l.classes}} {{d-button action="change" actionParam=link.id translatedLabel=link.label class=link.classes}}
{{d-button action="remove" actionParam=l.id icon="times" class="remove"}} {{#unless link.first}}
{{d-button action="back" actionParam=link icon="arrow-left" class="back"}}
{{/unless}}
{{#unless link.last}}
{{d-button action="forward" actionParam=link icon="arrow-right" class="forward"}}
{{/unless}}
{{d-button action="remove" actionParam=link.id icon="times" class="remove"}}
</div> </div>
{{/each}} {{/each}}
{{/if}} {{/if}}

Datei anzeigen

@ -392,7 +392,7 @@ class CustomWizard::Action
user_ids.each { |user_id| group.group_users.build(user_id: user_id) } user_ids.each { |user_id| group.group_users.build(user_id: user_id) }
end end
GroupActionLogger.new(user, group, skip_guardian: true).log_change_group_settings GroupActionLogger.new(user, group).log_change_group_settings
log_success("Group created", group.name) log_success("Group created", group.name)
result.output = group.name result.output = group.name

Datei anzeigen

@ -76,6 +76,7 @@ class CustomWizard::Builder
end end
@wizard.update! @wizard.update!
CustomWizard::Submission.cleanup_incomplete_submissions(@wizard)
@wizard @wizard
end end

Datei anzeigen

@ -3,7 +3,7 @@ class CustomWizard::Submission
include ActiveModel::SerializerSupport include ActiveModel::SerializerSupport
KEY ||= "submissions" KEY ||= "submissions"
META ||= %w(submitted_at route_to redirect_on_complete redirect_to) META ||= %w(updated_at submitted_at route_to redirect_on_complete redirect_to)
attr_reader :id, attr_reader :id,
:user, :user,
@ -45,6 +45,7 @@ class CustomWizard::Submission
submission_list = self.class.list(wizard, user_id: user.id) submission_list = self.class.list(wizard, user_id: user.id)
submissions = submission_list.select { |submission| submission.id != self.id } submissions = submission_list.select { |submission| submission.id != self.id }
self.updated_at = Time.now.iso8601
submissions.push(self) submissions.push(self)
submission_data = submissions.map { |submission| data_to_save(submission) } submission_data = submissions.map { |submission| data_to_save(submission) }
@ -96,6 +97,29 @@ class CustomWizard::Submission
new(wizard, data, user_id) new(wizard, data, user_id)
end end
def self.cleanup_incomplete_submissions(wizard)
user_id = wizard.user.id
all_submissions = list(wizard, user_id: user_id)
sorted_submissions = all_submissions.sort_by do |submission|
zero_epoch_time = DateTime.strptime("0", '%s')
[
submission.submitted_at ? Time.iso8601(submission.submitted_at) : zero_epoch_time,
submission.updated_at ? Time.iso8601(submission.updated_at) : zero_epoch_time
]
end.reverse
has_incomplete = false
valid_submissions = sorted_submissions.select do |submission|
to_be_included = submission.submitted_at || !has_incomplete
has_incomplete = true if !submission.submitted_at
to_be_included
end
valid_data = valid_submissions.map { |submission| submission.data_to_save(submission) }
PluginStore.set("#{wizard.id}_#{KEY}", user_id, valid_data)
end
def self.list(wizard, user_id: nil, order_by: nil) def self.list(wizard, user_id: nil, order_by: nil)
params = { plugin_name: "#{wizard.id}_#{KEY}" } params = { plugin_name: "#{wizard.id}_#{KEY}" }
params[:key] = user_id if user_id.present? params[:key] = user_id if user_id.present?

Datei anzeigen

@ -32,13 +32,15 @@ class ::CustomWizard::UpdateValidator
@updater.errors.add(field_id, I18n.t('wizard.field.required', label: label)) @updater.errors.add(field_id, I18n.t('wizard.field.required', label: label))
end end
if min_length.present? && value.is_a?(String) && value.strip.length < min_length.to_i if value.is_a?(String) && (stripped_length = value.strip.length) > 0
if min_length.present? && stripped_length < min_length.to_i
@updater.errors.add(field_id, I18n.t('wizard.field.too_short', label: label, min: min_length.to_i)) @updater.errors.add(field_id, I18n.t('wizard.field.too_short', label: label, min: min_length.to_i))
end end
if max_length.present? && value.is_a?(String) && value.strip.length > max_length.to_i if max_length.present? && stripped_length > max_length.to_i
@updater.errors.add(field_id, I18n.t('wizard.field.too_long', label: label, max: max_length.to_i)) @updater.errors.add(field_id, I18n.t('wizard.field.too_long', label: label, max: max_length.to_i))
end end
end
if is_url_type(field) && value.present? && !check_if_url(value) if is_url_type(field) && value.present? && !check_if_url(value)
@updater.errors.add(field_id, I18n.t('wizard.field.not_url', label: label)) @updater.errors.add(field_id, I18n.t('wizard.field.not_url', label: label))

Datei anzeigen

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
# name: discourse-custom-wizard # name: discourse-custom-wizard
# about: Create custom wizards # about: Create custom wizards
# version: 0.8.0 # version: 0.8.1
# authors: Angus McLeod # authors: Angus McLeod
# url: https://github.com/paviliondev/discourse-custom-wizard # url: https://github.com/paviliondev/discourse-custom-wizard
# contact emails: angus@thepavilion.io # contact emails: angus@thepavilion.io
@ -33,6 +33,7 @@ if respond_to?(:register_svg_icon)
register_svg_icon "chevron-right" register_svg_icon "chevron-right"
register_svg_icon "chevron-left" register_svg_icon "chevron-left"
register_svg_icon "save" register_svg_icon "save"
register_svg_icon "arrow-right"
end end
class ::Sprockets::DirectiveProcessor class ::Sprockets::DirectiveProcessor

Datei anzeigen

@ -40,4 +40,50 @@ describe CustomWizard::Submission do
it "list submissions by wizard and user" do it "list submissions by wizard and user" do
expect(described_class.list(@wizard, user_id: user.id).size).to eq(1) expect(described_class.list(@wizard, user_id: user.id).size).to eq(1)
end end
context "#cleanup_incomplete_submissions" do
it "cleans up redundant incomplete submissions on each build" do
freeze_time Time.now + 1
described_class.new(@wizard, step_1_field_1: "I am the second submission").save
builder = CustomWizard::Builder.new(@wizard.id, @wizard.user)
builder.build
sub_list = described_class.list(@wizard, user_id: @wizard.user.id)
expect(sub_list.length).to eq(1)
expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the second submission")
end
it "handles submissions without 'updated_at' field correctly" do
described_class.new(@wizard, step_1_field_1: "I am the second submission").save
described_class.new(@wizard, step_1_field_1: "I am the third submission").save
sub_data = PluginStore.get("#{@wizard.id}_submissions", @wizard.user.id)
sub_data.each do |sub|
sub['updated_at'] = nil
end
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, sub_data)
builder = CustomWizard::Builder.new(@wizard.id, @wizard.user)
builder.build
sub_list = described_class.list(@wizard, user_id: @wizard.user.id)
expect(sub_list.length).to eq(1)
expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the third submission")
end
it "handles submissions with and without 'updated_at' field correctly" do
freeze_time Time.now + 1
described_class.new(@wizard, step_1_field_1: "I am the second submission").save
freeze_time Time.now + 2
described_class.new(@wizard, step_1_field_1: "I am the third submission").save
sub_data = PluginStore.get("#{@wizard.id}_submissions", @wizard.user.id)
sub_data[0]['updated_at'] = nil
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, sub_data)
builder = CustomWizard::Builder.new(@wizard.id, @wizard.user)
builder.build
sub_list = described_class.list(@wizard, user_id: @wizard.user.id)
expect(sub_list.length).to eq(1)
expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the third submission")
end
end
end end

Datei anzeigen

@ -97,6 +97,31 @@ describe CustomWizard::UpdateValidator do
).to eq(nil) ).to eq(nil)
end end
it "applies min length only if the input is non-empty" do
min_length = 3
@template[:steps][0][:fields][0][:min_length] = min_length
CustomWizard::Template.save(@template)
updater = perform_validation('step_1', step_1_field_1: '')
expect(
updater.errors.messages[:step_1_field_1].first
).to eq(nil)
end
it "applies max length only if the input is non-empty" do
max_length = 100
@template[:steps][0][:fields][0][:max_length] = max_length
CustomWizard::Template.save(@template)
updater = perform_validation('step_1', step_1_field_1: "")
expect(
updater.errors.messages[:step_1_field_1].first
).to eq(nil)
end
it 'standardises boolean entries' do it 'standardises boolean entries' do
updater = perform_validation('step_2', step_2_field_5: 'false') updater = perform_validation('step_2', step_2_field_5: 'false')
expect(updater.submission['step_2_field_5']).to eq(false) expect(updater.submission['step_2_field_5']).to eq(false)

Datei anzeigen

@ -11,4 +11,7 @@ if ENV['SIMPLECOV']
end end
end end
require 'oj'
Oj.default_options = Oj.default_options.merge(cache_str: -1)
require 'rails_helper' require 'rails_helper'