1
0
Fork 0

Commits vergleichen

..

Keine gemeinsamen Commits. „main“ und „remove_subs_and_notices“ haben vollständig unterschiedliche Historien.

437 geänderte Dateien mit 11871 neuen und 18344 gelöschten Zeilen

Datei anzeigen

@ -1,3 +1,2 @@
3.1.999: 1f35b80f85e5fd1efb7f4851f0845700432febdc
2.7.99: e07a57e398b6b1676ab42a7e34467556fca5416b 2.7.99: e07a57e398b6b1676ab42a7e34467556fca5416b
2.5.1: bb85b3a0d2c0ab6b59bcb405731c39089ec6731c 2.5.1: bb85b3a0d2c0ab6b59bcb405731c39089ec6731c

Datei anzeigen

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

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

Datei anzeigen

@ -36,9 +36,9 @@ jobs:
uses: actions/github-script@v5 uses: actions/github-script@v5
with: with:
script: | script: |
const semver = require('semver'); const semver = require('semver');
const { head_version, base_version } = process.env; const { head_version, base_version } = process.env;
if (semver.lte(head_version, base_version)) { if (semver.lte(head_version, base_version)) {
core.setFailed("Head version is equal to or lower than base version."); core.setFailed("Head version is equal to or lower than base version.");
} }

143
.github/workflows/plugin-tests.yml gevendort Normale Datei
Datei anzeigen

@ -0,0 +1,143 @@
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: ["6.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: haya14busa/action-cond@v1
id: discourse_branch
with:
cond: ${{ github.base_ref == 'stable' }}
if_true: "stable"
if_false: "tests-passed"
- uses: actions/checkout@v2
with:
repository: discourse/discourse
ref: ${{ steps.discourse_branch.outputs.value }}
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 }}
ref: "${{ github.base_ref }}"
fetch-depth: 1
- 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'
run: |
if [ -e plugins/${{ steps.repo-name.outputs.value }}/.simplecov ]
then
cp plugins/${{ steps.repo-name.outputs.value }}/.simplecov .simplecov
export COVERAGE=1
fi
bin/rake plugin:spec[${{ steps.repo-name.outputs.value }}]
- name: Plugin QUnit
if: matrix.build_type == 'frontend'
run: QUNIT_SKIP_CORE=1 LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bin/rake "qunit:test['600000','/w/qunit']"
timeout-minutes: 30

3
.gitignore gevendort
Datei anzeigen

