Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-05-19 23:40:07 +02:00
Commits vergleichen
41 Commits
a871a7c11a
...
f13376cffa
Autor | SHA1 | Datum | |
---|---|---|---|
f13376cffa | |||
895ee9dd96 | |||
996f953ac5 | |||
93cfdfb4d5 | |||
d42bddf158 | |||
325feb78cc | |||
e5359aa649 | |||
ca9e96ccf5 | |||
1ab2262ca3 | |||
64b3bc41c5 | |||
326baeee9f | |||
782872ce2b | |||
5ae661f41b | |||
dbab8ca9a8 | |||
18821e2eee | |||
ae4cca6ed6 | |||
404e54a24c | |||
2b96fc53fc | |||
908bca742f | |||
7b3d848df0 | |||
007ab7ac37 | |||
9c43f89cd3 | |||
ac5d41d914 | |||
bafb09a502 | |||
092fd10c38 | |||
235ff68133 | |||
12bdf642f4 | |||
0d5c9393b2 | |||
30b2651490 | |||
3ac50bc300 | |||
654a00d84b | |||
dc9df6c8fd | |||
34229abf09 | |||
1255d05d21 | |||
e07a5ac59b | |||
ac71bb90a5 | |||
de48cd1c55 | |||
7d0bde23be | |||
17f7ecc0dd | |||
359d8131f7 | |||
233e091bbb |
13
README.md
13
README.md
|
@ -10,17 +10,12 @@ The Custom Wizard Plugin lets you make forms for your Discourse forum. Better us
|
|||
|
||||
If you're not sure how to install a plugin in Discourse, please follow the [plugin installation guide](https://meta.discourse.org/t/install-a-plugin/19157) or contact your Discourse hosting provider.
|
||||
|
||||
## Subscriptions
|
||||
You can install the plugin right away and use the basic features. If you need more, we offer [several subscription options](https://custom-wizard.pavilion.tech/pricing), including a community subscription for smaller non-profit and charitable sites.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Read the full documentation here](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/), or go directly to the relevant section
|
||||
|
||||
- [Wizard Administration](https://coop.pavilion.tech/t/1602)
|
||||
- [Wizard Settings](https://coop.pavilion.tech/t/1614)
|
||||
- [Step Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/step-settings)
|
||||
- [Field Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/field-settings)
|
||||
- [Conditional Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/conditional-settings)
|
||||
- [Field Interpolation](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/field-interpolation)
|
||||
- [Handling Dates and Times](https://coop.pavilion.tech/t/1708)
|
||||
- [Read the full documentation here](https://coop.pavilion.tech/docs?ascending=true&category=82&order=title)
|
||||
|
||||
## Support
|
||||
|
||||
|
|
|
@ -166,7 +166,10 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
visibility_level: mapped_params,
|
||||
members_visibility_level: mapped_params,
|
||||
add_event: mapped_params,
|
||||
add_location: mapped_params
|
||||
add_location: mapped_params,
|
||||
public_exit: mapped_params,
|
||||
public_admission: mapped_params,
|
||||
primary_group: mapped_params
|
||||
]
|
||||
)
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
@ -11,8 +10,6 @@ import CustomWizard, {
|
|||
import { alias, not } from "@ember/object/computed";
|
||||
import discourseLater from "discourse-common/lib/later";
|
||||
|
||||
const alreadyWarned = {};
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":wizard-step", "step.id"],
|
||||
saving: null,
|
||||
|
@ -197,27 +194,9 @@ export default Component.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
const step = this.step;
|
||||
const result = step.validate();
|
||||
this.step.validate();
|
||||
|
||||
if (result.warnings.length) {
|
||||
const unwarned = result.warnings.filter((w) => !alreadyWarned[w]);
|
||||
if (unwarned.length) {
|
||||
unwarned.forEach((w) => (alreadyWarned[w] = true));
|
||||
return window.bootbox.confirm(
|
||||
unwarned.map((w) => I18n.t(`wizard.${w}`)).join("\n"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
this.advance();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (step.get("valid")) {
|
||||
if (this.step.get("valid")) {
|
||||
this.advance();
|
||||
} else {
|
||||
this.autoFocus();
|
||||
|
|
|
@ -173,6 +173,9 @@ const action = {
|
|||
visibility_level: null,
|
||||
members_visibility_level: null,
|
||||
custom_fields: null,
|
||||
public_exit: true,
|
||||
public_admission: true,
|
||||
primary_group: true,
|
||||
},
|
||||
},
|
||||
mapped: [
|
||||
|
@ -205,6 +208,9 @@ const action = {
|
|||
"members_visibility_level",
|
||||
"add_event",
|
||||
"add_location",
|
||||
"public_exit",
|
||||
"public_admission",
|
||||
"primary_group",
|
||||
],
|
||||
required: ["id", "type"],
|
||||
dependent: {},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { getOwner } from "@ember/application";
|
|||
import { readOnly } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const PRODUCT_PAGE = "https://custom-wizard.pavilion.tech";
|
||||
const PRODUCT_PAGE = "https://custom-wizard.pavilion.tech/pricing";
|
||||
const SUPPORT_MESSAGE =
|
||||
"https://coop.pavilion.tech/new-message?username=support&title=Custom%20Wizard%20Support";
|
||||
const MANAGER_CATEGORY =
|
||||
|
|
|
@ -25,7 +25,6 @@ export default EmberObject.extend(ValidState, {
|
|||
type: null,
|
||||
value: null,
|
||||
required: null,
|
||||
warning: null,
|
||||
|
||||
@discourseComputed("wizardId", "stepId", "id")
|
||||
i18nKey(wizardId, stepId, id) {
|
||||
|
|
|
@ -35,19 +35,12 @@ export default EmberObject.extend(ValidState, {
|
|||
|
||||
validate() {
|
||||
let allValid = true;
|
||||
const result = { warnings: [] };
|
||||
|
||||
this.fields.forEach((field) => {
|
||||
allValid = allValid && field.check();
|
||||
const warning = field.get("warning");
|
||||
if (warning) {
|
||||
result.warnings.push(warning);
|
||||
}
|
||||
});
|
||||
|
||||
this.setValid(allValid);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
fieldError(id, description) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import getUrl from "discourse-common/lib/get-url";
|
||||
import CustomWizardField from "./custom-wizard-field";
|
||||
import CustomWizardStep from "./custom-wizard-step";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
const CustomWizard = EmberObject.extend({
|
||||
@discourseComputed("steps.length")
|
||||
|
@ -34,7 +35,7 @@ CustomWizard.reopenClass({
|
|||
restart(wizardId) {
|
||||
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
|
||||
.then(() => {
|
||||
window.location.href = `/w/${wizardId}`;
|
||||
DiscourseURL.redirectTo(getUrl(`/w/${wizardId}`));
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
@ -44,7 +45,7 @@ CustomWizard.reopenClass({
|
|||
if (result.redirect_on_complete) {
|
||||
url = result.redirect_on_complete;
|
||||
}
|
||||
window.location.href = getUrl(url);
|
||||
DiscourseURL.redirectTo(getUrl(url));
|
||||
},
|
||||
|
||||
build(wizardJson) {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { findCustomWizard, updateCachedWizard } from "../models/custom-wizard";
|
||||
import I18n from "I18n";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import bootbox from "bootbox";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
dialog: service(),
|
||||
|
||||
titleToken() {
|
||||
const wizard = this.modelFor("custom-wizard");
|
||||
return wizard ? wizard.name || wizard.id : I18n.t("wizard.custom_title");
|
||||
|
@ -30,7 +32,7 @@ export default DiscourseRoute.extend({
|
|||
{
|
||||
label: I18n.t("wizard.incomplete_submission.restart"),
|
||||
class: "btn btn-default",
|
||||
callback: () => {
|
||||
action: () => {
|
||||
wizardModel.restart();
|
||||
},
|
||||
},
|
||||
|
@ -40,11 +42,7 @@ export default DiscourseRoute.extend({
|
|||
},
|
||||
];
|
||||
|
||||
const options = {
|
||||
onEscape: false,
|
||||
};
|
||||
|
||||
bootbox.dialog(title, buttons, options);
|
||||
this.dialog.dialog({ title, buttons, type: "confirm" });
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { tracked } from "@glimmer/tracking";
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
const PRODUCT_PAGE = "https://custom-wizard.pavilion.tech";
|
||||
const PRODUCT_PAGE = "https://custom-wizard.pavilion.tech/pricing";
|
||||
const SUPPORT_MESSAGE =
|
||||
"https://coop.pavilion.tech/new-message?username=support&title=Custom%20Wizard%20Support";
|
||||
const MANAGER_CATEGORY =
|
||||
|
|
|
@ -740,6 +740,60 @@
|
|||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.create_group.public_exit"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=action.public_exit
|
||||
property="public_exit"
|
||||
onUpdate=(action "mappedFieldUpdated")
|
||||
options=(hash
|
||||
textSelection=true
|
||||
wizardFieldSelection=true
|
||||
userFieldSelection=true
|
||||
context="action"
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.create_group.public_admission"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=action.public_admission
|
||||
property="public_admission"
|
||||
onUpdate=(action "mappedFieldUpdated")
|
||||
options=(hash
|
||||
textSelection=true
|
||||
wizardFieldSelection=true
|
||||
userFieldSelection=true
|
||||
context="action"
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.create_group.primary_group"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=action.primary_group
|
||||
property="primary_group"
|
||||
onUpdate=(action "mappedFieldUpdated")
|
||||
options=(hash
|
||||
textSelection=true
|
||||
wizardFieldSelection=true
|
||||
userFieldSelection=true
|
||||
context="action"
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if createCategory}}
|
||||
|
|
|
@ -383,6 +383,9 @@ de:
|
|||
messageable_level: Nachrichtbare Ebene
|
||||
visibility_level: Sichtbarkeitsstufe
|
||||
members_visibility_level: Sichtbarkeitsstufe der Mitglieder
|
||||
public_exit: Erlaube Gruppenaustritt
|
||||
public_admission: Erlaube der Gruppe beizutreten
|
||||
primary_group: Primäre Gruppe
|
||||
custom_field:
|
||||
nav_label: "Benutzerdefinierte Felder"
|
||||
add: "Hinzufügen"
|
||||
|
|
|
@ -429,6 +429,9 @@ en:
|
|||
messageable_level: Messageable Level
|
||||
visibility_level: Visibility Level
|
||||
members_visibility_level: Members Visibility Level
|
||||
public_exit: Allow Group exit
|
||||
public_admission: Allow Group joining
|
||||
primary_group: Primary Group
|
||||
|
||||
custom_field:
|
||||
nav_label: "Custom Fields"
|
||||
|
|
|
@ -666,6 +666,9 @@ class CustomWizard::Action
|
|||
visibility_level
|
||||
members_visibility_level
|
||||
grant_trust_level
|
||||
public_exit
|
||||
public_admission
|
||||
primary_group
|
||||
).each do |attr|
|
||||
input = action[attr]
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
# name: discourse-custom-wizard
|
||||
# about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more.
|
||||
# version: 2.6.0
|
||||
# version: 2.6.3
|
||||
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever, Juan Marcos Gutierrez Ramos
|
||||
# url: https://github.com/paviliondev/discourse-custom-wizard
|
||||
# contact_emails: development@pavilion.tech
|
||||
|
@ -9,7 +9,7 @@
|
|||
# meta_topic_id: 73345
|
||||
|
||||
gem 'liquid', '5.0.1', require: true
|
||||
gem "discourse_subscription_client", "0.1.1", require_name: "discourse_subscription_client"
|
||||
gem "discourse_subscription_client", "0.1.2", require_name: "discourse_subscription_client"
|
||||
gem 'discourse_plugin_statistics', '0.1.0.pre7', require: true
|
||||
register_asset 'stylesheets/common/admin.scss'
|
||||
register_asset 'stylesheets/common/wizard.scss'
|
||||
|
|
26
spec/fixtures/actions/create_group.json
gevendort
26
spec/fixtures/actions/create_group.json
gevendort
|
@ -100,5 +100,29 @@
|
|||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"public_exit": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"public_admission": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"primary_group": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
26
spec/fixtures/actions/create_group_bad_user.json
gevendort
26
spec/fixtures/actions/create_group_bad_user.json
gevendort
|
@ -100,5 +100,29 @@
|
|||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"public_exit": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"public_admission": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
],
|
||||
"primary_group": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "false",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { visit } from "@ember/test-helpers";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import {
|
||||
acceptance,
|
||||
|
@ -12,9 +12,12 @@ import {
|
|||
wizardGuest,
|
||||
wizardNoUser,
|
||||
wizardNotPermitted,
|
||||
wizardResumeOnRevisit,
|
||||
} from "../helpers/wizard";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import sinon from "sinon";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import I18n from "I18n";
|
||||
|
||||
acceptance("Wizard | Not logged in", function (needs) {
|
||||
needs.pretender((server, helper) => {
|
||||
|
@ -194,3 +197,53 @@ acceptance("Wizard | Guest access", function (needs) {
|
|||
assert.strictEqual($("body.custom-wizard").length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Wizard | Resume on revisit", function (needs) {
|
||||
needs.user();
|
||||
|
||||
test("Shows dialog", async function (assert) {
|
||||
pretender.get("/w/wizard.json", () => {
|
||||
return response(wizardResumeOnRevisit);
|
||||
});
|
||||
|
||||
await visit("/w/wizard");
|
||||
|
||||
assert.strictEqual(count(".dialog-content:visible"), 1);
|
||||
assert.strictEqual(
|
||||
query(".dialog-header h3").textContent.trim(),
|
||||
I18n.t("wizard.incomplete_submission.title", {
|
||||
date: moment(wizardResumeOnRevisit.submission_last_updated_at).format(
|
||||
"MMMM Do YYYY"
|
||||
),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("Resumes when resumed", async function (assert) {
|
||||
pretender.get("/w/wizard.json", () => {
|
||||
return response(wizardResumeOnRevisit);
|
||||
});
|
||||
await visit("/w/wizard");
|
||||
await click(".dialog-footer .btn-primary");
|
||||
assert.strictEqual(count(".dialog-content:visible"), 0);
|
||||
});
|
||||
|
||||
test("Restarts when restarted", async function (assert) {
|
||||
sinon.stub(DiscourseURL, "redirectTo");
|
||||
let skips = 0;
|
||||
pretender.get("/w/wizard.json", () => {
|
||||
return response(wizardResumeOnRevisit);
|
||||
});
|
||||
pretender.put("/w/wizard/skip", () => {
|
||||
skips++;
|
||||
return response({});
|
||||
});
|
||||
await visit("/w/wizard");
|
||||
await click(".dialog-footer .btn-default");
|
||||
assert.strictEqual(skips, 1);
|
||||
assert.ok(
|
||||
DiscourseURL.redirectTo.calledWith("/w/wizard"),
|
||||
"resuming wizard works"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,6 +23,10 @@ wizard.resume_on_revisit = false;
|
|||
wizard.submission_last_updated_at = "2022-03-11T20:00:18+01:00";
|
||||
wizard.subscribed = false;
|
||||
|
||||
const wizardResumeOnRevisit = cloneJSON(wizard);
|
||||
wizardResumeOnRevisit.start = "step_2";
|
||||
wizardResumeOnRevisit.resume_on_revisit = true;
|
||||
|
||||
const stepNotPermitted = cloneJSON(wizard);
|
||||
stepNotPermitted.steps[0].permitted = false;
|
||||
|
||||
|
@ -44,6 +48,7 @@ export {
|
|||
wizardNotPermitted,
|
||||
wizardCompleted,
|
||||
wizardGuest,
|
||||
wizardResumeOnRevisit,
|
||||
stepNotPermitted,
|
||||
allFieldsWizard,
|
||||
wizard,
|
||||
|
|
Laden …
In neuem Issue referenzieren