Commits vergleichen
6 Commits
main
...
update_sub
Autor | SHA1 | Datum | |
---|---|---|---|
|
16eb609b55 | ||
|
a81b4f8eb5 | ||
|
7c84deda18 | ||
|
d351577ea3 | ||
|
5a347b656a | ||
|
7de00ca040 |
586 geänderte Dateien mit 9242 neuen und 58044 gelöschten Zeilen
|
@ -1,3 +1,2 @@
|
|||
3.1.999: 1f35b80f85e5fd1efb7f4851f0845700432febdc
|
||||
2.7.99: e07a57e398b6b1676ab42a7e34467556fca5416b
|
||||
2.5.1: bb85b3a0d2c0ab6b59bcb405731c39089ec6731c
|
||||
|
|
13
.github/workflows/discourse-plugin.yml
gevendort
13
.github/workflows/discourse-plugin.yml
gevendort
|
@ -1,13 +0,0 @@
|
|||
name: Discourse Plugin
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1
|
56
.github/workflows/plugin-linting.yml
gevendort
Normale Datei
56
.github/workflows/plugin-linting.yml
gevendort
Normale Datei
|
@ -0,0 +1,56 @@
|
|||
name: Linting
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- stable
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
- name: Set up ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.7
|
||||
|
||||
- name: Setup bundler
|
||||
run: gem install bundler -v 2.1.4 --no-doc
|
||||
|
||||
- name: Setup gems
|
||||
run: bundle install --jobs 4
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install --dev
|
||||
|
||||
- name: ESLint
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern {test,assets}/javascripts
|
||||
|
||||
- name: Prettier
|
||||
run: |
|
||||
yarn prettier -v
|
||||
if [ -d "assets" ]; then \
|
||||
yarn prettier --list-different "assets/**/*.{scss,js,es6}" ; \
|
||||
fi
|
||||
if [ -d "test" ]; then \
|
||||
yarn prettier --list-different "test/**/*.{js,es6}" ; \
|
||||
fi
|
||||
|
||||
- name: Ember template lint
|
||||
run: yarn ember-template-lint assets/javascripts
|
||||
|
||||
- name: Rubocop
|
||||
run: bundle exec rubocop .
|
10
.github/workflows/plugin-metadata.yml
gevendort
10
.github/workflows/plugin-metadata.yml
gevendort
|
@ -36,9 +36,9 @@ jobs:
|
|||
uses: actions/github-script@v5
|
||||
with:
|
||||
script: |
|
||||
const semver = require('semver');
|
||||
const { head_version, base_version } = process.env;
|
||||
const semver = require('semver');
|
||||
const { head_version, base_version } = process.env;
|
||||
|
||||
if (semver.lte(head_version, base_version)) {
|
||||
core.setFailed("Head version is equal to or lower than base version.");
|
||||
}
|
||||
if (semver.lte(head_version, base_version)) {
|
||||
core.setFailed("Head version is equal to or lower than base version.");
|
||||
}
|
||||
|
|
141
.github/workflows/plugin-tests.yml
gevendort
Normale Datei
141
.github/workflows/plugin-tests.yml
gevendort
Normale Datei
|
@ -0,0 +1,141 @@
|
|||
name: Plugin Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- stable
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 */12 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.build_type }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
DISCOURSE_HOSTNAME: www.example.com
|
||||
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
|
||||
RAILS_ENV: test
|
||||
PGHOST: localhost
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
build_type: ["backend", "frontend"]
|
||||
ruby: ["2.7"]
|
||||
postgres: ["12"]
|
||||
redis: ["4.x"]
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:${{ matrix.postgres }}
|
||||
ports:
|
||||
- 5432:5432
|
||||
env:
|
||||
POSTGRES_USER: discourse
|
||||
POSTGRES_PASSWORD: discourse
|
||||
options: >-
|
||||
--mount type=tmpfs,destination=/var/lib/postgresql/data
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: discourse/discourse
|
||||
ref: "tests-passed"
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Fetch Repo Name
|
||||
id: repo-name
|
||||
run: echo "::set-output name=value::$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')"
|
||||
|
||||
- name: Install plugin
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: plugins/${{ steps.repo-name.outputs.value }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Check spec existence
|
||||
id: check_spec
|
||||
uses: andstor/file-existence-action@v1
|
||||
with:
|
||||
files: "plugins/${{ steps.repo-name.outputs.value }}/spec"
|
||||
|
||||
- name: Check qunit existence
|
||||
id: check_qunit
|
||||
uses: andstor/file-existence-action@v1
|
||||
with:
|
||||
files: "plugins/${{ steps.repo-name.outputs.value }}/test/javascripts"
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Setup packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev gifsicle jpegoptim optipng jhead
|
||||
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh
|
||||
|
||||
- name: Update imagemagick
|
||||
if: matrix.build_type == 'backend'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-imagemagick
|
||||
chmod +x install-imagemagick
|
||||
sudo ./install-imagemagick
|
||||
|
||||
- name: Setup redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
|
||||
- name: Setup ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Lint English locale
|
||||
if: matrix.build_type == 'backend'
|
||||
run: bundle exec ruby script/i18n_lint.rb "plugins/${{ steps.repo-name.outputs.value }}/locales/{client,server}.en.yml"
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ matrix.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install --dev
|
||||
|
||||
- name: Migrate database
|
||||
run: |
|
||||
bin/rake db:create
|
||||
bin/rake db:migrate
|
||||
|
||||
- name: Plugin RSpec with Coverage
|
||||
if: matrix.build_type == 'backend' && steps.check_spec.outputs.files_exists == 'true'
|
||||
run: SIMPLECOV=1 bin/rake plugin:spec[${{ steps.repo-name.outputs.value }}]
|
||||
|
||||
- name: Plugin QUnit
|
||||
if: matrix.build_type == 'frontend' && steps.check_qunit.outputs.files_exists == 'true'
|
||||
run: bundle exec rake plugin:qunit['${{ steps.repo-name.outputs.value }}','1200000']
|
||||
timeout-minutes: 30
|
3
.gitignore
gevendort
3
.gitignore
gevendort
|
@ -1,8 +1,7 @@
|
|||
coverage/*
|
||||
!coverage/.last_run.json
|
||||
gems/*
|
||||
gems/
|
||||
.bundle/
|
||||
auto_generated
|
||||
.DS_Store
|
||||
node_modules/
|
||||
vendor/*
|
||||
|
|
|
@ -1,8 +1,2 @@
|
|||
inherit_gem:
|
||||
rubocop-discourse: default.yml
|
||||
|
||||
RSpec/ContextWording:
|
||||
Enabled: false
|
||||
|
||||
RSpec/DescribeClass:
|
||||
Enabled: false
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
plugin = "discourse-custom-wizard"
|
||||
|
||||
SimpleCov.configure do
|
||||
track_files "plugins/#{plugin}/**/*.rb"
|
||||
add_filter { |src| !(src.filename =~ /(\/#{plugin}\/app\/|\/#{plugin}\/lib\/)/) }
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
All code in this repository is Copyright 2023 by Angus McLeod.
|
||||
All code in this repository is Copyright 2018 by Angus McLeod.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
31
Gemfile.lock
31
Gemfile.lock
|
@ -2,32 +2,31 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
ast (2.4.2)
|
||||
json (2.6.2)
|
||||
parallel (1.22.1)
|
||||
parser (3.1.2.1)
|
||||
parallel (1.20.1)
|
||||
parser (3.0.1.0)
|
||||
ast (~> 2.4.1)
|
||||
rainbow (3.1.1)
|
||||
regexp_parser (2.6.0)
|
||||
rainbow (3.0.0)
|
||||
regexp_parser (2.1.1)
|
||||
rexml (3.2.5)
|
||||
rubocop (1.36.0)
|
||||
json (~> 2.3)
|
||||
rubocop (1.12.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.1.2.1)
|
||||
parser (>= 3.0.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.20.1, < 2.0)
|
||||
rexml
|
||||
rubocop-ast (>= 1.2.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.22.0)
|
||||
parser (>= 3.1.1.0)
|
||||
rubocop-discourse (3.0)
|
||||
rubocop-ast (1.4.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.13.2)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-rspec (2.2.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-progressbar (1.11.0)
|
||||
unicode-display_width (2.3.0)
|
||||
unicode-display_width (2.0.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
|
28
README.md
28
README.md
|
@ -1,27 +1,3 @@
|
|||
# Discourse Custom Wizard Plugin
|
||||
# discourse-custom-wizard
|
||||
|
||||
The Custom Wizard Plugin lets you make forms for your Discourse forum. Better user onboarding, structured posting, data enrichment, automated actions and much more for your community.
|
||||
|
||||
<img src="https://camo.githubusercontent.com/593432f1fc9658ffca104065668cc88fa21dffcd3002cb78ffd50c71f33a2523/68747470733a2f2f706176696c696f6e2d6173736574732e6e7963332e63646e2e6469676974616c6f6365616e7370616365732e636f6d2f706c7567696e732f77697a6172642d7265706f7369746f72792d62616e6e65722e706e67" alt="" data-canonical-src="https://pavilion-assets.nyc3.cdn.digitaloceanspaces.com/plugins/wizard-repository-banner.png" style="max-width: 100%;" width="400">
|
||||
|
||||
👋 Looking to report an issue? We're managing issues for this plugin using our [bug report wizard](https://coop.pavilion.tech/w/bug-report).
|
||||
|
||||
## Install
|
||||
|
||||
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.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Read the full documentation here](https://coop.pavilion.tech/c/82), 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://coop.pavilion.tech/t/1735)
|
||||
- [Field Settings](https://coop.pavilion.tech/t/1580)
|
||||
- [Conditional Settings](https://coop.pavilion.tech/t/1673)
|
||||
- [Field Interpolation](https://coop.pavilion.tech/t/1557)
|
||||
- [Handling Dates and Times](https://coop.pavilion.tech/t/1708)
|
||||
|
||||
## Support
|
||||
|
||||
- [Report an issue](https://coop.pavilion.tech/w/bug-report)
|
||||
See further: https://thepavilion.io/c/knowledge/discourse/custom-wizard/118
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
The security of Discourse plugins are premised on the security of [Discourse](https://github.com/discourse/discourse). Please first consider whether a security issue is best reported and handled by the Discourse team. You can view the Discourse security policy [here](https://github.com/discourse/discourse/security/policy).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find a security vulnerability that is specific to this plugin, please report it to development@pavilion.tech. Security issues always take precedence over all other work. All commits specific to security are prefixed with SECURITY.
|
|
@ -1,39 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::WizardController < ::CustomWizard::WizardClientController
|
||||
def show
|
||||
if wizard.present?
|
||||
render json: CustomWizard::WizardSerializer.new(wizard, scope: guardian, root: false).as_json, status: 200
|
||||
else
|
||||
render json: { error: I18n.t('wizard.none') }
|
||||
end
|
||||
end
|
||||
|
||||
def skip
|
||||
params.require(:wizard_id)
|
||||
|
||||
if wizard.required && !wizard.completed? && wizard.permitted?
|
||||
return render json: { error: I18n.t('wizard.no_skip') }
|
||||
end
|
||||
|
||||
result = { success: 'OK' }
|
||||
|
||||
if current_user && wizard.can_access?
|
||||
if redirect_to = wizard.current_submission&.redirect_to
|
||||
result.merge!(redirect_to: redirect_to)
|
||||
end
|
||||
|
||||
wizard.cleanup_on_skip!
|
||||
end
|
||||
|
||||
render json: result
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def wizard
|
||||
@wizard ||= begin
|
||||
return nil unless @builder.present?
|
||||
@builder.build({ reset: params[:reset] }, params)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::WizardClientController < ::ApplicationController
|
||||
before_action :ensure_plugin_enabled
|
||||
before_action :set_builder
|
||||
|
||||
private
|
||||
|
||||
def ensure_plugin_enabled
|
||||
unless SiteSetting.custom_wizard_enabled
|
||||
redirect_to path("/")
|
||||
end
|
||||
end
|
||||
|
||||
def guest_id
|
||||
return nil if current_user.present?
|
||||
cookies[:custom_wizard_guest_id] ||= CustomWizard::Wizard.generate_guest_id
|
||||
cookies[:custom_wizard_guest_id]
|
||||
end
|
||||
|
||||
def set_builder
|
||||
@builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user, guest_id)
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::SubmissionSerializer < ApplicationSerializer
|
||||
attributes :id,
|
||||
:fields,
|
||||
:submitted_at,
|
||||
:user
|
||||
|
||||
def include_user?
|
||||
object.wizard.user.present?
|
||||
end
|
||||
|
||||
def user
|
||||
::BasicUserSerializer.new(object.wizard.user, root: false).as_json
|
||||
end
|
||||
|
||||
def fields
|
||||
@fields ||= begin
|
||||
result = {}
|
||||
|
||||
object.wizard.template['steps'].each do |step|
|
||||
step['fields'].each do |field|
|
||||
if value = object.fields[field['id']]
|
||||
result[field['id']] = {
|
||||
value: value,
|
||||
type: field['type'],
|
||||
label: field['label']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Custom Wizard QUnit Test Runner</title>
|
||||
<%= discourse_stylesheet_link_tag(:test_helper, theme_id: nil) %>
|
||||
<%= discourse_stylesheet_link_tag :wizard, theme_id: nil %>
|
||||
<%= discourse_stylesheet_link_tag :wizard_custom %>
|
||||
<%= preload_script "locales/en" %>
|
||||
<%= preload_script "ember_jquery" %>
|
||||
<%= preload_script "wizard-vendor" %>
|
||||
<%= preload_script "wizard-custom" %>
|
||||
<%= preload_script "wizard-raw-templates" %>
|
||||
<%= preload_script "wizard-plugin" %>
|
||||
<%= preload_script "pretty-text-bundle" %>
|
||||
<%= preload_script "wizard-qunit" %>
|
||||
<%= csrf_meta_tags %>
|
||||
|
||||
<script src="<%= ExtraLocalesController.url("wizard") %>"></script>
|
||||
|
||||
<%= tag.meta id: 'data-discourse-setup', data: client_side_setup_data %>
|
||||
<meta name="discourse_theme_id" content="">
|
||||
<meta name="discourse-base-uri" content="<%= Discourse.base_path %>">
|
||||
</head>
|
||||
<body class="custom-wizard">
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -2,6 +2,7 @@ import Component from "@ember/component";
|
|||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { alias, equal, or } from "@ember/object/computed";
|
||||
import I18n from "I18n";
|
||||
import { buildSubscriptionContent } from "../lib/wizard";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "tr",
|
||||
|
@ -35,6 +36,16 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@discourseComputed("subscription")
|
||||
customFieldTypes(subscription) {
|
||||
return buildSubscriptionContent("custom_fields", "types", subscription);
|
||||
},
|
||||
|
||||
@discourseComputed("subscription")
|
||||
customFieldKlasses(subscription) {
|
||||
return buildSubscriptionContent("custom_fields", "klass", subscription);
|
||||
},
|
||||
|
||||
@observes("field.klass")
|
||||
clearSerializersWhenClassChanges() {
|
||||
this.set("field.serializers", null);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,13 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
keyPress(e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
actions: {
|
||||
onChangeValue(value) {
|
||||
this.set("field.value", value);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,3 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,3 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,7 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
keyPress(e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
keyPress(e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,5 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: ["fieldClass"],
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import { dasherize } from "@ember/string";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { cookAsync } from "discourse/lib/text";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [
|
||||
":wizard-field",
|
||||
"typeClasses",
|
||||
"field.invalid",
|
||||
"field.id",
|
||||
],
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
cookAsync(this.field.translatedDescription).then((cookedDescription) => {
|
||||
this.set("cookedDescription", cookedDescription);
|
||||
});
|
||||
},
|
||||
|
||||
@discourseComputed("field.type", "field.id")
|
||||
typeClasses: (type, id) =>
|
||||
`${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`,
|
||||
|
||||
@discourseComputed("field.id")
|
||||
fieldClass: (id) => `field-${dasherize(id)} wizard-focusable`,
|
||||
|
||||
@discourseComputed("field.type", "field.id")
|
||||
inputComponentName(type, id) {
|
||||
if (["text_only"].includes(type)) {
|
||||
return false;
|
||||
}
|
||||
return dasherize(type === "component" ? id : `custom-wizard-field-${type}`);
|
||||
},
|
||||
|
||||
@discourseComputed("field.type")
|
||||
textType(fieldType) {
|
||||
return ["text", "textarea"].includes(fieldType);
|
||||
},
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
import CustomWizard from "../models/custom-wizard";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { dasherize } from "@ember/string";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":wizard-no-access", "reasonClass"],
|
||||
|
||||
@discourseComputed("reason")
|
||||
reasonClass(reason) {
|
||||
return dasherize(reason);
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
siteName() {
|
||||
return this.siteSettings.title || "";
|
||||
},
|
||||
|
||||
actions: {
|
||||
skip() {
|
||||
if (this.currentUser) {
|
||||
CustomWizard.skip(this.get("wizardId"));
|
||||
} else {
|
||||
window.location = getURL("/");
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":wizard-step-form", "customStepClass"],
|
||||
|
||||
@discourseComputed("step.id")
|
||||
customStepClass: (stepId) => `wizard-step-${stepId}`,
|
||||
});
|
|
@ -1,227 +0,0 @@
|
|||
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";
|
||||
import { cookAsync } from "discourse/lib/text";
|
||||
import CustomWizard, {
|
||||
updateCachedWizard,
|
||||
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
|
||||
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,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("stylingDropdown", {});
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
cookAsync(this.step.translatedTitle).then((cookedTitle) => {
|
||||
this.set("cookedTitle", cookedTitle);
|
||||
});
|
||||
cookAsync(this.step.translatedDescription).then((cookedDescription) => {
|
||||
this.set("cookedDescription", cookedDescription);
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.autoFocus();
|
||||
},
|
||||
|
||||
@discourseComputed("step.index", "wizard.required")
|
||||
showQuitButton: (index, required) => index === 0 && !required,
|
||||
|
||||
showNextButton: not("step.final"),
|
||||
showDoneButton: alias("step.final"),
|
||||
|
||||
@discourseComputed(
|
||||
"step.index",
|
||||
"step.displayIndex",
|
||||
"wizard.totalSteps",
|
||||
"wizard.completed"
|
||||
)
|
||||
showFinishButton: (index, displayIndex, total, completed) => {
|
||||
return index !== 0 && displayIndex !== total && completed;
|
||||
},
|
||||
|
||||
@discourseComputed("step.index")
|
||||
showBackButton: (index) => index > 0,
|
||||
|
||||
@discourseComputed("step.banner")
|
||||
bannerImage(src) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
return getUrl(src);
|
||||
},
|
||||
|
||||
@discourseComputed("step.id")
|
||||
bannerAndDescriptionClass(id) {
|
||||
return `wizard-banner-and-description wizard-banner-and-description-${id}`;
|
||||
},
|
||||
|
||||
@discourseComputed("step.fields.[]")
|
||||
primaryButtonIndex(fields) {
|
||||
return fields.length + 1;
|
||||
},
|
||||
|
||||
@discourseComputed("step.fields.[]")
|
||||
secondaryButtonIndex(fields) {
|
||||
return fields.length + 2;
|
||||
},
|
||||
|
||||
@observes("step.id")
|
||||
_stepChanged() {
|
||||
this.set("saving", false);
|
||||
this.autoFocus();
|
||||
},
|
||||
|
||||
@observes("step.message")
|
||||
_handleMessage: function () {
|
||||
const message = this.get("step.message");
|
||||
this.showMessage(message);
|
||||
},
|
||||
|
||||
@discourseComputed("step.index", "wizard.totalSteps")
|
||||
barStyle(displayIndex, totalSteps) {
|
||||
let ratio = parseFloat(displayIndex) / parseFloat(totalSteps - 1);
|
||||
if (ratio < 0) {
|
||||
ratio = 0;
|
||||
}
|
||||
if (ratio > 1) {
|
||||
ratio = 1;
|
||||
}
|
||||
|
||||
return htmlSafe(`width: ${ratio * 200}px`);
|
||||
},
|
||||
|
||||
@discourseComputed("step.fields")
|
||||
includeSidebar(fields) {
|
||||
return !!fields.findBy("show_in_sidebar");
|
||||
},
|
||||
|
||||
autoFocus() {
|
||||
discourseLater(() => {
|
||||
schedule("afterRender", () => {
|
||||
if ($(".invalid .wizard-focusable").length) {
|
||||
this.animateInvalidFields();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
animateInvalidFields() {
|
||||
schedule("afterRender", () => {
|
||||
let $invalid = $(".invalid .wizard-focusable");
|
||||
if ($invalid.length) {
|
||||
$([document.documentElement, document.body]).animate(
|
||||
{
|
||||
scrollTop: $invalid.offset().top - 200,
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
advance() {
|
||||
this.set("saving", true);
|
||||
this.get("step")
|
||||
.save()
|
||||
.then((response) => {
|
||||
updateCachedWizard(CustomWizard.build(response["wizard"]));
|
||||
|
||||
if (response["final"]) {
|
||||
CustomWizard.finished(response);
|
||||
} else {
|
||||
this.goNext(response);
|
||||
}
|
||||
})
|
||||
.catch(() => this.animateInvalidFields())
|
||||
.finally(() => this.set("saving", false));
|
||||
},
|
||||
|
||||
actions: {
|
||||
quit() {
|
||||
this.get("wizard").skip();
|
||||
},
|
||||
|
||||
done() {
|
||||
this.send("nextStep");
|
||||
},
|
||||
|
||||
showMessage(message) {
|
||||
this.sendAction(message);
|
||||
},
|
||||
|
||||
stylingDropdownChanged(id, value) {
|
||||
this.set("stylingDropdown", { id, value });
|
||||
},
|
||||
|
||||
exitEarly() {
|
||||
const step = this.step;
|
||||
step.validate();
|
||||
|
||||
if (step.get("valid")) {
|
||||
this.set("saving", true);
|
||||
|
||||
step
|
||||
.save()
|
||||
.then(() => this.send("quit"))
|
||||
.finally(() => this.set("saving", false));
|
||||
} else {
|
||||
this.autoFocus();
|
||||
}
|
||||
},
|
||||
|
||||
backStep() {
|
||||
if (this.saving) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.goBack();
|
||||
},
|
||||
|
||||
nextStep() {
|
||||
if (this.saving) {
|
||||
return;
|
||||
}
|
||||
|
||||
const step = this.step;
|
||||
const result = 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")) {
|
||||
this.advance();
|
||||
} else {
|
||||
this.autoFocus();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
import TagChooser from "select-kit/components/tag-chooser";
|
||||
|
||||
export default TagChooser.extend({
|
||||
searchTags(url, data, callback) {
|
||||
if (this.tagGroups) {
|
||||
let tagGroupsString = this.tagGroups.join(",");
|
||||
data.filterForInput = {
|
||||
name: "custom-wizard-tag-chooser",
|
||||
groups: tagGroupsString,
|
||||
};
|
||||
}
|
||||
|
||||
return this._super(url, data, callback);
|
||||
},
|
||||
});
|
|
@ -1,34 +0,0 @@
|
|||
<DModal @closeModal={{@closeModal}} @title={{this.title}}>
|
||||
{{#if loading}}
|
||||
<LoadingSpinner size="large" />
|
||||
{{else}}
|
||||
<div class="edit-directory-columns-container">
|
||||
{{#each @model.columns as |column|}}
|
||||
<div class="edit-directory-column">
|
||||
<div class="left-content">
|
||||
<label class="column-name">
|
||||
<Input @type="checkbox" @checked={{column.enabled}} />
|
||||
{{directory-table-header-title
|
||||
field=column.label
|
||||
translated=true
|
||||
}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="modal-footer">
|
||||
<DButton
|
||||
class="btn-primary"
|
||||
@label="directory.edit_columns.save"
|
||||
@action={{action "save"}}
|
||||
/>
|
||||
|
||||
<DButton
|
||||
class="btn-secondary reset-to-default"
|
||||
@label="directory.edit_columns.reset_to_default"
|
||||
@action={{action "resetToDefault"}}
|
||||
/>
|
||||
</div>
|
||||
</DModal>
|
|
@ -1,15 +0,0 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default class AdminWizardsColumnComponent extends Component {
|
||||
title = I18n.t("admin.wizard.edit_columns");
|
||||
|
||||
@action save() {
|
||||
this.args.closeModal();
|
||||
}
|
||||
|
||||
@action resetToDefault() {
|
||||
this.args.model.reset();
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<DModal
|
||||
@closeModal={{@closeModal}}
|
||||
class="next-session-time-modal"
|
||||
@title={{this.title}}
|
||||
>
|
||||
<DateTimeInput
|
||||
@date={{this.bufferedDateTime}}
|
||||
@onChange={{action "dateTimeChanged"}}
|
||||
@showTime="true"
|
||||
@clearable="true"
|
||||
/>
|
||||
<div class="modal-footer">
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
class="btn-primary"
|
||||
@label="admin.wizard.after_time_modal.done"
|
||||
@disabled={{this.submitDisabled}}
|
||||
/>
|
||||
</div>
|
||||
</DModal>
|
|
@ -1,30 +0,0 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default class NextSessionScheduledComponent extends Component {
|
||||
@tracked bufferedDateTime;
|
||||
title = I18n.t("admin.wizard.after_time_modal.title");
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.bufferedDateTime = this.args.model.dateTime
|
||||
? moment(this.args.model.dateTime)
|
||||
: moment(Date.now());
|
||||
}
|
||||
|
||||
get submitDisabled() {
|
||||
return moment().isAfter(this.bufferedDateTime);
|
||||
}
|
||||
|
||||
@action submit() {
|
||||
const dateTime = this.bufferedDateTime;
|
||||
this.args.model.update(moment(dateTime).utc().toISOString());
|
||||
this.args.closeModal();
|
||||
}
|
||||
|
||||
@action dateTimeChanged(dateTime) {
|
||||
this.bufferedDateTime = dateTime;
|
||||
}
|
||||
}
|
|
@ -1,25 +1,24 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Subscription from "../mixins/subscription";
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
classNameBindings: [":wizard-subscription-container", "subscribed"],
|
||||
export default Component.extend({
|
||||
classNameBindings: [":subscription-container", "subscribed"],
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedIcon(subscribed) {
|
||||
return subscribed ? "check" : "times";
|
||||
return subscribed ? "check" : "dash";
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedLabel(subscribed) {
|
||||
return `admin.wizard.subscription.${
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.label`;
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedTitle(subscribed) {
|
||||
return `admin.wizard.subscription.${
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.title`;
|
||||
},
|
|
@ -1,6 +1,10 @@
|
|||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||
import { empty, equal, or } from "@ember/object/computed";
|
||||
import { notificationLevels, selectKitContent } from "../lib/wizard";
|
||||
import {
|
||||
buildSubscriptionContent,
|
||||
notificationLevels,
|
||||
selectKitContent,
|
||||
} from "../lib/wizard";
|
||||
import { computed } from "@ember/object";
|
||||
import UndoChanges from "../mixins/undo-changes";
|
||||
import Component from "@ember/component";
|
||||
|
@ -15,7 +19,6 @@ export default Component.extend(UndoChanges, {
|
|||
createTopic: equal("action.type", "create_topic"),
|
||||
updateProfile: equal("action.type", "update_profile"),
|
||||
watchCategories: equal("action.type", "watch_categories"),
|
||||
watchTags: equal("action.type", "watch_tags"),
|
||||
sendMessage: equal("action.type", "send_message"),
|
||||
openComposer: equal("action.type", "open_composer"),
|
||||
sendToApi: equal("action.type", "send_to_api"),
|
||||
|
@ -37,11 +40,13 @@ export default Component.extend(UndoChanges, {
|
|||
availableNotificationLevels: notificationLevels.map((type) => {
|
||||
return {
|
||||
id: type,
|
||||
name: I18n.t(`admin.wizard.action.watch_x.notification_level.${type}`),
|
||||
name: I18n.t(
|
||||
`admin.wizard.action.watch_categories.notification_level.${type}`
|
||||
),
|
||||
};
|
||||
}),
|
||||
|
||||
messageUrl: "https://discourse.pluginmanager.org/t/action-settings",
|
||||
messageUrl: "https://thepavilion.io/t/2810",
|
||||
|
||||
@discourseComputed("action.type")
|
||||
messageKey(type) {
|
||||
|
@ -92,13 +97,8 @@ export default Component.extend(UndoChanges, {
|
|||
return apis.find((a) => a.name === api).endpoints;
|
||||
},
|
||||
|
||||
@discourseComputed("fieldTypes")
|
||||
hasEventField(fieldTypes) {
|
||||
return fieldTypes.map((ft) => ft.id).includes("event");
|
||||
},
|
||||
|
||||
@discourseComputed("fieldTypes")
|
||||
hasLocationField(fieldTypes) {
|
||||
return fieldTypes.map((ft) => ft.id).includes("location");
|
||||
@discourseComputed("subscription")
|
||||
actionTypes(subscription) {
|
||||
return buildSubscriptionContent("action", "type", subscription);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -27,7 +27,7 @@ export default Component.extend(UndoChanges, {
|
|||
isTextType: or("isText", "isTextarea", "isComposer"),
|
||||
isComposerPreview: equal("field.type", "composer_preview"),
|
||||
categoryPropertyTypes: selectKitContent(["id", "slug"]),
|
||||
messageUrl: "https://discourse.pluginmanager.org/t/field-settings",
|
||||
messageUrl: "https://thepavilion.io/t/2809",
|
||||
|
||||
@discourseComputed("field.type")
|
||||
validations(type) {
|
||||
|
@ -85,8 +85,8 @@ export default Component.extend(UndoChanges, {
|
|||
if (this.isDropdown) {
|
||||
options.wizardFieldSelection = "key,value";
|
||||
options.userFieldOptionsSelection = "output";
|
||||
options.textSelection = "key,value";
|
||||
options.inputTypes = "association,conditional,assignment";
|
||||
options.textSelection = "key,value,output";
|
||||
options.inputTypes = "conditional,association,assignment";
|
||||
options.pairConnector = "association";
|
||||
options.keyPlaceholder = "admin.wizard.key";
|
||||
options.valuePlaceholder = "admin.wizard.value";
|
||||
|
@ -143,17 +143,11 @@ export default Component.extend(UndoChanges, {
|
|||
|
||||
actions: {
|
||||
imageUploadDone(upload) {
|
||||
this.setProperties({
|
||||
"field.image": upload.url,
|
||||
"field.image_upload_id": upload.id,
|
||||
});
|
||||
this.set("field.image", upload.url);
|
||||
},
|
||||
|
||||
imageUploadDeleted() {
|
||||
this.setProperties({
|
||||
"field.image": null,
|
||||
"field.image_upload_id": null,
|
||||
});
|
||||
this.set("field.image", null);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -24,17 +24,11 @@ export default Component.extend({
|
|||
|
||||
actions: {
|
||||
bannerUploadDone(upload) {
|
||||
this.setProperties({
|
||||
"step.banner": upload.url,
|
||||
"step.banner_upload_id": upload.id,
|
||||
});
|
||||
this.set("step.banner", upload.url);
|
||||
},
|
||||
|
||||
bannerUploadDeleted() {
|
||||
this.setProperties({
|
||||
"step.banner": null,
|
||||
"step.banner_upload_id": null,
|
||||
});
|
||||
this.set("step.banner", null);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -71,17 +71,6 @@ export default Component.extend({
|
|||
});
|
||||
},
|
||||
|
||||
getNextIndex() {
|
||||
const items = this.items;
|
||||
if (!items || items.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const numbers = items
|
||||
.map((i) => Number(i.id.split("_").pop()))
|
||||
.sort((a, b) => a - b);
|
||||
return numbers[numbers.length - 1];
|
||||
},
|
||||
|
||||
actions: {
|
||||
add() {
|
||||
const items = this.get("items");
|
||||
|
@ -89,9 +78,15 @@ export default Component.extend({
|
|||
let params = setWizardDefaults({}, itemType);
|
||||
|
||||
params.isNew = true;
|
||||
params.index = this.getNextIndex();
|
||||
|
||||
let id = `${itemType}_${params.index + 1}`;
|
||||
let index = 0;
|
||||
if (items.length) {
|
||||
index = items.length;
|
||||
}
|
||||
|
||||
params.index = index;
|
||||
|
||||
let id = `${itemType}_${index + 1}`;
|
||||
if (itemType === "field") {
|
||||
id = `${this.parentId}_${id}`;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
import Component from "@ember/component";
|
||||
import { bind, later } from "@ember/runloop";
|
||||
import I18n from "I18n";
|
||||
import Subscription from "../mixins/subscription";
|
||||
|
||||
const customFieldActionMap = {
|
||||
topic: ["create_topic", "send_message"],
|
||||
|
@ -27,7 +26,7 @@ const customFieldActionMap = {
|
|||
|
||||
const values = ["present", "true", "false"];
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
export default Component.extend({
|
||||
classNameBindings: [":mapper-selector", "activeType"],
|
||||
|
||||
showText: computed("activeType", function () {
|
||||
|
@ -117,9 +116,6 @@ export default Component.extend(Subscription, {
|
|||
groupEnabled: computed("options.groupSelection", "inputType", function () {
|
||||
return this.optionEnabled("groupSelection");
|
||||
}),
|
||||
guestGroup: computed("options.guestGroup", "inputType", function () {
|
||||
return this.optionEnabled("guestGroup");
|
||||
}),
|
||||
userEnabled: computed("options.userSelection", "inputType", function () {
|
||||
return this.optionEnabled("userSelection");
|
||||
}),
|
||||
|
@ -130,29 +126,7 @@ export default Component.extend(Subscription, {
|
|||
return this.connector === "is";
|
||||
}),
|
||||
|
||||
@discourseComputed("site.groups", "guestGroup", "subscriptionType")
|
||||
groups(groups, guestGroup, subscriptionType) {
|
||||
let result = groups;
|
||||
if (!guestGroup) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (["standard", "business"].includes(subscriptionType)) {
|
||||
let guestIndex;
|
||||
result.forEach((r, index) => {
|
||||
if (r.id === 0) {
|
||||
r.name = I18n.t("admin.wizard.selector.label.users");
|
||||
guestIndex = index;
|
||||
}
|
||||
});
|
||||
result.splice(guestIndex, 0, {
|
||||
id: -1,
|
||||
name: I18n.t("admin.wizard.selector.label.guests"),
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
groups: alias("site.groups"),
|
||||
categories: alias("site.categories"),
|
||||
showComboBox: or(
|
||||
"showWizardField",
|
||||
|
@ -403,7 +377,7 @@ export default Component.extend(Subscription, {
|
|||
this.changeValue(event.target.value);
|
||||
},
|
||||
|
||||
changeUserValue(value) {
|
||||
changeUserValue(previousValue, value) {
|
||||
this.changeValue(value);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -32,7 +32,6 @@ export default Component.extend({
|
|||
pairConnector: options.pairConnector || null,
|
||||
outputConnector: options.outputConnector || null,
|
||||
context: options.context || null,
|
||||
guestGroup: options.guestGroup || false,
|
||||
};
|
||||
|
||||
let inputTypes = ["key", "value", "output"];
|
||||
|
|
19
assets/javascripts/discourse/components/wizard-notice-row.js.es6
Normale Datei
19
assets/javascripts/discourse/components/wizard-notice-row.js.es6
Normale Datei
|
@ -0,0 +1,19 @@
|
|||
import Component from "@ember/component";
|
||||
import NoticeMessage from "../mixins/notice-message";
|
||||
|
||||
export default Component.extend(NoticeMessage, {
|
||||
tagName: "tr",
|
||||
attributeBindings: ["notice.id:data-notice-id"],
|
||||
classNameBindings: [
|
||||
":wizard-notice-row",
|
||||
"notice.typeClass",
|
||||
"notice.expired:expired",
|
||||
"notice.dismissed:dismissed",
|
||||
],
|
||||
|
||||
actions: {
|
||||
dismiss() {
|
||||
this.notice.dismiss();
|
||||
},
|
||||
},
|
||||
});
|
29
assets/javascripts/discourse/components/wizard-notice.js.es6
Normale Datei
29
assets/javascripts/discourse/components/wizard-notice.js.es6
Normale Datei
|
@ -0,0 +1,29 @@
|
|||
import Component from "@ember/component";
|
||||
import NoticeMessage from "../mixins/notice-message";
|
||||
|
||||
export default Component.extend(NoticeMessage, {
|
||||
attributeBindings: ["notice.id:data-notice-id"],
|
||||
classNameBindings: [
|
||||
":wizard-notice",
|
||||
"notice.typeClass",
|
||||
"notice.dismissed:dismissed",
|
||||
"notice.expired:expired",
|
||||
"notice.hidden:hidden",
|
||||
],
|
||||
|
||||
actions: {
|
||||
dismiss() {
|
||||
this.set("dismissing", true);
|
||||
this.notice.dismiss().then(() => {
|
||||
this.set("dismissing", false);
|
||||
});
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.set("hiding", true);
|
||||
this.notice.hide().then(() => {
|
||||
this.set("hiding", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,30 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Subscription from "../mixins/subscription";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
tagName: "a",
|
||||
classNameBindings: [":wizard-subscription-badge", "subscriptionType"],
|
||||
attributeBindings: ["title"],
|
||||
|
||||
@discourseComputed("subscriptionType")
|
||||
i18nKey(type) {
|
||||
return `admin.wizard.subscription.type.${type ? type : "none"}`;
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
title(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.title`);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
label(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.label`);
|
||||
},
|
||||
|
||||
click() {
|
||||
DiscourseURL.routeTo(this.subscriptionLink);
|
||||
},
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Subscription from "../mixins/subscription";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
tagName: "a",
|
||||
classNameBindings: [":btn", ":btn-pavilion-support", "subscriptionType"],
|
||||
attributeBindings: ["title"],
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
i18nKey(subscribed) {
|
||||
return `admin.wizard.subscription.cta.${
|
||||
subscribed ? "subscribed" : "none"
|
||||
}`;
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
icon(subscribed) {
|
||||
return subscribed ? "far-life-ring" : "external-link-alt";
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
title(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.title`);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
label(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.label`);
|
||||
},
|
||||
|
||||
click() {
|
||||
window.open(this.subscriptionCtaLink, "_blank").focus();
|
||||
},
|
||||
});
|
|
@ -1,18 +1,6 @@
|
|||
import SingleSelectComponent from "select-kit/components/single-select";
|
||||
import Subscription from "../mixins/subscription";
|
||||
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
const nameKey = function (feature, attribute, value) {
|
||||
if (feature === "action") {
|
||||
return `admin.wizard.action.${value}.label`;
|
||||
} else {
|
||||
return `admin.wizard.${feature}.${attribute}.${value}`;
|
||||
}
|
||||
};
|
||||
|
||||
export default SingleSelectComponent.extend(Subscription, {
|
||||
export default SingleSelectComponent.extend({
|
||||
classNames: ["combo-box", "wizard-subscription-selector"],
|
||||
|
||||
selectKitOptions: {
|
||||
|
@ -25,71 +13,6 @@ export default SingleSelectComponent.extend(Subscription, {
|
|||
caretDownIcon: "caret-down",
|
||||
},
|
||||
|
||||
allowedSubscriptionTypes(feature, attribute, value) {
|
||||
let attributes = this.subscriptionAttributes[feature];
|
||||
if (!attributes || !attributes[attribute]) {
|
||||
return ["none"];
|
||||
}
|
||||
let allowedTypes = [];
|
||||
Object.keys(attributes[attribute]).forEach((subscriptionType) => {
|
||||
let values = attributes[attribute][subscriptionType];
|
||||
if (values[0] === "*" || values.includes(value)) {
|
||||
allowedTypes.push(subscriptionType);
|
||||
}
|
||||
});
|
||||
return allowedTypes;
|
||||
},
|
||||
|
||||
@discourseComputed("feature", "attribute", "wizard.allowGuests")
|
||||
content(feature, attribute) {
|
||||
return filterValues(this.wizard, feature, attribute)
|
||||
.map((value) => {
|
||||
let allowedSubscriptionTypes = this.allowedSubscriptionTypes(
|
||||
feature,
|
||||
attribute,
|
||||
value
|
||||
);
|
||||
|
||||
let subscriptionRequired =
|
||||
allowedSubscriptionTypes.length &&
|
||||
!allowedSubscriptionTypes.includes("none");
|
||||
|
||||
let attrs = {
|
||||
id: value,
|
||||
name: I18n.t(nameKey(feature, attribute, value)),
|
||||
subscriptionRequired,
|
||||
};
|
||||
|
||||
if (subscriptionRequired) {
|
||||
let subscribed = allowedSubscriptionTypes.includes(
|
||||
this.subscriptionType
|
||||
);
|
||||
let selectorKey = subscribed ? "subscribed" : "not_subscribed";
|
||||
let selectorLabel = `admin.wizard.subscription.${selectorKey}.selector`;
|
||||
|
||||
attrs.disabled = !subscribed;
|
||||
attrs.selectorLabel = selectorLabel;
|
||||
}
|
||||
|
||||
return attrs;
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
if (a.subscriptionType && !b.subscriptionType) {
|
||||
return 1;
|
||||
}
|
||||
if (!a.subscriptionType && b.subscriptionType) {
|
||||
return -1;
|
||||
}
|
||||
if (a.subscriptionType === b.subscriptionType) {
|
||||
return a.subscriptionType
|
||||
? a.subscriptionType.localeCompare(b.subscriptionType)
|
||||
: 0;
|
||||
} else {
|
||||
return a.subscriptionType === "standard" ? -1 : 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
modifyComponentForRow() {
|
||||
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
||||
},
|
||||
|
|
55
assets/javascripts/discourse/components/wizard-subscription.js.es6
Normale Datei
55
assets/javascripts/discourse/components/wizard-subscription.js.es6
Normale Datei
|
@ -0,0 +1,55 @@
|
|||
import Component from "@ember/component";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [
|
||||
":custom-wizard-subscription",
|
||||
"subscription.active:active:inactive",
|
||||
],
|
||||
subscribed: notEmpty("subscription"),
|
||||
|
||||
@discourseComputed("subscription.type")
|
||||
title(type) {
|
||||
return type
|
||||
? I18n.t(`admin.wizard.subscription.subscription.title.${type}`)
|
||||
: I18n.t("admin.wizard.subscription.not_subscribed");
|
||||
},
|
||||
|
||||
@discourseComputed("subscription.active")
|
||||
stateClass(active) {
|
||||
return active ? "active" : "inactive";
|
||||
},
|
||||
|
||||
@discourseComputed("stateClass")
|
||||
stateLabel(stateClass) {
|
||||
return I18n.t(
|
||||
`admin.wizard.subscription.subscription.status.${stateClass}`
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
update() {
|
||||
this.set("updating", true);
|
||||
CustomWizardSubscription.update()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
||||
updateIcon: "check",
|
||||
subscription: result.subscription,
|
||||
});
|
||||
} else {
|
||||
this.set("updateIcon", "times");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("updating", false);
|
||||
setTimeout(() => {
|
||||
this.set("updateIcon", null);
|
||||
}, 7000);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -25,9 +25,9 @@ export default Component.extend({
|
|||
textState: "text-collapsed",
|
||||
toggleText: I18n.t("admin.wizard.expand_text"),
|
||||
|
||||
@discourseComputed("value", "isUser", "isSubmittedAt")
|
||||
hasValue(value, isUser, isSubmittedAt) {
|
||||
if (isUser || isSubmittedAt) {
|
||||
@discourseComputed("value", "isUser")
|
||||
hasValue(value, isUser) {
|
||||
if (isUser) {
|
||||
return value;
|
||||
}
|
||||
return value && value.value;
|
||||
|
|
|
@ -5,7 +5,11 @@ import { scheduleOnce } from "@ember/runloop";
|
|||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
|
||||
const excludedUserProperties = ["profile_background", "card_background"];
|
||||
const excludedUserProperties = [
|
||||
"avatar",
|
||||
"profile_background",
|
||||
"card_background",
|
||||
];
|
||||
|
||||
export default Component.extend({
|
||||
classNames: "wizard-text-editor",
|
||||
|
@ -48,12 +52,12 @@ export default Component.extend({
|
|||
|
||||
@discourseComputed("wizardFields")
|
||||
wizardFieldList(wizardFields) {
|
||||
return (wizardFields || []).map((f) => ` w{${f.id}}`);
|
||||
return wizardFields.map((f) => ` w{${f.id}}`);
|
||||
},
|
||||
|
||||
@discourseComputed("wizardActions")
|
||||
wizardActionList(wizardActions) {
|
||||
return (wizardActions || []).map((a) => ` w{${a.id}}`);
|
||||
return wizardActions.map((a) => ` w{${a.id}}`);
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{{#if notices}}
|
||||
{{#each notices as |notice|}}
|
||||
{{wizard-notice notice=notice showPlugin=true}}
|
||||
{{/each}}
|
||||
{{/if}}
|
|
@ -0,0 +1,19 @@
|
|||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default {
|
||||
shouldRender(attrs, ctx) {
|
||||
return ctx.siteSettings.wizard_critical_notices_on_dashboard;
|
||||
},
|
||||
|
||||
setupComponent(attrs, component) {
|
||||
const controller = getOwner(this).lookup("controller:admin-dashboard");
|
||||
|
||||
component.set("notices", controller.get("customWizardCriticalNotices"));
|
||||
controller.addObserver("customWizardCriticalNotices.[]", () => {
|
||||
if (this._state === "destroying") {
|
||||
return;
|
||||
}
|
||||
component.set("notices", controller.get("customWizardCriticalNotices"));
|
||||
});
|
||||
},
|
||||
};
|
|
@ -4,4 +4,4 @@
|
|||
{{#if wizardErrorNotice}}
|
||||
{{d-icon "exclaimation-circle"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
</label>
|
||||
<div class="controls">
|
||||
{{combo-box
|
||||
value=wizardListVal
|
||||
content=wizardList
|
||||
onChange=(action "changeWizard")
|
||||
options=(hash none="admin.wizard.select")
|
||||
}}
|
||||
value=wizardListVal
|
||||
content=wizardList
|
||||
onChange=(action "changeWizard")
|
||||
options=(hash
|
||||
none="admin.wizard.select"
|
||||
)}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import CustomWizardAdmin from "../../models/custom-wizard-admin";
|
||||
import CustomWizard from "../../models/custom-wizard";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default {
|
||||
setupComponent(attrs, component) {
|
||||
CustomWizardAdmin.all()
|
||||
CustomWizard.all()
|
||||
.then((result) => {
|
||||
component.set("wizardList", result);
|
||||
})
|
||||
|
|
|
@ -1,10 +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>
|
||||
<a href={{wizard.url}}>{{i18n "wizard.complete_custom" name=wizard.name}}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
|
|
|
@ -4,14 +4,10 @@ import CustomWizardApi from "../models/custom-wizard-api";
|
|||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||
import { and, equal, not } from "@ember/object/computed";
|
||||
import { selectKitContent } from "../lib/wizard";
|
||||
import { underscore } from "@ember/string";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Controller.extend({
|
||||
router: service(),
|
||||
|
||||
queryParams: ["refresh_list"],
|
||||
loadingSubscriptions: false,
|
||||
notAuthorized: not("api.authorized"),
|
||||
|
@ -24,8 +20,29 @@ export default Controller.extend({
|
|||
"application/x-www-form-urlencoded",
|
||||
]),
|
||||
successCodes: selectKitContent([
|
||||
100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301,
|
||||
302, 303, 303, 304, 305, 306, 307, 308,
|
||||
100,
|
||||
101,
|
||||
102,
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207,
|
||||
208,
|
||||
226,
|
||||
300,
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
]),
|
||||
|
||||
@discourseComputed(
|
||||
|
@ -71,11 +88,6 @@ export default Controller.extend({
|
|||
twoLeggedOauth: equal("api.authType", "oauth_2"),
|
||||
threeLeggedOauth: equal("api.authType", "oauth_3"),
|
||||
|
||||
@discourseComputed("api.isNew")
|
||||
nameClass(isNew) {
|
||||
return isNew ? "new" : "saved";
|
||||
},
|
||||
|
||||
actions: {
|
||||
addParam() {
|
||||
this.get("api.authParams").pushObject({});
|
||||
|
@ -101,7 +113,7 @@ export default Controller.extend({
|
|||
|
||||
if (authType === "oauth_2") {
|
||||
this.set("authorizing", true);
|
||||
ajax(`/admin/wizards/apis/${underscore(name)}/authorize`)
|
||||
ajax(`/admin/wizards/apis/${name.underscore()}/authorize`)
|
||||
.catch(popupAjaxError)
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
|
@ -137,6 +149,7 @@ export default Controller.extend({
|
|||
const api = this.get("api");
|
||||
const name = api.name;
|
||||
const authType = api.authType;
|
||||
let refreshList = false; // eslint-disable-line
|
||||
let error;
|
||||
|
||||
if (!name || !authType) {
|
||||
|
@ -151,6 +164,11 @@ export default Controller.extend({
|
|||
data["title"] = api.title;
|
||||
}
|
||||
|
||||
const originalTitle = this.get("api.originalTitle");
|
||||
if (api.get("isNew") || (originalTitle && api.title !== originalTitle)) {
|
||||
refreshList = true;
|
||||
}
|
||||
|
||||
if (api.get("isNew")) {
|
||||
data["new"] = true;
|
||||
}
|
||||
|
@ -170,11 +188,11 @@ export default Controller.extend({
|
|||
if (!api[rp]) {
|
||||
let key = rp.replace("auth", "");
|
||||
error = `${I18n.t(
|
||||
`admin.wizard.api.auth.${underscore(key)}`
|
||||
`admin.wizard.api.auth.${key.underscore()}`
|
||||
)} is required for ${authType}`;
|
||||
break;
|
||||
}
|
||||
data[underscore(rp)] = api[rp];
|
||||
data[rp.underscore()] = api[rp];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +222,7 @@ export default Controller.extend({
|
|||
|
||||
this.set("updating", true);
|
||||
|
||||
ajax(`/admin/wizards/api/${underscore(name)}`, {
|
||||
ajax(`/admin/wizards/api/${name.underscore()}`, {
|
||||
type: "PUT",
|
||||
data,
|
||||
})
|
||||
|
@ -227,7 +245,7 @@ export default Controller.extend({
|
|||
|
||||
this.set("updating", true);
|
||||
|
||||
ajax(`/admin/wizards/api/${underscore(name)}`, {
|
||||
ajax(`/admin/wizards/api/${name.underscore()}`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
|
@ -245,13 +263,13 @@ export default Controller.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
ajax(`/admin/wizards/api/${underscore(name)}/logs`, {
|
||||
ajax(`/admin/wizards/api/${name.underscore()}/logs`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.router.transitionTo("adminWizardsApis").then(() => {
|
||||
this.transitionToRoute("adminWizardsApis").then(() => {
|
||||
this.send("refreshModel");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
actions: {
|
||||
save() {
|
||||
this.send("closeModal");
|
||||
},
|
||||
|
||||
resetToDefault() {
|
||||
this.get("model.reset")();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -4,7 +4,7 @@ import CustomWizardCustomField from "../models/custom-wizard-custom-field";
|
|||
export default Controller.extend({
|
||||
messageKey: "create",
|
||||
fieldKeys: ["klass", "type", "name", "serializers"],
|
||||
documentationUrl: "https://discourse.pluginmanager.org/t/custom-fields",
|
||||
documentationUrl: "https://thepavilion.io/t/3572",
|
||||
|
||||
actions: {
|
||||
addField() {
|
||||
|
|
|
@ -7,7 +7,7 @@ import I18n from "I18n";
|
|||
import { underscore } from "@ember/string";
|
||||
|
||||
export default Controller.extend({
|
||||
messageUrl: "https://discourse.pluginmanager.org/t/wizard-manager",
|
||||
messageUrl: "https://thepavilion.io/t/3652",
|
||||
messageKey: "info",
|
||||
messageIcon: "info-circle",
|
||||
messageClass: "info",
|
||||
|
@ -68,7 +68,7 @@ export default Controller.extend({
|
|||
file: null,
|
||||
filename: null,
|
||||
});
|
||||
document.getElementById("custom-wizard-file-upload").value = "";
|
||||
$("#file-upload").val("");
|
||||
},
|
||||
|
||||
@observes("importing", "destroying")
|
||||
|
@ -83,7 +83,7 @@ export default Controller.extend({
|
|||
|
||||
actions: {
|
||||
upload() {
|
||||
document.getElementById("custom-wizard-file-upload").click();
|
||||
$("#file-upload").click();
|
||||
},
|
||||
|
||||
clearFile() {
|
||||
|
@ -102,7 +102,7 @@ export default Controller.extend({
|
|||
if (maxFileSize < file.size) {
|
||||
this.setMessage("error", "file_size_error");
|
||||
this.set("file", null);
|
||||
document.getElementById("custom-wizard-file-upload").value = "";
|
||||
$("#file-upload").val("");
|
||||
} else {
|
||||
this.setProperties({
|
||||
file,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import Controller from "@ember/controller";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { A } from "@ember/array";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
messageUrl: "https://thepavilion.io/t/3652",
|
||||
messageKey: "info",
|
||||
messageIcon: "info-circle",
|
||||
messageClass: "info",
|
||||
hasNotices: notEmpty("notices"),
|
||||
page: 0,
|
||||
loadingMore: false,
|
||||
canLoadMore: true,
|
||||
|
||||
@discourseComputed("notices.[]", "notices.@each.dismissed")
|
||||
allDismisssed(notices) {
|
||||
return notices.every((n) => !n.canDismiss || n.dismissed);
|
||||
},
|
||||
|
||||
loadMoreNotices() {
|
||||
if (!this.canLoadMore) {
|
||||
return;
|
||||
}
|
||||
const page = this.get("page");
|
||||
this.set("loadingMore", true);
|
||||
|
||||
CustomWizardNotice.list({ page, include_all: true })
|
||||
.then((result) => {
|
||||
if (result.notices.length === 0) {
|
||||
this.set("canLoadMore", false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.get("notices").pushObjects(
|
||||
A(result.notices.map((notice) => CustomWizardNotice.create(notice)))
|
||||
);
|
||||
})
|
||||
.finally(() => this.set("loadingMore", false));
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (this.canLoadMore) {
|
||||
this.set("page", this.page + 1);
|
||||
this.loadMoreNotices();
|
||||
}
|
||||
},
|
||||
|
||||
dismissAll() {
|
||||
bootbox.confirm(
|
||||
I18n.t("admin.wizard.notice.dismiss_all.confirm"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.set("loadingMore", true);
|
||||
CustomWizardNotice.dismissAll().finally(() =>
|
||||
this.set("loadingMore", false)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -2,13 +2,10 @@ import Controller from "@ember/controller";
|
|||
import { empty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
import AdminWizardsColumnsModal from "../components/modal/admin-wizards-columns";
|
||||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import { formatModel } from "../lib/wizard-submission";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
|
||||
export default Controller.extend({
|
||||
modal: service(),
|
||||
downloadUrl: fmt("wizard.id", "/admin/wizards/submissions/%@/download"),
|
||||
noResults: empty("submissions"),
|
||||
page: 0,
|
||||
|
@ -19,12 +16,10 @@ export default Controller.extend({
|
|||
const wizardId = this.get("wizard.id");
|
||||
|
||||
this.set("loadingMore", true);
|
||||
CustomWizardAdmin.submissions(wizardId, page)
|
||||
CustomWizard.submissions(wizardId, page)
|
||||
.then((result) => {
|
||||
if (result.submissions) {
|
||||
const { submissions } = formatModel(result);
|
||||
|
||||
this.get("submissions").pushObjects(submissions);
|
||||
this.get("submissions").pushObjects(result.submissions);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -32,7 +27,7 @@ export default Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
@discourseComputed("submissions.[]", "fields.@each.enabled")
|
||||
@discourseComputed("submissions", "fields.@each.enabled")
|
||||
displaySubmissions(submissions, fields) {
|
||||
let result = [];
|
||||
|
||||
|
@ -59,7 +54,7 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
showEditColumnsModal() {
|
||||
return this.modal.show(AdminWizardsColumnsModal, {
|
||||
return showModal("admin-wizards-columns", {
|
||||
model: {
|
||||
columns: this.get("fields"),
|
||||
reset: () => {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
messageUrl: "https://thepavilion.io/t/3652",
|
||||
messageType: "info",
|
||||
messageKey: null,
|
||||
showSubscription: alias("model.authentication.active"),
|
||||
|
||||
setup() {
|
||||
const authentication = this.get("model.authentication");
|
||||
const subscription = this.get("model.subscription");
|
||||
const subscribed = subscription && subscription.active;
|
||||
const authenticated = authentication && authentication.active;
|
||||
|
||||
if (!subscribed) {
|
||||
this.set("messageKey", authenticated ? "not_subscribed" : "authorize");
|
||||
} else {
|
||||
this.set(
|
||||
"messageKey",
|
||||
!authenticated
|
||||
? "subscription_expiring"
|
||||
: subscribed
|
||||
? "subscription_active"
|
||||
: "subscription_inactive"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.server")
|
||||
messageOpts(server) {
|
||||
return { server };
|
||||
},
|
||||
|
||||
actions: {
|
||||
unauthorize() {
|
||||
this.set("unauthorizing", true);
|
||||
|
||||
CustomWizardSubscription.unauthorize()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
||||
messageKey: "unauthorized",
|
||||
messageType: "warn",
|
||||
"model.authentication": null,
|
||||
"model.subscription": null,
|
||||
});
|
||||
} else {
|
||||
this.setProperties({
|
||||
messageKey: "unauthorize_failed",
|
||||
messageType: "error",
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("unauthorizing", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -3,18 +3,15 @@ import {
|
|||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
import NextSessionScheduledModal from "../components/modal/next-session-scheduled";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { generateId, wizardFieldList } from "../lib/wizard";
|
||||
import { dasherize } from "@ember/string";
|
||||
import { later, scheduleOnce } from "@ember/runloop";
|
||||
import Controller from "@ember/controller";
|
||||
import copyText from "discourse/lib/copy-text";
|
||||
import I18n from "I18n";
|
||||
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
|
||||
export default Controller.extend({
|
||||
modal: service(),
|
||||
hasName: notEmpty("wizard.name"),
|
||||
|
||||
@observes("currentStep")
|
||||
|
@ -39,8 +36,7 @@ export default Controller.extend({
|
|||
|
||||
@discourseComputed("wizard.id")
|
||||
wizardUrl(wizardId) {
|
||||
let baseUrl = window.location.href.split("/admin");
|
||||
return baseUrl[0] + "/w/" + dasherize(wizardId);
|
||||
return window.location.origin + "/w/" + dasherize(wizardId);
|
||||
},
|
||||
|
||||
@discourseComputed("wizard.after_time_scheduled")
|
||||
|
@ -63,34 +59,6 @@ export default Controller.extend({
|
|||
return wizardFieldList(steps);
|
||||
},
|
||||
|
||||
@discourseComputed("fieldTypes", "wizard.allowGuests")
|
||||
filteredFieldTypes(fieldTypes) {
|
||||
const fieldTypeIds = fieldTypes.map((f) => f.id);
|
||||
const allowedTypeIds = filterValues(
|
||||
this.wizard,
|
||||
"field",
|
||||
"type",
|
||||
fieldTypeIds
|
||||
);
|
||||
return fieldTypes.filter((f) => allowedTypeIds.includes(f.id));
|
||||
},
|
||||
|
||||
getErrorMessage(result) {
|
||||
if (result.backend_validation_error) {
|
||||
return result.backend_validation_error;
|
||||
}
|
||||
|
||||
let errorType = "failed";
|
||||
let errorParams = {};
|
||||
|
||||
if (result.error) {
|
||||
errorType = result.error.type;
|
||||
errorParams = result.error.params;
|
||||
}
|
||||
|
||||
return I18n.t(`admin.wizard.error.${errorType}`, errorParams);
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.setProperties({
|
||||
|
@ -116,7 +84,18 @@ export default Controller.extend({
|
|||
}
|
||||
})
|
||||
.catch((result) => {
|
||||
this.set("error", this.getErrorMessage(result));
|
||||
let errorType = "failed";
|
||||
let errorParams = {};
|
||||
|
||||
if (result.error) {
|
||||
errorType = result.error.type;
|
||||
errorParams = result.error.params;
|
||||
}
|
||||
|
||||
this.set(
|
||||
"error",
|
||||
I18n.t(`admin.wizard.error.${errorType}`, errorParams)
|
||||
);
|
||||
|
||||
later(() => this.set("error", null), 10000);
|
||||
})
|
||||
|
@ -128,13 +107,15 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
setNextSessionScheduled() {
|
||||
this.modal.show(NextSessionScheduledModal, {
|
||||
let controller = showModal("next-session-scheduled", {
|
||||
model: {
|
||||
dateTime: this.wizard.after_time_scheduled,
|
||||
update: (dateTime) =>
|
||||
this.set("wizard.after_time_scheduled", dateTime),
|
||||
},
|
||||
});
|
||||
|
||||
controller.setup();
|
||||
},
|
||||
|
||||
copyUrl() {
|
||||
|
|
|
@ -21,6 +21,5 @@ export default Controller.extend({
|
|||
return key;
|
||||
},
|
||||
|
||||
messageUrl:
|
||||
"https://discourse.pluginmanager.org/c/discourse-custom-wizard/documentation",
|
||||
messageUrl: "https://thepavilion.io/c/knowledge/discourse/custom-wizard",
|
||||
});
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { equal, or } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
export default Controller.extend({
|
||||
businessSubscription: equal("subscriptionType", "business"),
|
||||
communitySubscription: equal("subscriptionType", "community"),
|
||||
standardSubscription: equal("subscriptionType", "standard"),
|
||||
showApi: or("businessSubscription", "communitySubscription"),
|
||||
adminWizardsNotices: controller(),
|
||||
|
||||
unsubscribe() {
|
||||
this.messageBus.unsubscribe("/custom-wizard/notices");
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.unsubscribe();
|
||||
this.messageBus.subscribe("/custom-wizard/notices", (data) => {
|
||||
if (isPresent(data.active_notice_count)) {
|
||||
this.set("activeNoticeCount", data.active_notice_count);
|
||||
this.adminWizardsNotices.setProperties({
|
||||
notices: A(),
|
||||
page: 0,
|
||||
canLoadMore: true,
|
||||
});
|
||||
this.adminWizardsNotices.loadMoreNotices();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { or } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const reasons = {
|
||||
noWizard: "none",
|
||||
requiresLogin: "requires_login",
|
||||
notPermitted: "not_permitted",
|
||||
completed: "completed",
|
||||
};
|
||||
|
||||
export default Controller.extend({
|
||||
noAccess: or("noWizard", "requiresLogin", "notPermitted", "completed"),
|
||||
|
||||
@discourseComputed("noAccessReason")
|
||||
noAccessI18nKey(reason) {
|
||||
return reason ? `wizard.${reasons[reason]}` : "wizard.none";
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
noAccessReason() {
|
||||
return Object.keys(reasons).find((reason) => this.get(reason));
|
||||
},
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({
|
||||
queryParams: ["reset"],
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({
|
||||
title: "admin.wizard.after_time_modal.title",
|
||||
|
||||
setup() {
|
||||
this.set("bufferedDateTime", moment(this.model.dateTime));
|
||||
},
|
||||
|
||||
@discourseComputed("bufferedDateTime")
|
||||
submitDisabled(dateTime) {
|
||||
return moment().isAfter(dateTime);
|
||||
},
|
||||
|
||||
actions: {
|
||||
submit() {
|
||||
const dateTime = this.get("bufferedDateTime");
|
||||
this.get("model.update")(moment(dateTime).utc().toISOString());
|
||||
this.send("closeModal");
|
||||
},
|
||||
|
||||
dateTimeChanged(dateTime) {
|
||||
this.set("bufferedDateTime", dateTime);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -58,6 +58,16 @@ export default {
|
|||
path: "/manager",
|
||||
resetNamespace: true,
|
||||
});
|
||||
|
||||
this.route("adminWizardsSubscription", {
|
||||
path: "/subscription",
|
||||
resetNamespace: true,
|
||||
});
|
||||
|
||||
this.route("adminWizardsNotices", {
|
||||
path: "/notices",
|
||||
resetNamespace: true,
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
export default function () {
|
||||
this.route(
|
||||
"customWizard",
|
||||
{ path: "/w/:wizard_id", resetNamespace: true },
|
||||
function () {
|
||||
this.route("customWizardStep", {
|
||||
path: "/steps/:step_id",
|
||||
resetNamespace: true,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
6
assets/javascripts/discourse/helpers/custom-wizard.js.es6
Normale Datei
6
assets/javascripts/discourse/helpers/custom-wizard.js.es6
Normale Datei
|
@ -0,0 +1,6 @@
|
|||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { dasherize } from "@ember/string";
|
||||
|
||||
registerUnbound("dasherize", function (string) {
|
||||
return dasherize(string);
|
||||
});
|
43
assets/javascripts/discourse/helpers/notice-badge.js.es6
Normale Datei
43
assets/javascripts/discourse/helpers/notice-badge.js.es6
Normale Datei
|
@ -0,0 +1,43 @@
|
|||
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import I18n from "I18n";
|
||||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
registerUnbound("notice-badge", function (attrs) {
|
||||
let tag = attrs.url ? "a" : "div";
|
||||
let attrStr = "";
|
||||
if (attrs.title) {
|
||||
attrStr += `title='${I18n.t(attrs.title)}'`;
|
||||
}
|
||||
if (attrs.url) {
|
||||
attrStr += `href='${attrs.url}'`;
|
||||
}
|
||||
let html = `<${tag} class="${
|
||||
attrs.class ? `${attrs.class} ` : ""
|
||||
}notice-badge" ${attrStr}>`;
|
||||
if (attrs.icon) {
|
||||
html += iconHTML(attrs.icon);
|
||||
}
|
||||
if (attrs.label) {
|
||||
if (attrs.icon) {
|
||||
html += " ";
|
||||
}
|
||||
html += `<span>${I18n.t(attrs.label)}</span>`;
|
||||
}
|
||||
if (attrs.date) {
|
||||
if (attrs.icon || attrs.label) {
|
||||
html += " ";
|
||||
}
|
||||
let dateAttrs = {};
|
||||
if (attrs.leaveAgo) {
|
||||
dateAttrs = {
|
||||
format: "medium",
|
||||
leaveAgo: true,
|
||||
};
|
||||
}
|
||||
html += autoUpdatingRelativeAge(new Date(attrs.date), dateAttrs);
|
||||
}
|
||||
html += `</${tag}>`;
|
||||
return htmlSafe(html);
|
||||
});
|
|
@ -1,25 +0,0 @@
|
|||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import I18n from "I18n";
|
||||
import Handlebars from "handlebars";
|
||||
|
||||
export default registerUnbound(
|
||||
"wizard-char-counter",
|
||||
function (body, maxLength) {
|
||||
let bodyLength = body ? body.length : 0;
|
||||
let finalString;
|
||||
|
||||
if (maxLength) {
|
||||
let isOverMax = bodyLength > maxLength ? "true" : "false";
|
||||
finalString = `<div class="body-length" data-length=${bodyLength} data-over-max=${isOverMax}>${bodyLength} / ${I18n.t(
|
||||
"wizard.x_characters",
|
||||
{ count: parseInt(maxLength, 10) }
|
||||
)}</div>`;
|
||||
} else {
|
||||
finalString = `<div class="body-length">${I18n.t("wizard.x_characters", {
|
||||
count: parseInt(bodyLength, 10),
|
||||
})}</div>`;
|
||||
}
|
||||
|
||||
return new Handlebars.SafeString(finalString);
|
||||
}
|
||||
);
|
|
@ -1,12 +1,14 @@
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import { A } from "@ember/array";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
export default {
|
||||
name: "custom-wizard-edits",
|
||||
initialize(container) {
|
||||
const siteSettings = container.lookup("service:site-settings");
|
||||
const siteSettings = container.lookup("site-settings:main");
|
||||
|
||||
if (!siteSettings.custom_wizard_enabled) {
|
||||
return;
|
||||
|
@ -21,6 +23,50 @@ export default {
|
|||
};
|
||||
|
||||
withPluginApi("0.8.36", (api) => {
|
||||
api.modifyClass("route:admin-dashboard", {
|
||||
pluginId: "custom-wizard",
|
||||
|
||||
setupController(controller) {
|
||||
this._super(...arguments);
|
||||
|
||||
controller.loadCriticalNotices();
|
||||
controller.subscribe();
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("controller:admin-dashboard", {
|
||||
pluginId: "custom-wizard",
|
||||
criticalNotices: A(),
|
||||
|
||||
unsubscribe() {
|
||||
this.messageBus.unsubscribe("/custom-wizard/notices");
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.unsubscribe();
|
||||
this.messageBus.subscribe("/custom-wizard/notices", (data) => {
|
||||
if (isPresent(data.active_notice_count)) {
|
||||
this.loadCriticalNotices();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadCriticalNotices() {
|
||||
CustomWizardNotice.list({
|
||||
type: ["connection_error", "warning"],
|
||||
archetype: "plugin_status",
|
||||
visible: true,
|
||||
}).then((result) => {
|
||||
if (result.notices && result.notices.length) {
|
||||
const criticalNotices = A(
|
||||
result.notices.map((n) => CustomWizardNotice.create(n))
|
||||
);
|
||||
this.set("customWizardCriticalNotices", criticalNotices);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("component:d-navigation", {
|
||||
pluginId: "custom-wizard",
|
||||
actions: {
|
||||
|
@ -36,63 +82,6 @@ export default {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("component:uppy-image-uploader", {
|
||||
pluginId: "custom-wizard",
|
||||
// Needed to ensure appEvents get registered when navigating between steps
|
||||
@observes("id")
|
||||
initOnStepChange() {
|
||||
if (/wizard-field|wizard-step/.test(this.id)) {
|
||||
this._initialize();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("component:d-editor", {
|
||||
pluginId: "custom-wizard",
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.wizardComposer) {
|
||||
this.appEvents.on(
|
||||
`wizard-editor:insert-text`,
|
||||
this,
|
||||
"_wizardInsertText"
|
||||
);
|
||||
this.appEvents.on(
|
||||
"wizard-editor:replace-text",
|
||||
this,
|
||||
"_wizardReplaceText"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_wizardInsertText(text, options) {
|
||||
if (
|
||||
this.session.wizardEventFieldId === this.fieldId &&
|
||||
this.element
|
||||
) {
|
||||
this.insertText(text, options);
|
||||
}
|
||||
},
|
||||
|
||||
_wizardReplaceText(oldVal, newVal, opts = {}) {
|
||||
if (this.session.wizardEventFieldId === this.fieldId) {
|
||||
this.replaceText(oldVal, newVal, opts);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("component:category-chooser", {
|
||||
categoriesByScope(options = {}) {
|
||||
let categories = this._super(options);
|
||||
|
||||
return categories.filter((category) => {
|
||||
return !category.custom_fields?.create_topic_wizard;
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { dasherize } from "@ember/string";
|
||||
import ApplicationRoute from "discourse/routes/application";
|
||||
|
||||
export default {
|
||||
name: "custom-wizard-redirect",
|
||||
after: "message-bus",
|
||||
|
||||
initialize(container) {
|
||||
const messageBus = container.lookup("service:message-bus");
|
||||
const siteSettings = container.lookup("service:site-settings");
|
||||
initialize: function (container) {
|
||||
const messageBus = container.lookup("message-bus:main");
|
||||
const siteSettings = container.lookup("site-settings:main");
|
||||
|
||||
if (!siteSettings.custom_wizard_enabled) {
|
||||
if (!siteSettings.custom_wizard_enabled || !messageBus) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,27 +17,28 @@ export default {
|
|||
window.location.href = wizardUrl;
|
||||
});
|
||||
|
||||
withPluginApi("0.8.36", (api) => {
|
||||
api.onAppEvent("page:changed", (data) => {
|
||||
const currentUser = api.getCurrentUser();
|
||||
|
||||
if (currentUser) {
|
||||
const redirectToWizard = currentUser.redirect_to_wizard;
|
||||
const excludedPaths = siteSettings.wizard_redirect_exclude_paths
|
||||
ApplicationRoute.reopen({
|
||||
actions: {
|
||||
willTransition(transition) {
|
||||
const redirectToWizard = this.get("currentUser.redirect_to_wizard");
|
||||
const excludedPaths = this.siteSettings.wizard_redirect_exclude_paths
|
||||
.split("|")
|
||||
.concat(["loading"]);
|
||||
|
||||
if (
|
||||
redirectToWizard &&
|
||||
!data.url.includes("ignore_redirect") &&
|
||||
data.currentRouteName !== "customWizardStep" &&
|
||||
!excludedPaths.find((p) => {
|
||||
return data.currentRouteName.indexOf(p) > -1;
|
||||
})
|
||||
(!transition.intent.name ||
|
||||
!excludedPaths.find((p) => {
|
||||
return transition.intent.name.indexOf(p) > -1;
|
||||
}))
|
||||
) {
|
||||
DiscourseURL.routeTo(`/w/${dasherize(redirectToWizard)}`);
|
||||
transition.abort();
|
||||
window.location = "/w/" + redirectToWizard.dasherize();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return this._super(transition);
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -35,7 +35,6 @@ function inputTypesContent(options = {}) {
|
|||
const connectors = {
|
||||
pair: [
|
||||
"equal",
|
||||
"not_equal",
|
||||
"greater",
|
||||
"less",
|
||||
"greater_or_equal",
|
||||
|
|
|
@ -41,7 +41,6 @@ const step = {
|
|||
index: null,
|
||||
title: null,
|
||||
banner: null,
|
||||
banner_upload_id: null,
|
||||
raw_description: null,
|
||||
required_data: null,
|
||||
required_data_message: null,
|
||||
|
@ -66,15 +65,13 @@ const field = {
|
|||
index: null,
|
||||
label: null,
|
||||
image: null,
|
||||
image_upload_id: null,
|
||||
description: null,
|
||||
property: null,
|
||||
required: null,
|
||||
type: null,
|
||||
condition: null,
|
||||
tag_groups: null,
|
||||
},
|
||||
types: {},
|
||||
type: {},
|
||||
mapped: ["prefill", "content", "condition", "index"],
|
||||
required: ["id", "type"],
|
||||
dependent: {},
|
||||
|
@ -87,7 +84,7 @@ const action = {
|
|||
run_after: "wizard_completion",
|
||||
type: null,
|
||||
},
|
||||
types: {
|
||||
type: {
|
||||
create_topic: {
|
||||
title: null,
|
||||
post: null,
|
||||
|
@ -99,8 +96,6 @@ const action = {
|
|||
custom_fields: null,
|
||||
skip_redirect: null,
|
||||
suppress_notifications: null,
|
||||
add_event: null,
|
||||
add_location: null,
|
||||
},
|
||||
send_message: {
|
||||
title: null,
|
||||
|
@ -133,12 +128,6 @@ const action = {
|
|||
wizard_user: true,
|
||||
usernames: null,
|
||||
},
|
||||
watch_tags: {
|
||||
tags: null,
|
||||
notification_level: null,
|
||||
wizard_user: true,
|
||||
usernames: null,
|
||||
},
|
||||
send_to_api: {
|
||||
api: null,
|
||||
api_endpoint: null,
|
||||
|
@ -203,83 +192,60 @@ const action = {
|
|||
"messageable_level",
|
||||
"visibility_level",
|
||||
"members_visibility_level",
|
||||
"add_event",
|
||||
"add_location",
|
||||
],
|
||||
required: ["id", "type"],
|
||||
dependent: {},
|
||||
objectArrays: {},
|
||||
};
|
||||
|
||||
const filters = {
|
||||
allow_guests: {
|
||||
field: {
|
||||
type: [
|
||||
"text",
|
||||
"textarea",
|
||||
"text_only",
|
||||
"date",
|
||||
"time",
|
||||
"date_time",
|
||||
"number",
|
||||
"checkbox",
|
||||
"url",
|
||||
"dropdown",
|
||||
"tag",
|
||||
"category",
|
||||
"group",
|
||||
"user_selector",
|
||||
],
|
||||
},
|
||||
action: {
|
||||
type: ["route_to", "send_message"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const custom_field = {
|
||||
klass: ["topic", "post", "group", "category"],
|
||||
type: ["string", "boolean", "integer", "json"],
|
||||
};
|
||||
|
||||
export function buildFieldTypes(types) {
|
||||
wizardSchema.field.types = types;
|
||||
wizardSchema.field.type = Object.keys(types);
|
||||
}
|
||||
|
||||
field.type = Object.keys(field.types);
|
||||
action.type = Object.keys(action.types);
|
||||
|
||||
const wizardSchema = {
|
||||
wizard,
|
||||
step,
|
||||
field,
|
||||
custom_field,
|
||||
action,
|
||||
filters,
|
||||
};
|
||||
|
||||
export function buildFieldValidations(validations) {
|
||||
wizardSchema.field.validations = validations;
|
||||
export function hasRequiredSubscription(
|
||||
currentSubscriptionType,
|
||||
featureSubscriptionType
|
||||
) {
|
||||
const types = wizardSchema.subscription.types;
|
||||
return (
|
||||
types.indexOf(currentSubscriptionType) >=
|
||||
types.indexOf(featureSubscriptionType)
|
||||
);
|
||||
}
|
||||
|
||||
export function filterValues(currentWizard, feature, attribute, values = null) {
|
||||
values = values || wizardSchema[feature][attribute];
|
||||
export function subscriptionType(klass, attribute, value) {
|
||||
let attributes = wizardSchema.subscription.features[klass];
|
||||
|
||||
if (currentWizard && currentWizard.allowGuests) {
|
||||
const filteredFeature = wizardSchema.filters.allow_guests[feature];
|
||||
if (filteredFeature) {
|
||||
const filtered = filteredFeature[attribute];
|
||||
if (filtered) {
|
||||
values = values.filter((v) => filtered.includes(v));
|
||||
}
|
||||
}
|
||||
if (!attributes || !attributes[attribute] || !attributes[attribute][value]) {
|
||||
return wizardSchema.subscription.types[0];
|
||||
} else {
|
||||
return attributes[attribute][value];
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
const siteSettings = getOwner(this).lookup("service:site-settings");
|
||||
export function buildSchema(model) {
|
||||
wizardSchema.subscription = {};
|
||||
|
||||
let features = model.subscription_features;
|
||||
features["field"]["types"] = features["field"]["type"];
|
||||
features["action"]["types"] = features["action"]["type"];
|
||||
|
||||
wizardSchema.subscription.features = features;
|
||||
wizardSchema.subscription.types = model.subscription_types;
|
||||
wizardSchema.field.types = model.field_types;
|
||||
wizardSchema.field.validations = model.realtime_validations;
|
||||
}
|
||||
|
||||
const siteSettings = getOwner(this).lookup("site-settings:main");
|
||||
if (siteSettings.wizard_apis_enabled) {
|
||||
wizardSchema.action.types.send_to_api = {
|
||||
api: null,
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
|
||||
function formatModel(model) {
|
||||
let fields = [
|
||||
EmberObject.create({
|
||||
id: "submitted_at",
|
||||
label: "Submitted At",
|
||||
enabled: true,
|
||||
}),
|
||||
EmberObject.create({ id: "username", label: "User", enabled: true }),
|
||||
];
|
||||
let submissions = [];
|
||||
|
||||
model.submissions.forEach((s) => {
|
||||
let submission = {
|
||||
submitted_at: s.submitted_at,
|
||||
username: s.user,
|
||||
};
|
||||
|
||||
Object.keys(s.fields).forEach((fieldId) => {
|
||||
if (!fields.some((field) => field.id === fieldId)) {
|
||||
fields.push(
|
||||
EmberObject.create({
|
||||
id: fieldId,
|
||||
label: s.fields[fieldId].label,
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
submission[fieldId] = s.fields[fieldId];
|
||||
});
|
||||
|
||||
submissions.push(EmberObject.create(submission));
|
||||
});
|
||||
|
||||
return { fields, submissions };
|
||||
}
|
||||
|
||||
export { formatModel };
|
|
@ -1,5 +1,8 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import wizardSchema from "./wizard-schema";
|
||||
import wizardSchema, {
|
||||
hasRequiredSubscription,
|
||||
subscriptionType,
|
||||
} from "./wizard-schema";
|
||||
import I18n from "I18n";
|
||||
|
||||
function selectKitContent(content) {
|
||||
|
@ -34,10 +37,6 @@ function camelCase(string) {
|
|||
});
|
||||
}
|
||||
|
||||
function translationOrText(i18nKey, text) {
|
||||
return I18n.findTranslation(i18nKey) ? I18n.t(i18nKey) : text;
|
||||
}
|
||||
|
||||
const userProperties = [
|
||||
"name",
|
||||
"username",
|
||||
|
@ -115,6 +114,25 @@ function wizardFieldList(steps = [], opts = {}) {
|
|||
}, []);
|
||||
}
|
||||
|
||||
function buildSubscriptionContent(klass, attribute, currentSubscription) {
|
||||
let attributes = wizardSchema[klass];
|
||||
let values = attributes[attribute];
|
||||
|
||||
if (typeof values === "object") {
|
||||
values = Object.keys(values);
|
||||
}
|
||||
|
||||
return values.map((value) => {
|
||||
let type = subscriptionType(klass, attribute, value);
|
||||
return {
|
||||
id: value,
|
||||
name: I18n.t(`admin.wizard.${klass}.${attribute}.${value}.label`),
|
||||
subscription: type,
|
||||
disabled: hasRequiredSubscription(currentSubscription, type),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
selectKitContent,
|
||||
generateName,
|
||||
|
@ -126,5 +144,5 @@ export {
|
|||
notificationLevels,
|
||||
wizardFieldList,
|
||||
sentenceCase,
|
||||
translationOrText,
|
||||
buildSubscriptionContent,
|
||||
};
|
||||
|
|
68
assets/javascripts/discourse/mixins/notice-message.js.es6
Normale Datei
68
assets/javascripts/discourse/mixins/notice-message.js.es6
Normale Datei
|
@ -0,0 +1,68 @@
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import { bind, scheduleOnce } from "@ember/runloop";
|
||||
import { cookAsync } from "discourse/lib/text";
|
||||
import { createPopper } from "@popperjs/core";
|
||||
|
||||
export default Mixin.create({
|
||||
showCookedMessage: false,
|
||||
|
||||
didReceiveAttrs() {
|
||||
const message = this.notice.message;
|
||||
cookAsync(message).then((cooked) => {
|
||||
this.set("cookedMessage", cooked);
|
||||
});
|
||||
},
|
||||
|
||||
createMessageModal() {
|
||||
let container = this.element.querySelector(".notice-message");
|
||||
let modal = this.element.querySelector(".cooked-notice-message");
|
||||
|
||||
this._popper = createPopper(container, modal, {
|
||||
strategy: "absolute",
|
||||
placement: "bottom-start",
|
||||
modifiers: [
|
||||
{
|
||||
name: "preventOverflow",
|
||||
},
|
||||
{
|
||||
name: "offset",
|
||||
options: {
|
||||
offset: [0, 5],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
$(document).on("click", bind(this, this.documentClick));
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
$(document).off("click", bind(this, this.documentClick));
|
||||
},
|
||||
|
||||
documentClick(event) {
|
||||
if (this._state === "destroying") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!event.target.closest(
|
||||
`[data-notice-id="${this.notice.id}"] .notice-message`
|
||||
)
|
||||
) {
|
||||
this.set("showCookedMessage", false);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleCookedMessage() {
|
||||
this.toggleProperty("showCookedMessage");
|
||||
|
||||
if (this.showCookedMessage) {
|
||||
scheduleOnce("afterRender", this, this.createMessageModal);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const PRODUCT_PAGE = "https://custom-wizard.pavilion.tech";
|
||||
const SUPPORT_MESSAGE =
|
||||
"https://coop.pavilion.tech/new-message?username=support&title=Custom%20Wizard%20Support";
|
||||
const MANAGER_CATEGORY =
|
||||
"https://discourse.pluginmanager.org/c/discourse-custom-wizard";
|
||||
|
||||
export default Mixin.create({
|
||||
subscriptionLandingUrl: PRODUCT_PAGE,
|
||||
subscriptionClientUrl: "/admin/plugins/subscription-client",
|
||||
|
||||
@discourseComputed
|
||||
adminWizards() {
|
||||
return getOwner(this).lookup("controller:admin-wizards");
|
||||
},
|
||||
|
||||
subscribed: readOnly("adminWizards.subscribed"),
|
||||
subscriptionType: readOnly("adminWizards.subscriptionType"),
|
||||
businessSubscription: readOnly("adminWizards.businessSubscription"),
|
||||
communitySubscription: readOnly("adminWizards.communitySubscription"),
|
||||
standardSubscription: readOnly("adminWizards.standardSubscription"),
|
||||
subscriptionAttributes: readOnly("adminWizards.subscriptionAttributes"),
|
||||
subscriptionClientInstalled: readOnly(
|
||||
"adminWizards.subscriptionClientInstalled"
|
||||
),
|
||||
|
||||
@discourseComputed("subscriptionClientInstalled")
|
||||
subscriptionLink(subscriptionClientInstalled) {
|
||||
return subscriptionClientInstalled
|
||||
? this.subscriptionClientUrl
|
||||
: this.subscriptionLandingUrl;
|
||||
},
|
||||
|
||||
@discourseComputed("subscriptionType")
|
||||
subscriptionCtaLink(subscriptionType) {
|
||||
switch (subscriptionType) {
|
||||
case "none":
|
||||
return PRODUCT_PAGE;
|
||||
case "standard":
|
||||
return SUPPORT_MESSAGE;
|
||||
case "business":
|
||||
return SUPPORT_MESSAGE;
|
||||
case "community":
|
||||
return MANAGER_CATEGORY;
|
||||
default:
|
||||
return PRODUCT_PAGE;
|
||||
}
|
||||
},
|
||||
});
|
|
@ -4,8 +4,6 @@ import { get, set } from "@ember/object";
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import { deepEqual } from "discourse-common/lib/object";
|
||||
|
||||
const observedCache = [];
|
||||
|
||||
export default Mixin.create({
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
@ -34,13 +32,7 @@ export default Mixin.create({
|
|||
};
|
||||
|
||||
listProperties(componentType, opts).forEach((property) => {
|
||||
if (observedCache.includes(property)) {
|
||||
obj.removeObserver(property, this, this.toggleUndo);
|
||||
let index = observedCache.indexOf(property);
|
||||
if (index !== -1) {
|
||||
observedCache.splice(index, 1);
|
||||
}
|
||||
}
|
||||
obj.removeObserver(property, this, this.toggleUndo);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -53,9 +45,6 @@ export default Mixin.create({
|
|||
};
|
||||
|
||||
listProperties(componentType, opts).forEach((property) => {
|
||||
if (observedCache.indexOf(property) === -1) {
|
||||
observedCache.push(property);
|
||||
}
|
||||
obj.addObserver(property, this, this.toggleUndo);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export const States = {
|
||||
UNCHECKED: 0,
|
||||
INVALID: 1,
|
||||
VALID: 2,
|
||||
};
|
||||
|
||||
export default {
|
||||
_validState: null,
|
||||
errorDescription: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("_validState", States.UNCHECKED);
|
||||
},
|
||||
|
||||
@discourseComputed("_validState")
|
||||
valid: (state) => state === States.VALID,
|
||||
|
||||
@discourseComputed("_validState")
|
||||
invalid: (state) => state === States.INVALID,
|
||||
|
||||
@discourseComputed("_validState")
|
||||
unchecked: (state) => state === States.UNCHECKED,
|
||||
|
||||
setValid(valid, description) {
|
||||
this.set("_validState", valid ? States.VALID : States.INVALID);
|
||||
|
||||
if (!valid && description && description.length) {
|
||||
this.set("errorDescription", description);
|
||||
} else {
|
||||
this.set("errorDescription", null);
|
||||
}
|
||||
},
|
||||
};
|
|
@ -1,242 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import { buildProperties, mapped, present } from "../lib/wizard-json";
|
||||
import { listProperties, snakeCase } from "../lib/wizard";
|
||||
import wizardSchema from "../lib/wizard-schema";
|
||||
import { Promise } from "rsvp";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const GUEST_GROUP_ID = -1;
|
||||
|
||||
const CustomWizardAdmin = EmberObject.extend({
|
||||
@discourseComputed("permitted.@each.output")
|
||||
allowGuests(permitted) {
|
||||
return (
|
||||
permitted &&
|
||||
permitted.filter((p) => p.output && p.output.includes(GUEST_GROUP_ID))
|
||||
.length
|
||||
);
|
||||
},
|
||||
|
||||
save(opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let wizard = this.buildJson(this, "wizard");
|
||||
|
||||
if (wizard.error) {
|
||||
reject(wizard);
|
||||
}
|
||||
|
||||
let data = {
|
||||
wizard,
|
||||
};
|
||||
|
||||
if (opts.create) {
|
||||
data.create = true;
|
||||
}
|
||||
|
||||
ajax(`/admin/wizards/wizard/${wizard.id}`, {
|
||||
type: "PUT",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
}).then((result) => {
|
||||
if (result.backend_validation_error) {
|
||||
reject(result);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
buildJson(object, type, result = {}) {
|
||||
let objectType = object.type || null;
|
||||
|
||||
if (wizardSchema[type].types) {
|
||||
if (!objectType) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property: "type" },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
for (let property of listProperties(type, { objectType })) {
|
||||
let value = object.get(property);
|
||||
|
||||
result = this.validateValue(property, value, object, type, result);
|
||||
|
||||
if (result.error) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mapped(property, type)) {
|
||||
value = this.buildMappedJson(value);
|
||||
}
|
||||
|
||||
if (value !== undefined && value !== null) {
|
||||
result[property] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.error) {
|
||||
for (let arrayObjectType of Object.keys(
|
||||
wizardSchema[type].objectArrays
|
||||
)) {
|
||||
let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
|
||||
let objectArray = object.get(arraySchema.property);
|
||||
|
||||
if (arraySchema.required && !present(objectArray)) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property: arraySchema.property },
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
result[arraySchema.property] = [];
|
||||
|
||||
for (let item of objectArray) {
|
||||
let itemProps = this.buildJson(item, arrayObjectType);
|
||||
|
||||
if (itemProps.error) {
|
||||
result.error = itemProps.error;
|
||||
break;
|
||||
} else {
|
||||
result[arraySchema.property].push(itemProps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
validateValue(property, value, object, type, result) {
|
||||
if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property },
|
||||
};
|
||||
}
|
||||
|
||||
let dependent = wizardSchema[type].dependent[property];
|
||||
if (dependent && value && !object[dependent]) {
|
||||
result.error = {
|
||||
type: "dependent",
|
||||
params: { property, dependent },
|
||||
};
|
||||
}
|
||||
|
||||
if (property === "api_body") {
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {
|
||||
result.error = {
|
||||
type: "invalid",
|
||||
params: { type, property },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
buildMappedJson(value) {
|
||||
if (typeof value === "string" || Number.isInteger(value)) {
|
||||
return value;
|
||||
}
|
||||
if (!value || !value.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inputs = value;
|
||||
let result = [];
|
||||
|
||||
inputs.forEach((inpt) => {
|
||||
let input = {
|
||||
type: inpt.type,
|
||||
};
|
||||
|
||||
if (inpt.connector) {
|
||||
input.connector = inpt.connector;
|
||||
}
|
||||
|
||||
if (present(inpt.output)) {
|
||||
input.output = inpt.output;
|
||||
input.output_type = snakeCase(inpt.output_type);
|
||||
input.output_connector = inpt.output_connector;
|
||||
}
|
||||
|
||||
if (present(inpt.pairs)) {
|
||||
input.pairs = [];
|
||||
|
||||
inpt.pairs.forEach((pr) => {
|
||||
if (present(pr.key) && present(pr.value)) {
|
||||
let pairParams = {
|
||||
index: pr.index,
|
||||
key: pr.key,
|
||||
key_type: snakeCase(pr.key_type),
|
||||
value: pr.value,
|
||||
value_type: snakeCase(pr.value_type),
|
||||
connector: pr.connector,
|
||||
};
|
||||
|
||||
input.pairs.push(pairParams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
(input.type === "assignment" && present(input.output)) ||
|
||||
present(input.pairs)
|
||||
) {
|
||||
result.push(input);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.length) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
remove() {
|
||||
return ajax(`/admin/wizards/wizard/${this.id}`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.then(() => this.destroy())
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
CustomWizardAdmin.reopenClass({
|
||||
all() {
|
||||
return ajax("/admin/wizards/wizard", {
|
||||
type: "GET",
|
||||
})
|
||||
.then((result) => {
|
||||
return result.wizard_list;
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
submissions(wizardId, page = 0) {
|
||||
return ajax(`/admin/wizards/submissions/${wizardId}`, {
|
||||
type: "GET",
|
||||
data: {
|
||||
page,
|
||||
},
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
create(wizardJson = {}) {
|
||||
const wizard = this._super.apply(this);
|
||||
wizard.setProperties(buildProperties(wizardJson));
|
||||
return wizard;
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardAdmin;
|
|
@ -1,79 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import ValidState from "discourse/plugins/discourse-custom-wizard/discourse/mixins/valid-state";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { translationOrText } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard";
|
||||
|
||||
const StandardFieldValidation = [
|
||||
"text",
|
||||
"number",
|
||||
"textarea",
|
||||
"dropdown",
|
||||
"tag",
|
||||
"image",
|
||||
"user_selector",
|
||||
"text_only",
|
||||
"composer",
|
||||
"category",
|
||||
"group",
|
||||
"date",
|
||||
"time",
|
||||
"date_time",
|
||||
];
|
||||
|
||||
export default EmberObject.extend(ValidState, {
|
||||
id: null,
|
||||
type: null,
|
||||
value: null,
|
||||
required: null,
|
||||
warning: null,
|
||||
|
||||
@discourseComputed("wizardId", "stepId", "id")
|
||||
i18nKey(wizardId, stepId, id) {
|
||||
return `${wizardId}.${stepId}.${id}`;
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey", "label")
|
||||
translatedLabel(i18nKey, label) {
|
||||
return translationOrText(`${i18nKey}.label`, label);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey", "placeholder")
|
||||
translatedPlaceholder(i18nKey, placeholder) {
|
||||
return translationOrText(`${i18nKey}.placeholder`, placeholder);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey", "description")
|
||||
translatedDescription(i18nKey, description) {
|
||||
return translationOrText(`${i18nKey}.description`, description);
|
||||
},
|
||||
|
||||
check() {
|
||||
if (this.customCheck) {
|
||||
return this.customCheck();
|
||||
}
|
||||
|
||||
let valid = this.valid;
|
||||
|
||||
if (!this.required) {
|
||||
this.setValid(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
const val = this.get("value");
|
||||
const type = this.get("type");
|
||||
|
||||
if (type === "checkbox") {
|
||||
valid = val;
|
||||
} else if (type === "upload") {
|
||||
valid = val && val.id > 0;
|
||||
} else if (StandardFieldValidation.indexOf(type) > -1) {
|
||||
valid = val && val.toString().length > 0;
|
||||
} else if (type === "url") {
|
||||
valid = true;
|
||||
}
|
||||
|
||||
this.setValid(Boolean(valid));
|
||||
|
||||
return valid;
|
||||
},
|
||||
});
|
74
assets/javascripts/discourse/models/custom-wizard-notice.js.es6
Normale Datei
74
assets/javascripts/discourse/models/custom-wizard-notice.js.es6
Normale Datei
|
@ -0,0 +1,74 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { and, not, notEmpty } from "@ember/object/computed";
|
||||
import { dasherize } from "@ember/string";
|
||||
import I18n from "I18n";
|
||||
|
||||
const CustomWizardNotice = EmberObject.extend({
|
||||
expired: notEmpty("expired_at"),
|
||||
dismissed: notEmpty("dismissed_at"),
|
||||
hidden: notEmpty("hidden_at"),
|
||||
notHidden: not("hidden"),
|
||||
notDismissed: not("dismissed"),
|
||||
canDismiss: and("dismissable", "notDismissed"),
|
||||
canHide: and("can_hide", "notHidden"),
|
||||
|
||||
@discourseComputed("type")
|
||||
typeClass(type) {
|
||||
return dasherize(type);
|
||||
},
|
||||
|
||||
@discourseComputed("type")
|
||||
typeLabel(type) {
|
||||
return I18n.t(`admin.wizard.notice.type.${type}`);
|
||||
},
|
||||
|
||||
dismiss() {
|
||||
if (!this.get("canDismiss")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ajax(`/admin/wizards/notice/${this.get("id")}/dismiss`, {
|
||||
type: "PUT",
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.set("dismissed_at", result.dismissed_at);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
hide() {
|
||||
if (!this.get("canHide")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ajax(`/admin/wizards/notice/${this.get("id")}/hide`, { type: "PUT" })
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.set("hidden_at", result.hidden_at);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
CustomWizardNotice.reopenClass({
|
||||
list(data = {}) {
|
||||
return ajax("/admin/wizards/notice", {
|
||||
type: "GET",
|
||||
data,
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
dismissAll() {
|
||||
return ajax("/admin/wizards/notice/dismiss", {
|
||||
type: "PUT",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardNotice;
|
|
@ -1,114 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import ValidState from "discourse/plugins/discourse-custom-wizard/discourse/mixins/valid-state";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { later } from "@ember/runloop";
|
||||
import { translationOrText } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard";
|
||||
|
||||
export default EmberObject.extend(ValidState, {
|
||||
id: null,
|
||||
|
||||
@discourseComputed("wizardId", "id")
|
||||
i18nKey(wizardId, stepId) {
|
||||
return `${wizardId}.${stepId}`;
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey", "title")
|
||||
translatedTitle(i18nKey, title) {
|
||||
return translationOrText(`${i18nKey}.title`, title);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey", "description")
|
||||
translatedDescription(i18nKey, description) {
|
||||
return translationOrText(`${i18nKey}.description`, description);
|
||||
},
|
||||
|
||||
@discourseComputed("index")
|
||||
displayIndex: (index) => index + 1,
|
||||
|
||||
@discourseComputed("fields.[]")
|
||||
fieldsById(fields) {
|
||||
const lookup = {};
|
||||
fields.forEach((field) => (lookup[field.get("id")] = field));
|
||||
return lookup;
|
||||
},
|
||||
|
||||
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) {
|
||||
const field = this.fields.findBy("id", id);
|
||||
if (field) {
|
||||
field.setValid(false, description);
|
||||
}
|
||||
},
|
||||
|
||||
save() {
|
||||
const wizardId = this.get("wizardId");
|
||||
const fields = {};
|
||||
|
||||
this.get("fields").forEach((f) => {
|
||||
if (f.type !== "text_only") {
|
||||
fields[f.id] = f.value;
|
||||
}
|
||||
});
|
||||
|
||||
return ajax({
|
||||
url: `/w/${wizardId}/steps/${this.get("id")}`,
|
||||
type: "PUT",
|
||||
data: { fields },
|
||||
}).catch((response) => {
|
||||
if (response.jqXHR) {
|
||||
response = response.jqXHR;
|
||||
}
|
||||
if (response && response.responseJSON && response.responseJSON.errors) {
|
||||
let wizardErrors = [];
|
||||
response.responseJSON.errors.forEach((err) => {
|
||||
if (err.field === wizardId) {
|
||||
wizardErrors.push(err.description);
|
||||
} else if (err.field) {
|
||||
this.fieldError(err.field, err.description);
|
||||
} else if (err) {
|
||||
wizardErrors.push(err);
|
||||
}
|
||||
});
|
||||
if (wizardErrors.length) {
|
||||
this.handleWizardError(wizardErrors.join("\n"));
|
||||
}
|
||||
this.animateInvalidFields();
|
||||
throw response;
|
||||
}
|
||||
|
||||
if (response && response.responseText) {
|
||||
const responseText = response.responseText;
|
||||
const start = responseText.indexOf(">") + 1;
|
||||
const end = responseText.indexOf("plugins");
|
||||
const message = responseText.substring(start, end);
|
||||
this.handleWizardError(message);
|
||||
throw message;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleWizardError(message) {
|
||||
this.set("message", {
|
||||
state: "error",
|
||||
text: message,
|
||||
});
|
||||
later(() => this.set("message", null), 6000);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import EmberObject from "@ember/object";
|
||||
|
||||
const CustomWizardSubscription = EmberObject.extend();
|
||||
|
||||
const basePath = "/admin/wizards/subscription";
|
||||
|
||||
CustomWizardSubscription.reopenClass({
|
||||
status() {
|
||||
return ajax(basePath, {
|
||||
type: "GET",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
authorize() {
|
||||
window.location.href = `${basePath}/authorize`;
|
||||
},
|
||||
|
||||
unauthorize() {
|
||||
return ajax(`${basePath}/authorize`, {
|
||||
type: "DELETE",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
update() {
|
||||
return ajax(basePath, {
|
||||
type: "POST",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardSubscription;
|
|
@ -1,127 +1,272 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
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 { Promise } from "rsvp";
|
||||
import { listProperties, snakeCase } from "../lib/wizard";
|
||||
import { buildProperties, mapped, present } from "../lib/wizard-json";
|
||||
import wizardSchema from "../lib/wizard-schema";
|
||||
|
||||
const CustomWizard = EmberObject.extend({
|
||||
@discourseComputed("steps.length")
|
||||
totalSteps: (length) => length,
|
||||
save(opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let wizard = this.buildJson(this, "wizard");
|
||||
|
||||
skip() {
|
||||
if (this.required && !this.completed && this.permitted) {
|
||||
return;
|
||||
}
|
||||
CustomWizard.skip(this.id);
|
||||
if (wizard.error) {
|
||||
reject(wizard);
|
||||
}
|
||||
|
||||
let data = {
|
||||
wizard,
|
||||
};
|
||||
|
||||
if (opts.create) {
|
||||
data.create = true;
|
||||
}
|
||||
|
||||
ajax(`/admin/wizards/wizard/${wizard.id}`, {
|
||||
type: "PUT",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
}).then((result) => {
|
||||
if (result.error) {
|
||||
reject(result);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
restart() {
|
||||
CustomWizard.restart(this.id);
|
||||
buildJson(object, type, result = {}) {
|
||||
let objectType = object.type || null;
|
||||
|
||||
if (wizardSchema[type].types) {
|
||||
if (!objectType) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property: "type" },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
for (let property of listProperties(type, { objectType })) {
|
||||
let value = object.get(property);
|
||||
|
||||
result = this.validateValue(property, value, object, type, result);
|
||||
|
||||
if (result.error) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mapped(property, type)) {
|
||||
value = this.buildMappedJson(value);
|
||||
}
|
||||
|
||||
if (value !== undefined && value !== null) {
|
||||
result[property] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.error) {
|
||||
for (let arrayObjectType of Object.keys(
|
||||
wizardSchema[type].objectArrays
|
||||
)) {
|
||||
let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
|
||||
let objectArray = object.get(arraySchema.property);
|
||||
|
||||
if (arraySchema.required && !present(objectArray)) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property: arraySchema.property },
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
result[arraySchema.property] = [];
|
||||
|
||||
for (let item of objectArray) {
|
||||
let itemProps = this.buildJson(item, arrayObjectType);
|
||||
|
||||
if (itemProps.error) {
|
||||
result.error = itemProps.error;
|
||||
break;
|
||||
} else {
|
||||
result[arraySchema.property].push(itemProps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
validateValue(property, value, object, type, result) {
|
||||
if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
|
||||
result.error = {
|
||||
type: "required",
|
||||
params: { type, property },
|
||||
};
|
||||
}
|
||||
|
||||
let dependent = wizardSchema[type].dependent[property];
|
||||
if (dependent && value && !object[dependent]) {
|
||||
result.error = {
|
||||
type: "dependent",
|
||||
params: { property, dependent },
|
||||
};
|
||||
}
|
||||
|
||||
if (property === "api_body") {
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {
|
||||
result.error = {
|
||||
type: "invalid",
|
||||
params: { type, property },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
buildMappedJson(value) {
|
||||
if (typeof value === "string" || Number.isInteger(value)) {
|
||||
return value;
|
||||
}
|
||||
if (!value || !value.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inputs = value;
|
||||
let result = [];
|
||||
|
||||
inputs.forEach((inpt) => {
|
||||
let input = {
|
||||
type: inpt.type,
|
||||
};
|
||||
|
||||
if (inpt.connector) {
|
||||
input.connector = inpt.connector;
|
||||
}
|
||||
|
||||
if (present(inpt.output)) {
|
||||
input.output = inpt.output;
|
||||
input.output_type = snakeCase(inpt.output_type);
|
||||
input.output_connector = inpt.output_connector;
|
||||
}
|
||||
|
||||
if (present(inpt.pairs)) {
|
||||
input.pairs = [];
|
||||
|
||||
inpt.pairs.forEach((pr) => {
|
||||
if (present(pr.key) && present(pr.value)) {
|
||||
let pairParams = {
|
||||
index: pr.index,
|
||||
key: pr.key,
|
||||
key_type: snakeCase(pr.key_type),
|
||||
value: pr.value,
|
||||
value_type: snakeCase(pr.value_type),
|
||||
connector: pr.connector,
|
||||
};
|
||||
|
||||
input.pairs.push(pairParams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
(input.type === "assignment" && present(input.output)) ||
|
||||
present(input.pairs)
|
||||
) {
|
||||
result.push(input);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.length) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
remove() {
|
||||
return ajax(`/admin/wizards/wizard/${this.id}`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.then(() => this.destroy())
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
CustomWizard.reopenClass({
|
||||
skip(wizardId) {
|
||||
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
|
||||
all() {
|
||||
return ajax("/admin/wizards/wizard", {
|
||||
type: "GET",
|
||||
})
|
||||
.then((result) => {
|
||||
CustomWizard.finished(result);
|
||||
return result.wizard_list;
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
restart(wizardId) {
|
||||
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
|
||||
.then(() => {
|
||||
window.location.href = `/w/${wizardId}`;
|
||||
submissions(wizardId, page = null) {
|
||||
let data = {};
|
||||
|
||||
if (page) {
|
||||
data.page = page;
|
||||
}
|
||||
|
||||
return ajax(`/admin/wizards/submissions/${wizardId}`, {
|
||||
type: "GET",
|
||||
data,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.wizard) {
|
||||
let fields = [{ id: "username", label: "User" }];
|
||||
let submissions = [];
|
||||
let wizard = result.wizard;
|
||||
let total = result.total;
|
||||
|
||||
result.submissions.forEach((s) => {
|
||||
let submission = {
|
||||
username: s.user,
|
||||
};
|
||||
|
||||
Object.keys(s.fields).forEach((fieldId) => {
|
||||
if (!fields.some((field) => field.id === fieldId)) {
|
||||
fields.push({ id: fieldId, label: s.fields[fieldId].label });
|
||||
}
|
||||
submission[fieldId] = s.fields[fieldId];
|
||||
});
|
||||
submission["submitted_at"] = s.submitted_at;
|
||||
submissions.push(submission);
|
||||
});
|
||||
|
||||
let submittedAt = {
|
||||
id: "submitted_at",
|
||||
label: "Submitted At",
|
||||
};
|
||||
|
||||
fields.push(submittedAt);
|
||||
|
||||
return {
|
||||
wizard,
|
||||
fields,
|
||||
submissions,
|
||||
total,
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
finished(result) {
|
||||
let url = "/";
|
||||
if (result.redirect_on_complete) {
|
||||
url = result.redirect_on_complete;
|
||||
}
|
||||
window.location.href = getUrl(url);
|
||||
},
|
||||
|
||||
build(wizardJson) {
|
||||
if (!wizardJson) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!wizardJson.completed && wizardJson.steps) {
|
||||
wizardJson.steps = wizardJson.steps
|
||||
.map((step) => {
|
||||
const stepObj = CustomWizardStep.create(step);
|
||||
stepObj.wizardId = wizardJson.id;
|
||||
|
||||
stepObj.fields.sort((a, b) => {
|
||||
return parseFloat(a.number) - parseFloat(b.number);
|
||||
});
|
||||
|
||||
let tabindex = 1;
|
||||
stepObj.fields.forEach((f) => {
|
||||
f.tabindex = tabindex;
|
||||
|
||||
if (["date_time"].includes(f.type)) {
|
||||
tabindex = tabindex + 2;
|
||||
} else {
|
||||
tabindex++;
|
||||
}
|
||||
});
|
||||
|
||||
stepObj.fields = stepObj.fields.map((f) => {
|
||||
f.wizardId = wizardJson.id;
|
||||
f.stepId = stepObj.id;
|
||||
return CustomWizardField.create(f);
|
||||
});
|
||||
|
||||
return stepObj;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return parseFloat(a.index) - parseFloat(b.index);
|
||||
});
|
||||
}
|
||||
return CustomWizard.create(wizardJson);
|
||||
create(wizardJson = {}) {
|
||||
const wizard = this._super.apply(this);
|
||||
wizard.setProperties(buildProperties(wizardJson));
|
||||
return wizard;
|
||||
},
|
||||
});
|
||||
|
||||
export function findCustomWizard(wizardId, params = {}) {
|
||||
let url = `/w/${wizardId}.json`;
|
||||
|
||||
let paramKeys = Object.keys(params).filter((k) => {
|
||||
if (k === "wizard_id") {
|
||||
return false;
|
||||
}
|
||||
return !!params[k];
|
||||
});
|
||||
|
||||
if (paramKeys.length) {
|
||||
url += "?";
|
||||
paramKeys.forEach((k, i) => {
|
||||
if (i > 0) {
|
||||
url += "&";
|
||||
}
|
||||
url += `${k}=${params[k]}`;
|
||||
});
|
||||
}
|
||||
|
||||
return ajax(url).then((result) => {
|
||||
return CustomWizard.build(result);
|
||||
});
|
||||
}
|
||||
|
||||
let _wizard_store;
|
||||
|
||||
export function updateCachedWizard(wizard) {
|
||||
_wizard_store = wizard;
|
||||
}
|
||||
|
||||
export function getCachedWizard() {
|
||||
return _wizard_store;
|
||||
}
|
||||
|
||||
export default CustomWizard;
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import CustomWizardApi from "../models/custom-wizard-api";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model(params) {
|
||||
if (params.name === "create") {
|
||||
return CustomWizardApi.create({ isNew: true });
|
||||
|
@ -13,12 +10,6 @@ export default DiscourseRoute.extend({
|
|||
}
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
if (model === null) {
|
||||
return this.router.transitionTo("adminWizardsApi");
|
||||
}
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set("api", model);
|
||||
},
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import CustomWizardApi from "../models/custom-wizard-api";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model() {
|
||||
return CustomWizardApi.list();
|
||||
},
|
||||
|
@ -28,11 +25,11 @@ export default DiscourseRoute.extend({
|
|||
actions: {
|
||||
changeApi(apiName) {
|
||||
this.controllerFor("adminWizardsApi").set("apiName", apiName);
|
||||
this.router.transitionTo("adminWizardsApiShow", apiName);
|
||||
this.transitionTo("adminWizardsApiShow", apiName);
|
||||
},
|
||||
|
||||
afterDestroy() {
|
||||
this.router.transitionTo("adminWizardsApi").then(() => this.refresh());
|
||||
this.transitionTo("adminWizardsApi").then(() => this.refresh());
|
||||
},
|
||||
|
||||
afterSave(apiName) {
|
||||
|
@ -41,7 +38,7 @@ export default DiscourseRoute.extend({
|
|||
|
||||
createApi() {
|
||||
this.controllerFor("adminWizardsApi").set("apiName", "create");
|
||||
this.router.transitionTo("adminWizardsApiShow", "create");
|
||||
this.transitionTo("adminWizardsApiShow", "create");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,9 +9,13 @@ export default DiscourseRoute.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
const customFields = A(model.custom_fields || []);
|
||||
const subscribed = model.subscribed;
|
||||
const subscription = model.subscription;
|
||||
|
||||
controller.setProperties({
|
||||
customFields,
|
||||
subscribed,
|
||||
subscription,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
import CustomWizardLogs from "../models/custom-wizard-logs";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { A } from "@ember/array";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model(params) {
|
||||
return CustomWizardLogs.list(params.wizardId);
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
if (model === null) {
|
||||
return this.router.transitionTo("adminWizardsLogs");
|
||||
}
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
wizard: model.wizard,
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model() {
|
||||
return ajax(`/admin/wizards/wizard`);
|
||||
},
|
||||
|
@ -21,7 +18,7 @@ export default DiscourseRoute.extend({
|
|||
actions: {
|
||||
changeWizard(wizardId) {
|
||||
this.controllerFor("adminWizardsLogs").set("wizardId", wizardId);
|
||||
this.router.transitionTo("adminWizardsLogsShow", wizardId);
|
||||
this.transitionTo("adminWizardsLogsShow", wizardId);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardAdmin.all();
|
||||
return CustomWizard.all();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
|
|
17
assets/javascripts/discourse/routes/admin-wizards-notices.js.es6
Normale Datei
17
assets/javascripts/discourse/routes/admin-wizards-notices.js.es6
Normale Datei
|
@ -0,0 +1,17 @@
|
|||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardNotice.list({ include_all: true });
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
notices: A(
|
||||
model.notices.map((notice) => CustomWizardNotice.create(notice))
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
|
@ -1,29 +1,23 @@
|
|||
import { A } from "@ember/array";
|
||||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import EmberObject from "@ember/object";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { formatModel } from "../lib/wizard-submission";
|
||||
import { inject as service } from "@ember/service";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model(params) {
|
||||
return CustomWizardAdmin.submissions(params.wizardId);
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
if (model === null) {
|
||||
return this.router.transitionTo("adminWizardsSubmissions");
|
||||
}
|
||||
return CustomWizard.submissions(params.wizardId);
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
const { fields, submissions } = formatModel(model);
|
||||
|
||||
const fields = model.fields.map((f) => {
|
||||
const fieldsObject = EmberObject.create(f);
|
||||
fieldsObject.enabled = true;
|
||||
return fieldsObject;
|
||||
});
|
||||
controller.setProperties({
|
||||
wizard: model.wizard,
|
||||
fields: A(fields),
|
||||
submissions: A(submissions),
|
||||
submissions: A(model.submissions),
|
||||
total: model.total,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model() {
|
||||
return ajax(`/admin/wizards/wizard`);
|
||||
},
|
||||
|
@ -21,7 +18,7 @@ export default DiscourseRoute.extend({
|
|||
actions: {
|
||||
changeWizard(wizardId) {
|
||||
this.controllerFor("adminWizardsSubmissions").set("wizardId", wizardId);
|
||||
this.router.transitionTo("adminWizardsSubmissionsShow", wizardId);
|
||||
this.transitionTo("adminWizardsSubmissionsShow", wizardId);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardSubscription.status();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set("model", model);
|
||||
controller.setup();
|
||||
},
|
||||
|
||||
actions: {
|
||||
authorize() {
|
||||
CustomWizardSubscription.authorize();
|
||||
},
|
||||
},
|
||||
});
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden …
In neuem Issue referenzieren