@ -1,8 +1,7 @@
coverage/* coverage/*
!coverage/.last_run.json !coverage/.last_run.json
gems/* gems/
.bundle/ .bundle/
auto_generated auto_generated
.DS_Store .DS_Store
node_modules/ node_modules/
vendor/*

Datei anzeigen

@ -1,8 +1,2 @@
inherit_gem: inherit_gem:
rubocop-discourse: default.yml rubocop-discourse: default.yml
RSpec/ContextWording:
Enabled: false
RSpec/DescribeClass:
Enabled: false

Datei anzeigen

@ -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 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 it under the terms of the GNU General Public License as published by

Datei anzeigen

@ -2,32 +2,31 @@ GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
ast (2.4.2) ast (2.4.2)
json (2.6.2) parallel (1.20.1)
parallel (1.22.1) parser (3.0.1.0)
parser (3.1.2.1)
ast (~> 2.4.1) ast (~> 2.4.1)
rainbow (3.1.1) rainbow (3.0.0)
regexp_parser (2.6.0) regexp_parser (2.1.1)
rexml (3.2.5) rexml (3.2.5)
rubocop (1.36.0) rubocop (1.12.1)
json (~> 2.3)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 3.1.2.1) parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0) regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0) rexml
rubocop-ast (>= 1.20.1, < 2.0) rubocop-ast (>= 1.2.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0) unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.22.0) rubocop-ast (1.4.1)
parser (>= 3.1.1.0) parser (>= 2.7.1.5)
rubocop-discourse (3.0) rubocop-discourse (2.4.1)
rubocop (>= 1.1.0) rubocop (>= 1.1.0)
rubocop-rspec (>= 2.0.0) rubocop-rspec (>= 2.0.0)
rubocop-rspec (2.13.2) rubocop-rspec (2.2.0)
rubocop (~> 1.33) rubocop (~> 1.0)
rubocop-ast (>= 1.1.0)
ruby-progressbar (1.11.0) ruby-progressbar (1.11.0)
unicode-display_width (2.3.0) unicode-display_width (2.0.0)
PLATFORMS PLATFORMS
ruby ruby

Datei anzeigen

@ -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. See further: https://thepavilion.io/c/knowledge/discourse/custom-wizard/118
<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)

Datei anzeigen

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

Datei anzeigen

@ -8,7 +8,7 @@ class CustomWizard::AdminController < ::Admin::AdminController
subscribed: subcription.subscribed?, subscribed: subcription.subscribed?,
subscription_type: subcription.type, subscription_type: subcription.type,
subscription_attributes: CustomWizard::Subscription.attributes, subscription_attributes: CustomWizard::Subscription.attributes,
subscription_client_installed: CustomWizard::Subscription.client_installed? subscription_client_installed: subcription.client_installed?
) )
end end

Datei anzeigen

@ -20,10 +20,6 @@ class CustomWizard::AdminApiController < CustomWizard::AdminController
raise Discourse::InvalidParameters, "An API with that name already exists: '#{current.title || current.name}'" raise Discourse::InvalidParameters, "An API with that name already exists: '#{current.title || current.name}'"
end end
unless subscription.includes?(:api, :all)
raise Discourse::InvalidParameters, "Your subscription doesn't include API features."
end
PluginStoreRow.transaction do PluginStoreRow.transaction do
CustomWizard::Api.set(api_params[:name], title: api_params[:title]) CustomWizard::Api.set(api_params[:name], title: api_params[:title])
@ -134,8 +130,4 @@ class CustomWizard::AdminApiController < CustomWizard::AdminController
@auth_data ||= auth_data @auth_data ||= auth_data
end end
def subscription
@subscription ||= CustomWizard::Subscription.new
end
end end

Datei anzeigen

@ -22,12 +22,7 @@ class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
end end
def download def download
content = ActiveModel::ArraySerializer.new( send_data submission_list.submissions.to_json,
CustomWizard::Submission.list(@wizard).submissions,
each_serializer: CustomWizard::SubmissionSerializer
)
send_data content.to_json,
filename: "#{Discourse.current_hostname}-wizard-submissions-#{@wizard.name}.json", filename: "#{Discourse.current_hostname}-wizard-submissions-#{@wizard.name}.json",
content_type: "application/json", content_type: "application/json",
disposition: "attachment" disposition: "attachment"

Datei anzeigen

@ -88,7 +88,6 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
:title, :title,
:key, :key,
:banner, :banner,
:banner_upload_id,
:raw_description, :raw_description,
:required_data_message, :required_data_message,
:force_final, :force_final,
@ -100,7 +99,6 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
:index, :index,
:label, :label,
:image, :image,
:image_upload_id,
:description, :description,
:required, :required,
:key, :key,
@ -114,7 +112,6 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
:property, :property,
:preview_template, :preview_template,
:placeholder, :placeholder,
:can_create_tag,
prefill: mapped_params, prefill: mapped_params,
content: mapped_params, content: mapped_params,
condition: mapped_params, condition: mapped_params,
@ -164,9 +161,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
mentionable_level: mapped_params, mentionable_level: mapped_params,
messageable_level: mapped_params, messageable_level: mapped_params,
visibility_level: mapped_params, visibility_level: mapped_params,
members_visibility_level: mapped_params, members_visibility_level: mapped_params
add_event: mapped_params,
add_location: mapped_params
] ]
) )
end end

Datei anzeigen

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::StepsController < ::CustomWizard::WizardClientController class CustomWizard::StepsController < ::ApplicationController
before_action :ensure_logged_in
before_action :ensure_can_update before_action :ensure_can_update
def update def update
@ -21,7 +22,7 @@ class CustomWizard::StepsController < ::CustomWizard::WizardClientController
if updater.success? if updater.success?
wizard_id = update_params[:wizard_id] wizard_id = update_params[:wizard_id]
builder = CustomWizard::Builder.new(wizard_id, current_user, guest_id) builder = CustomWizard::Builder.new(wizard_id, current_user)
@wizard = builder.build(force: true) @wizard = builder.build(force: true)
current_step = @wizard.find_step(update[:step_id]) current_step = @wizard.find_step(update[:step_id])
@ -84,6 +85,7 @@ class CustomWizard::StepsController < ::CustomWizard::WizardClientController
private private
def ensure_can_update def ensure_can_update
@builder = CustomWizard::Builder.new(update_params[:wizard_id], current_user)
raise Discourse::InvalidParameters.new(:wizard_id) if @builder.template.nil? raise Discourse::InvalidParameters.new(:wizard_id) if @builder.template.nil?
raise Discourse::InvalidAccess.new if !@builder.wizard || !@builder.wizard.can_access? raise Discourse::InvalidAccess.new if !@builder.wizard || !@builder.wizard.can_access?

Datei anzeigen

@ -1,10 +1,39 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::WizardController < ::CustomWizard::WizardClientController class CustomWizard::WizardController < ::ActionController::Base
def show helper ApplicationHelper
if wizard.present?
render json: CustomWizard::WizardSerializer.new(wizard, scope: guardian, root: false).as_json, status: 200 include CurrentUser
else include CanonicalURL::ControllerExtensions
render json: { error: I18n.t('wizard.none') } include GlobalPath
prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'app', 'views'))
layout :set_wizard_layout
before_action :preload_wizard_json
before_action :ensure_plugin_enabled
before_action :ensure_logged_in, only: [:skip]
helper_method :wizard_page_title
helper_method :wizard_theme_id
helper_method :wizard_theme_lookup
helper_method :wizard_theme_translations_lookup
def set_wizard_layout
action_name === 'qunit' ? 'qunit' : 'wizard'
end
def index
respond_to do |format|
format.json do
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
format.html do
render "default/empty"
end
end end
end end
@ -28,12 +57,69 @@ class CustomWizard::WizardController < ::CustomWizard::WizardClientController
render json: result render json: result
end end
def qunit
raise Discourse::InvalidAccess.new if Rails.env.production?
respond_to do |format|
format.html do
render "default/empty"
end
end
end
protected protected
def ensure_logged_in
raise Discourse::NotLoggedIn.new unless current_user.present?
end
def guardian
@guardian ||= Guardian.new(current_user, request)
end
def wizard def wizard
@wizard ||= begin @wizard ||= begin
return nil unless @builder.present? builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user)
@builder.build({ reset: params[:reset] }, params) return nil unless builder.present?
opts = {}
opts[:reset] = params[:reset]
builder.build(opts, params)
end
end
def wizard_page_title
wizard ? (wizard.name || wizard.id) : I18n.t('wizard.custom_title')
end
def wizard_theme_id
wizard ? wizard.theme_id : nil
end
def wizard_theme_lookup(name)
Theme.lookup_field(wizard_theme_id, view_context.mobile_view? ? :mobile : :desktop, name)
end
def wizard_theme_translations_lookup
Theme.lookup_field(wizard_theme_id, :translations, I18n.locale)
end
def preload_wizard_json
return if request.xhr? || request.format.json?
return if request.method != "GET"
store_preloaded("siteSettings", SiteSetting.client_settings_json)
end
def store_preloaded(key, json)
@preloaded ||= {}
@preloaded[key] = json.gsub("</", "<\\/")
end
private
def ensure_plugin_enabled
unless SiteSetting.custom_wizard_enabled
redirect_to path("/")
end end
end end
end end

Datei anzeigen

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

Datei anzeigen

@ -2,15 +2,12 @@
class CustomWizard::SubmissionSerializer < ApplicationSerializer class CustomWizard::SubmissionSerializer < ApplicationSerializer
attributes :id, attributes :id,
:fields, :fields,
:submitted_at, :submitted_at
:user
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
def include_user? def include_user?
object.wizard.user.present? object.user.present?
end
def user
::BasicUserSerializer.new(object.wizard.user, root: false).as_json
end end
def fields def fields

Datei anzeigen

@ -17,7 +17,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
:property, :property,
:content, :content,
:tag_groups, :tag_groups,
:can_create_tag,
:validations, :validations,
:max_length, :max_length,
:char_counter, :char_counter,
@ -99,10 +98,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
object.tag_groups object.tag_groups
end end
def can_create_tag
object.can_create_tag
end
def validations def validations
validations = {} validations = {}
object.validations&.each do |type, props| object.validations&.each do |type, props|

Datei anzeigen

@ -9,10 +9,14 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
:completed, :completed,
:required, :required,
:permitted, :permitted,
:uncategorized_category_id,
:categories,
:subscribed,
:resume_on_revisit :resume_on_revisit
has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects
has_one :user, serializer: ::BasicUserSerializer, embed: :objects has_one :user, serializer: ::BasicUserSerializer, embed: :objects
has_many :groups, serializer: ::BasicGroupSerializer, embed: :objects
def completed def completed
object.completed? object.completed?
@ -43,4 +47,28 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
def include_steps? def include_steps?
!include_completed? !include_completed?
end end
def include_categories?
object.needs_categories
end
def include_groups?
object.needs_groups
end
def uncategorized_category_id
SiteSetting.uncategorized_category_id
end
def include_uncategorized_category_id?
object.needs_categories
end
def categories
object.categories.map { |c| c.to_h }
end
def subscribed
CustomWizard::Subscription.subscribed?
end
end end

Datei anzeigen

@ -0,0 +1,62 @@
<html>
<head>
<%= discourse_color_scheme_stylesheets %>
<%= discourse_stylesheet_link_tag :wizard, theme_id: nil %>
<%= discourse_stylesheet_link_tag :wizard_custom %>
<%- if wizard_theme_id.present? %>
<%= discourse_stylesheet_link_tag (mobile_view? ? :mobile_theme : :desktop_theme), theme_id: wizard_theme_id %>
<%- end %>
<%= preload_script "locales/#{I18n.locale}" %>
<%= 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" %>
<script src="<%= ExtraLocalesController.url("wizard") %>"></script>
<%= csrf_meta_tags %>
<%- unless customization_disabled? %>
<%= wizard_theme_translations_lookup %>
<%= raw wizard_theme_lookup("head_tag") %>
<%- end %>
<%= server_plugin_outlet "custom_wizard" %>
<%= tag.meta id: 'data-discourse-setup', data: client_side_setup_data %>
<meta name="discourse_theme_id" content="<%= wizard_theme_id %>">
<meta name="discourse-base-uri" content="<%= Discourse.base_path %>">
<%= render partial: "layouts/head" %>
<title><%= wizard_page_title %></title>
</head>
<body class='custom-wizard'>
<%- unless customization_disabled? %>
<%= raw wizard_theme_lookup("header") %>
<%- end %>
<div id='custom-wizard-main'></div>
<%- unless customization_disabled? %>
<%= raw wizard_theme_lookup("body_tag") %>
<%- end %>
<%- if current_user %>
<%= preload_script 'wizard-custom-start' %>
<%- else %>
<%= preload_script 'wizard-custom-guest' %>
<%- end %>
<div id="svg-sprites" style="display:none;">
<div class="fontawesome">
<%= raw SvgSprite.bundle %>
</div>
</div>
<div class="hidden" id="data-preloaded-wizard" data-preloaded-wizard="<%= preloaded_json %>"></div>
</body>
</html>

Datei anzeigen

@ -1,3 +0,0 @@
import Component from "@ember/component";
export default Component.extend({});

Datei anzeigen

@ -1,3 +0,0 @@
import Component from "@ember/component";
export default Component.extend({});

Datei anzeigen

@ -1,3 +0,0 @@
import Component from "@ember/component";
export default Component.extend({});

Datei anzeigen

@ -1,3 +0,0 @@
import Component from "@ember/component";
export default Component.extend({});

Datei anzeigen

@ -1,3 +0,0 @@
import Component from "@ember/component";
export default Component.extend({});

Datei anzeigen

@ -1,3 +0,0 @@
import TimeInput from "discourse/components/time-input";
export default TimeInput.extend({});

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,4 +1,5 @@
import { default as discourseComputed } from "discourse-common/utils/decorators"; import { default as discourseComputed } from "discourse-common/utils/decorators";
import { subscriptionSelectKitContent } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-subscription";
import { empty, equal, or } from "@ember/object/computed"; import { empty, equal, or } from "@ember/object/computed";
import { notificationLevels, selectKitContent } from "../lib/wizard"; import { notificationLevels, selectKitContent } from "../lib/wizard";
import { computed } from "@ember/object"; import { computed } from "@ember/object";
@ -15,7 +16,6 @@ export default Component.extend(UndoChanges, {
createTopic: equal("action.type", "create_topic"), createTopic: equal("action.type", "create_topic"),
updateProfile: equal("action.type", "update_profile"), updateProfile: equal("action.type", "update_profile"),
watchCategories: equal("action.type", "watch_categories"), watchCategories: equal("action.type", "watch_categories"),
watchTags: equal("action.type", "watch_tags"),
sendMessage: equal("action.type", "send_message"), sendMessage: equal("action.type", "send_message"),
openComposer: equal("action.type", "open_composer"), openComposer: equal("action.type", "open_composer"),
sendToApi: equal("action.type", "send_to_api"), sendToApi: equal("action.type", "send_to_api"),
@ -37,11 +37,13 @@ export default Component.extend(UndoChanges, {
availableNotificationLevels: notificationLevels.map((type) => { availableNotificationLevels: notificationLevels.map((type) => {
return { return {
id: type, 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") @discourseComputed("action.type")
messageKey(type) { messageKey(type) {
@ -92,13 +94,8 @@ export default Component.extend(UndoChanges, {
return apis.find((a) => a.name === api).endpoints; return apis.find((a) => a.name === api).endpoints;
}, },
@discourseComputed("fieldTypes") @discourseComputed
hasEventField(fieldTypes) { actionTypes() {
return fieldTypes.map((ft) => ft.id).includes("event"); return subscriptionSelectKitContent("action", "types");
},
@discourseComputed("fieldTypes")
hasLocationField(fieldTypes) {
return fieldTypes.map((ft) => ft.id).includes("location");
}, },
}); });

Datei anzeigen

@ -27,7 +27,7 @@ export default Component.extend(UndoChanges, {
isTextType: or("isText", "isTextarea", "isComposer"), isTextType: or("isText", "isTextarea", "isComposer"),
isComposerPreview: equal("field.type", "composer_preview"), isComposerPreview: equal("field.type", "composer_preview"),
categoryPropertyTypes: selectKitContent(["id", "slug"]), categoryPropertyTypes: selectKitContent(["id", "slug"]),
messageUrl: "https://discourse.pluginmanager.org/t/field-settings", messageUrl: "https://thepavilion.io/t/2809",
@discourseComputed("field.type") @discourseComputed("field.type")
validations(type) { validations(type) {
@ -143,17 +143,11 @@ export default Component.extend(UndoChanges, {
actions: { actions: {
imageUploadDone(upload) { imageUploadDone(upload) {
this.setProperties({ this.set("field.image", upload.url);
"field.image": upload.url,
"field.image_upload_id": upload.id,
});
}, },
imageUploadDeleted() { imageUploadDeleted() {
this.setProperties({ this.set("field.image", null);
"field.image": null,
"field.image_upload_id": null,
});
}, },
}, },
}); });

Datei anzeigen

@ -24,17 +24,11 @@ export default Component.extend({
actions: { actions: {
bannerUploadDone(upload) { bannerUploadDone(upload) {
this.setProperties({ this.set("step.banner", upload.url);
"step.banner": upload.url,
"step.banner_upload_id": upload.id,
});
}, },
bannerUploadDeleted() { bannerUploadDeleted() {
this.setProperties({ this.set("step.banner", null);
"step.banner": null,
"step.banner_upload_id": null,
});
}, },
}, },
}); });

Datei anzeigen

@ -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: { actions: {
add() { add() {
const items = this.get("items"); const items = this.get("items");
@ -89,9 +78,16 @@ export default Component.extend({
let params = setWizardDefaults({}, itemType); let params = setWizardDefaults({}, itemType);
params.isNew = true; params.isNew = true;
params.index = this.getNextIndex();
let id = `${itemType}_${params.index + 1}`; let index = 0;
if (items.length) {
let last_item = items[items.length - 1];
index = Number(last_item.id.split("_").pop());
}
params.index = index;
let id = `${itemType}_${index + 1}`;
if (itemType === "field") { if (itemType === "field") {
id = `${this.parentId}_${id}`; id = `${this.parentId}_${id}`;
} }

Datei anzeigen

@ -15,7 +15,6 @@ import {
import Component from "@ember/component"; import Component from "@ember/component";
import { bind, later } from "@ember/runloop"; import { bind, later } from "@ember/runloop";
import I18n from "I18n"; import I18n from "I18n";
import Subscription from "../mixins/subscription";
const customFieldActionMap = { const customFieldActionMap = {
topic: ["create_topic", "send_message"], topic: ["create_topic", "send_message"],
@ -27,7 +26,7 @@ const customFieldActionMap = {
const values = ["present", "true", "false"]; const values = ["present", "true", "false"];
export default Component.extend(Subscription, { export default Component.extend({
classNameBindings: [":mapper-selector", "activeType"], classNameBindings: [":mapper-selector", "activeType"],
showText: computed("activeType", function () { showText: computed("activeType", function () {
@ -117,9 +116,6 @@ export default Component.extend(Subscription, {
groupEnabled: computed("options.groupSelection", "inputType", function () { groupEnabled: computed("options.groupSelection", "inputType", function () {
return this.optionEnabled("groupSelection"); return this.optionEnabled("groupSelection");
}), }),
guestGroup: computed("options.guestGroup", "inputType", function () {
return this.optionEnabled("guestGroup");
}),
userEnabled: computed("options.userSelection", "inputType", function () { userEnabled: computed("options.userSelection", "inputType", function () {
return this.optionEnabled("userSelection"); return this.optionEnabled("userSelection");
}), }),
@ -130,29 +126,7 @@ export default Component.extend(Subscription, {
return this.connector === "is"; return this.connector === "is";
}), }),
@discourseComputed("site.groups", "guestGroup", "subscriptionType") groups: alias("site.groups"),
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;
},
categories: alias("site.categories"), categories: alias("site.categories"),
showComboBox: or( showComboBox: or(
"showWizardField", "showWizardField",
@ -403,7 +377,7 @@ export default Component.extend(Subscription, {
this.changeValue(event.target.value); this.changeValue(event.target.value);
}, },
changeUserValue(value) { changeUserValue(previousValue, value) {
this.changeValue(value); this.changeValue(value);
}, },
}, },

Datei anzeigen

@ -32,7 +32,6 @@ export default Component.extend({
pairConnector: options.pairConnector || null, pairConnector: options.pairConnector || null,
outputConnector: options.outputConnector || null, outputConnector: options.outputConnector || null,
context: options.context || null, context: options.context || null,
guestGroup: options.guestGroup || false,
}; };
let inputTypes = ["key", "value", "output"]; let inputTypes = ["key", "value", "output"];

Datei anzeigen

@ -11,7 +11,7 @@ export default Component.extend(Subscription, {
@discourseComputed("subscriptionType") @discourseComputed("subscriptionType")
i18nKey(type) { i18nKey(type) {
return `admin.wizard.subscription.type.${type ? type : "none"}`; return `admin.wizard.subscription_container.type.${type ? type : "none"}`;
}, },
@discourseComputed("i18nKey") @discourseComputed("i18nKey")

Datei anzeigen

@ -7,19 +7,19 @@ export default Component.extend(Subscription, {
@discourseComputed("subscribed") @discourseComputed("subscribed")
subscribedIcon(subscribed) { subscribedIcon(subscribed) {
return subscribed ? "check" : "times"; return subscribed ? "check" : "dash";
}, },
@discourseComputed("subscribed") @discourseComputed("subscribed")
subscribedLabel(subscribed) { subscribedLabel(subscribed) {
return `admin.wizard.subscription.${ return `admin.wizard.subscription_container.${
subscribed ? "subscribed" : "not_subscribed" subscribed ? "subscribed" : "not_subscribed"
}.label`; }.label`;
}, },
@discourseComputed("subscribed") @discourseComputed("subscribed")
subscribedTitle(subscribed) { subscribedTitle(subscribed) {
return `admin.wizard.subscription.${ return `admin.wizard.subscription_container.${
subscribed ? "subscribed" : "not_subscribed" subscribed ? "subscribed" : "not_subscribed"
}.title`; }.title`;
}, },

Datei anzeigen

@ -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();
},
});

Datei anzeigen

@ -1,6 +1,10 @@
import SingleSelectComponent from "select-kit/components/single-select"; import SingleSelectComponent from "select-kit/components/single-select";
import Subscription from "../mixins/subscription"; import Subscription from "../mixins/subscription";
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema"; import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
import {
subscriptionTypeSufficient,
subscriptionTypes,
} from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-subscription";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "I18n"; import I18n from "I18n";
@ -25,69 +29,45 @@ export default SingleSelectComponent.extend(Subscription, {
caretDownIcon: "caret-down", caretDownIcon: "caret-down",
}, },
allowedSubscriptionTypes(feature, attribute, value) { requiredSubscriptionType(feature, attribute, value) {
let attributes = this.subscriptionAttributes[feature]; let attributes = this.subscriptionAttributes[feature];
if (!attributes || !attributes[attribute]) { if (!attributes || !attributes[attribute]) {
return ["none"]; return null;
} }
let allowedTypes = [];
Object.keys(attributes[attribute]).forEach((subscriptionType) => { let requiredType = null;
Object.keys(attributes[attribute]).some((subscriptionType) => {
let values = attributes[attribute][subscriptionType]; let values = attributes[attribute][subscriptionType];
if (values[0] === "*" || values.includes(value)) { if (values[0] === "*" || values.includes(value)) {
allowedTypes.push(subscriptionType); if (subscriptionTypes.includes(subscriptionType)) {
requiredType = subscriptionType;
}
return true;
} }
return false;
}); });
return allowedTypes;
return requiredType;
}, },
@discourseComputed("feature", "attribute", "wizard.allowGuests") @discourseComputed("feature", "attribute")
content(feature, attribute) { content(feature, attribute) {
return filterValues(this.wizard, feature, attribute) return wizardSchema[feature][attribute].map((value) => {
.map((value) => { let requiredSubscriptionType = this.requiredSubscriptionType(
let allowedSubscriptionTypes = this.allowedSubscriptionTypes( feature,
feature, attribute,
attribute, value
value );
); return {
id: value,
let subscriptionRequired = name: I18n.t(nameKey(feature, attribute, value)),
allowedSubscriptionTypes.length && subscriptionType: requiredSubscriptionType,
!allowedSubscriptionTypes.includes("none"); disabled: !subscriptionTypeSufficient(
this.subscriptionType,
let attrs = { requiredSubscriptionType
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() { modifyComponentForRow() {

Datei anzeigen

@ -25,9 +25,9 @@ export default Component.extend({
textState: "text-collapsed", textState: "text-collapsed",
toggleText: I18n.t("admin.wizard.expand_text"), toggleText: I18n.t("admin.wizard.expand_text"),
@discourseComputed("value", "isUser", "isSubmittedAt") @discourseComputed("value", "isUser")
hasValue(value, isUser, isSubmittedAt) { hasValue(value, isUser) {
if (isUser || isSubmittedAt) { if (isUser) {
return value; return value;
} }
return value && value.value; return value && value.value;

Datei anzeigen

@ -5,7 +5,11 @@ import { scheduleOnce } from "@ember/runloop";
import Component from "@ember/component"; import Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
const excludedUserProperties = ["profile_background", "card_background"]; const excludedUserProperties = [
"avatar",
"profile_background",
"card_background",
];
export default Component.extend({ export default Component.extend({
classNames: "wizard-text-editor", classNames: "wizard-text-editor",
@ -48,12 +52,12 @@ export default Component.extend({
@discourseComputed("wizardFields") @discourseComputed("wizardFields")
wizardFieldList(wizardFields) { wizardFieldList(wizardFields) {
return (wizardFields || []).map((f) => ` w{${f.id}}`); return wizardFields.map((f) => ` w{${f.id}}`);
}, },
@discourseComputed("wizardActions") @discourseComputed("wizardActions")
wizardActionList(wizardActions) { wizardActionList(wizardActions) {
return (wizardActions || []).map((a) => ` w{${a.id}}`); return wizardActions.map((a) => ` w{${a.id}}`);
}, },
actions: { actions: {

Datei anzeigen

@ -4,4 +4,4 @@
{{#if wizardErrorNotice}} {{#if wizardErrorNotice}}
{{d-icon "exclaimation-circle"}} {{d-icon "exclaimation-circle"}}
{{/if}} {{/if}}
{{/if}} {{/if}}

Datei anzeigen

@ -9,7 +9,8 @@
value=wizardListVal value=wizardListVal
content=wizardList content=wizardList
onChange=(action "changeWizard") onChange=(action "changeWizard")
options=(hash none="admin.wizard.select") options=(hash
}} none="admin.wizard.select"
)}}
</div> </div>
</section> </section>

Datei anzeigen

@ -1,9 +1,9 @@
import CustomWizardAdmin from "../../models/custom-wizard-admin"; import CustomWizard from "../../models/custom-wizard";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
export default { export default {
setupComponent(attrs, component) { setupComponent(attrs, component) {
CustomWizardAdmin.all() CustomWizard.all()
.then((result) => { .then((result) => {
component.set("wizardList", result); component.set("wizardList", result);
}) })

Datei anzeigen

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

Datei anzeigen

@ -4,14 +4,10 @@ import CustomWizardApi from "../models/custom-wizard-api";
import { default as discourseComputed } from "discourse-common/utils/decorators"; import { default as discourseComputed } from "discourse-common/utils/decorators";
import { and, equal, not } from "@ember/object/computed"; import { and, equal, not } from "@ember/object/computed";
import { selectKitContent } from "../lib/wizard"; import { selectKitContent } from "../lib/wizard";
import { underscore } from "@ember/string";
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import { inject as service } from "@ember/service";
export default Controller.extend({ export default Controller.extend({
router: service(),
queryParams: ["refresh_list"], queryParams: ["refresh_list"],
loadingSubscriptions: false, loadingSubscriptions: false,
notAuthorized: not("api.authorized"), notAuthorized: not("api.authorized"),
@ -24,8 +20,29 @@ export default Controller.extend({
"application/x-www-form-urlencoded", "application/x-www-form-urlencoded",
]), ]),
successCodes: selectKitContent([ successCodes: selectKitContent([
100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 100,
302, 303, 303, 304, 305, 306, 307, 308, 101,
102,
200,
201,
202,
203,
204,
205,
206,
207,
208,
226,
300,
301,
302,
303,
303,
304,
305,
306,
307,
308,
]), ]),
@discourseComputed( @discourseComputed(
@ -71,11 +88,6 @@ export default Controller.extend({
twoLeggedOauth: equal("api.authType", "oauth_2"), twoLeggedOauth: equal("api.authType", "oauth_2"),
threeLeggedOauth: equal("api.authType", "oauth_3"), threeLeggedOauth: equal("api.authType", "oauth_3"),
@discourseComputed("api.isNew")
nameClass(isNew) {
return isNew ? "new" : "saved";
},
actions: { actions: {
addParam() { addParam() {
this.get("api.authParams").pushObject({}); this.get("api.authParams").pushObject({});
@ -101,7 +113,7 @@ export default Controller.extend({
if (authType === "oauth_2") { if (authType === "oauth_2") {
this.set("authorizing", true); this.set("authorizing", true);
ajax(`/admin/wizards/apis/${underscore(name)}/authorize`) ajax(`/admin/wizards/apis/${name.underscore()}/authorize`)
.catch(popupAjaxError) .catch(popupAjaxError)
.then((result) => { .then((result) => {
if (result.success) { if (result.success) {
@ -137,6 +149,7 @@ export default Controller.extend({
const api = this.get("api"); const api = this.get("api");
const name = api.name; const name = api.name;
const authType = api.authType; const authType = api.authType;
let refreshList = false; // eslint-disable-line
let error; let error;
if (!name || !authType) { if (!name || !authType) {
@ -151,6 +164,11 @@ export default Controller.extend({
data["title"] = api.title; data["title"] = api.title;
} }
const originalTitle = this.get("api.originalTitle");
if (api.get("isNew") || (originalTitle && api.title !== originalTitle)) {
refreshList = true;
}
if (api.get("isNew")) { if (api.get("isNew")) {
data["new"] = true; data["new"] = true;
} }
@ -170,11 +188,11 @@ export default Controller.extend({
if (!api[rp]) { if (!api[rp]) {
let key = rp.replace("auth", ""); let key = rp.replace("auth", "");
error = `${I18n.t( error = `${I18n.t(
`admin.wizard.api.auth.${underscore(key)}` `admin.wizard.api.auth.${key.underscore()}`
)} is required for ${authType}`; )} is required for ${authType}`;
break; break;
} }
data[underscore(rp)] = api[rp]; data[rp.underscore()] = api[rp];
} }
} }
@ -204,7 +222,7 @@ export default Controller.extend({
this.set("updating", true); this.set("updating", true);
ajax(`/admin/wizards/api/${underscore(name)}`, { ajax(`/admin/wizards/api/${name.underscore()}`, {
type: "PUT", type: "PUT",
data, data,
}) })
@ -227,7 +245,7 @@ export default Controller.extend({
this.set("updating", true); this.set("updating", true);
ajax(`/admin/wizards/api/${underscore(name)}`, { ajax(`/admin/wizards/api/${name.underscore()}`, {
type: "DELETE", type: "DELETE",
}) })
.catch(popupAjaxError) .catch(popupAjaxError)
@ -245,13 +263,13 @@ export default Controller.extend({
return; return;
} }
ajax(`/admin/wizards/api/${underscore(name)}/logs`, { ajax(`/admin/wizards/api/${name.underscore()}/logs`, {
type: "DELETE", type: "DELETE",
}) })
.catch(popupAjaxError) .catch(popupAjaxError)
.then((result) => { .then((result) => {
if (result.success) { if (result.success) {
this.router.transitionTo("adminWizardsApis").then(() => { this.transitionToRoute("adminWizardsApis").then(() => {
this.send("refreshModel"); this.send("refreshModel");
}); });
} }

Datei anzeigen

@ -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")();
},
},
});

Datei anzeigen

@ -4,7 +4,7 @@ import CustomWizardCustomField from "../models/custom-wizard-custom-field";
export default Controller.extend({ export default Controller.extend({
messageKey: "create", messageKey: "create",
fieldKeys: ["klass", "type", "name", "serializers"], fieldKeys: ["klass", "type", "name", "serializers"],
documentationUrl: "https://discourse.pluginmanager.org/t/custom-fields", documentationUrl: "https://thepavilion.io/t/3572",
actions: { actions: {
addField() { addField() {

Datei anzeigen

@ -7,7 +7,7 @@ import I18n from "I18n";
import { underscore } from "@ember/string"; import { underscore } from "@ember/string";
export default Controller.extend({ export default Controller.extend({
messageUrl: "https://discourse.pluginmanager.org/t/wizard-manager", messageUrl: "https://thepavilion.io/t/3652",
messageKey: "info", messageKey: "info",
messageIcon: "info-circle", messageIcon: "info-circle",
messageClass: "info", messageClass: "info",
@ -68,7 +68,7 @@ export default Controller.extend({
file: null, file: null,
filename: null, filename: null,
}); });
document.getElementById("custom-wizard-file-upload").value = ""; $("#file-upload").val("");
}, },
@observes("importing", "destroying") @observes("importing", "destroying")
@ -83,7 +83,7 @@ export default Controller.extend({
actions: { actions: {
upload() { upload() {
document.getElementById("custom-wizard-file-upload").click(); $("#file-upload").click();
}, },
clearFile() { clearFile() {
@ -102,7 +102,7 @@ export default Controller.extend({
if (maxFileSize < file.size) { if (maxFileSize < file.size) {
this.setMessage("error", "file_size_error"); this.setMessage("error", "file_size_error");
this.set("file", null); this.set("file", null);
document.getElementById("custom-wizard-file-upload").value = ""; $("#file-upload").val("");
} else { } else {
this.setProperties({ this.setProperties({
file, file,

Datei anzeigen

@ -2,13 +2,10 @@ import Controller from "@ember/controller";
import { empty } from "@ember/object/computed"; import { empty } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { fmt } from "discourse/lib/computed"; import { fmt } from "discourse/lib/computed";
import { inject as service } from "@ember/service"; import showModal from "discourse/lib/show-modal";
import AdminWizardsColumnsModal from "../components/modal/admin-wizards-columns"; import CustomWizard from "../models/custom-wizard";
import CustomWizardAdmin from "../models/custom-wizard-admin";
import { formatModel } from "../lib/wizard-submission";
export default Controller.extend({ export default Controller.extend({
modal: service(),
downloadUrl: fmt("wizard.id", "/admin/wizards/submissions/%@/download"), downloadUrl: fmt("wizard.id", "/admin/wizards/submissions/%@/download"),
noResults: empty("submissions"), noResults: empty("submissions"),
page: 0, page: 0,
@ -19,12 +16,10 @@ export default Controller.extend({
const wizardId = this.get("wizard.id"); const wizardId = this.get("wizard.id");
this.set("loadingMore", true); this.set("loadingMore", true);
CustomWizardAdmin.submissions(wizardId, page) CustomWizard.submissions(wizardId, page)
.then((result) => { .then((result) => {
if (result.submissions) { if (result.submissions) {
const { submissions } = formatModel(result); this.get("submissions").pushObjects(result.submissions);
this.get("submissions").pushObjects(submissions);
} }
}) })
.finally(() => { .finally(() => {
@ -32,7 +27,7 @@ export default Controller.extend({
}); });
}, },
@discourseComputed("submissions.[]", "fields.@each.enabled") @discourseComputed("submissions", "fields.@each.enabled")
displaySubmissions(submissions, fields) { displaySubmissions(submissions, fields) {
let result = []; let result = [];
@ -59,7 +54,7 @@ export default Controller.extend({
}, },
showEditColumnsModal() { showEditColumnsModal() {
return this.modal.show(AdminWizardsColumnsModal, { return showModal("admin-wizards-columns", {
model: { model: {
columns: this.get("fields"), columns: this.get("fields"),
reset: () => { reset: () => {

Datei anzeigen

@ -3,18 +3,15 @@ import {
observes, observes,
} from "discourse-common/utils/decorators"; } from "discourse-common/utils/decorators";
import { notEmpty } from "@ember/object/computed"; import { notEmpty } from "@ember/object/computed";
import { inject as service } from "@ember/service"; import showModal from "discourse/lib/show-modal";
import NextSessionScheduledModal from "../components/modal/next-session-scheduled";
import { generateId, wizardFieldList } from "../lib/wizard"; import { generateId, wizardFieldList } from "../lib/wizard";
import { dasherize } from "@ember/string"; import { dasherize } from "@ember/string";
import { later, scheduleOnce } from "@ember/runloop"; import { later, scheduleOnce } from "@ember/runloop";
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import copyText from "discourse/lib/copy-text"; import copyText from "discourse/lib/copy-text";
import I18n from "I18n"; import I18n from "I18n";
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
export default Controller.extend({ export default Controller.extend({
modal: service(),
hasName: notEmpty("wizard.name"), hasName: notEmpty("wizard.name"),
@observes("currentStep") @observes("currentStep")
@ -39,8 +36,7 @@ export default Controller.extend({
@discourseComputed("wizard.id") @discourseComputed("wizard.id")
wizardUrl(wizardId) { wizardUrl(wizardId) {
let baseUrl = window.location.href.split("/admin"); return window.location.origin + "/w/" + dasherize(wizardId);
return baseUrl[0] + "/w/" + dasherize(wizardId);
}, },
@discourseComputed("wizard.after_time_scheduled") @discourseComputed("wizard.after_time_scheduled")
@ -62,19 +58,6 @@ export default Controller.extend({
} }
return wizardFieldList(steps); 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) { getErrorMessage(result) {
if (result.backend_validation_error) { if (result.backend_validation_error) {
return result.backend_validation_error; return result.backend_validation_error;
@ -128,13 +111,15 @@ export default Controller.extend({
}, },
setNextSessionScheduled() { setNextSessionScheduled() {
this.modal.show(NextSessionScheduledModal, { let controller = showModal("next-session-scheduled", {
model: { model: {
dateTime: this.wizard.after_time_scheduled, dateTime: this.wizard.after_time_scheduled,
update: (dateTime) => update: (dateTime) =>
this.set("wizard.after_time_scheduled", dateTime), this.set("wizard.after_time_scheduled", dateTime),
}, },
}); });
controller.setup();
}, },
copyUrl() { copyUrl() {

Datei anzeigen

@ -21,6 +21,5 @@ export default Controller.extend({
return key; return key;
}, },
messageUrl: messageUrl: "https://thepavilion.io/c/knowledge/discourse/custom-wizard",
"https://discourse.pluginmanager.org/c/discourse-custom-wizard/documentation",
}); });

Datei anzeigen

@ -1,9 +1,7 @@
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import { equal, or } from "@ember/object/computed"; import { equal } from "@ember/object/computed";
export default Controller.extend({ export default Controller.extend({
businessSubscription: equal("subscriptionType", "business"), businessSubscription: equal("subscriptionType", "business"),
communitySubscription: equal("subscriptionType", "community"),
standardSubscription: equal("subscriptionType", "standard"), standardSubscription: equal("subscriptionType", "standard"),
showApi: or("businessSubscription", "communitySubscription"),
}); });

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,6 @@
import { registerUnbound } from "discourse-common/lib/helpers";
import { dasherize } from "@ember/string";
registerUnbound("dasherize", function (string) {
return dasherize(string);
});

Datei anzeigen

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

Datei anzeigen

@ -1,12 +1,11 @@
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import getUrl from "discourse-common/lib/get-url"; import getUrl from "discourse-common/lib/get-url";
import { observes } from "discourse-common/utils/decorators";
export default { export default {
name: "custom-wizard-edits", name: "custom-wizard-edits",
initialize(container) { initialize(container) {
const siteSettings = container.lookup("service:site-settings"); const siteSettings = container.lookup("site-settings:main");
if (!siteSettings.custom_wizard_enabled) { if (!siteSettings.custom_wizard_enabled) {
return; return;
@ -36,63 +35,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;
});
},
});
}); });
}, },
}; };

Datei anzeigen

@ -1,16 +1,14 @@
import DiscourseURL from "discourse/lib/url"; import ApplicationRoute from "discourse/routes/application";
import { withPluginApi } from "discourse/lib/plugin-api";
import { dasherize } from "@ember/string";
export default { export default {
name: "custom-wizard-redirect", name: "custom-wizard-redirect",
after: "message-bus", after: "message-bus",
initialize(container) { initialize: function (container) {
const messageBus = container.lookup("service:message-bus"); const messageBus = container.lookup("message-bus:main");
const siteSettings = container.lookup("service:site-settings"); const siteSettings = container.lookup("site-settings:main");
if (!siteSettings.custom_wizard_enabled) { if (!siteSettings.custom_wizard_enabled || !messageBus) {
return; return;
} }
@ -19,27 +17,28 @@ export default {
window.location.href = wizardUrl; window.location.href = wizardUrl;
}); });
withPluginApi("0.8.36", (api) => { ApplicationRoute.reopen({
api.onAppEvent("page:changed", (data) => { actions: {
const currentUser = api.getCurrentUser(); willTransition(transition) {
const redirectToWizard = this.get("currentUser.redirect_to_wizard");
if (currentUser) { const excludedPaths = this.siteSettings.wizard_redirect_exclude_paths
const redirectToWizard = currentUser.redirect_to_wizard;
const excludedPaths = siteSettings.wizard_redirect_exclude_paths
.split("|") .split("|")
.concat(["loading"]); .concat(["loading"]);
if ( if (
redirectToWizard && redirectToWizard &&
!data.url.includes("ignore_redirect") && (!transition.intent.name ||
data.currentRouteName !== "customWizardStep" && !excludedPaths.find((p) => {
!excludedPaths.find((p) => { return transition.intent.name.indexOf(p) > -1;
return data.currentRouteName.indexOf(p) > -1; }))
})
) { ) {
DiscourseURL.routeTo(`/w/${dasherize(redirectToWizard)}`); transition.abort();
window.location = "/w/" + redirectToWizard.dasherize();
} }
}
}); return this._super(transition);
},
},
}); });
}, },
}; };

Datei anzeigen

@ -35,7 +35,6 @@ function inputTypesContent(options = {}) {
const connectors = { const connectors = {
pair: [ pair: [
"equal", "equal",
"not_equal",
"greater", "greater",
"less", "less",
"greater_or_equal", "greater_or_equal",

Datei anzeigen

@ -41,7 +41,6 @@ const step = {
index: null, index: null,
title: null, title: null,
banner: null, banner: null,
banner_upload_id: null,
raw_description: null, raw_description: null,
required_data: null, required_data: null,
required_data_message: null, required_data_message: null,
@ -66,13 +65,11 @@ const field = {
index: null, index: null,
label: null, label: null,
image: null, image: null,
image_upload_id: null,
description: null, description: null,
property: null, property: null,
required: null, required: null,
type: null, type: null,
condition: null, condition: null,
tag_groups: null,
}, },
types: {}, types: {},
mapped: ["prefill", "content", "condition", "index"], mapped: ["prefill", "content", "condition", "index"],
@ -99,8 +96,6 @@ const action = {
custom_fields: null, custom_fields: null,
skip_redirect: null, skip_redirect: null,
suppress_notifications: null, suppress_notifications: null,
add_event: null,
add_location: null,
}, },
send_message: { send_message: {
title: null, title: null,
@ -133,12 +128,6 @@ const action = {
wizard_user: true, wizard_user: true,
usernames: null, usernames: null,
}, },
watch_tags: {
tags: null,
notification_level: null,
wizard_user: true,
usernames: null,
},
send_to_api: { send_to_api: {
api: null, api: null,
api_endpoint: null, api_endpoint: null,
@ -203,50 +192,17 @@ const action = {
"messageable_level", "messageable_level",
"visibility_level", "visibility_level",
"members_visibility_level", "members_visibility_level",
"add_event",
"add_location",
], ],
required: ["id", "type"], required: ["id", "type"],
dependent: {}, dependent: {},
objectArrays: {}, 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 = { const custom_field = {
klass: ["topic", "post", "group", "category"], klass: ["topic", "post", "group", "category"],
type: ["string", "boolean", "integer", "json"], 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); field.type = Object.keys(field.types);
action.type = Object.keys(action.types); action.type = Object.keys(action.types);
@ -256,30 +212,17 @@ const wizardSchema = {
field, field,
custom_field, custom_field,
action, action,
filters,
}; };
export function buildFieldTypes(types) {
wizardSchema.field.types = types;
}
export function buildFieldValidations(validations) { export function buildFieldValidations(validations) {
wizardSchema.field.validations = validations; wizardSchema.field.validations = validations;
} }
export function filterValues(currentWizard, feature, attribute, values = null) { const siteSettings = getOwner(this).lookup("site-settings:main");
values = values || wizardSchema[feature][attribute];
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));
}
}
}
return values;
}
const siteSettings = getOwner(this).lookup("service:site-settings");
if (siteSettings.wizard_apis_enabled) { if (siteSettings.wizard_apis_enabled) {
wizardSchema.action.types.send_to_api = { wizardSchema.action.types.send_to_api = {
api: null, api: null,

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,22 @@
const subscriptionTypes = ["standard", "business"];
function subscriptionTypeSufficient(subscriptionType, requiredType) {
if (requiredType && !subscriptionType) {
return false;
}
if (requiredType === "none" || requiredType === null) {
return true;
}
if (
requiredType === "standard" &&
subscriptionTypes.includes(subscriptionType)
) {
return true;
}
if (requiredType === "business" && subscriptionType === "business") {
return true;
}
return false;
}
export { subscriptionTypeSufficient, subscriptionTypes };

Datei anzeigen

@ -1,6 +1,5 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import wizardSchema from "./wizard-schema"; import wizardSchema from "./wizard-schema";
import I18n from "I18n";
function selectKitContent(content) { function selectKitContent(content) {
return content.map((i) => ({ id: i, name: i })); return content.map((i) => ({ id: i, name: i }));
@ -34,10 +33,6 @@ function camelCase(string) {
}); });
} }
function translationOrText(i18nKey, text) {
return I18n.findTranslation(i18nKey) ? I18n.t(i18nKey) : text;
}
const userProperties = [ const userProperties = [
"name", "name",
"username", "username",
@ -126,5 +121,4 @@ export {
notificationLevels, notificationLevels,
wizardFieldList, wizardFieldList,
sentenceCase, sentenceCase,
translationOrText,
}; };

Datei anzeigen

@ -3,14 +3,8 @@ import { getOwner } from "discourse-common/lib/get-owner";
import { readOnly } from "@ember/object/computed"; import { readOnly } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators"; 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({ export default Mixin.create({
subscriptionLandingUrl: PRODUCT_PAGE, subscriptionLandingUrl: "https://custom-wizard.pavilion.tech",
subscriptionClientUrl: "/admin/plugins/subscription-client", subscriptionClientUrl: "/admin/plugins/subscription-client",
@discourseComputed @discourseComputed
@ -21,7 +15,6 @@ export default Mixin.create({
subscribed: readOnly("adminWizards.subscribed"), subscribed: readOnly("adminWizards.subscribed"),
subscriptionType: readOnly("adminWizards.subscriptionType"), subscriptionType: readOnly("adminWizards.subscriptionType"),
businessSubscription: readOnly("adminWizards.businessSubscription"), businessSubscription: readOnly("adminWizards.businessSubscription"),
communitySubscription: readOnly("adminWizards.communitySubscription"),
standardSubscription: readOnly("adminWizards.standardSubscription"), standardSubscription: readOnly("adminWizards.standardSubscription"),
subscriptionAttributes: readOnly("adminWizards.subscriptionAttributes"), subscriptionAttributes: readOnly("adminWizards.subscriptionAttributes"),
subscriptionClientInstalled: readOnly( subscriptionClientInstalled: readOnly(
@ -34,20 +27,4 @@ export default Mixin.create({
? this.subscriptionClientUrl ? this.subscriptionClientUrl
: this.subscriptionLandingUrl; : 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;
}
},
}); });

Datei anzeigen

@ -4,8 +4,6 @@ import { get, set } from "@ember/object";
import Mixin from "@ember/object/mixin"; import Mixin from "@ember/object/mixin";
import { deepEqual } from "discourse-common/lib/object"; import { deepEqual } from "discourse-common/lib/object";
const observedCache = [];
export default Mixin.create({ export default Mixin.create({
didInsertElement() { didInsertElement() {
this._super(...arguments); this._super(...arguments);
@ -34,13 +32,7 @@ export default Mixin.create({
}; };
listProperties(componentType, opts).forEach((property) => { listProperties(componentType, opts).forEach((property) => {
if (observedCache.includes(property)) { obj.removeObserver(property, this, this.toggleUndo);
obj.removeObserver(property, this, this.toggleUndo);
let index = observedCache.indexOf(property);
if (index !== -1) {
observedCache.splice(index, 1);
}
}
}); });
}, },
@ -53,9 +45,6 @@ export default Mixin.create({
}; };
listProperties(componentType, opts).forEach((property) => { listProperties(componentType, opts).forEach((property) => {
if (observedCache.indexOf(property) === -1) {
observedCache.push(property);
}
obj.addObserver(property, this, this.toggleUndo); obj.addObserver(property, this, this.toggleUndo);
}); });
}, },

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,127 +1,272 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators"; import { Promise } from "rsvp";
import getUrl from "discourse-common/lib/get-url"; import { listProperties, snakeCase } from "../lib/wizard";
import CustomWizardField from "./custom-wizard-field"; import { buildProperties, mapped, present } from "../lib/wizard-json";
import CustomWizardStep from "./custom-wizard-step"; import wizardSchema from "../lib/wizard-schema";
const CustomWizard = EmberObject.extend({ const CustomWizard = EmberObject.extend({
@discourseComputed("steps.length") save(opts) {
totalSteps: (length) => length, return new Promise((resolve, reject) => {
let wizard = this.buildJson(this, "wizard");
skip() { if (wizard.error) {
if (this.required && !this.completed && this.permitted) { reject(wizard);
return; }
}
CustomWizard.skip(this.id); 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);
}
});
});
}, },
restart() { buildJson(object, type, result = {}) {
CustomWizard.restart(this.id); 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({ CustomWizard.reopenClass({
skip(wizardId) { all() {
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" }) return ajax("/admin/wizards/wizard", {
type: "GET",
})
.then((result) => { .then((result) => {
CustomWizard.finished(result); return result.wizard_list;
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, },
restart(wizardId) { submissions(wizardId, page = null) {
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" }) let data = {};
.then(() => {
window.location.href = `/w/${wizardId}`; 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); .catch(popupAjaxError);
}, },
finished(result) { create(wizardJson = {}) {
let url = "/"; const wizard = this._super.apply(this);
if (result.redirect_on_complete) { wizard.setProperties(buildProperties(wizardJson));
url = result.redirect_on_complete; return wizard;
}
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);
}, },
}); });
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; export default CustomWizard;

Datei anzeigen

@ -1,10 +1,7 @@
import CustomWizardApi from "../models/custom-wizard-api"; import CustomWizardApi from "../models/custom-wizard-api";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model(params) { model(params) {
if (params.name === "create") { if (params.name === "create") {
return CustomWizardApi.create({ isNew: true }); 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) { setupController(controller, model) {
controller.set("api", model); controller.set("api", model);
}, },

Datei anzeigen

@ -1,10 +1,7 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import CustomWizardApi from "../models/custom-wizard-api"; import CustomWizardApi from "../models/custom-wizard-api";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model() { model() {
return CustomWizardApi.list(); return CustomWizardApi.list();
}, },
@ -28,11 +25,11 @@ export default DiscourseRoute.extend({
actions: { actions: {
changeApi(apiName) { changeApi(apiName) {
this.controllerFor("adminWizardsApi").set("apiName", apiName); this.controllerFor("adminWizardsApi").set("apiName", apiName);
this.router.transitionTo("adminWizardsApiShow", apiName); this.transitionTo("adminWizardsApiShow", apiName);
}, },
afterDestroy() { afterDestroy() {
this.router.transitionTo("adminWizardsApi").then(() => this.refresh()); this.transitionTo("adminWizardsApi").then(() => this.refresh());
}, },
afterSave(apiName) { afterSave(apiName) {
@ -41,7 +38,7 @@ export default DiscourseRoute.extend({
createApi() { createApi() {
this.controllerFor("adminWizardsApi").set("apiName", "create"); this.controllerFor("adminWizardsApi").set("apiName", "create");
this.router.transitionTo("adminWizardsApiShow", "create"); this.transitionTo("adminWizardsApiShow", "create");
}, },
}, },
}); });

Datei anzeigen

@ -1,21 +1,12 @@
import CustomWizardLogs from "../models/custom-wizard-logs"; import CustomWizardLogs from "../models/custom-wizard-logs";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { A } from "@ember/array"; import { A } from "@ember/array";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model(params) { model(params) {
return CustomWizardLogs.list(params.wizardId); return CustomWizardLogs.list(params.wizardId);
}, },
afterModel(model) {
if (model === null) {
return this.router.transitionTo("adminWizardsLogs");
}
},
setupController(controller, model) { setupController(controller, model) {
controller.setProperties({ controller.setProperties({
wizard: model.wizard, wizard: model.wizard,

Datei anzeigen

@ -1,10 +1,7 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model() { model() {
return ajax(`/admin/wizards/wizard`); return ajax(`/admin/wizards/wizard`);
}, },
@ -21,7 +18,7 @@ export default DiscourseRoute.extend({
actions: { actions: {
changeWizard(wizardId) { changeWizard(wizardId) {
this.controllerFor("adminWizardsLogs").set("wizardId", wizardId); this.controllerFor("adminWizardsLogs").set("wizardId", wizardId);
this.router.transitionTo("adminWizardsLogsShow", wizardId); this.transitionTo("adminWizardsLogsShow", wizardId);
}, },
}, },
}); });

Datei anzeigen

@ -1,9 +1,9 @@
import CustomWizardAdmin from "../models/custom-wizard-admin"; import CustomWizard from "../models/custom-wizard";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
model() { model() {
return CustomWizardAdmin.all(); return CustomWizard.all();
}, },
setupController(controller, model) { setupController(controller, model) {

Datei anzeigen

@ -1,29 +1,23 @@
import { A } from "@ember/array"; import { A } from "@ember/array";
import CustomWizardAdmin from "../models/custom-wizard-admin"; import EmberObject from "@ember/object";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { formatModel } from "../lib/wizard-submission"; import CustomWizard from "../models/custom-wizard";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model(params) { model(params) {
return CustomWizardAdmin.submissions(params.wizardId); return CustomWizard.submissions(params.wizardId);
},
afterModel(model) {
if (model === null) {
return this.router.transitionTo("adminWizardsSubmissions");
}
}, },
setupController(controller, model) { 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({ controller.setProperties({
wizard: model.wizard, wizard: model.wizard,
fields: A(fields), fields: A(fields),
submissions: A(submissions), submissions: A(model.submissions),
total: model.total, total: model.total,
}); });
}, },

Datei anzeigen

@ -1,10 +1,7 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model() { model() {
return ajax(`/admin/wizards/wizard`); return ajax(`/admin/wizards/wizard`);
}, },
@ -21,7 +18,7 @@ export default DiscourseRoute.extend({
actions: { actions: {
changeWizard(wizardId) { changeWizard(wizardId) {
this.controllerFor("adminWizardsSubmissions").set("wizardId", wizardId); this.controllerFor("adminWizardsSubmissions").set("wizardId", wizardId);
this.router.transitionTo("adminWizardsSubmissionsShow", wizardId); this.transitionTo("adminWizardsSubmissionsShow", wizardId);
}, },
}, },
}); });

Datei anzeigen

@ -1,12 +1,9 @@
import CustomWizardAdmin from "../models/custom-wizard-admin"; import CustomWizard from "../models/custom-wizard";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import I18n from "I18n"; import I18n from "I18n";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model(params) { model(params) {
if (params.wizardId === "create") { if (params.wizardId === "create") {
return { create: true }; return { create: true };
@ -17,15 +14,13 @@ export default DiscourseRoute.extend({
afterModel(model) { afterModel(model) {
if (model.none) { if (model.none) {
return this.router.transitionTo("adminWizardsWizard"); return this.transitionTo("adminWizardsWizard");
} }
}, },
setupController(controller, model) { setupController(controller, model) {
const parentModel = this.modelFor("adminWizardsWizard"); const parentModel = this.modelFor("adminWizardsWizard");
const wizard = CustomWizardAdmin.create( const wizard = CustomWizard.create(!model || model.create ? {} : model);
!model || model.create ? {} : model
);
const fieldTypes = Object.keys(parentModel.field_types).map((type) => { const fieldTypes = Object.keys(parentModel.field_types).map((type) => {
return { return {
id: type, id: type,

Datei anzeigen

@ -4,11 +4,8 @@ import EmberObject, { set } from "@ember/object";
import { A } from "@ember/array"; import { A } from "@ember/array";
import { all } from "rsvp"; import { all } from "rsvp";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model() { model() {
return ajax("/admin/wizards/wizard"); return ajax("/admin/wizards/wizard");
}, },
@ -83,14 +80,14 @@ export default DiscourseRoute.extend({
this.controllerFor("adminWizardsWizard").set("wizardId", wizardId); this.controllerFor("adminWizardsWizard").set("wizardId", wizardId);
if (wizardId) { if (wizardId) {
this.router.transitionTo("adminWizardsWizardShow", wizardId); this.transitionTo("adminWizardsWizardShow", wizardId);
} else { } else {
this.router.transitionTo("adminWizardsWizard"); this.transitionTo("adminWizardsWizard");
} }
}, },
afterDestroy() { afterDestroy() {
this.router.transitionTo("adminWizardsWizard").then(() => this.refresh()); this.transitionTo("adminWizardsWizard").then(() => this.refresh());
}, },
afterSave(wizardId) { afterSave(wizardId) {
@ -99,7 +96,7 @@ export default DiscourseRoute.extend({
createWizard() { createWizard() {
this.controllerFor("adminWizardsWizard").set("wizardId", "create"); this.controllerFor("adminWizardsWizard").set("wizardId", "create");
this.router.transitionTo("adminWizardsWizardShow", "create"); this.transitionTo("adminWizardsWizardShow", "create");
}, },
}, },
}); });

Datei anzeigen

@ -1,10 +1,7 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
router: service(),
model() { model() {
return ajax("/admin/wizards"); return ajax("/admin/wizards");
}, },
@ -20,7 +17,7 @@ export default DiscourseRoute.extend({
afterModel(model, transition) { afterModel(model, transition) {
if (transition.targetName === "adminWizards.index") { if (transition.targetName === "adminWizards.index") {
this.router.transitionTo("adminWizardsWizard"); this.transitionTo("adminWizardsWizard");
} }
}, },
}); });

Datei anzeigen

@ -8,12 +8,7 @@
{{/if}} {{/if}}
{{/if}} {{/if}}
{{d-button {{d-button label="admin.wizard.api.save" action=(action "save") class="btn-primary" disabled=saveDisabled}}
label="admin.wizard.api.save"
action=(action "save")
class="btn-primary"
disabled=saveDisabled
}}
{{#if showRemove}} {{#if showRemove}}
{{d-button action=(action "remove") label="admin.wizard.api.remove"}} {{d-button action=(action "remove") label="admin.wizard.api.remove"}}
@ -26,32 +21,26 @@
{{/if}} {{/if}}
</div> </div>
<div class="wizard-header large"> <div class="wizard-header">
{{#if api.isNew}} {{#if api.isNew}}
{{i18n "admin.wizard.api.new"}} {{i18n "admin.wizard.api.new"}}
{{else}} {{else}}
<span>{{api.title}}</span> {{api.title}}
{{/if}} {{/if}}
</div> </div>
<div class="metadata"> <div class="metadata">
<div class="title"> <div class="title">
<label>{{i18n "admin.wizard.api.title"}}</label> <label>{{i18n "admin.wizard.api.title"}}</label>
<Input {{input value=api.title placeholder=(i18n "admin.wizard.api.title_placeholder")}}
@value={{this.api.title}}
placeholder={{i18n "admin.wizard.api.title_placeholder"}}
/>
</div> </div>
<div class="name {{nameClass}}"> <div class="name">
<label>{{i18n "admin.wizard.api.name"}}</label> <label>{{i18n "admin.wizard.api.name"}}</label>
{{#if api.isNew}} {{#if api.isNew}}
<Input {{input value=api.name placeholder=(i18n "admin.wizard.api.name_placeholder")}}
@value={{this.api.name}}
placeholder={{i18n "admin.wizard.api.name_placeholder"}}
/>
{{else}} {{else}}
<span>{{api.name}}</span> {{api.name}}
{{/if}} {{/if}}
</div> </div>
</div> </div>
@ -67,16 +56,14 @@
<span>{{authErrorMessage}}</span> <span>{{authErrorMessage}}</span>
{{/if}} {{/if}}
{{/if}} {{/if}}
{{d-button {{d-button label="admin.wizard.api.auth.btn"
label="admin.wizard.api.auth.btn" action=(action "authorize")
action=(action "authorize") disabled=authDisabled
disabled=authDisabled class="btn-primary"}}
class="btn-primary"
}}
{{/if}} {{/if}}
</div> </div>
<div class="wizard-header medium"> <div class="wizard-header">
{{i18n "admin.wizard.api.auth.label"}} {{i18n "admin.wizard.api.auth.label"}}
</div> </div>
</div> </div>
@ -84,7 +71,7 @@
<div class="wizard-api-authentication"> <div class="wizard-api-authentication">
<div class="settings"> <div class="settings">
<div class="wizard-header small"> <div class="wizard-header medium">
{{i18n "admin.wizard.api.auth.settings"}} {{i18n "admin.wizard.api.auth.settings"}}
</div> </div>
@ -106,8 +93,9 @@
value=api.authType value=api.authType
content=authorizationTypes content=authorizationTypes
onChange=(action (mut api.authType)) onChange=(action (mut api.authType))
options=(hash none="admin.wizard.api.auth.type_none") options=(hash
}} none="admin.wizard.api.auth.type_none"
)}}
</div> </div>
</div> </div>
@ -116,7 +104,7 @@
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.url"}}</label> <label>{{i18n "admin.wizard.api.auth.url"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.authUrl}} /> {{input value=api.authUrl}}
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -124,21 +112,21 @@
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.token_url"}}</label> <label>{{i18n "admin.wizard.api.auth.token_url"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.tokenUrl}} /> {{input value=api.tokenUrl}}
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.client_id"}}</label> <label>{{i18n "admin.wizard.api.auth.client_id"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.clientId}} /> {{input value=api.clientId}}
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.client_secret"}}</label> <label>{{i18n "admin.wizard.api.auth.client_secret"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.clientSecret}} /> {{input value=api.clientSecret}}
</div> </div>
</div> </div>
@ -147,26 +135,12 @@
<div class="controls"> <div class="controls">
{{#each api.authParams as |param|}} {{#each api.authParams as |param|}}
<div class="param"> <div class="param">
<Input {{input value=param.key placeholder=(i18n "admin.wizard.key")}}
@value={{this.param.key}} {{input value=param.value placeholder=(i18n "admin.wizard.value")}}
placeholder={{i18n "admin.wizard.key"}} {{d-button action=(action "removeParam") actionParam=param icon="times"}}
/>
<Input
@value={{this.param.value}}
placeholder={{i18n "admin.wizard.value"}}
/>
{{d-button
action=(action "removeParam")
actionParam=param
icon="times"
}}
</div> </div>
{{/each}} {{/each}}
{{d-button {{d-button label="admin.wizard.api.auth.params.new" icon="plus" action=(action "addParam")}}
label="admin.wizard.api.auth.params.new"
icon="plus"
action=(action "addParam")
}}
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -175,14 +149,14 @@
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.username"}}</label> <label>{{i18n "admin.wizard.api.auth.username"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.username}} /> {{input value=api.username}}
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.wizard.api.auth.password"}}</label> <label>{{i18n "admin.wizard.api.auth.password"}}</label>
<div class="controls"> <div class="controls">
<Input @value={{this.api.password}} /> {{input value=api.password}}
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -200,7 +174,7 @@
{{/if}} {{/if}}
</div> </div>
<div class="wizard-header small"> <div class="wizard-header medium">
{{i18n "admin.wizard.api.status.label"}} {{i18n "admin.wizard.api.status.label"}}
</div> </div>
@ -246,16 +220,12 @@
{{/if}} {{/if}}
</div> </div>
<div class="wizard-header medium"> <div class="wizard-header">
{{i18n "admin.wizard.api.endpoint.label"}} {{i18n "admin.wizard.api.endpoint.label"}}
</div> </div>
<div class="wizard-api-endpoints"> <div class="wizard-api-endpoints">
{{d-button {{d-button action=(action "addEndpoint") label="admin.wizard.api.endpoint.add" icon="plus"}}
action=(action "addEndpoint")
label="admin.wizard.api.endpoint.add"
icon="plus"
}}
{{#if api.endpoints}} {{#if api.endpoints}}
<div class="endpoint-list"> <div class="endpoint-list">
@ -265,43 +235,38 @@
<div class="endpoint"> <div class="endpoint">
<div class="endpoint-"> <div class="endpoint-">
<div class="top"> <div class="top">
<Input {{input value=endpoint.name
@value={{endpoint.name}} placeholder=(i18n "admin.wizard.api.endpoint.name")}}
placeholder={{i18n "admin.wizard.api.endpoint.name"}} {{input value=endpoint.url
/> placeholder=(i18n "admin.wizard.api.endpoint.url")
<Input class="endpoint-url"}}
@value={{endpoint.url}} {{d-button action=(action "removeEndpoint")
placeholder={{i18n "admin.wizard.api.endpoint.url"}} actionParam=endpoint
class="endpoint-url" icon="times"
/> class="remove-endpoint"}}
{{d-button
action=(action "removeEndpoint")
actionParam=endpoint
icon="times"
class="remove-endpoint"
}}
</div> </div>
<div class="bottom"> <div class="bottom">
{{combo-box {{combo-box
content=endpointMethods content=endpointMethods
value=endpoint.method value=endpoint.method
onChange=(action (mut endpoint.method)) onChange=(action (mut endpoint.method))
options=(hash none="admin.wizard.api.endpoint.method") options=(hash
}} none="admin.wizard.api.endpoint.method"
)}}
{{combo-box {{combo-box
content=contentTypes content=contentTypes
value=endpoint.content_type value=endpoint.content_type
onChange=(action (mut endpoint.content_type)) onChange=(action (mut endpoint.content_type))
options=(hash none="admin.wizard.api.endpoint.content_type") options=(hash
}} none="admin.wizard.api.endpoint.content_type"
)}}
{{multi-select {{multi-select
value=endpoint.success_codes value=endpoint.success_codes
content=successCodes content=successCodes
onChange=(action (mut endpoint.success_codes)) onChange=(action (mut endpoint.success_codes))
options=(hash options=(hash
none="admin.wizard.api.endpoint.success_codes" none="admin.wizard.api.endpoint.success_codes"
) )}}
}}
</div> </div>
</div> </div>
</div> </div>
@ -312,16 +277,11 @@
{{/if}} {{/if}}
</div> </div>
<div class="wizard-header medium"> <div class="wizard-header">
{{i18n "admin.wizard.api.log.label"}} {{i18n "admin.wizard.api.log.label"}}
{{d-button action=(action "clearLogs")
<div class="controls"> icon="trash-alt"
{{d-button class="clear-logs"}}
action=(action "clearLogs")
class="clear-logs"
label="admin.wizard.api.log.clear"
}}
</div>
</div> </div>
<div class="wizard-api-log"> <div class="wizard-api-log">
@ -340,10 +300,7 @@
<td>{{logentry.time}}</td> <td>{{logentry.time}}</td>
<td class="user-image"> <td class="user-image">
<div class="user-image-inner"> <div class="user-image-inner">
<a <a href={{logentry.userpath}} data-user-card={{logentry.username}}>{{avatar logentry imageSize="large"}}</a>
href={{logentry.userpath}}
data-user-card={{logentry.username}}
>{{avatar logentry imageSize="medium"}}</a>
</div> </div>
</td> </td>
<td>{{logentry.status}}</td> <td>{{logentry.status}}</td>
@ -354,4 +311,4 @@
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>

Datei anzeigen

@ -3,16 +3,16 @@
value=apiName value=apiName
content=apiList content=apiList
onChange=(route-action "changeApi") onChange=(route-action "changeApi")
options=(hash none="admin.wizard.api.select") options=(hash
}} none="admin.wizard.api.select"
)}}
{{d-button {{d-button
action=(route-action "createApi") action="createApi"
label="admin.wizard.api.create" label="admin.wizard.api.create"
icon="plus" icon="plus"}}
}}
</div> </div>
<div class="admin-wizard-container"> <div class="admin-wizard-container">
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -5,8 +5,7 @@
{{d-button {{d-button
label="admin.wizard.custom_field.add" label="admin.wizard.custom_field.add"
icon="plus" icon="plus"
action=(action "addField") action="addField"}}
}}
</div> </div>
</div> </div>
@ -15,8 +14,7 @@
opts=messageOpts opts=messageOpts
type=messageType type=messageType
url=documentationUrl url=documentationUrl
component="custom_fields" component="custom_fields"}}
}}
<div class="admin-wizard-container"> <div class="admin-wizard-container">
{{#if customFields}} {{#if customFields}}
@ -34,10 +32,9 @@
{{custom-field-input {{custom-field-input
field=field field=field
removeField=(action "removeField") removeField=(action "removeField")
saveField=(action "saveField") saveField=(action "saveField")}}
}}
{{/each}} {{/each}}
</tbody> </tbody>
</table> </table>
{{/if}} {{/if}}
</div> </div>

Datei anzeigen

@ -8,9 +8,8 @@
{{d-button {{d-button
label="refresh" label="refresh"
icon="sync" icon="sync"
action=(action "refresh") action="refresh"
class="refresh" class="refresh"}}
}}
</div> </div>
</div> </div>
@ -32,10 +31,7 @@
{{#each logs as |log|}} {{#each logs as |log|}}
<tr> <tr>
{{#each-in log as |field value|}} {{#each-in log as |field value|}}
<td class="small">{{wizard-table-field <td class="small">{{wizard-table-field field=field value=value}}</td>
field=field
value=value
}}</td>
{{/each-in}} {{/each-in}}
</tr> </tr>
{{/each}} {{/each}}
@ -46,4 +42,4 @@
{{conditional-loading-spinner condition=refreshing}} {{conditional-loading-spinner condition=refreshing}}
{{/load-more}} {{/load-more}}
</div> </div>
{{/if}} {{/if}}

Datei anzeigen

@ -3,17 +3,17 @@
value=wizardId value=wizardId
content=wizardList content=wizardList
onChange=(route-action "changeWizard") onChange=(route-action "changeWizard")
options=(hash none="admin.wizard.select") options=(hash
}} none="admin.wizard.select"
)}}
</div> </div>
{{wizard-message {{wizard-message
key=messageKey key=messageKey
opts=messageOpts opts=messageOpts
url=documentationUrl url=documentationUrl
component="logs" component="logs"}}
}}
<div class="admin-wizard-container"> <div class="admin-wizard-container">
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -11,35 +11,30 @@
</div> </div>
{{/if}} {{/if}}
<Input {{input
id="custom-wizard-file-upload" id="file-upload"
@type="file" type="file"
accept="application/json" accept="application/json"
{{on "input" (action "setFile")}} change=(action "setFile")}}
/>
{{d-button {{d-button
id="upload-button" id="upload-button"
label="admin.wizard.manager.upload" label="admin.wizard.manager.upload"
action=(action "upload") action=(action "upload")}}
}}
{{d-button {{d-button
id="import-button" id="import-button"
label="admin.wizard.manager.import" label="admin.wizard.manager.import"
action=(action "import") action=(action "import")
disabled=importDisabled disabled=importDisabled}}
}}
{{d-button {{d-button
id="export-button" id="export-button"
label="admin.wizard.manager.export" label="admin.wizard.manager.export"
action=(action "export") action=(action "export")
disabled=exportDisabled disabled=exportDisabled}}
}}
{{d-button {{d-button
id="destroy-button" id="destroy-button"
label="admin.wizard.manager.destroy" label="admin.wizard.manager.destroy"
action=(action "destroy") action=(action "destroy")
disabled=destoryDisabled disabled=destoryDisabled}}
}}
</div> </div>
</div> </div>
@ -50,8 +45,7 @@
opts=messageOpts opts=messageOpts
items=messageItems items=messageItems
loading=loading loading=loading
component="manager" component="manager"}}
}}
<div class="admin-wizard-container"> <div class="admin-wizard-container">
<table class="table grid"> <table class="table grid">
@ -71,21 +65,19 @@
{{/link-to}} {{/link-to}}
</td> </td>
<td class="control-column"> <td class="control-column">
<Input {{input
@type="checkbox" type="checkbox"
class="export" class="export"
{{on "change" (action "selectWizard")}} change=(action "selectWizard")}}
/>
</td> </td>
<td class="control-column"> <td class="control-column">
<Input {{input
@type="checkbox" type="checkbox"
class="destroy" class="destroy"
{{on "change" (action "selectWizard")}} change=(action "selectWizard")}}
/>
</td> </td>
</tr> </tr>
{{/each}} {{/each}}
</tbody> </tbody>
</table> </table>
</div> </div>

Datei anzeigen

@ -58,4 +58,4 @@
{{conditional-loading-spinner condition=loadingMore}} {{conditional-loading-spinner condition=loadingMore}}
{{/load-more}} {{/load-more}}
</div> </div>
{{/if}} {{/if}}

Datei anzeigen

@ -3,17 +3,17 @@
value=wizardId value=wizardId
content=wizardList content=wizardList
onChange=(route-action "changeWizard") onChange=(route-action "changeWizard")
options=(hash none="admin.wizard.select") options=(hash
}} none="admin.wizard.select"
)}}
</div> </div>
{{wizard-message {{wizard-message
key=messageKey key=messageKey
opts=messageOpts opts=messageOpts
url=documentationUrl url=documentationUrl
component="submissions" component="submissions"}}
}}
<div class="admin-wizard-container"> <div class="admin-wizard-container">
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -1,31 +1,18 @@
{{#if wizard}} {{#if wizard}}
<div class="wizard-header large"> <div class="wizard-header large">
<Input {{input
@value={{this.wizard.name}}
name="name" name="name"
placeholder={{i18n "admin.wizard.name_placeholder"}} value=wizard.name
/> placeholderKey="admin.wizard.name_placeholder"}}
<div class="wizard-url"> <div class="wizard-url">
{{#if wizard.name}} {{#if wizard.name}}
{{#if copiedUrl}} {{#if copiedUrl}}
{{d-button {{d-button class="btn-hover pull-right" icon="copy" label="ip_lookup.copied"}}
class="btn-hover pull-right"
icon="copy"
label="ip_lookup.copied"
}}
{{else}} {{else}}
{{d-button {{d-button action=(action "copyUrl") class="pull-right no-text" icon="copy"}}
action=(action "copyUrl")
class="pull-right no-text"
icon="copy"
}}
{{/if}} {{/if}}
<a <a href={{wizardUrl}} target="_blank" rel="noopener noreferrer">{{wizardUrl}}</a>
href={{wizardUrl}}
target="_blank"
rel="noopener noreferrer"
>{{wizardUrl}}</a>
{{/if}} {{/if}}
</div> </div>
</div> </div>
@ -36,12 +23,11 @@
<label>{{i18n "admin.wizard.background"}}</label> <label>{{i18n "admin.wizard.background"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input {{input
@value={{this.wizard.background}}
name="background" name="background"
placeholder={{i18n "admin.wizard.background_placeholder"}} value=wizard.background
class="small" placeholderKey="admin.wizard.background_placeholder"
/> class="small"}}
</div> </div>
</div> </div>
@ -55,8 +41,9 @@
valueProperty="id" valueProperty="id"
value=wizard.theme_id value=wizard.theme_id
onChange=(action (mut wizard.theme_id)) onChange=(action (mut wizard.theme_id))
options=(hash none="admin.wizard.no_theme") options=(hash
}} none="admin.wizard.no_theme"
)}}
</div> </div>
</div> </div>
</div> </div>
@ -68,21 +55,11 @@
<div class="wizard-settings"> <div class="wizard-settings">
<div class="setting"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.save_submissions"}}</label> <label>{{i18n "admin.wizard.required"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.save_submissions}} /> {{input type="checkbox" checked=wizard.required}}
<span>{{i18n "admin.wizard.save_submissions_label"}}</span> <span>{{i18n "admin.wizard.required_label"}}</span>
</div>
</div>
<div class="setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.multiple_submissions"}}</label>
</div>
<div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.multiple_submissions}} />
<span>{{i18n "admin.wizard.multiple_submissions_label"}}</span>
</div> </div>
</div> </div>
@ -91,17 +68,27 @@
<label>{{i18n "admin.wizard.after_signup"}}</label> <label>{{i18n "admin.wizard.after_signup"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.after_signup}} /> {{input type="checkbox" checked=wizard.after_signup}}
<span>{{i18n "admin.wizard.after_signup_label"}}</span> <span>{{i18n "admin.wizard.after_signup_label"}}</span>
</div> </div>
</div> </div>
<div class="setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.multiple_submissions"}}</label>
</div>
<div class="setting-value">
{{input type="checkbox" checked=wizard.multiple_submissions}}
<span>{{i18n "admin.wizard.multiple_submissions_label"}}</span>
</div>
</div>
<div class="setting"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.prompt_completion"}}</label> <label>{{i18n "admin.wizard.prompt_completion"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.prompt_completion}} /> {{input type="checkbox" checked=wizard.prompt_completion}}
<span>{{i18n "admin.wizard.prompt_completion_label"}}</span> <span>{{i18n "admin.wizard.prompt_completion_label"}}</span>
</div> </div>
</div> </div>
@ -111,25 +98,42 @@
<label>{{i18n "admin.wizard.after_time"}}</label> <label>{{i18n "admin.wizard.after_time"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.after_time}} /> {{input type="checkbox" checked=wizard.after_time}}
<span>{{i18n "admin.wizard.after_time_label"}}</span> <span>{{i18n "admin.wizard.after_time_label"}}</span>
{{d-button {{d-button
action=(action "setNextSessionScheduled") action="setNextSessionScheduled"
translatedLabel=nextSessionScheduledLabel translatedLabel=nextSessionScheduledLabel
class="btn-after-time" class="btn-after-time"
icon="far-calendar" icon="far-calendar"}}
}} </div>
</div>
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.permitted"}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=wizard.permitted
options=(hash
context="wizard"
inputTypes="assignment,validation"
groupSelection="output"
userFieldSelection="key"
textSelection="value"
inputConnector="and"
)}}
</div> </div>
</div> </div>
{{#wizard-subscription-container}} {{#wizard-subscription-container}}
<div class="setting"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.required"}}</label> <label>{{i18n "admin.wizard.save_submissions"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.required}} /> {{input type="checkbox" checked=wizard.save_submissions}}
<span>{{i18n "admin.wizard.required_label"}}</span> <span>{{i18n "admin.wizard.save_submissions_label"}}</span>
</div> </div>
</div> </div>
@ -138,34 +142,17 @@
<label>{{i18n "admin.wizard.restart_on_revisit"}}</label> <label>{{i18n "admin.wizard.restart_on_revisit"}}</label>
</div> </div>
<div class="setting-value"> <div class="setting-value">
<Input @type="checkbox" @checked={{this.wizard.restart_on_revisit}} /> {{input type="checkbox" checked=wizard.restart_on_revisit}}
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span> <span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
</div> </div>
</div> </div>
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.permitted"}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=wizard.permitted
options=(hash
context="wizard"
inputTypes="assignment,validation"
groupSelection="output"
guestGroup=true
userFieldSelection="key"
textSelection="value"
inputConnector="and"
)
}}
</div>
</div>
{{/wizard-subscription-container}} {{/wizard-subscription-container}}
</div> </div>
{{wizard-links itemType="step" current=currentStep items=wizard.steps}} {{wizard-links
itemType="step"
current=currentStep
items=wizard.steps}}
{{#if currentStep}} {{#if currentStep}}
{{wizard-custom-step {{wizard-custom-step
@ -173,37 +160,28 @@
wizard=wizard wizard=wizard
currentField=currentField currentField=currentField
wizardFields=wizardFields wizardFields=wizardFields
fieldTypes=filteredFieldTypes fieldTypes=fieldTypes
subscribed=subscribed subscribed=subscribed}}
}}
{{/if}} {{/if}}
{{wizard-links {{wizard-links
itemType="action" itemType="action"
current=currentAction current=currentAction
items=wizard.actions items=wizard.actions
generateLabels=true generateLabels=true}}
}}
{{#each wizard.actions as |wizardAction|}} {{#each wizard.actions as |action|}}
{{wizard-custom-action {{wizard-custom-action
action=wizardAction action=action
currentActionId=currentAction.id currentActionId=currentAction.id
wizard=wizard wizard=wizard
apis=apis apis=apis
removeAction="removeAction" removeAction="removeAction"
wizardFields=wizardFields wizardFields=wizardFields}}
fieldTypes=filteredFieldTypes
}}
{{/each}} {{/each}}
<div class="admin-wizard-buttons"> <div class="admin-wizard-buttons">
<button <button {{action "save"}} disabled={{disableSave}} class="btn btn-primary" type="button">
{{action "save"}}
disabled={{disableSave}}
class="btn btn-primary"
type="button"
>
{{i18n "admin.wizard.save"}} {{i18n "admin.wizard.save"}}
</button> </button>
@ -219,4 +197,4 @@
<span class="error">{{d-icon "times"}}{{error}}</span> <span class="error">{{d-icon "times"}}{{error}}</span>
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}

Datei anzeigen

@ -3,18 +3,21 @@
value=wizardListVal value=wizardListVal
content=wizardList content=wizardList
onChange=(route-action "changeWizard") onChange=(route-action "changeWizard")
options=(hash none="admin.wizard.select") options=(hash
}} none="admin.wizard.select"
)}}
{{d-button {{d-button
action=(route-action "createWizard") action="createWizard"
label="admin.wizard.create" label="admin.wizard.create"
icon="plus" icon="plus"}}
}}
</div> </div>
{{wizard-message key=messageKey url=messageUrl component="wizard"}} {{wizard-message
key=messageKey
url=messageUrl
component="wizard"}}
<div class="admin-wizard-container settings"> <div class="admin-wizard-container settings">
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -1,28 +1,21 @@
{{#admin-nav}} {{#admin-nav}}
{{nav-item route="adminWizardsWizard" label="admin.wizard.nav_label"}} {{nav-item route="adminWizardsWizard" label="admin.wizard.nav_label"}}
{{nav-item {{nav-item route="adminWizardsCustomFields" label="admin.wizard.custom_field.nav_label"}}
route="adminWizardsCustomFields" {{nav-item route="adminWizardsSubmissions" label="admin.wizard.submissions.nav_label"}}
label="admin.wizard.custom_field.nav_label" {{#if businessSubscription}}
}}
{{nav-item
route="adminWizardsSubmissions"
label="admin.wizard.submissions.nav_label"
}}
{{#if showApi}}
{{nav-item route="adminWizardsApi" label="admin.wizard.api.nav_label"}} {{nav-item route="adminWizardsApi" label="admin.wizard.api.nav_label"}}
{{/if}} {{/if}}
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}} {{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
{{nav-item {{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
route="adminWizardsManager"
label="admin.wizard.manager.nav_label"
}}
<div class="admin-actions"> <div class="admin-actions">
{{wizard-subscription-badge}} {{wizard-subscription-badge}}
{{wizard-subscription-cta}} <a target="_blank" class="btn btn-pavilion-support" rel="noreferrer noopener" href="https://thepavilion.io/w/support" title={{i18n "admin.wizard.support_button.title"}}>
{{d-icon "far-life-ring"}}{{i18n "admin.wizard.support_button.label"}}
</a>
</div> </div>
{{/admin-nav}} {{/admin-nav}}
<div class="admin-container"> <div class="admin-container">
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -5,8 +5,9 @@
feature="custom_field" feature="custom_field"
attribute="klass" attribute="klass"
onChange=(action (mut field.klass)) onChange=(action (mut field.klass))
options=(hash none="admin.wizard.custom_field.klass.select") options=(hash
}} none="admin.wizard.custom_field.klass.select"
)}}
</td> </td>
<td> <td>
{{wizard-subscription-selector {{wizard-subscription-selector
@ -14,22 +15,23 @@
feature="custom_field" feature="custom_field"
attribute="type" attribute="type"
onChange=(action (mut field.type)) onChange=(action (mut field.type))
options=(hash none="admin.wizard.custom_field.type.select") options=(hash
}} none="admin.wizard.custom_field.type.select"
)}}
</td> </td>
<td class="input"> <td class="input">
<Input {{input
@value={{this.field.name}} value=field.name
placeholder={{i18n "admin.wizard.custom_field.name.select"}} placeholder=(i18n "admin.wizard.custom_field.name.select")}}
/>
</td> </td>
<td class="multi-select"> <td class="multi-select">
{{multi-select {{multi-select
value=field.serializers value=field.serializers
content=serializerContent content=serializerContent
onChange=(action (mut field.serializers)) onChange=(action (mut field.serializers))
options=(hash none="admin.wizard.custom_field.serializers.select") options=(hash
}} none="admin.wizard.custom_field.serializers.select"
)}}
</td> </td>
<td class="actions"> <td class="actions">
{{#if loading}} {{#if loading}}
@ -40,18 +42,19 @@
{{/if}} {{/if}}
{{/if}} {{/if}}
{{d-button {{d-button
action=(action "destroy") action="destroy"
icon="trash-alt" icon="trash-alt"
class="destroy" class="destroy"
disabled=destroyDisabled disabled=destroyDisabled}}
}}
{{d-button {{d-button
icon="save" icon="save"
action=(action "save") action="save"
disabled=saveDisabled disabled=saveDisabled
class="save" class="save"}}
}} {{d-button
{{d-button action=(action "close") icon="times" disabled=closeDisabled}} action="close"
icon="times"
disabled=closeDisabled}}
</td> </td>
{{else}} {{else}}
<td><label>{{field.klass}}</label></td> <td><label>{{field.klass}}</label></td>
@ -74,7 +77,7 @@
</td> </td>
{{else}} {{else}}
<td class="actions"> <td class="actions">
{{d-button action=(action "edit") icon="pencil-alt"}} {{d-button action="edit" icon="pencil-alt"}}
</td> </td>
{{/if}} {{/if}}
{{/if}} {{/if}}

Datei anzeigen

@ -1,11 +0,0 @@
<Input
@type={{this.inputType}}
@value={{readonly this.value}}
class="date-picker"
placeholder={{this.placeholder}}
tabindex={{this.tabindex}}
{{on "input" (action "onChangeDate")}}
autocomplete="off"
/>
<div class="picker-container"></div>

Datei anzeigen

@ -1,8 +0,0 @@
{{custom-wizard-category-selector
categories=categories
class=fieldClass
whitelist=field.content
onChange=(action (mut categories))
tabindex=field.tabindex
options=(hash maximum=field.limit)
}}

Datei anzeigen

@ -1,7 +0,0 @@
<Input
id={{this.field.id}}
@type="checkbox"
@checked={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
/>

Datei anzeigen

@ -1,25 +0,0 @@
{{custom-wizard-composer-editor
field=field
composer=composer
wizard=wizard
fieldClass=fieldClass
groupsMentioned=(action "groupsMentioned")
cannotSeeMention=(action "cannotSeeMention")
importQuote=(action "importQuote")
togglePreview=(action "togglePreview")
afterRefresh=(action "afterRefresh")
}}
<div class="bottom-bar">
<button
class="wizard-btn toggle-preview"
{{action "togglePreview"}}
type="button"
>
<span class="d-button-label">{{i18n togglePreviewLabel}}</span>
</button>
{{#if field.char_counter}}
{{wizard-char-counter field.value field.max_length}}
{{/if}}
</div>

Datei anzeigen

@ -1,10 +0,0 @@
{{custom-wizard-group-selector
groups=site.groups
class=fieldClass
field=field
whitelist=field.content
value=field.value
tabindex=field.tabindex
onChange=(action (mut field.value))
options=(hash none="select_kit.default_header_text")
}}

Datei anzeigen

@ -1,8 +0,0 @@
<Input
id={{this.field.id}}
step="0.01"
@type="number"
@value={{this.field.value}}
tabindex={{this.field.tabindex}}
class={{this.fieldClass}}
/>

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen