Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-26 11:00:28 +01:00
Merge branch 'main' into dependabot/npm_and_yarn/async-2.6.4
Dieser Commit ist enthalten in:
Commit
80fedfafd1
491 geänderte Dateien mit 20921 neuen und 13682 gelöschten Zeilen
|
@ -1,2 +1,4 @@
|
||||||
|
3.2.0.beta2: 1ee2f7d8babafe32912372fbbfa50c89f5b09ba9
|
||||||
|
3.1.999: 1f35b80f85e5fd1efb7f4851f0845700432febdc
|
||||||
2.7.99: e07a57e398b6b1676ab42a7e34467556fca5416b
|
2.7.99: e07a57e398b6b1676ab42a7e34467556fca5416b
|
||||||
2.5.1: bb85b3a0d2c0ab6b59bcb405731c39089ec6731c
|
2.5.1: bb85b3a0d2c0ab6b59bcb405731c39089ec6731c
|
||||||
|
|
13
.github/workflows/discourse-plugin.yml
gevendort
Normale Datei
13
.github/workflows/discourse-plugin.yml
gevendort
Normale Datei
|
@ -0,0 +1,13 @@
|
||||||
|
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
56
.github/workflows/plugin-linting.yml
gevendort
|
@ -1,56 +0,0 @@
|
||||||
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 .
|
|
139
.github/workflows/plugin-tests.yml
gevendort
139
.github/workflows/plugin-tests.yml
gevendort
|
@ -1,139 +0,0 @@
|
||||||
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@v3
|
|
||||||
with:
|
|
||||||
repository: discourse/discourse
|
|
||||||
ref: ${{ steps.discourse_branch.outputs.value }}
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install plugin
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
path: plugins/${{ github.event.repository.name }}
|
|
||||||
ref: "${{ github.head_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: LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 QUNIT_SKIP_CORE=1 bin/rake qunit:test['600000','/w/qunit']
|
|
||||||
timeout-minutes: 10
|
|
3
.gitignore
gevendort
3
.gitignore
gevendort
|
@ -1,7 +1,8 @@
|
||||||
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/*
|
||||||
|
|
|
@ -1,2 +1,11 @@
|
||||||
inherit_gem:
|
inherit_gem:
|
||||||
rubocop-discourse: default.yml
|
rubocop-discourse: default.yml
|
||||||
|
|
||||||
|
RSpec/ContextWording:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
RSpec/DescribeClass:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Discourse/TimeEqMatcher:
|
||||||
|
Enabled: false
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
All code in this repository is Copyright 2018 by Angus McLeod.
|
All code in this repository is Copyright 2023 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
|
||||||
|
|
31
Gemfile.lock
31
Gemfile.lock
|
@ -2,31 +2,32 @@ GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
parallel (1.20.1)
|
json (2.6.2)
|
||||||
parser (3.0.1.0)
|
parallel (1.22.1)
|
||||||
|
parser (3.1.2.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
rainbow (3.0.0)
|
rainbow (3.1.1)
|
||||||
regexp_parser (2.1.1)
|
regexp_parser (2.6.0)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rubocop (1.12.1)
|
rubocop (1.36.0)
|
||||||
|
json (~> 2.3)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.0.0.0)
|
parser (>= 3.1.2.1)
|
||||||
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
|
rexml (>= 3.2.5, < 4.0)
|
||||||
rubocop-ast (>= 1.2.0, < 2.0)
|
rubocop-ast (>= 1.20.1, < 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.4.1)
|
rubocop-ast (1.22.0)
|
||||||
parser (>= 2.7.1.5)
|
parser (>= 3.1.1.0)
|
||||||
rubocop-discourse (2.4.1)
|
rubocop-discourse (3.0)
|
||||||
rubocop (>= 1.1.0)
|
rubocop (>= 1.1.0)
|
||||||
rubocop-rspec (>= 2.0.0)
|
rubocop-rspec (>= 2.0.0)
|
||||||
rubocop-rspec (2.2.0)
|
rubocop-rspec (2.13.2)
|
||||||
rubocop (~> 1.0)
|
rubocop (~> 1.33)
|
||||||
rubocop-ast (>= 1.1.0)
|
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
unicode-display_width (2.0.0)
|
unicode-display_width (2.3.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
32
README.md
32
README.md
|
@ -1,3 +1,31 @@
|
||||||
# discourse-custom-wizard
|
# Discourse Custom Wizard Plugin
|
||||||
|
|
||||||
See further: https://thepavilion.io/c/knowledge/discourse/custom-wizard/118
|
The Custom Wizard Plugin lets you make forms for your Discourse forum. Better user onboarding, structured posting, data enrichment, automated actions and much more for your community.
|
||||||
|
|
||||||
|
<img src="https://camo.githubusercontent.com/593432f1fc9658ffca104065668cc88fa21dffcd3002cb78ffd50c71f33a2523/68747470733a2f2f706176696c696f6e2d6173736574732e6e7963332e63646e2e6469676974616c6f6365616e7370616365732e636f6d2f706c7567696e732f77697a6172642d7265706f7369746f72792d62616e6e65722e706e67" alt="" data-canonical-src="https://pavilion-assets.nyc3.cdn.digitaloceanspaces.com/plugins/wizard-repository-banner.png" style="max-width: 100%;" width="400">
|
||||||
|
|
||||||
|
👋 Looking to report an issue? We're managing issues for this plugin using our [bug report wizard](https://pavilion.tech/products/discourse-custom-wizard-plugin/support/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://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/), or go directly to the relevant section
|
||||||
|
|
||||||
|
- [Wizard Administration](https://coop.pavilion.tech/t/1602)
|
||||||
|
- [Wizard Settings](https://coop.pavilion.tech/t/1614)
|
||||||
|
- [Step Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/step-settings)
|
||||||
|
- [Field Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/field-settings)
|
||||||
|
- [Conditional Settings](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/conditional-settings)
|
||||||
|
- [Field Interpolation](https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/field-interpolation)
|
||||||
|
- [Handling Dates and Times](https://coop.pavilion.tech/t/1708)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- [Report an issue](https://pavilion.tech/products/discourse-custom-wizard-plugin/support/bug-report)
|
||||||
|
|
||||||
|
## Statistics
|
||||||
|
|
||||||
|
For improved service and development, this plugin collects some generalised quantitative data related to version and usage. No personal or sensitive information is gathered. Please email contact@pavilion.tech if you have any questions or concerns about our data collection.
|
||||||
|
|
7
SECURITY.md
Normale Datei
7
SECURITY.md
Normale Datei
|
@ -0,0 +1,7 @@
|
||||||
|
# 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.
|
|
@ -2,9 +2,6 @@
|
||||||
class CustomWizard::AdminController < ::Admin::AdminController
|
class CustomWizard::AdminController < ::Admin::AdminController
|
||||||
before_action :ensure_admin
|
before_action :ensure_admin
|
||||||
|
|
||||||
def index
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_wizard
|
def find_wizard
|
||||||
|
|
|
@ -20,6 +20,10 @@ 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])
|
||||||
|
|
||||||
|
@ -130,4 +134,8 @@ class CustomWizard::AdminApiController < CustomWizard::AdminController
|
||||||
|
|
||||||
@auth_data ||= auth_data
|
@auth_data ||= auth_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def subscription
|
||||||
|
@subscription ||= CustomWizard::Subscription.new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
||||||
def index
|
def index
|
||||||
render_json_dump(custom_field_list)
|
render_json_dump(
|
||||||
|
custom_fields: custom_field_list
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|
|
@ -1,9 +1,44 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::AdminLogsController < CustomWizard::AdminController
|
class CustomWizard::AdminLogsController < CustomWizard::AdminController
|
||||||
|
before_action :find_wizard, except: [:index]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render_serialized(
|
render json: ActiveModel::ArraySerializer.new(
|
||||||
CustomWizard::Log.list(params[:page].to_i, params[:limit].to_i),
|
CustomWizard::Wizard.list(current_user),
|
||||||
CustomWizard::LogSerializer
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render_json_dump(
|
||||||
|
wizard: CustomWizard::BasicWizardSerializer.new(@wizard, root: false),
|
||||||
|
logs: ActiveModel::ArraySerializer.new(
|
||||||
|
log_list.logs,
|
||||||
|
each_serializer: CustomWizard::LogSerializer
|
||||||
|
),
|
||||||
|
total: log_list.total
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def log_list
|
||||||
|
@log_list ||= begin
|
||||||
|
list = CustomWizard::Log.list(params[:page].to_i, params[:limit].to_i, params[:wizard_id])
|
||||||
|
|
||||||
|
if list.logs.any? && (usernames = list.logs.map(&:username)).present?
|
||||||
|
user_map = User.where(username: usernames)
|
||||||
|
.reduce({}) do |result, user|
|
||||||
|
result[user.username] = user
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
list.logs.each do |log_item|
|
||||||
|
log_item.user = user_map[log_item.username]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
list
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,12 +13,21 @@ class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
def show
|
def show
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
wizard: CustomWizard::BasicWizardSerializer.new(@wizard, root: false),
|
wizard: CustomWizard::BasicWizardSerializer.new(@wizard, root: false),
|
||||||
submissions: ActiveModel::ArraySerializer.new(ordered_submissions, each_serializer: CustomWizard::SubmissionSerializer)
|
submissions: ActiveModel::ArraySerializer.new(
|
||||||
|
submission_list.submissions,
|
||||||
|
each_serializer: CustomWizard::SubmissionSerializer
|
||||||
|
),
|
||||||
|
total: submission_list.total
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def download
|
def download
|
||||||
send_data ordered_submissions.to_json,
|
content = ActiveModel::ArraySerializer.new(
|
||||||
|
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"
|
||||||
|
@ -26,7 +35,7 @@ class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def ordered_submissions
|
def submission_list
|
||||||
CustomWizard::Submission.list(@wizard, order_by: 'id')
|
CustomWizard::Submission.list(@wizard, page: params[:page].to_i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
18
app/controllers/custom_wizard/admin/subscription.rb
Normale Datei
18
app/controllers/custom_wizard/admin/subscription.rb
Normale Datei
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::SubscriptionController < ::Admin::AdminController
|
||||||
|
before_action :ensure_admin
|
||||||
|
|
||||||
|
def index
|
||||||
|
if params[:update_from_remote]
|
||||||
|
subscription = CustomWizard::Subscription.new(true)
|
||||||
|
else
|
||||||
|
subscription = CustomWizard::Subscription.new
|
||||||
|
end
|
||||||
|
|
||||||
|
render_json_dump(
|
||||||
|
subscribed: subscription.subscribed?,
|
||||||
|
subscription_type: subscription.type,
|
||||||
|
subscription_attributes: CustomWizard::Subscription.attributes,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -88,6 +88,7 @@ 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,
|
||||||
|
@ -99,6 +100,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
:index,
|
:index,
|
||||||
:label,
|
:label,
|
||||||
:image,
|
:image,
|
||||||
|
:image_upload_id,
|
||||||
:description,
|
:description,
|
||||||
:required,
|
:required,
|
||||||
:key,
|
:key,
|
||||||
|
@ -112,6 +114,7 @@ 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,
|
||||||
|
@ -161,7 +164,9 @@ 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
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::StepsController < ::ApplicationController
|
class CustomWizard::StepsController < ::CustomWizard::WizardClientController
|
||||||
before_action :ensure_logged_in
|
|
||||||
before_action :ensure_can_update
|
before_action :ensure_can_update
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@ -22,7 +21,7 @@ class CustomWizard::StepsController < ::ApplicationController
|
||||||
|
|
||||||
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)
|
builder = CustomWizard::Builder.new(wizard_id, current_user, guest_id)
|
||||||
@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])
|
||||||
|
@ -85,7 +84,6 @@ class CustomWizard::StepsController < ::ApplicationController
|
||||||
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?
|
||||||
|
|
||||||
|
|
|
@ -1,41 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::WizardController < ::ActionController::Base
|
class CustomWizard::WizardController < ::CustomWizard::WizardClientController
|
||||||
helper ApplicationHelper
|
def show
|
||||||
|
|
||||||
include CurrentUser
|
|
||||||
include CanonicalURL::ControllerExtensions
|
|
||||||
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?
|
if wizard.present?
|
||||||
render json: CustomWizard::WizardSerializer.new(wizard, scope: guardian, root: false).as_json, status: 200
|
render json: CustomWizard::WizardSerializer.new(wizard, scope: guardian, root: false).as_json, status: 200
|
||||||
else
|
else
|
||||||
render json: { error: I18n.t('wizard.none') }
|
render json: { error: I18n.t('wizard.none') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
format.html do
|
|
||||||
render "default/empty"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def skip
|
def skip
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
|
@ -57,69 +28,12 @@ class CustomWizard::WizardController < ::ActionController::Base
|
||||||
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
|
||||||
builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user)
|
return nil unless @builder.present?
|
||||||
return nil unless builder.present?
|
@builder.build({ reset: params[:reset] }, params)
|
||||||
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
|
||||||
|
|
23
app/controllers/custom_wizard/wizard_client.rb
Normale Datei
23
app/controllers/custom_wizard/wizard_client.rb
Normale Datei
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::WizardClientController < ::ApplicationController
|
||||||
|
before_action :ensure_plugin_enabled
|
||||||
|
before_action :set_builder
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_plugin_enabled
|
||||||
|
unless SiteSetting.custom_wizard_enabled
|
||||||
|
redirect_to path("/")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def guest_id
|
||||||
|
return nil if current_user.present?
|
||||||
|
cookies[:custom_wizard_guest_id] ||= CustomWizard::Wizard.generate_guest_id
|
||||||
|
cookies[:custom_wizard_guest_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_builder
|
||||||
|
@builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user, guest_id)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CustomWizard::LogSerializer < ApplicationSerializer
|
class CustomWizard::LogSerializer < ApplicationSerializer
|
||||||
attributes :message, :date
|
attributes :date,
|
||||||
|
:action,
|
||||||
|
:username,
|
||||||
|
:message
|
||||||
|
|
||||||
|
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::SubmissionSerializer < ApplicationSerializer
|
class CustomWizard::SubmissionSerializer < ApplicationSerializer
|
||||||
attributes :id,
|
attributes :id,
|
||||||
:username,
|
|
||||||
:fields,
|
:fields,
|
||||||
:submitted_at,
|
:submitted_at,
|
||||||
:route_to,
|
:user
|
||||||
:redirect_on_complete,
|
|
||||||
:redirect_to
|
|
||||||
|
|
||||||
def username
|
def include_user?
|
||||||
object.user.present? ?
|
object.wizard.user.present?
|
||||||
object.user.username :
|
end
|
||||||
I18n.t('admin.wizard.submission.no_user', user_id: object.user_id)
|
|
||||||
|
def user
|
||||||
|
::BasicUserSerializer.new(object.wizard.user, root: false).as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def fields
|
||||||
|
@fields ||= begin
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
object.wizard.template['steps'].each do |step|
|
||||||
|
step['fields'].each do |field|
|
||||||
|
if value = object.fields[field['id']]
|
||||||
|
result[field['id']] = {
|
||||||
|
value: value,
|
||||||
|
type: field['type'],
|
||||||
|
label: field['label']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,7 @@ 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,
|
||||||
|
@ -42,13 +43,8 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
object.value
|
object.value
|
||||||
end
|
end
|
||||||
|
|
||||||
def i18n_key
|
|
||||||
@i18n_key ||= "wizard.step.#{object.step.id}.fields.#{object.id}".underscore
|
|
||||||
end
|
|
||||||
|
|
||||||
def label
|
def label
|
||||||
return object.label if object.label.present?
|
I18n.t("#{i18n_key}.label", default: object.label, base_url: Discourse.base_url)
|
||||||
I18n.t("#{object.key || i18n_key}.label", default: '')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_label?
|
def include_label?
|
||||||
|
@ -56,14 +52,21 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
return object.description if object.description.present?
|
I18n.t("#{i18n_key}.description", default: object.description, base_url: Discourse.base_url)
|
||||||
I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_description?
|
def include_description?
|
||||||
description.present?
|
description.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def placeholder
|
||||||
|
I18n.t("#{i18n_key}.placeholder", default: object.placeholder)
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_placeholder?
|
||||||
|
placeholder.present?
|
||||||
|
end
|
||||||
|
|
||||||
def image
|
def image
|
||||||
object.image
|
object.image
|
||||||
end
|
end
|
||||||
|
@ -72,15 +75,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
object.image.present?
|
object.image.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def placeholder
|
|
||||||
return object.placeholder if object.placeholder.present?
|
|
||||||
I18n.t("#{object.key || i18n_key}.placeholder", default: '')
|
|
||||||
end
|
|
||||||
|
|
||||||
def include_placeholder?
|
|
||||||
placeholder.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def file_types
|
def file_types
|
||||||
object.file_types
|
object.file_types
|
||||||
end
|
end
|
||||||
|
@ -105,6 +99,10 @@ 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|
|
||||||
|
@ -127,4 +125,14 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
def preview_template
|
def preview_template
|
||||||
object.preview_template
|
object.preview_template
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def i18n_key
|
||||||
|
@i18n_key ||= "#{object.step.wizard.id}.#{object.step.id}.#{object.id}".underscore
|
||||||
|
end
|
||||||
|
|
||||||
|
def subscribed?
|
||||||
|
@subscribed ||= CustomWizard::Subscription.subscribed?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,13 +9,10 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
|
||||||
:completed,
|
:completed,
|
||||||
:required,
|
:required,
|
||||||
:permitted,
|
:permitted,
|
||||||
:uncategorized_category_id,
|
|
||||||
:categories,
|
|
||||||
: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?
|
||||||
|
@ -46,24 +43,4 @@ 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
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,13 +39,8 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer
|
||||||
object.previous.present?
|
object.previous.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def i18n_key
|
|
||||||
@i18n_key ||= "wizard.step.#{object.id}".underscore
|
|
||||||
end
|
|
||||||
|
|
||||||
def title
|
def title
|
||||||
return PrettyText.cook(object.title) if object.title
|
I18n.t("#{i18n_key}.title", default: object.title, base_url: Discourse.base_url)
|
||||||
PrettyText.cook(I18n.t("#{object.key || i18n_key}.title", default: ''))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_title?
|
def include_title?
|
||||||
|
@ -53,8 +48,7 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
return object.description if object.description
|
I18n.t("#{i18n_key}.description", default: object.description, base_url: Discourse.base_url)
|
||||||
PrettyText.cook(I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_description?
|
def include_description?
|
||||||
|
@ -80,4 +74,10 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer
|
||||||
def final
|
def final
|
||||||
object.final?
|
object.final?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def i18n_key
|
||||||
|
@i18n_key ||= "#{object.wizard.id}.#{object.id}".underscore
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<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>
|
|
|
@ -3,27 +3,12 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||||
import { alias, equal, or } from "@ember/object/computed";
|
import { alias, equal, or } from "@ember/object/computed";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
const generateContent = function (array, type) {
|
|
||||||
return array.map((key) => ({
|
|
||||||
id: key,
|
|
||||||
name: I18n.t(`admin.wizard.custom_field.${type}.${key}`),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
tagName: "tr",
|
tagName: "tr",
|
||||||
topicSerializers: ["topic_view", "topic_list_item"],
|
topicSerializers: ["topic_view", "topic_list_item"],
|
||||||
postSerializers: ["post"],
|
postSerializers: ["post"],
|
||||||
groupSerializers: ["basic_group"],
|
groupSerializers: ["basic_group"],
|
||||||
categorySerializers: ["basic_category"],
|
categorySerializers: ["basic_category"],
|
||||||
klassContent: generateContent(
|
|
||||||
["topic", "post", "group", "category"],
|
|
||||||
"klass"
|
|
||||||
),
|
|
||||||
typeContent: generateContent(
|
|
||||||
["string", "boolean", "integer", "json"],
|
|
||||||
"type"
|
|
||||||
),
|
|
||||||
showInputs: or("field.new", "field.edit"),
|
showInputs: or("field.new", "field.edit"),
|
||||||
classNames: ["custom-field-input"],
|
classNames: ["custom-field-input"],
|
||||||
loading: or("saving", "destroying"),
|
loading: or("saving", "destroying"),
|
||||||
|
@ -40,9 +25,13 @@ export default Component.extend({
|
||||||
const serializers = this.get(`${klass}Serializers`);
|
const serializers = this.get(`${klass}Serializers`);
|
||||||
|
|
||||||
if (serializers) {
|
if (serializers) {
|
||||||
return generateContent(serializers, "serializers");
|
return serializers.reduce((result, key) => {
|
||||||
} else {
|
result.push({
|
||||||
return [];
|
id: key,
|
||||||
|
name: I18n.t(`admin.wizard.custom_field.serializers.${key}`),
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@ import {
|
||||||
observes,
|
observes,
|
||||||
} from "discourse-common/utils/decorators";
|
} from "discourse-common/utils/decorators";
|
||||||
import { renderAvatar } from "discourse/helpers/user-avatar";
|
import { renderAvatar } from "discourse/helpers/user-avatar";
|
||||||
import userSearch from "../lib/user-search";
|
import userSearch from "discourse/lib/user-search";
|
||||||
import WizardI18n from "../lib/wizard-i18n";
|
import I18n from "I18n";
|
||||||
import Handlebars from "handlebars";
|
import Handlebars from "handlebars";
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import TextField from "@ember/component/text-field";
|
import TextField from "discourse/components/text-field";
|
||||||
|
|
||||||
const template = function (params) {
|
const template = function (params) {
|
||||||
const options = params.options;
|
const options = params.options;
|
||||||
|
@ -41,7 +41,7 @@ export default TextField.extend({
|
||||||
|
|
||||||
@computed("placeholderKey")
|
@computed("placeholderKey")
|
||||||
placeholder(placeholderKey) {
|
placeholder(placeholderKey) {
|
||||||
return placeholderKey ? WizardI18n(placeholderKey) : "";
|
return placeholderKey ? I18n.t(placeholderKey) : "";
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("usernames")
|
@observes("usernames")
|
|
@ -1,5 +1,6 @@
|
||||||
import ComposerEditor from "discourse/components/composer-editor";
|
import ComposerEditor from "discourse/components/composer-editor";
|
||||||
import {
|
import {
|
||||||
|
bind,
|
||||||
default as discourseComputed,
|
default as discourseComputed,
|
||||||
on,
|
on,
|
||||||
} from "discourse-common/utils/decorators";
|
} from "discourse-common/utils/decorators";
|
||||||
|
@ -8,16 +9,21 @@ import { scheduleOnce } from "@ember/runloop";
|
||||||
import { caretPosition, inCodeBlock } from "discourse/lib/utilities";
|
import { caretPosition, inCodeBlock } from "discourse/lib/utilities";
|
||||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
import Site from "../models/site";
|
import Site from "discourse/models/site";
|
||||||
import { uploadIcon } from "discourse/lib/uploads";
|
import { uploadIcon } from "discourse/lib/uploads";
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
|
import InsertHyperlink from "discourse/components/modal/insert-hyperlink";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
|
const IMAGE_MARKDOWN_REGEX =
|
||||||
|
/!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
|
||||||
|
|
||||||
export default ComposerEditor.extend({
|
export default ComposerEditor.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-composer-editor",
|
modal: service(),
|
||||||
|
|
||||||
classNameBindings: ["fieldClass"],
|
classNameBindings: ["fieldClass"],
|
||||||
allowUpload: true,
|
allowUpload: true,
|
||||||
showLink: false,
|
showLink: false,
|
||||||
showHyperlinkBox: false,
|
|
||||||
topic: null,
|
topic: null,
|
||||||
showToolbar: true,
|
showToolbar: true,
|
||||||
focusTarget: "reply",
|
focusTarget: "reply",
|
||||||
|
@ -26,7 +32,8 @@ export default ComposerEditor.extend({
|
||||||
popupMenuOptions: [],
|
popupMenuOptions: [],
|
||||||
draftStatus: "null",
|
draftStatus: "null",
|
||||||
replyPlaceholder: alias("field.translatedPlaceholder"),
|
replyPlaceholder: alias("field.translatedPlaceholder"),
|
||||||
uploadingFieldId: null,
|
wizardEventFieldId: null,
|
||||||
|
composerEventPrefix: "wizard-editor",
|
||||||
|
|
||||||
@on("didInsertElement")
|
@on("didInsertElement")
|
||||||
_composerEditorInit() {
|
_composerEditorInit() {
|
||||||
|
@ -35,7 +42,7 @@ export default ComposerEditor.extend({
|
||||||
if (this.siteSettings.enable_mentions) {
|
if (this.siteSettings.enable_mentions) {
|
||||||
$input.autocomplete({
|
$input.autocomplete({
|
||||||
template: findRawTemplate("user-selector-autocomplete"),
|
template: findRawTemplate("user-selector-autocomplete"),
|
||||||
dataSource: (term) => this.userSearchTerm.call(this, term),
|
dataSource: (term) => this._userSearchTerm.call(this, term),
|
||||||
key: "@",
|
key: "@",
|
||||||
transformComplete: (v) => v.username || v.name,
|
transformComplete: (v) => v.username || v.name,
|
||||||
afterComplete: (value) => {
|
afterComplete: (value) => {
|
||||||
|
@ -75,43 +82,13 @@ export default ComposerEditor.extend({
|
||||||
$input.on("scroll", this._throttledSyncEditorAndPreviewScroll);
|
$input.on("scroll", this._throttledSyncEditorAndPreviewScroll);
|
||||||
this._bindUploadTarget();
|
this._bindUploadTarget();
|
||||||
|
|
||||||
const wizardEventNames = ["insert-text", "replace-text"];
|
const field = this.field;
|
||||||
const eventPrefix = this.eventPrefix;
|
this.editorInputClass = `.${dasherize(field.type)}-${dasherize(
|
||||||
const session = this.get("session");
|
field.id
|
||||||
this.appEvents.reopen({
|
)} .d-editor-input`;
|
||||||
trigger(name, ...args) {
|
|
||||||
let eventParts = name.split(":");
|
|
||||||
let currentEventPrefix = eventParts[0];
|
|
||||||
let currentEventName = eventParts[1];
|
|
||||||
|
|
||||||
if (
|
this._uppyInstance.on("file-added", () => {
|
||||||
currentEventPrefix !== "wizard-editor" &&
|
this.session.set("wizardEventFieldId", field.id);
|
||||||
wizardEventNames.some((wen) => wen === currentEventName)
|
|
||||||
) {
|
|
||||||
let wizardName = name.replace(eventPrefix, "wizard-editor");
|
|
||||||
if (currentEventName === "insert-text") {
|
|
||||||
args = {
|
|
||||||
text: args[0],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (currentEventName === "replace-text") {
|
|
||||||
args = {
|
|
||||||
oldVal: args[0],
|
|
||||||
newVal: args[1],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let wizardArgs = Object.assign(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
fieldId: session.get("uploadingFieldId"),
|
|
||||||
},
|
|
||||||
args
|
|
||||||
);
|
|
||||||
return this._super(wizardName, wizardArgs);
|
|
||||||
} else {
|
|
||||||
return this._super(name, ...args);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -133,17 +110,33 @@ export default ComposerEditor.extend({
|
||||||
return uploadIcon(false, this.siteSettings);
|
return uploadIcon(false, this.siteSettings);
|
||||||
},
|
},
|
||||||
|
|
||||||
click(e) {
|
@bind
|
||||||
if ($(e.target).hasClass("wizard-composer-hyperlink")) {
|
_handleImageDeleteButtonClick(event) {
|
||||||
this.set("showHyperlinkBox", false);
|
if (!event.target.classList.contains("delete-image-button")) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const index = parseInt(
|
||||||
|
event.target.closest(".button-wrapper").dataset.imageIndex,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
const matchingPlaceholder =
|
||||||
|
this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
|
||||||
|
|
||||||
|
this.session.set("wizardEventFieldId", this.field.id);
|
||||||
|
this.appEvents.trigger(
|
||||||
|
"composer:replace-text",
|
||||||
|
matchingPlaceholder[index],
|
||||||
|
"",
|
||||||
|
{ regex: IMAGE_MARKDOWN_REGEX, index }
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
extraButtons(toolbar) {
|
extraButtons(toolbar) {
|
||||||
const component = this;
|
const component = this;
|
||||||
|
|
||||||
if (this.allowUpload && this.uploadIcon && !this.site.mobileView) {
|
if (this.allowUpload && this.uploadIcon) {
|
||||||
toolbar.addButton({
|
toolbar.addButton({
|
||||||
id: "upload",
|
id: "upload",
|
||||||
group: "insertions",
|
group: "insertions",
|
||||||
|
@ -159,7 +152,7 @@ export default ComposerEditor.extend({
|
||||||
shortcut: "K",
|
shortcut: "K",
|
||||||
trimLeading: true,
|
trimLeading: true,
|
||||||
unshift: true,
|
unshift: true,
|
||||||
sendAction: () => component.set("showHyperlinkBox", true),
|
sendAction: (event) => component.send("showLinkModal", event),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.siteSettings.mentionables_enabled) {
|
if (this.siteSettings.mentionables_enabled) {
|
||||||
|
@ -188,33 +181,32 @@ export default ComposerEditor.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
previewUpdated($preview) {
|
previewUpdated(preview) {
|
||||||
highlightSyntax($preview[0], this.siteSettings, this.session);
|
highlightSyntax(preview, this.siteSettings, this.session);
|
||||||
|
|
||||||
if (this.siteSettings.mentionables_enabled) {
|
if (this.siteSettings.mentionables_enabled) {
|
||||||
const { linkSeenMentionableItems } = requirejs(
|
const { linkSeenMentionableItems } = requirejs(
|
||||||
"discourse/plugins/discourse-mentionables/discourse/lib/mentionable-items-preview-styling"
|
"discourse/plugins/discourse-mentionables/discourse/lib/mentionable-items-preview-styling"
|
||||||
);
|
);
|
||||||
linkSeenMentionableItems($preview, this.siteSettings);
|
linkSeenMentionableItems(preview, this.siteSettings);
|
||||||
}
|
}
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
addLink(linkName, linkUrl) {
|
showLinkModal(toolbarEvent) {
|
||||||
let link = `[${linkName}](${linkUrl})`;
|
let linkText = "";
|
||||||
this.appEvents.trigger("wizard-editor:insert-text", {
|
this._lastSel = toolbarEvent.selected;
|
||||||
fieldId: this.field.id,
|
|
||||||
text: link,
|
|
||||||
});
|
|
||||||
this.set("showHyperlinkBox", false);
|
|
||||||
},
|
|
||||||
|
|
||||||
hideBox() {
|
if (this._lastSel) {
|
||||||
this.set("showHyperlinkBox", false);
|
linkText = this._lastSel.value;
|
||||||
|
}
|
||||||
|
this.modal.show(InsertHyperlink, {
|
||||||
|
model: { linkText, toolbarEvent },
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
showUploadModal() {
|
showUploadModal() {
|
||||||
this.session.set("uploadingFieldId", this.field.id);
|
this.session.set("wizardEventFieldId", this.field.id);
|
||||||
document.getElementById(this.fileUploadElementId).click();
|
document.getElementById(this.fileUploadElementId).click();
|
||||||
},
|
},
|
||||||
},
|
},
|
|
@ -3,7 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default DateInput.extend({
|
export default DateInput.extend({
|
||||||
useNativePicker: false,
|
useNativePicker: false,
|
||||||
layoutName: "wizard/templates/components/wizard-date-input",
|
classNameBindings: ["fieldClass"],
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
placeholder() {
|
placeholder() {
|
|
@ -2,7 +2,7 @@ import DateTimeInput from "discourse/components/date-time-input";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default DateTimeInput.extend({
|
export default DateTimeInput.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-date-time-input",
|
classNameBindings: ["fieldClass"],
|
||||||
|
|
||||||
@discourseComputed("timeFirst", "tabindex")
|
@discourseComputed("timeFirst", "tabindex")
|
||||||
timeTabindex(timeFirst, tabindex) {
|
timeTabindex(timeFirst, tabindex) {
|
|
@ -3,8 +3,6 @@ import Category from "discourse/models/category";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-category",
|
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
const property = this.field.property || "id";
|
const property = this.field.property || "id";
|
||||||
const value = this.field.value;
|
const value = this.field.value;
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({});
|
|
@ -7,8 +7,6 @@ import { ajax } from "discourse/lib/ajax";
|
||||||
import { on } from "discourse-common/utils/decorators";
|
import { on } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-composer-preview",
|
|
||||||
|
|
||||||
@on("init")
|
@on("init")
|
||||||
updatePreview() {
|
updatePreview() {
|
||||||
if (this.isDestroyed) {
|
if (this.isDestroyed) {
|
|
@ -6,8 +6,6 @@ import EmberObject from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-composer",
|
|
||||||
|
|
||||||
showPreview: false,
|
showPreview: false,
|
||||||
classNameBindings: [
|
classNameBindings: [
|
||||||
":wizard-field-composer",
|
":wizard-field-composer",
|
|
@ -2,8 +2,6 @@ import Component from "@ember/component";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-date-time",
|
|
||||||
|
|
||||||
@observes("dateTime")
|
@observes("dateTime")
|
||||||
setValue() {
|
setValue() {
|
||||||
this.set("field.value", this.dateTime.format(this.field.format));
|
this.set("field.value", this.dateTime.format(this.field.format));
|
|
@ -2,8 +2,6 @@ import Component from "@ember/component";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-date",
|
|
||||||
|
|
||||||
@observes("date")
|
@observes("date")
|
||||||
setValue() {
|
setValue() {
|
||||||
this.set("field.value", this.date.format(this.field.format));
|
this.set("field.value", this.date.format(this.field.format));
|
|
@ -1,8 +1,6 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-dropdown",
|
|
||||||
|
|
||||||
keyPress(e) {
|
keyPress(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({});
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({});
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({});
|
|
@ -1,8 +1,6 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-text",
|
|
||||||
|
|
||||||
keyPress(e) {
|
keyPress(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
|
@ -1,8 +1,6 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-textarea",
|
|
||||||
|
|
||||||
keyPress(e) {
|
keyPress(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
|
@ -2,7 +2,7 @@ import Component from "@ember/component";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-time",
|
classNameBindings: ["fieldClass"],
|
||||||
|
|
||||||
@observes("time")
|
@observes("time")
|
||||||
setValue() {
|
setValue() {
|
|
@ -3,9 +3,8 @@ import Component from "@ember/component";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend(UppyUploadMixin, {
|
export default Component.extend(UppyUploadMixin, {
|
||||||
layoutName: "wizard/templates/components/wizard-field-upload",
|
|
||||||
classNames: ["wizard-field-upload"],
|
classNames: ["wizard-field-upload"],
|
||||||
classNameBindings: ["isImage"],
|
classNameBindings: ["isImage", "fieldClass"],
|
||||||
uploading: false,
|
uploading: false,
|
||||||
type: computed(function () {
|
type: computed(function () {
|
||||||
return `wizard_${this.field.id}`;
|
return `wizard_${this.field.id}`;
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({});
|
|
@ -1,5 +1,5 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field-tag",
|
classNameBindings: ["fieldClass"],
|
||||||
});
|
});
|
|
@ -1,10 +1,9 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { cook } from "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite";
|
import { cook } from "discourse/lib/text";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-field",
|
|
||||||
classNameBindings: [
|
classNameBindings: [
|
||||||
":wizard-field",
|
":wizard-field",
|
||||||
"typeClasses",
|
"typeClasses",
|
||||||
|
@ -12,6 +11,14 @@ export default Component.extend({
|
||||||
"field.id",
|
"field.id",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
cook(this.field.translatedDescription).then((cookedDescription) => {
|
||||||
|
this.set("cookedDescription", cookedDescription);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed("field.type", "field.id")
|
@discourseComputed("field.type", "field.id")
|
||||||
typeClasses: (type, id) =>
|
typeClasses: (type, id) =>
|
||||||
`${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`,
|
`${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`,
|
||||||
|
@ -24,12 +31,7 @@ export default Component.extend({
|
||||||
if (["text_only"].includes(type)) {
|
if (["text_only"].includes(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return dasherize(type === "component" ? id : `wizard-field-${type}`);
|
return dasherize(type === "component" ? id : `custom-wizard-field-${type}`);
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("field.translatedDescription")
|
|
||||||
cookedDescription(description) {
|
|
||||||
return cook(description);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("field.type")
|
@discourseComputed("field.type")
|
|
@ -3,7 +3,6 @@ import { computed } from "@ember/object";
|
||||||
import { makeArray } from "discourse-common/lib/helpers";
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
export default ComboBox.extend({
|
export default ComboBox.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-group-selector",
|
|
||||||
content: computed("groups.[]", "field.content.[]", function () {
|
content: computed("groups.[]", "field.content.[]", function () {
|
||||||
const whitelist = makeArray(this.field.content);
|
const whitelist = makeArray(this.field.content);
|
||||||
return this.groups
|
return this.groups
|
|
@ -1,11 +1,11 @@
|
||||||
import CustomWizard from "../models/wizard";
|
import CustomWizard from "../models/custom-wizard";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
|
import getURL from "discourse-common/lib/get-url";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [":wizard-no-access", "reasonClass"],
|
classNameBindings: [":wizard-no-access", "reasonClass"],
|
||||||
layoutName: "wizard/templates/components/wizard-no-access",
|
|
||||||
|
|
||||||
@discourseComputed("reason")
|
@discourseComputed("reason")
|
||||||
reasonClass(reason) {
|
reasonClass(reason) {
|
||||||
|
@ -19,7 +19,11 @@ export default Component.extend({
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
skip() {
|
skip() {
|
||||||
|
if (this.currentUser) {
|
||||||
CustomWizard.skip(this.get("wizardId"));
|
CustomWizard.skip(this.get("wizardId"));
|
||||||
|
} else {
|
||||||
|
window.location = getURL("/");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
|
@ -4,7 +4,6 @@ import { observes } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ["wizard-similar-topics"],
|
classNames: ["wizard-similar-topics"],
|
||||||
layoutName: "wizard/templates/components/wizard-similar-topics",
|
|
||||||
showTopics: true,
|
showTopics: true,
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
|
@ -4,15 +4,16 @@ import I18n from "I18n";
|
||||||
import getUrl from "discourse-common/lib/get-url";
|
import getUrl from "discourse-common/lib/get-url";
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import { cook } from "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite";
|
import { cook } from "discourse/lib/text";
|
||||||
import { updateCachedWizard } from "discourse/plugins/discourse-custom-wizard/wizard/models/wizard";
|
import CustomWizard, {
|
||||||
|
updateCachedWizard,
|
||||||
|
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
|
||||||
import { alias, not } from "@ember/object/computed";
|
import { alias, not } from "@ember/object/computed";
|
||||||
import CustomWizard from "../models/wizard";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
|
|
||||||
const alreadyWarned = {};
|
const alreadyWarned = {};
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/wizard-step",
|
|
||||||
classNameBindings: [":wizard-step", "step.id"],
|
classNameBindings: [":wizard-step", "step.id"],
|
||||||
saving: null,
|
saving: null,
|
||||||
|
|
||||||
|
@ -21,6 +22,17 @@ export default Component.extend({
|
||||||
this.set("stylingDropdown", {});
|
this.set("stylingDropdown", {});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
cook(this.step.translatedTitle).then((cookedTitle) => {
|
||||||
|
this.set("cookedTitle", cookedTitle);
|
||||||
|
});
|
||||||
|
cook(this.step.translatedDescription).then((cookedDescription) => {
|
||||||
|
this.set("cookedDescription", cookedDescription);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.autoFocus();
|
this.autoFocus();
|
||||||
|
@ -32,16 +44,6 @@ export default Component.extend({
|
||||||
showNextButton: not("step.final"),
|
showNextButton: not("step.final"),
|
||||||
showDoneButton: alias("step.final"),
|
showDoneButton: alias("step.final"),
|
||||||
|
|
||||||
@discourseComputed("step.translatedTitle")
|
|
||||||
cookedTitle(title) {
|
|
||||||
return cook(title);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("step.translatedDescription")
|
|
||||||
cookedDescription(description) {
|
|
||||||
return cook(description);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"step.index",
|
"step.index",
|
||||||
"step.displayIndex",
|
"step.displayIndex",
|
||||||
|
@ -90,16 +92,6 @@ export default Component.extend({
|
||||||
this.showMessage(message);
|
this.showMessage(message);
|
||||||
},
|
},
|
||||||
|
|
||||||
keyPress(event) {
|
|
||||||
if (event.key === "Enter") {
|
|
||||||
if (this.showDoneButton) {
|
|
||||||
this.send("quit");
|
|
||||||
} else {
|
|
||||||
this.send("nextStep");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("step.index", "wizard.totalSteps")
|
@discourseComputed("step.index", "wizard.totalSteps")
|
||||||
barStyle(displayIndex, totalSteps) {
|
barStyle(displayIndex, totalSteps) {
|
||||||
let ratio = parseFloat(displayIndex) / parseFloat(totalSteps - 1);
|
let ratio = parseFloat(displayIndex) / parseFloat(totalSteps - 1);
|
||||||
|
@ -119,34 +111,24 @@ export default Component.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
autoFocus() {
|
autoFocus() {
|
||||||
|
discourseLater(() => {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
const $invalid = $(
|
if ($(".invalid .wizard-focusable").length) {
|
||||||
".wizard-field.invalid:nth-of-type(1) .wizard-focusable"
|
this.animateInvalidFields();
|
||||||
);
|
|
||||||
|
|
||||||
if ($invalid.length) {
|
|
||||||
return $invalid.focus();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
$(".wizard-focusable:first").focus();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
animateInvalidFields() {
|
animateInvalidFields() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
let $element = $(
|
let $invalid = $(".invalid .wizard-focusable");
|
||||||
".invalid input[type=text],.invalid textarea,.invalid input[type=checkbox],.invalid .select-kit"
|
if ($invalid.length) {
|
||||||
);
|
|
||||||
|
|
||||||
if ($element.length) {
|
|
||||||
$([document.documentElement, document.body]).animate(
|
$([document.documentElement, document.body]).animate(
|
||||||
{
|
{
|
||||||
scrollTop: $element.offset().top - 200,
|
scrollTop: $invalid.offset().top - 200,
|
||||||
},
|
},
|
||||||
400,
|
400
|
||||||
function () {
|
|
||||||
$element.wiggle(2, 100);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -4,7 +4,10 @@ export default TagChooser.extend({
|
||||||
searchTags(url, data, callback) {
|
searchTags(url, data, callback) {
|
||||||
if (this.tagGroups) {
|
if (this.tagGroups) {
|
||||||
let tagGroupsString = this.tagGroups.join(",");
|
let tagGroupsString = this.tagGroups.join(",");
|
||||||
data.tag_groups = tagGroupsString;
|
data.filterForInput = {
|
||||||
|
name: "custom-wizard-tag-chooser",
|
||||||
|
groups: tagGroupsString,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._super(url, data, callback);
|
return this._super(url, data, callback);
|
|
@ -1,7 +1,7 @@
|
||||||
import computed from "discourse-common/utils/decorators";
|
import computed from "discourse-common/utils/decorators";
|
||||||
import { isLTR, isRTL, siteDir } from "discourse/lib/text-direction";
|
import { isLTR, isRTL, siteDir } from "discourse/lib/text-direction";
|
||||||
import WizardI18n from "../lib/wizard-i18n";
|
import I18n from "I18n";
|
||||||
import TextField from "@ember/component/text-field";
|
import TextField from "discourse/components/text-field";
|
||||||
|
|
||||||
export default TextField.extend({
|
export default TextField.extend({
|
||||||
attributeBindings: [
|
attributeBindings: [
|
||||||
|
@ -39,6 +39,6 @@ export default TextField.extend({
|
||||||
|
|
||||||
@computed("placeholderKey")
|
@computed("placeholderKey")
|
||||||
placeholder(placeholderKey) {
|
placeholder(placeholderKey) {
|
||||||
return placeholderKey ? WizardI18n(placeholderKey) : "";
|
return placeholderKey ? I18n.t(placeholderKey) : "";
|
||||||
},
|
},
|
||||||
});
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
import TimeInput from "discourse/components/time-input";
|
||||||
|
|
||||||
|
export default TimeInput.extend({});
|
|
@ -1,8 +1,6 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layoutName: "wizard/templates/components/field-validators",
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
perform() {
|
perform() {
|
||||||
this.appEvents.trigger("custom-wizard:validate");
|
this.appEvents.trigger("custom-wizard:validate");
|
|
@ -0,0 +1,34 @@
|
||||||
|
<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>
|
|
@ -0,0 +1,17 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<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>
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default class NextSessionScheduledComponent extends Component {
|
||||||
|
@tracked bufferedDateTime;
|
||||||
|
title = I18n.t("admin.wizard.after_time_modal.title");
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.bufferedDateTime = this.args.model.dateTime
|
||||||
|
? moment(this.args.model.dateTime)
|
||||||
|
: moment(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
get submitDisabled() {
|
||||||
|
return moment().isAfter(this.bufferedDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
submit() {
|
||||||
|
const dateTime = this.bufferedDateTime;
|
||||||
|
this.args.model.update(moment(dateTime).utc().toISOString());
|
||||||
|
this.args.closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
dateTimeChanged(dateTime) {
|
||||||
|
this.bufferedDateTime = dateTime;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import WizardFieldValidator from "../../wizard/components/validator";
|
import WizardFieldValidator from "discourse/plugins/discourse-custom-wizard/discourse/components/validator";
|
||||||
import { deepMerge } from "discourse-common/lib/object";
|
import { deepMerge } from "discourse-common/lib/object";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||||
import { cancel, later } from "@ember/runloop";
|
import { cancel, later } from "@ember/runloop";
|
||||||
|
@ -10,7 +10,6 @@ import { dasherize } from "@ember/string";
|
||||||
|
|
||||||
export default WizardFieldValidator.extend({
|
export default WizardFieldValidator.extend({
|
||||||
classNames: ["similar-topics-validator"],
|
classNames: ["similar-topics-validator"],
|
||||||
layoutName: "wizard/templates/components/similar-topics-validator",
|
|
||||||
similarTopics: null,
|
similarTopics: null,
|
||||||
hasInput: notEmpty("field.value"),
|
hasInput: notEmpty("field.value"),
|
||||||
hasSimilarTopics: notEmpty("similarTopics"),
|
hasSimilarTopics: notEmpty("similarTopics"),
|
|
@ -1,12 +1,10 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { equal } from "@ember/object/computed";
|
import { equal } from "@ember/object/computed";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax, getToken } from "discourse/lib/ajax";
|
||||||
import { getToken } from "wizard/lib/ajax";
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ["validator"],
|
classNames: ["validator"],
|
||||||
classNameBindings: ["isValid", "isInvalid"],
|
classNameBindings: ["isValid", "isInvalid"],
|
||||||
layoutName: "wizard/templates/components/validator",
|
|
||||||
validMessageKey: null,
|
validMessageKey: null,
|
||||||
invalidMessageKey: null,
|
invalidMessageKey: null,
|
||||||
isValid: null,
|
isValid: null,
|
|
@ -1,21 +0,0 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
|
||||||
import Component from "@ember/component";
|
|
||||||
|
|
||||||
export default Component.extend({
|
|
||||||
classNames: "wizard-advanced-toggle",
|
|
||||||
|
|
||||||
@discourseComputed("showAdvanced")
|
|
||||||
toggleClass(showAdvanced) {
|
|
||||||
let classes = "btn";
|
|
||||||
if (showAdvanced) {
|
|
||||||
classes += " btn-primary";
|
|
||||||
}
|
|
||||||
return classes;
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
toggleAdvanced() {
|
|
||||||
this.toggleProperty("showAdvanced");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
import { and, 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";
|
||||||
import wizardSchema from "../lib/wizard-schema";
|
|
||||||
import UndoChanges from "../mixins/undo-changes";
|
import UndoChanges from "../mixins/undo-changes";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
@ -16,6 +15,7 @@ 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"),
|
||||||
|
@ -25,8 +25,6 @@ export default Component.extend(UndoChanges, {
|
||||||
createGroup: equal("action.type", "create_group"),
|
createGroup: equal("action.type", "create_group"),
|
||||||
apiEmpty: empty("action.api"),
|
apiEmpty: empty("action.api"),
|
||||||
groupPropertyTypes: selectKitContent(["id", "name"]),
|
groupPropertyTypes: selectKitContent(["id", "name"]),
|
||||||
hasAdvanced: or("hasCustomFields", "routeTo"),
|
|
||||||
showAdvanced: and("hasAdvanced", "action.type"),
|
|
||||||
hasCustomFields: or(
|
hasCustomFields: or(
|
||||||
"basicTopicFields",
|
"basicTopicFields",
|
||||||
"updateProfile",
|
"updateProfile",
|
||||||
|
@ -36,22 +34,15 @@ export default Component.extend(UndoChanges, {
|
||||||
basicTopicFields: or("createTopic", "sendMessage", "openComposer"),
|
basicTopicFields: or("createTopic", "sendMessage", "openComposer"),
|
||||||
publicTopicFields: or("createTopic", "openComposer"),
|
publicTopicFields: or("createTopic", "openComposer"),
|
||||||
showPostAdvanced: or("createTopic", "sendMessage"),
|
showPostAdvanced: or("createTopic", "sendMessage"),
|
||||||
actionTypes: Object.keys(wizardSchema.action.types).map((type) => {
|
|
||||||
return {
|
|
||||||
id: type,
|
|
||||||
name: I18n.t(`admin.wizard.action.${type}.label`),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
availableNotificationLevels: notificationLevels.map((type) => {
|
availableNotificationLevels: notificationLevels.map((type) => {
|
||||||
return {
|
return {
|
||||||
id: type,
|
id: type,
|
||||||
name: I18n.t(
|
name: I18n.t(`admin.wizard.action.watch_x.notification_level.${type}`),
|
||||||
`admin.wizard.action.watch_categories.notification_level.${type}`
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
messageUrl: "https://thepavilion.io/t/2810",
|
messageUrl:
|
||||||
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/action-settings",
|
||||||
|
|
||||||
@discourseComputed("action.type")
|
@discourseComputed("action.type")
|
||||||
messageKey(type) {
|
messageKey(type) {
|
||||||
|
@ -101,4 +92,14 @@ export default Component.extend(UndoChanges, {
|
||||||
}
|
}
|
||||||
return apis.find((a) => a.name === api).endpoints;
|
return apis.find((a) => a.name === api).endpoints;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("fieldTypes")
|
||||||
|
hasEventField(fieldTypes) {
|
||||||
|
return fieldTypes.map((ft) => ft.id).includes("event");
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("fieldTypes")
|
||||||
|
hasLocationField(fieldTypes) {
|
||||||
|
return fieldTypes.map((ft) => ft.id).includes("location");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
import { alias, equal, or } from "@ember/object/computed";
|
import { equal, or } from "@ember/object/computed";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import { selectKitContent } from "../lib/wizard";
|
import { selectKitContent } from "../lib/wizard";
|
||||||
import UndoChanges from "../mixins/undo-changes";
|
import UndoChanges from "../mixins/undo-changes";
|
||||||
|
@ -27,8 +27,8 @@ 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"]),
|
||||||
showAdvanced: alias("field.type"),
|
messageUrl:
|
||||||
messageUrl: "https://thepavilion.io/t/2809",
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/field-settings",
|
||||||
|
|
||||||
@discourseComputed("field.type")
|
@discourseComputed("field.type")
|
||||||
validations(type) {
|
validations(type) {
|
||||||
|
@ -144,11 +144,17 @@ export default Component.extend(UndoChanges, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
imageUploadDone(upload) {
|
imageUploadDone(upload) {
|
||||||
this.set("field.image", upload.url);
|
this.setProperties({
|
||||||
|
"field.image": upload.url,
|
||||||
|
"field.image_upload_id": upload.id,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
imageUploadDeleted() {
|
imageUploadDeleted() {
|
||||||
this.set("field.image", null);
|
this.setProperties({
|
||||||
|
"field.image": null,
|
||||||
|
"field.image_upload_id": null,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,11 +24,17 @@ export default Component.extend({
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
bannerUploadDone(upload) {
|
bannerUploadDone(upload) {
|
||||||
this.set("step.banner", upload.url);
|
this.setProperties({
|
||||||
|
"step.banner": upload.url,
|
||||||
|
"step.banner_upload_id": upload.id,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
bannerUploadDeleted() {
|
bannerUploadDeleted() {
|
||||||
this.set("step.banner", null);
|
this.setProperties({
|
||||||
|
"step.banner": null,
|
||||||
|
"step.banner_upload_id": null,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -71,6 +71,17 @@ 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");
|
||||||
|
@ -78,7 +89,7 @@ export default Component.extend({
|
||||||
let params = setWizardDefaults({}, itemType);
|
let params = setWizardDefaults({}, itemType);
|
||||||
|
|
||||||
params.isNew = true;
|
params.isNew = true;
|
||||||
params.index = items.length;
|
params.index = this.getNextIndex();
|
||||||
|
|
||||||
let id = `${itemType}_${params.index + 1}`;
|
let id = `${itemType}_${params.index + 1}`;
|
||||||
if (itemType === "field") {
|
if (itemType === "field") {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
default as discourseComputed,
|
default as discourseComputed,
|
||||||
observes,
|
observes,
|
||||||
} from "discourse-common/utils/decorators";
|
} from "discourse-common/utils/decorators";
|
||||||
import { getOwner } from "discourse-common/lib/get-owner";
|
import { getOwner } from "@ember/application";
|
||||||
import { defaultSelectionType, selectionTypes } from "../lib/wizard-mapper";
|
import { defaultSelectionType, selectionTypes } from "../lib/wizard-mapper";
|
||||||
import {
|
import {
|
||||||
generateName,
|
generateName,
|
||||||
|
@ -15,6 +15,7 @@ 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 { inject as service } from "@ember/service";
|
||||||
|
|
||||||
const customFieldActionMap = {
|
const customFieldActionMap = {
|
||||||
topic: ["create_topic", "send_message"],
|
topic: ["create_topic", "send_message"],
|
||||||
|
@ -28,6 +29,7 @@ const values = ["present", "true", "false"];
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [":mapper-selector", "activeType"],
|
classNameBindings: [":mapper-selector", "activeType"],
|
||||||
|
subscription: service(),
|
||||||
|
|
||||||
showText: computed("activeType", function () {
|
showText: computed("activeType", function () {
|
||||||
return this.showInput("text");
|
return this.showInput("text");
|
||||||
|
@ -116,6 +118,9 @@ export default Component.extend({
|
||||||
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");
|
||||||
}),
|
}),
|
||||||
|
@ -126,7 +131,33 @@ export default Component.extend({
|
||||||
return this.connector === "is";
|
return this.connector === "is";
|
||||||
}),
|
}),
|
||||||
|
|
||||||
groups: alias("site.groups"),
|
@discourseComputed(
|
||||||
|
"site.groups",
|
||||||
|
"guestGroup",
|
||||||
|
"subscription.subscriptionType"
|
||||||
|
)
|
||||||
|
groups(groups, guestGroup, subscriptionType) {
|
||||||
|
let result = groups;
|
||||||
|
if (!guestGroup) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["standard", "business"].includes(subscriptionType)) {
|
||||||
|
let guestIndex;
|
||||||
|
result.forEach((r, index) => {
|
||||||
|
if (r.id === 0) {
|
||||||
|
r.name = I18n.t("admin.wizard.selector.label.users");
|
||||||
|
guestIndex = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result.splice(guestIndex, 0, {
|
||||||
|
id: -1,
|
||||||
|
name: I18n.t("admin.wizard.selector.label.guests"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
categories: alias("site.categories"),
|
categories: alias("site.categories"),
|
||||||
showComboBox: or(
|
showComboBox: or(
|
||||||
"showWizardField",
|
"showWizardField",
|
||||||
|
@ -377,7 +408,7 @@ export default Component.extend({
|
||||||
this.changeValue(event.target.value);
|
this.changeValue(event.target.value);
|
||||||
},
|
},
|
||||||
|
|
||||||
changeUserValue(previousValue, value) {
|
changeUserValue(value) {
|
||||||
this.changeValue(value);
|
this.changeValue(value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,6 +32,7 @@ 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"];
|
||||||
|
|
|
@ -6,6 +6,7 @@ import I18n from "I18n";
|
||||||
const icons = {
|
const icons = {
|
||||||
error: "times-circle",
|
error: "times-circle",
|
||||||
success: "check-circle",
|
success: "check-circle",
|
||||||
|
warn: "exclamation-circle",
|
||||||
info: "info-circle",
|
info: "info-circle",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ["realtime-validations"],
|
classNames: ["realtime-validations", "setting", "full", "subscription"],
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
timeUnits() {
|
timeUnits() {
|
||||||
return ["days", "weeks", "months", "years"].map((unit) => {
|
return ["days", "weeks", "months", "years"].map((unit) => {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<DButton
|
||||||
|
@icon={{this.updateIcon}}
|
||||||
|
@action={{this.update}}
|
||||||
|
class="btn update"
|
||||||
|
@disabled={{this.updating}}
|
||||||
|
@title="admin.wizard.subscription.update.title"
|
||||||
|
>
|
||||||
|
{{#if this.updating}}
|
||||||
|
{{loading-spinner size="small"}}
|
||||||
|
{{/if}}
|
||||||
|
</DButton>
|
||||||
|
<DButton
|
||||||
|
@action={{this.click}}
|
||||||
|
class="wizard-subscription-badge {{this.subscription.subscriptionType}}"
|
||||||
|
@title={{this.title}}
|
||||||
|
>
|
||||||
|
{{d-icon "pavilion-logo"}}
|
||||||
|
<span>{{this.label}}</span>
|
||||||
|
</DButton>
|
46
assets/javascripts/discourse/components/wizard-subscription-badge.js
Normale Datei
46
assets/javascripts/discourse/components/wizard-subscription-badge.js
Normale Datei
|
@ -0,0 +1,46 @@
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { action, computed } from "@ember/object";
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default class WizardSubscriptionBadge extends Component {
|
||||||
|
@service subscription;
|
||||||
|
@tracked updating = false;
|
||||||
|
@tracked updateIcon = "sync";
|
||||||
|
basePath = "/admin/plugins/subscription-client";
|
||||||
|
|
||||||
|
@computed("subscription.subscriptionType")
|
||||||
|
get i18nKey() {
|
||||||
|
return `admin.wizard.subscription.type.${
|
||||||
|
this.subscription.subscriptionType
|
||||||
|
? this.subscription.subscriptionType
|
||||||
|
: "none"
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("i18nKey")
|
||||||
|
get title() {
|
||||||
|
return `${this.i18nKey}.title`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("i18nKey")
|
||||||
|
get label() {
|
||||||
|
return I18n.t(`${this.i18nKey}.label`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
click() {
|
||||||
|
window.open(this.subscription.subscriptionCtaLink, "_blank").focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
update() {
|
||||||
|
this.updating = true;
|
||||||
|
this.updateIcon = null;
|
||||||
|
this.subscription.updateSubscriptionStatus().finally(() => {
|
||||||
|
this.updateIcon = "sync";
|
||||||
|
this.updating = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<div
|
||||||
|
class="wizard-subscription-container
|
||||||
|
{{if this.subscription.subscribed 'subscribed'}}"
|
||||||
|
>
|
||||||
|
<div class="subscription-header">
|
||||||
|
<h4>{{i18n "admin.wizard.subscription.title"}}</h4>
|
||||||
|
|
||||||
|
<a href={{subscriptionLink}} title={{i18n subscribedTitle}}>
|
||||||
|
{{d-icon subscribedIcon}}
|
||||||
|
{{i18n subscribedLabel}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="subscription-settings">
|
||||||
|
{{yield}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,26 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
|
export default class WizardSubscriptionContainer extends Component {
|
||||||
|
@service subscription;
|
||||||
|
|
||||||
|
@computed("subscription.subscribed")
|
||||||
|
get subscribedIcon() {
|
||||||
|
return this.subscription.subscribed ? "check" : "times";
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("subscription.subscribed")
|
||||||
|
get subscribedLabel() {
|
||||||
|
return `admin.wizard.subscription.${
|
||||||
|
this.subscription.subscribed ? "subscribed" : "not_subscribed"
|
||||||
|
}.label`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("subscription.subscribed")
|
||||||
|
get subscribedTitle() {
|
||||||
|
return `admin.wizard.subscription.${
|
||||||
|
this.subscription.subscribed ? "subscribed" : "not_subscribed"
|
||||||
|
}.title`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
import SingleSelectComponent from "select-kit/components/single-select";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
const nameKey = function (feature, attribute, value) {
|
||||||
|
if (feature === "action") {
|
||||||
|
return `admin.wizard.action.${value}.label`;
|
||||||
|
} else {
|
||||||
|
return `admin.wizard.${feature}.${attribute}.${value}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SingleSelectComponent.extend({
|
||||||
|
classNames: ["combo-box", "wizard-subscription-selector"],
|
||||||
|
subscription: service(),
|
||||||
|
|
||||||
|
selectKitOptions: {
|
||||||
|
autoFilterable: false,
|
||||||
|
filterable: false,
|
||||||
|
showFullTitle: true,
|
||||||
|
headerComponent:
|
||||||
|
"wizard-subscription-selector/wizard-subscription-selector-header",
|
||||||
|
caretUpIcon: "caret-up",
|
||||||
|
caretDownIcon: "caret-down",
|
||||||
|
},
|
||||||
|
|
||||||
|
allowedSubscriptionTypes(feature, attribute, value) {
|
||||||
|
let attributes = this.subscription.subscriptionAttributes[feature];
|
||||||
|
if (!attributes || !attributes[attribute]) {
|
||||||
|
return ["none"];
|
||||||
|
}
|
||||||
|
let allowedTypes = [];
|
||||||
|
Object.keys(attributes[attribute]).forEach((subscriptionType) => {
|
||||||
|
let values = attributes[attribute][subscriptionType];
|
||||||
|
if (values[0] === "*" || values.includes(value)) {
|
||||||
|
allowedTypes.push(subscriptionType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return allowedTypes;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("feature", "attribute", "wizard.allowGuests")
|
||||||
|
content(feature, attribute) {
|
||||||
|
return filterValues(this.wizard, feature, attribute)
|
||||||
|
.map((value) => {
|
||||||
|
let allowedSubscriptionTypes = this.allowedSubscriptionTypes(
|
||||||
|
feature,
|
||||||
|
attribute,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
let subscriptionRequired =
|
||||||
|
allowedSubscriptionTypes.length &&
|
||||||
|
!allowedSubscriptionTypes.includes("none");
|
||||||
|
|
||||||
|
let attrs = {
|
||||||
|
id: value,
|
||||||
|
name: I18n.t(nameKey(feature, attribute, value)),
|
||||||
|
subscriptionRequired,
|
||||||
|
};
|
||||||
|
if (subscriptionRequired) {
|
||||||
|
let subscribed = allowedSubscriptionTypes.includes(
|
||||||
|
this.subscription.subscriptionType
|
||||||
|
);
|
||||||
|
let selectorKey = subscribed ? "subscribed" : "not_subscribed";
|
||||||
|
let selectorLabel = `admin.wizard.subscription.${selectorKey}.selector`;
|
||||||
|
|
||||||
|
attrs.disabled = !subscribed;
|
||||||
|
attrs.selectorLabel = selectorLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
})
|
||||||
|
.sort(function (a, b) {
|
||||||
|
if (a.subscriptionType && !b.subscriptionType) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!a.subscriptionType && b.subscriptionType) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.subscriptionType === b.subscriptionType) {
|
||||||
|
return a.subscriptionType
|
||||||
|
? a.subscriptionType.localeCompare(b.subscriptionType)
|
||||||
|
: 0;
|
||||||
|
} else {
|
||||||
|
return a.subscriptionType === "standard" ? -1 : 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
modifyComponentForRow() {
|
||||||
|
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
import SingleSelectHeaderComponent from "select-kit/components/select-kit/single-select-header";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { reads } from "@ember/object/computed";
|
||||||
|
|
||||||
|
export default SingleSelectHeaderComponent.extend({
|
||||||
|
classNames: ["combo-box-header", "wizard-subscription-selector-header"],
|
||||||
|
caretUpIcon: reads("selectKit.options.caretUpIcon"),
|
||||||
|
caretDownIcon: reads("selectKit.options.caretDownIcon"),
|
||||||
|
caretIcon: computed(
|
||||||
|
"selectKit.isExpanded",
|
||||||
|
"caretUpIcon",
|
||||||
|
"caretDownIcon",
|
||||||
|
function () {
|
||||||
|
return this.selectKit.isExpanded ? this.caretUpIcon : this.caretDownIcon;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
classNameBindings: ["isDisabled:disabled"],
|
||||||
|
|
||||||
|
@discourseComputed("item")
|
||||||
|
isDisabled() {
|
||||||
|
return this.item.disabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
click(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
if (!this.item.disabled) {
|
||||||
|
this.selectKit.select(this.rowValue, this.item);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="supplier-authorize">
|
||||||
|
<WizardSubscriptionBadge />
|
||||||
|
{{#if authorized}}
|
||||||
|
{{conditional-loading-spinner size="small" condition=unauthorizing}}
|
||||||
|
<DButton
|
||||||
|
class="deauthorize"
|
||||||
|
@title="admin.wizard.subscription.deauthorize.title"
|
||||||
|
@disabled={{unauthorizing}}
|
||||||
|
@action={{this.deauthorize}}
|
||||||
|
>
|
||||||
|
{{i18n "admin.wizard.subscription.deauthorize.label"}}
|
||||||
|
</DButton>
|
||||||
|
{{else}}
|
||||||
|
<DButton
|
||||||
|
@icon="id-card"
|
||||||
|
class="btn-primary"
|
||||||
|
@label="admin.wizard.subscription.authorize.label"
|
||||||
|
@title="admin.wizard.subscription.authorize.title"
|
||||||
|
@action={{this.authorize}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default class WizardSubscriptionStatus extends Component {
|
||||||
|
@service siteSettings;
|
||||||
|
@service subscription;
|
||||||
|
@tracked supplierId = null;
|
||||||
|
@tracked authorized = false;
|
||||||
|
@tracked unauthorizing = false;
|
||||||
|
basePath = "/admin/plugins/subscription-client/suppliers";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
ajax(`${this.basePath}`)
|
||||||
|
.then((result) => {
|
||||||
|
this.supplierId = result.suppliers[0].id;
|
||||||
|
this.authorized = result.suppliers[0].authorized;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.subscription.retrieveSubscriptionStatus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
authorize() {
|
||||||
|
window.location.href = `${this.basePath}/authorize?supplier_id=${this.supplierId}&final_landing_path=/admin/wizards/wizard`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
deauthorize() {
|
||||||
|
this.unauthorizing = true;
|
||||||
|
|
||||||
|
ajax(`${this.basePath}/authorize`, {
|
||||||
|
type: "DELETE",
|
||||||
|
data: {
|
||||||
|
supplier_id: this.supplierId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
this.supplierId = result.supplier.id;
|
||||||
|
this.authorized = !(result.supplier.authorized_at === null);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.unauthorizing = false;
|
||||||
|
this.subscription.retrieveSubscriptionStatus();
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
}
|
||||||
|
}
|
139
assets/javascripts/discourse/components/wizard-table-field.js.es6
Normale Datei
139
assets/javascripts/discourse/components/wizard-table-field.js.es6
Normale Datei
|
@ -0,0 +1,139 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { equal, notEmpty } from "@ember/object/computed";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNameBindings: ["value.type"],
|
||||||
|
isText: equal("value.type", "text"),
|
||||||
|
isComposer: equal("value.type", "composer"),
|
||||||
|
isDate: equal("value.type", "date"),
|
||||||
|
isTime: equal("value.type", "time"),
|
||||||
|
isDateTime: equal("value.type", "date_time"),
|
||||||
|
isNumber: equal("value.type", "number"),
|
||||||
|
isCheckbox: equal("value.type", "checkbox"),
|
||||||
|
isUrl: equal("value.type", "url"),
|
||||||
|
isUpload: equal("value.type", "upload"),
|
||||||
|
isDropdown: equal("value.type", "dropdown"),
|
||||||
|
isTag: equal("value.type", "tag"),
|
||||||
|
isCategory: equal("value.type", "category"),
|
||||||
|
isGroup: equal("value.type", "group"),
|
||||||
|
isUserSelector: equal("value.type", "user_selector"),
|
||||||
|
isSubmittedAt: equal("field", "submitted_at"),
|
||||||
|
isComposerPreview: equal("value.type", "composer_preview"),
|
||||||
|
textState: "text-collapsed",
|
||||||
|
toggleText: I18n.t("admin.wizard.expand_text"),
|
||||||
|
|
||||||
|
@discourseComputed("value", "isUser", "isSubmittedAt")
|
||||||
|
hasValue(value, isUser, isSubmittedAt) {
|
||||||
|
if (isUser || isSubmittedAt) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return value && value.value;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("field", "value.type")
|
||||||
|
isUser(field, type) {
|
||||||
|
return field === "username" || field === "user" || type === "user";
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value.type")
|
||||||
|
isLongtext(type) {
|
||||||
|
return type === "textarea" || type === "long_text";
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value")
|
||||||
|
checkboxValue(value) {
|
||||||
|
const isCheckbox = this.get("isCheckbox");
|
||||||
|
if (isCheckbox) {
|
||||||
|
if (value.value.includes("true")) {
|
||||||
|
return true;
|
||||||
|
} else if (value.value.includes("false")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
expandText() {
|
||||||
|
const state = this.get("textState");
|
||||||
|
|
||||||
|
if (state === "text-collapsed") {
|
||||||
|
this.set("textState", "text-expanded");
|
||||||
|
this.set("toggleText", I18n.t("admin.wizard.collapse_text"));
|
||||||
|
} else if (state === "text-expanded") {
|
||||||
|
this.set("textState", "text-collapsed");
|
||||||
|
this.set("toggleText", I18n.t("admin.wizard.expand_text"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value")
|
||||||
|
file(value) {
|
||||||
|
const isUpload = this.get("isUpload");
|
||||||
|
if (isUpload) {
|
||||||
|
return value.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value")
|
||||||
|
submittedUsers(value) {
|
||||||
|
const isUserSelector = this.get("isUserSelector");
|
||||||
|
const users = [];
|
||||||
|
|
||||||
|
if (isUserSelector) {
|
||||||
|
const userData = value.value;
|
||||||
|
const usernames = [];
|
||||||
|
|
||||||
|
if (userData.indexOf(",")) {
|
||||||
|
usernames.push(...userData.split(","));
|
||||||
|
|
||||||
|
usernames.forEach((u) => {
|
||||||
|
const user = {
|
||||||
|
username: u,
|
||||||
|
url: `/u/${u}`,
|
||||||
|
};
|
||||||
|
users.push(user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("isUser", "field", "value")
|
||||||
|
username(isUser, field, value) {
|
||||||
|
if (isUser) {
|
||||||
|
return value.username;
|
||||||
|
}
|
||||||
|
if (field === "username") {
|
||||||
|
return value.value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
showUsername: notEmpty("username"),
|
||||||
|
|
||||||
|
@discourseComputed("username")
|
||||||
|
userProfileUrl(username) {
|
||||||
|
if (username) {
|
||||||
|
return `/u/${username}`;
|
||||||
|
}
|
||||||
|
return "/";
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value")
|
||||||
|
categoryUrl(value) {
|
||||||
|
const isCategory = this.get("isCategory");
|
||||||
|
if (isCategory) {
|
||||||
|
return `/c/${value.value}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("value")
|
||||||
|
groupUrl(value) {
|
||||||
|
const isGroup = this.get("isGroup");
|
||||||
|
if (isGroup) {
|
||||||
|
return `/g/${value.value}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
|
@ -5,11 +5,7 @@ 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 = [
|
const excludedUserProperties = ["profile_background", "card_background"];
|
||||||
"avatar",
|
|
||||||
"profile_background",
|
|
||||||
"card_background",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: "wizard-text-editor",
|
classNames: "wizard-text-editor",
|
||||||
|
@ -52,12 +48,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: {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
{{#if currentUser.admin}}
|
{{#if currentUser.admin}}
|
||||||
{{nav-item route="adminWizards" label="admin.wizard.nav_label"}}
|
{{nav-item route="adminWizards" label="admin.wizard.nav_label"}}
|
||||||
|
|
||||||
|
{{#if wizardErrorNotice}}
|
||||||
|
{{d-icon "exclaimation-circle"}}
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
|
@ -9,8 +9,7 @@
|
||||||
value=wizardListVal
|
value=wizardListVal
|
||||||
content=wizardList
|
content=wizardList
|
||||||
onChange=(action "changeWizard")
|
onChange=(action "changeWizard")
|
||||||
options=(hash
|
options=(hash none="admin.wizard.select")
|
||||||
none="admin.wizard.select"
|
}}
|
||||||
)}}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
|
@ -1,9 +1,9 @@
|
||||||
import CustomWizard from "../../models/custom-wizard";
|
import CustomWizardAdmin from "../../models/custom-wizard-admin";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setupComponent(attrs, component) {
|
setupComponent(attrs, component) {
|
||||||
CustomWizard.all()
|
CustomWizardAdmin.all()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
component.set("wizardList", result);
|
component.set("wizardList", result);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
{{#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 "wizard.complete_custom" name=wizard.name}}</a>
|
<a href={{wizard.url}}>{{i18n
|
||||||
|
"wizard.complete_custom"
|
||||||
|
name=wizard.name
|
||||||
|
}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
|
@ -4,14 +4,18 @@ 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"),
|
||||||
endpointMethods: selectKitContent(["GET", "PUT", "POST", "PATCH", "DELETE"]),
|
endpointMethods: selectKitContent(["PUT", "POST", "PATCH", "DELETE"]),
|
||||||
showRemove: not("isNew"),
|
showRemove: not("isNew"),
|
||||||
showRedirectUri: and("threeLeggedOauth", "api.name"),
|
showRedirectUri: and("threeLeggedOauth", "api.name"),
|
||||||
responseIcon: null,
|
responseIcon: null,
|
||||||
|
@ -20,29 +24,8 @@ export default Controller.extend({
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
]),
|
]),
|
||||||
successCodes: selectKitContent([
|
successCodes: selectKitContent([
|
||||||
100,
|
100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301,
|
||||||
101,
|
302, 303, 303, 304, 305, 306, 307, 308,
|
||||||
102,
|
|
||||||
200,
|
|
||||||
201,
|
|
||||||
202,
|
|
||||||
203,
|
|
||||||
204,
|
|
||||||
205,
|
|
||||||
206,
|
|
||||||
207,
|
|
||||||
208,
|
|
||||||
226,
|
|
||||||
300,
|
|
||||||
301,
|
|
||||||
302,
|
|
||||||
303,
|
|
||||||
303,
|
|
||||||
304,
|
|
||||||
305,
|
|
||||||
306,
|
|
||||||
307,
|
|
||||||
308,
|
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
|
@ -88,6 +71,11 @@ 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({});
|
||||||
|
@ -113,7 +101,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/${name.underscore()}/authorize`)
|
ajax(`/admin/wizards/apis/${underscore(name)}/authorize`)
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
@ -149,7 +137,6 @@ 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) {
|
||||||
|
@ -164,11 +151,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -188,11 +170,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.${key.underscore()}`
|
`admin.wizard.api.auth.${underscore(key)}`
|
||||||
)} is required for ${authType}`;
|
)} is required for ${authType}`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data[rp.underscore()] = api[rp];
|
data[underscore(rp)] = api[rp];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +204,7 @@ export default Controller.extend({
|
||||||
|
|
||||||
this.set("updating", true);
|
this.set("updating", true);
|
||||||
|
|
||||||
ajax(`/admin/wizards/api/${name.underscore()}`, {
|
ajax(`/admin/wizards/api/${underscore(name)}`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
@ -245,7 +227,7 @@ export default Controller.extend({
|
||||||
|
|
||||||
this.set("updating", true);
|
this.set("updating", true);
|
||||||
|
|
||||||
ajax(`/admin/wizards/api/${name.underscore()}`, {
|
ajax(`/admin/wizards/api/${underscore(name)}`, {
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
|
@ -263,13 +245,13 @@ export default Controller.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ajax(`/admin/wizards/api/${name.underscore()}/logs`, {
|
ajax(`/admin/wizards/api/${underscore(name)}/logs`, {
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.transitionToRoute("adminWizardsApis").then(() => {
|
this.router.transitionTo("adminWizardsApis").then(() => {
|
||||||
this.send("refreshModel");
|
this.send("refreshModel");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ 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://thepavilion.io/t/3572",
|
documentationUrl:
|
||||||
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/custom-fields",
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
addField() {
|
addField() {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import { notEmpty } from "@ember/object/computed";
|
||||||
|
import CustomWizardLogs from "../models/custom-wizard-logs";
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
refreshing: false,
|
||||||
|
hasLogs: notEmpty("logs"),
|
||||||
|
page: 0,
|
||||||
|
canLoadMore: true,
|
||||||
|
logs: [],
|
||||||
|
messageKey: "viewing",
|
||||||
|
|
||||||
|
loadLogs() {
|
||||||
|
if (!this.canLoadMore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const page = this.get("page");
|
||||||
|
const wizardId = this.get("wizard.id");
|
||||||
|
|
||||||
|
this.set("refreshing", true);
|
||||||
|
|
||||||
|
CustomWizardLogs.list(wizardId, page)
|
||||||
|
.then((result) => {
|
||||||
|
this.set("logs", this.logs.concat(result.logs));
|
||||||
|
})
|
||||||
|
.finally(() => this.set("refreshing", false));
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("hasLogs", "refreshing")
|
||||||
|
noResults(hasLogs, refreshing) {
|
||||||
|
return !hasLogs && !refreshing;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
loadMore() {
|
||||||
|
if (!this.loadingMore && this.logs.length < this.total) {
|
||||||
|
this.set("page", (this.page += 1));
|
||||||
|
this.loadLogs();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.setProperties({
|
||||||
|
canLoadMore: true,
|
||||||
|
page: 0,
|
||||||
|
logs: [],
|
||||||
|
});
|
||||||
|
this.loadLogs();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,50 +1,35 @@
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
|
||||||
import { notEmpty } from "@ember/object/computed";
|
|
||||||
import CustomWizardLogs from "../models/custom-wizard-logs";
|
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
refreshing: false,
|
documentationUrl:
|
||||||
hasLogs: notEmpty("logs"),
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/",
|
||||||
page: 0,
|
|
||||||
canLoadMore: true,
|
|
||||||
logs: [],
|
|
||||||
|
|
||||||
loadLogs() {
|
@discourseComputed("wizardId")
|
||||||
if (!this.canLoadMore) {
|
wizardName(wizardId) {
|
||||||
return;
|
let currentWizard = this.wizardList.find(
|
||||||
|
(wizard) => wizard.id === wizardId
|
||||||
|
);
|
||||||
|
if (currentWizard) {
|
||||||
|
return currentWizard.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("wizardName")
|
||||||
|
messageOpts(wizardName) {
|
||||||
|
return {
|
||||||
|
wizardName,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("wizardId")
|
||||||
|
messageKey(wizardId) {
|
||||||
|
let key = "select";
|
||||||
|
|
||||||
|
if (wizardId) {
|
||||||
|
key = "viewing";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set("refreshing", true);
|
return key;
|
||||||
|
|
||||||
CustomWizardLogs.list()
|
|
||||||
.then((result) => {
|
|
||||||
if (!result || result.length === 0) {
|
|
||||||
this.set("canLoadMore", false);
|
|
||||||
}
|
|
||||||
this.set("logs", this.logs.concat(result));
|
|
||||||
})
|
|
||||||
.finally(() => this.set("refreshing", false));
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("hasLogs", "refreshing")
|
|
||||||
noResults(hasLogs, refreshing) {
|
|
||||||
return !hasLogs && !refreshing;
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
loadMore() {
|
|
||||||
this.set("page", (this.page += 1));
|
|
||||||
this.loadLogs();
|
|
||||||
},
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this.setProperties({
|
|
||||||
canLoadMore: true,
|
|
||||||
page: 0,
|
|
||||||
logs: [],
|
|
||||||
});
|
|
||||||
this.loadLogs();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,8 @@ import I18n from "I18n";
|
||||||
import { underscore } from "@ember/string";
|
import { underscore } from "@ember/string";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
messageUrl: "https://thepavilion.io/t/3652",
|
messageUrl:
|
||||||
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/wizard-manager",
|
||||||
messageKey: "info",
|
messageKey: "info",
|
||||||
messageIcon: "info-circle",
|
messageIcon: "info-circle",
|
||||||
messageClass: "info",
|
messageClass: "info",
|
||||||
|
@ -68,7 +69,7 @@ export default Controller.extend({
|
||||||
file: null,
|
file: null,
|
||||||
filename: null,
|
filename: null,
|
||||||
});
|
});
|
||||||
$("#file-upload").val("");
|
document.getElementById("custom-wizard-file-upload").value = "";
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("importing", "destroying")
|
@observes("importing", "destroying")
|
||||||
|
@ -83,7 +84,7 @@ export default Controller.extend({
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
upload() {
|
upload() {
|
||||||
$("#file-upload").click();
|
document.getElementById("custom-wizard-file-upload").click();
|
||||||
},
|
},
|
||||||
|
|
||||||
clearFile() {
|
clearFile() {
|
||||||
|
@ -102,7 +103,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);
|
||||||
$("#file-upload").val("");
|
document.getElementById("custom-wizard-file-upload").value = "";
|
||||||
} else {
|
} else {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
file,
|
file,
|
||||||
|
|
|
@ -1,6 +1,74 @@
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
import { empty } from "@ember/object/computed";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { fmt } from "discourse/lib/computed";
|
import { fmt } from "discourse/lib/computed";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import AdminWizardsColumnsModal from "../components/modal/admin-wizards-columns";
|
||||||
|
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||||
|
import { formatModel } from "../lib/wizard-submission";
|
||||||
|
|
||||||
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"),
|
||||||
|
page: 0,
|
||||||
|
total: 0,
|
||||||
|
|
||||||
|
loadMoreSubmissions() {
|
||||||
|
const page = this.get("page");
|
||||||
|
const wizardId = this.get("wizard.id");
|
||||||
|
|
||||||
|
this.set("loadingMore", true);
|
||||||
|
CustomWizardAdmin.submissions(wizardId, page)
|
||||||
|
.then((result) => {
|
||||||
|
if (result.submissions) {
|
||||||
|
const { submissions } = formatModel(result);
|
||||||
|
|
||||||
|
this.get("submissions").pushObjects(submissions);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.set("loadingMore", false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("submissions.[]", "fields.@each.enabled")
|
||||||
|
displaySubmissions(submissions, fields) {
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
submissions.forEach((submission) => {
|
||||||
|
let sub = {};
|
||||||
|
|
||||||
|
Object.keys(submission).forEach((fieldId) => {
|
||||||
|
if (fields.some((f) => f.id === fieldId && f.enabled)) {
|
||||||
|
sub[fieldId] = submission[fieldId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result.push(sub);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
loadMore() {
|
||||||
|
if (!this.loadingMore && this.submissions.length < this.total) {
|
||||||
|
this.set("page", this.get("page") + 1);
|
||||||
|
this.loadMoreSubmissions();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showEditColumnsModal() {
|
||||||
|
return this.modal.show(AdminWizardsColumnsModal, {
|
||||||
|
model: {
|
||||||
|
columns: this.get("fields"),
|
||||||
|
reset: () => {
|
||||||
|
this.get("fields").forEach((field) => {
|
||||||
|
field.set("enabled", true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
documentationUrl:
|
||||||
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/",
|
||||||
|
|
||||||
|
@discourseComputed("wizardId")
|
||||||
|
wizardName(wizardId) {
|
||||||
|
let currentWizard = this.wizardList.find(
|
||||||
|
(wizard) => wizard.id === wizardId
|
||||||
|
);
|
||||||
|
if (currentWizard) {
|
||||||
|
return currentWizard.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("wizardName")
|
||||||
|
messageOpts(wizardName) {
|
||||||
|
return {
|
||||||
|
wizardName,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("wizardId")
|
||||||
|
messageKey(wizardId) {
|
||||||
|
let key = "select";
|
||||||
|
|
||||||
|
if (wizardId) {
|
||||||
|
key = "viewing";
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
},
|
||||||
|
});
|
|
@ -3,15 +3,18 @@ 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 showModal from "discourse/lib/show-modal";
|
import { inject as service } from "@ember/service";
|
||||||
|
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")
|
||||||
|
@ -36,7 +39,8 @@ export default Controller.extend({
|
||||||
|
|
||||||
@discourseComputed("wizard.id")
|
@discourseComputed("wizard.id")
|
||||||
wizardUrl(wizardId) {
|
wizardUrl(wizardId) {
|
||||||
return window.location.origin + "/w/" + dasherize(wizardId);
|
let baseUrl = window.location.href.split("/admin");
|
||||||
|
return baseUrl[0] + "/w/" + dasherize(wizardId);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("wizard.after_time_scheduled")
|
@discourseComputed("wizard.after_time_scheduled")
|
||||||
|
@ -58,6 +62,19 @@ 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;
|
||||||
|
@ -92,7 +109,11 @@ export default Controller.extend({
|
||||||
wizard
|
wizard
|
||||||
.save(opts)
|
.save(opts)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
if (result.wizard_id) {
|
||||||
this.send("afterSave", result.wizard_id);
|
this.send("afterSave", result.wizard_id);
|
||||||
|
} else if (result.errors) {
|
||||||
|
this.set("error", result.errors.join(", "));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((result) => {
|
.catch((result) => {
|
||||||
this.set("error", this.getErrorMessage(result));
|
this.set("error", this.getErrorMessage(result));
|
||||||
|
@ -107,19 +128,13 @@ export default Controller.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setNextSessionScheduled() {
|
setNextSessionScheduled() {
|
||||||
let controller = showModal("next-session-scheduled", {
|
this.modal.show(NextSessionScheduledModal, {
|
||||||
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();
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleAdvanced() {
|
|
||||||
this.toggleProperty("wizard.showAdvanced");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
copyUrl() {
|
copyUrl() {
|
||||||
|
|
|
@ -21,5 +21,6 @@ export default Controller.extend({
|
||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
|
|
||||||
messageUrl: "https://thepavilion.io/c/knowledge/discourse/custom-wizard",
|
messageUrl:
|
||||||
|
"https://pavilion.tech/products/discourse-custom-wizard-plugin/documentation/",
|
||||||
});
|
});
|
||||||
|
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden …
In neuem Issue referenzieren