├── .editorconfig
├── .gitattributes
├── .gitignore
├── .rubocop.yml
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.md
├── Rakefile
├── _assets
├── defining_form.png
├── dummy_overview.png
├── editing_transition.png
├── importing_bpmn.png
└── workflow_net.png
├── _samples
├── diagram_1.bpmn
├── diagram_2.bpmn
├── diagram_3.bpmn
└── diagram_4.bpmn
├── app
├── jobs
│ └── workflow_core
│ │ └── application_job.rb
└── models
│ └── workflow_core
│ ├── application_record.rb
│ ├── place.rb
│ ├── token.rb
│ ├── transition.rb
│ ├── workflow.rb
│ └── workflow_instance.rb
├── bin
└── rails
├── db
└── migrate
│ ├── 20180910195950_create_workflows.rb
│ ├── 20180910200203_create_workflow_transitions.rb
│ ├── 20180910200454_create_workflow_places.rb
│ ├── 20180912223642_create_workflow_instances.rb
│ ├── 20180912223722_create_workflow_tokens.rb
│ └── 20191004190723_add_start_place_id_to_workflows.rb
├── lib
├── tasks
│ └── workflow_core_tasks.rake
├── workflow_core.rb
└── workflow_core
│ ├── concerns
│ └── models
│ │ ├── place.rb
│ │ ├── token.rb
│ │ ├── transition.rb
│ │ ├── workflow.rb
│ │ └── workflow_instance.rb
│ ├── engine.rb
│ └── version.rb
├── test
├── dummy
│ ├── Rakefile
│ ├── app
│ │ ├── assets
│ │ │ ├── config
│ │ │ │ └── manifest.js
│ │ │ ├── images
│ │ │ │ └── .keep
│ │ │ ├── javascripts
│ │ │ │ └── application.es6
│ │ │ └── stylesheets
│ │ │ │ └── application.scss
│ │ ├── controllers
│ │ │ ├── application_controller.rb
│ │ │ ├── concerns
│ │ │ │ └── .keep
│ │ │ ├── groups_controller.rb
│ │ │ ├── sessions_controller.rb
│ │ │ ├── users_controller.rb
│ │ │ ├── workflows
│ │ │ │ ├── application_controller.rb
│ │ │ │ ├── fields
│ │ │ │ │ ├── application_controller.rb
│ │ │ │ │ ├── options_controller.rb
│ │ │ │ │ └── validations_controller.rb
│ │ │ │ ├── fields_controller.rb
│ │ │ │ ├── instances
│ │ │ │ │ ├── application_controller.rb
│ │ │ │ │ └── tokens_controller.rb
│ │ │ │ ├── instances_controller.rb
│ │ │ │ ├── loads_controller.rb
│ │ │ │ ├── nested_forms
│ │ │ │ │ ├── application_controller.rb
│ │ │ │ │ └── fields_controller.rb
│ │ │ │ ├── transitions
│ │ │ │ │ ├── application_controller.rb
│ │ │ │ │ └── options_controller.rb
│ │ │ │ └── transitions_controller.rb
│ │ │ └── workflows_controller.rb
│ │ ├── decorators
│ │ │ └── .keep
│ │ ├── helpers
│ │ │ ├── application_helper.rb
│ │ │ ├── fields_helper.rb
│ │ │ └── transitions_helper.rb
│ │ ├── jobs
│ │ │ └── application_job.rb
│ │ ├── lib
│ │ │ ├── .keep
│ │ │ ├── bpmn
│ │ │ │ ├── definition_container.rb
│ │ │ │ ├── tokenizer.rb
│ │ │ │ └── tokens
│ │ │ │ │ ├── common_token.rb
│ │ │ │ │ ├── end_event.rb
│ │ │ │ │ ├── exclusive_gateway.rb
│ │ │ │ │ ├── extensions
│ │ │ │ │ └── condition_expression.rb
│ │ │ │ │ ├── inclusive_gateway.rb
│ │ │ │ │ ├── parallel_gateway.rb
│ │ │ │ │ ├── script_task.rb
│ │ │ │ │ ├── sequence_flow.rb
│ │ │ │ │ ├── start_event.rb
│ │ │ │ │ ├── task.rb
│ │ │ │ │ ├── token.rb
│ │ │ │ │ └── user_task.rb
│ │ │ └── script_engine.rb
│ │ ├── mailers
│ │ │ └── application_mailer.rb
│ │ ├── models
│ │ │ ├── application_record.rb
│ │ │ ├── concerns
│ │ │ │ ├── .keep
│ │ │ │ ├── acts_as_default_value.rb
│ │ │ │ ├── enum_attribute_localizable.rb
│ │ │ │ ├── fields
│ │ │ │ │ └── validations
│ │ │ │ │ │ ├── acceptance.rb
│ │ │ │ │ │ ├── confirmation.rb
│ │ │ │ │ │ ├── exclusion.rb
│ │ │ │ │ │ ├── format.rb
│ │ │ │ │ │ ├── inclusion.rb
│ │ │ │ │ │ ├── length.rb
│ │ │ │ │ │ ├── numericality.rb
│ │ │ │ │ │ └── presence.rb
│ │ │ │ ├── form_core
│ │ │ │ │ └── acts_as_default_value.rb
│ │ │ │ └── transitions
│ │ │ │ │ └── options
│ │ │ │ │ ├── assignable.rb
│ │ │ │ │ ├── field_overridable.rb
│ │ │ │ │ └── votable.rb
│ │ │ ├── field.rb
│ │ │ ├── field_options.rb
│ │ │ ├── fields.rb
│ │ │ ├── fields
│ │ │ │ ├── boolean_field.rb
│ │ │ │ ├── decimal_field.rb
│ │ │ │ ├── integer_field.rb
│ │ │ │ ├── multiple_nested_form_field.rb
│ │ │ │ ├── nested_form_field.rb
│ │ │ │ ├── options
│ │ │ │ │ ├── decimal_field.rb
│ │ │ │ │ ├── integer_field.rb
│ │ │ │ │ └── text_field.rb
│ │ │ │ ├── text_field.rb
│ │ │ │ └── validations
│ │ │ │ │ ├── boolean_field.rb
│ │ │ │ │ ├── decimal_field.rb
│ │ │ │ │ ├── integer_field.rb
│ │ │ │ │ ├── multiple_nested_form_field.rb
│ │ │ │ │ ├── nested_form_field.rb
│ │ │ │ │ └── text_field.rb
│ │ │ ├── form.rb
│ │ │ ├── group.rb
│ │ │ ├── metal_form.rb
│ │ │ ├── nested_form.rb
│ │ │ ├── non_configurable.rb
│ │ │ ├── place.rb
│ │ │ ├── places.rb
│ │ │ ├── places
│ │ │ │ ├── end_place.rb
│ │ │ │ └── start_place.rb
│ │ │ ├── token.rb
│ │ │ ├── token
│ │ │ │ └── payload.rb
│ │ │ ├── transition.rb
│ │ │ ├── transitions.rb
│ │ │ ├── transitions
│ │ │ │ ├── end.rb
│ │ │ │ ├── exclusive_choice.rb
│ │ │ │ ├── options
│ │ │ │ │ ├── assigning_assignees.rb
│ │ │ │ │ ├── decision.rb
│ │ │ │ │ ├── exclusive_choice.rb
│ │ │ │ │ └── user_task.rb
│ │ │ │ ├── parallel_split.rb
│ │ │ │ ├── sequence.rb
│ │ │ │ ├── simple_merge.rb
│ │ │ │ ├── start.rb
│ │ │ │ ├── synchronization.rb
│ │ │ │ └── variants
│ │ │ │ │ ├── assigning_assignees.rb
│ │ │ │ │ ├── decision.rb
│ │ │ │ │ └── user_task.rb
│ │ │ ├── user.rb
│ │ │ ├── virtual_model.rb
│ │ │ ├── workflow.rb
│ │ │ └── workflow_instance.rb
│ │ ├── presenters
│ │ │ ├── application_presenter.rb
│ │ │ ├── concerns
│ │ │ │ └── fields
│ │ │ │ │ └── presenter_for_number_field.rb
│ │ │ └── fields
│ │ │ │ ├── boolean_field_presenter.rb
│ │ │ │ ├── composite_field_presenter.rb
│ │ │ │ ├── decimal_field_presenter.rb
│ │ │ │ ├── field_presenter.rb
│ │ │ │ ├── integer_field_presenter.rb
│ │ │ │ ├── multiple_nested_form_field_presenter.rb
│ │ │ │ ├── nested_form_field_presenter.rb
│ │ │ │ └── text_field_presenter.rb
│ │ └── views
│ │ │ ├── _form_core
│ │ │ ├── field_options
│ │ │ │ ├── _decimal_field.html.erb
│ │ │ │ ├── _integer_field.html.erb
│ │ │ │ └── _text_field.html.erb
│ │ │ ├── fields
│ │ │ │ ├── _boolean_field.html.erb
│ │ │ │ ├── _decimal_field.html.erb
│ │ │ │ ├── _integer_field.html.erb
│ │ │ │ ├── _multiple_nested_form_field.html.erb
│ │ │ │ ├── _nested_form.html.erb
│ │ │ │ ├── _nested_form_field.html.erb
│ │ │ │ └── _text_field.html.erb
│ │ │ ├── preview
│ │ │ │ ├── _form.html.erb
│ │ │ │ └── _nested_form.html.erb
│ │ │ ├── render
│ │ │ │ └── _form.html.erb
│ │ │ └── validations
│ │ │ │ ├── _acceptance.html.erb
│ │ │ │ ├── _confirmation.html.erb
│ │ │ │ ├── _exclusion.html.erb
│ │ │ │ ├── _format.html.erb
│ │ │ │ ├── _inclusion.html.erb
│ │ │ │ ├── _length.html.erb
│ │ │ │ ├── _numericality.html.erb
│ │ │ │ └── _presence.html.erb
│ │ │ ├── _workflow_core
│ │ │ └── transition_options
│ │ │ │ ├── _action.html.erb
│ │ │ │ ├── _assignable.html.erb
│ │ │ │ ├── _assigning_assignees.html.erb
│ │ │ │ ├── _condition.html.erb
│ │ │ │ ├── _decision.html.erb
│ │ │ │ ├── _exclusive_choice.html.erb
│ │ │ │ ├── _field_overridable.html.erb
│ │ │ │ └── _user_task.html.erb
│ │ │ ├── groups
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ └── new.html.erb
│ │ │ ├── layouts
│ │ │ ├── _alert.html.erb
│ │ │ ├── _footer.html.erb
│ │ │ ├── _nav.html.erb
│ │ │ ├── _notice.html.erb
│ │ │ ├── application.html.erb
│ │ │ ├── workflow_instances.html.erb
│ │ │ └── workflows.html.erb
│ │ │ ├── users
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ └── new.html.erb
│ │ │ └── workflows
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── fields
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── new.html.erb
│ │ │ ├── options
│ │ │ │ ├── _form.html.erb
│ │ │ │ └── edit.html.erb
│ │ │ └── validations
│ │ │ │ ├── _form.html.erb
│ │ │ │ └── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── instances
│ │ │ ├── index.html.erb
│ │ │ ├── new.html.erb
│ │ │ ├── show.html.erb
│ │ │ └── tokens
│ │ │ │ ├── index.html.erb
│ │ │ │ └── show.html.erb
│ │ │ ├── loads
│ │ │ └── show.html.erb
│ │ │ ├── nested_forms
│ │ │ └── fields
│ │ │ │ ├── _form.html.erb
│ │ │ │ ├── edit.html.erb
│ │ │ │ ├── index.html.erb
│ │ │ │ └── new.html.erb
│ │ │ ├── new.html.erb
│ │ │ ├── show.html.erb
│ │ │ └── transitions
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── new.html.erb
│ │ │ └── options
│ │ │ ├── _form.html.erb
│ │ │ └── edit.html.erb
│ ├── bin
│ │ ├── bundle
│ │ ├── rails
│ │ ├── rake
│ │ ├── setup
│ │ ├── update
│ │ └── yarn
│ ├── config.ru
│ ├── config
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── cable.yml
│ │ ├── database.yml
│ │ ├── environment.rb
│ │ ├── environments
│ │ │ ├── development.rb
│ │ │ ├── production.rb
│ │ │ └── test.rb
│ │ ├── initializers
│ │ │ ├── application_controller_renderer.rb
│ │ │ ├── assets.rb
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── content_security_policy.rb
│ │ │ ├── cookies_serializer.rb
│ │ │ ├── filter_parameter_logging.rb
│ │ │ ├── form_core.rb
│ │ │ ├── inflections.rb
│ │ │ ├── mime_types.rb
│ │ │ └── wrap_parameters.rb
│ │ ├── locales
│ │ │ └── en.yml
│ │ ├── puma.rb
│ │ ├── routes.rb
│ │ ├── spring.rb
│ │ └── storage.yml
│ ├── db
│ │ ├── migrate
│ │ │ ├── 20180916202025_create_forms.form_core.rb
│ │ │ ├── 20180916202026_create_fields.form_core.rb
│ │ │ ├── 20180916202027_add_attachable_to_forms.rb
│ │ │ ├── 20180916202121_add_columns_to_fields.rb
│ │ │ ├── 20180916202124_add_position_to_fields.rb
│ │ │ ├── 20180916215022_add_columns_to_workflows.rb
│ │ │ ├── 20180917182517_create_groups.rb
│ │ │ ├── 20180917184018_create_users.rb
│ │ │ ├── 20180918202819_add_columns_to_transitions.rb
│ │ │ ├── 20180918202827_add_columns_to_places.rb
│ │ │ ├── 20180922095451_add_columns_to_workflow_instances.rb
│ │ │ └── 20180922095933_add_columns_to_workflow_tokens.rb
│ │ ├── schema.rb
│ │ └── seeds.rb
│ ├── lib
│ │ ├── assets
│ │ │ └── .keep
│ │ └── monkey_patches
│ │ │ ├── active_support.rb
│ │ │ ├── active_support
│ │ │ └── concern+prependable.rb
│ │ │ └── big_decimal.rb
│ ├── log
│ │ └── .keep
│ ├── mruby
│ │ ├── engine.gembox
│ │ └── lib
│ │ │ ├── .keep
│ │ │ ├── core_ext.rb
│ │ │ ├── harden.rb
│ │ │ ├── input.rb
│ │ │ ├── io.rb
│ │ │ ├── output.rb
│ │ │ └── script_kernel.rb
│ ├── package.json
│ ├── public
│ │ ├── 404.html
│ │ ├── 422.html
│ │ ├── 500.html
│ │ ├── apple-touch-icon-precomposed.png
│ │ ├── apple-touch-icon.png
│ │ └── favicon.ico
│ └── storage
│ │ └── .keep
├── fixtures
│ └── workflow_core
│ │ └── .keep
├── integration
│ └── .keep
├── models
│ └── workflow_core
│ │ └── .keep
├── test_helper.rb
└── workflow_core_test.rb
└── workflow_core.gemspec
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | indent_style = space
11 | indent_size = 2
12 | end_of_line = lf
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.rb diff=ruby
2 | *.gemspec diff=ruby
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | .bundle/
9 |
10 | # Ignore the default SQLite database.
11 | test/dummy/db/*.sqlite3
12 | test/dummy/db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | log/*.log
16 | !test/dummy/log/.keep
17 | !test/dummy/tmp/.keep
18 | test/dummy/log/*.log
19 | test/dummy/tmp/
20 |
21 | # Ignore uploaded files in development
22 | test/dummy/storage/*
23 | !test/dummy/storage/.keep
24 |
25 | # Ignore compiled mruby in dummy app
26 | /test/dummy/mruby/bin
27 |
28 | pkg/
29 | .byebug_history
30 |
31 | node_modules/
32 | test/dummy/public/packs
33 | test/dummy/node_modules/
34 | yarn-error.log
35 |
36 | *.gem
37 |
38 | .generators
39 | .rakeTasks
40 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.7.0
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5 |
6 | # Declare your gem's dependencies in workflow_core.gemspec.
7 | # Bundler will treat runtime dependencies like base dependencies, and
8 | # development dependencies will be added by default to the :development group.
9 | gemspec
10 |
11 | # Declare any dependencies that are still in development here instead of in
12 | # your gemspec. These might include edge Rails or gems from your path or
13 | # Git. Remember to move these dependencies to your gemspec before releasing
14 | # your gem to rubygems.org.
15 |
16 | # To use a debugger
17 | # gem 'byebug', group: [:development, :test]
18 |
19 | gem "rails", "~> 6.0.0"
20 | gem "sqlite3", "~> 1.4"
21 |
22 | # Use Puma as the app server
23 | gem "puma"
24 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
25 | gem "listen", ">= 3.0.5", "< 3.2"
26 | gem "web-console", group: :development
27 | # Call "byebug" anywhere in the code to stop execution and get a debugger console
28 | gem "byebug", group: %i[development test]
29 |
30 | # To support ES6
31 | gem "sprockets", "~> 4.0.0"
32 | # Support ES6
33 | gem "babel-transpiler"
34 | # Use SCSS for stylesheets
35 | gem "sassc-rails"
36 | # Use Uglifier as compressor for JavaScript assets
37 | gem "uglifier", ">= 1.3.0"
38 |
39 | gem "bulma-rails"
40 | gem "jquery-rails"
41 | gem "selectize-rails"
42 | gem "turbolinks"
43 |
44 | gem "rubocop"
45 | gem "rubocop-performance"
46 | gem "rubocop-rails"
47 |
48 | gem "activeentity"
49 | gem "cocoon"
50 | gem "form_core"
51 | gem "globalid"
52 | gem "script_core"
53 |
54 | gem "graphviz"
55 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Jun Jiang
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | begin
4 | require "bundler/setup"
5 | rescue LoadError
6 | puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7 | end
8 |
9 | require "rdoc/task"
10 |
11 | RDoc::Task.new(:rdoc) do |rdoc|
12 | rdoc.rdoc_dir = "rdoc"
13 | rdoc.title = "WorkflowCore"
14 | rdoc.options << "--line-numbers"
15 | rdoc.rdoc_files.include("README.md")
16 | rdoc.rdoc_files.include("lib/**/*.rb")
17 | end
18 |
19 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20 | load "rails/tasks/engine.rake"
21 |
22 | load "rails/tasks/statistics.rake"
23 |
24 | require "bundler/gem_tasks"
25 |
26 | require "rake/testtask"
27 |
28 | Rake::TestTask.new(:test) do |t|
29 | t.libs << "test"
30 | t.pattern = "test/**/*_test.rb"
31 | t.verbose = false
32 | end
33 |
34 | task default: :test
35 |
--------------------------------------------------------------------------------
/_assets/defining_form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/_assets/defining_form.png
--------------------------------------------------------------------------------
/_assets/dummy_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/_assets/dummy_overview.png
--------------------------------------------------------------------------------
/_assets/editing_transition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/_assets/editing_transition.png
--------------------------------------------------------------------------------
/_assets/importing_bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/_assets/importing_bpmn.png
--------------------------------------------------------------------------------
/_assets/workflow_net.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/_assets/workflow_net.png
--------------------------------------------------------------------------------
/app/jobs/workflow_core/application_job.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class ApplicationJob < ActiveJob::Base
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/app/models/workflow_core/application_record.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class ApplicationRecord < ActiveRecord::Base
5 | self.abstract_class = true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/workflow_core/place.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class Place < ApplicationRecord
5 | include WorkflowCore::Concerns::Models::Place
6 |
7 | self.table_name = "workflow_places"
8 |
9 | belongs_to :workflow
10 |
11 | belongs_to :input_transition, optional: true, foreign_key: "input_transition_id",
12 | class_name: "WorkflowCore::Transition"
13 | belongs_to :output_transition, optional: true, foreign_key: "output_transition_id",
14 | class_name: "WorkflowCore::Transition"
15 |
16 | has_many :tokens
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/models/workflow_core/token.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class Token < ApplicationRecord
5 | include WorkflowCore::Concerns::Models::Token
6 |
7 | self.table_name = "workflow_tokens"
8 |
9 | belongs_to :instance,
10 | class_name: "WorkflowCore::WorkflowInstance"
11 | belongs_to :workflow
12 |
13 | belongs_to :place
14 | belongs_to :previous, optional: true,
15 | class_name: "WorkflowCore::Token"
16 |
17 | enum status: {
18 | processing: 0,
19 | completed: 1,
20 | failed: 2,
21 | unexpected: 3,
22 | terminated: 4
23 | }
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/workflow_core/transition.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class Transition < ApplicationRecord
5 | include WorkflowCore::Concerns::Models::Transition
6 |
7 | self.table_name = "workflow_transitions"
8 |
9 | belongs_to :workflow
10 |
11 | has_many :input_places,
12 | dependent: :nullify,
13 | foreign_key: "output_transition_id",
14 | class_name: "WorkflowCore::Place",
15 | inverse_of: :output_transition
16 | has_many :output_places,
17 | dependent: :destroy,
18 | foreign_key: "input_transition_id",
19 | class_name: "WorkflowCore::Place",
20 | inverse_of: :input_transition
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/models/workflow_core/workflow.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class Workflow < ApplicationRecord
5 | include WorkflowCore::Concerns::Models::Workflow
6 |
7 | self.table_name = "workflows"
8 |
9 | belongs_to :start_place, class_name: "WorkflowCore::Place", dependent: :destroy, optional: true
10 |
11 | has_many :transitions, class_name: "WorkflowCore::Transition", dependent: :destroy
12 | has_many :places, class_name: "WorkflowCore::Place", dependent: :destroy
13 |
14 | has_many :instances, class_name: "WorkflowCore::WorkflowInstance", dependent: :destroy
15 | has_many :tokens, class_name: "WorkflowCore::Token", dependent: :destroy
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/models/workflow_core/workflow_instance.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class WorkflowInstance < ApplicationRecord
5 | include WorkflowCore::Concerns::Models::WorkflowInstance
6 |
7 | self.table_name = "workflow_instances"
8 |
9 | belongs_to :workflow
10 | has_many :tokens, foreign_key: "instance_id", dependent: :destroy
11 |
12 | enum status: {
13 | processing: 0,
14 | completed: 1,
15 | failed: 2,
16 | unexpected: 3,
17 | terminated: 4,
18 | draft: 10
19 | }
20 |
21 | serialize :payload
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | # This command will automatically be run when you run "rails" with Rails gems
5 | # installed from the root of your application.
6 |
7 | ENGINE_ROOT = File.expand_path("..", __dir__)
8 | ENGINE_PATH = File.expand_path("../lib/workflow_core/engine", __dir__)
9 | APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
10 |
11 | # Set up gems listed in the Gemfile.
12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
13 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
14 |
15 | require "rails/all"
16 | require "rails/engine/commands"
17 |
--------------------------------------------------------------------------------
/db/migrate/20180910195950_create_workflows.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateWorkflows < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :workflows do |t|
6 | t.string :type, null: false
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20180910200203_create_workflow_transitions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateWorkflowTransitions < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :workflow_transitions do |t|
6 | t.string :type, null: false
7 | t.references :workflow, foreign_key: true
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20180910200454_create_workflow_places.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateWorkflowPlaces < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :workflow_places do |t|
6 | t.references :input_transition, foreign_key: { to_table: "workflow_transitions" }
7 | t.references :output_transition, foreign_key: { to_table: "workflow_transitions" }
8 |
9 | t.string :type, null: false
10 | t.references :workflow, foreign_key: true
11 | t.timestamps
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20180912223642_create_workflow_instances.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateWorkflowInstances < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :workflow_instances do |t|
6 | t.text :payload
7 | t.integer :status, null: false, default: 0
8 |
9 | t.references :workflow, foreign_key: true
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20180912223722_create_workflow_tokens.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateWorkflowTokens < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :workflow_tokens do |t|
6 | t.integer :status, null: false, default: 0
7 |
8 | t.references :place, foreign_key: { to_table: "workflow_places" }
9 | t.references :previous, foreign_key: { to_table: "workflow_tokens" }
10 |
11 | t.references :instance, foreign_key: { to_table: "workflow_instances" }
12 | t.references :workflow, foreign_key: true
13 | t.timestamps
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/db/migrate/20191004190723_add_start_place_id_to_workflows.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddStartPlaceIdToWorkflows < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflows do |t|
6 | t.references :start_place, foreign_key: { to_table: "workflow_places" }
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/tasks/workflow_core_tasks.rake:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # desc "Explaining what the task does"
4 | # task :workflow_core do
5 | # # Task goes here
6 | # end
7 |
--------------------------------------------------------------------------------
/lib/workflow_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "workflow_core/engine"
4 |
5 | require "workflow_core/concerns/models/workflow"
6 | require "workflow_core/concerns/models/transition"
7 | require "workflow_core/concerns/models/place"
8 | require "workflow_core/concerns/models/workflow_instance"
9 | require "workflow_core/concerns/models/token"
10 |
11 | module WorkflowCore
12 | end
13 |
--------------------------------------------------------------------------------
/lib/workflow_core/concerns/models/place.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore::Concerns
4 | module Models
5 | module Place
6 | extend ActiveSupport::Concern
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/workflow_core/concerns/models/token.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore::Concerns
4 | module Models
5 | module Token
6 | extend ActiveSupport::Concern
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/workflow_core/concerns/models/transition.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore::Concerns
4 | module Models
5 | module Transition
6 | extend ActiveSupport::Concern
7 |
8 | def fire(token, transaction_options: { requires_new: true }, **options)
9 | transaction(**transaction_options) do
10 | on_fire(token, transaction_options, options)
11 | end
12 | rescue StandardError => e
13 | rescue_fire_error e
14 | end
15 |
16 | protected
17 |
18 | def on_fire(_token, _transaction_options, **_options)
19 | raise NotImplementedError
20 | end
21 |
22 | def rescue_fire_error(ex)
23 | raise ex
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/workflow_core/concerns/models/workflow.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore::Concerns
4 | module Models
5 | module Workflow
6 | extend ActiveSupport::Concern
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/workflow_core/concerns/models/workflow_instance.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore::Concerns
4 | module Models
5 | module WorkflowInstance
6 | extend ActiveSupport::Concern
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/workflow_core/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | class Engine < ::Rails::Engine
5 | isolate_namespace WorkflowCore
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/workflow_core/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module WorkflowCore
4 | VERSION = "0.0.3"
5 | end
6 |
--------------------------------------------------------------------------------
/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Add your own tasks in files placed in lib/tasks ending in .rake,
4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5 |
6 | require_relative "config/application"
7 |
8 | Rails.application.load_tasks
9 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/app/assets/images/.keep
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/application.es6:
--------------------------------------------------------------------------------
1 | //= require rails-ujs
2 | //= require turbolinks
3 | //= require jquery3
4 |
5 | //= require selectize
6 | //= require cocoon
7 |
8 | // Cheat form https://github.com/jgthms/bulma/blob/master/docs/_javascript/main.js
9 | document.addEventListener('DOMContentLoaded', () => {
10 |
11 | // Dropdowns
12 |
13 | const $dropdowns = getAll('.dropdown:not(.is-hoverable)');
14 |
15 | if ($dropdowns.length > 0) {
16 | $dropdowns.forEach($el => {
17 | $el.addEventListener('click', event => {
18 | event.stopPropagation();
19 | $el.classList.toggle('is-active');
20 | });
21 | });
22 |
23 | document.addEventListener('click', event => {
24 | closeDropdowns();
25 | });
26 | }
27 |
28 | function closeDropdowns() {
29 | $dropdowns.forEach($el => {
30 | $el.classList.remove('is-active');
31 | });
32 | }
33 |
34 | // Functions
35 |
36 | function getAll(selector) {
37 | return Array.prototype.slice.call(document.querySelectorAll(selector), 0);
38 | }
39 |
40 | // Utils
41 |
42 | function removeFromArray(array, value) {
43 | if (array.includes(value)) {
44 | const value_index = array.indexOf(value);
45 | array.splice(value_index, 1);
46 | }
47 |
48 | return array;
49 | }
50 |
51 | Array.prototype.diff = function (a) {
52 | return this.filter(function (i) {
53 | return a.indexOf(i) < 0;
54 | });
55 | };
56 | });
57 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
1 | @import "selectize";
2 | @import "bulma";
3 |
4 | body {
5 | display: flex;
6 | min-height: 100vh;
7 | flex-direction: column;
8 |
9 | & nav.nav {
10 | a.brand {
11 | padding: 0.5rem 0.75em 0.5em 0;
12 | }
13 | }
14 |
15 | & .main {
16 | flex: 1;
17 | }
18 |
19 | & footer.footer {
20 | padding: 3rem 1.5rem 3rem;
21 | }
22 | }
23 |
24 | .flash {
25 | overflow: hidden;
26 | top: 0;
27 | left: 0;
28 | right: 0;
29 | line-height: 2.5;
30 | background: $info;
31 | color: $text-invert;
32 | text-align: center;
33 | }
34 |
35 | #alert {
36 | background: $danger;
37 | }
38 |
39 | .nested_form_field {
40 | .collection {
41 | .nested_form {
42 | border: 1px solid $green;
43 | padding: 0.5em;
44 | margin-left: 0.75em;
45 | margin-bottom: 0.75rem;
46 | }
47 | }
48 | }
49 |
50 | .content {
51 | .nested-content {
52 | margin-left: 0.75em;
53 | margin-bottom: 1em;
54 | }
55 | }
56 |
57 | .message-body.content {
58 | > :first-child {
59 | margin-top: 0;
60 | }
61 | }
62 |
63 | .field {
64 | flex: 1;
65 | }
66 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationController < ActionController::Base
4 | helper_method :current_user
5 |
6 | private
7 |
8 | def current_user
9 | if session[:current_user_id].present?
10 | @_current_user ||=
11 | User.where(id: session[:current_user_id]).first
12 | end
13 | end
14 |
15 | def require_signed_in
16 | redirect_to users_url unless current_user
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/controllers/groups_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class GroupsController < ApplicationController
4 | before_action :set_group, only: %i[show edit update destroy]
5 |
6 | # GET /groups
7 | def index
8 | # https://ruby-china.org/topics/32802
9 | @groups = Group.includes(:parent)
10 | end
11 |
12 | # GET /groups/new
13 | def new
14 | @group = Group.new
15 | end
16 |
17 | # GET /groups/1/edit
18 | def edit; end
19 |
20 | # POST /groups
21 | def create
22 | @group = Group.new(group_params)
23 |
24 | if @group.save
25 | redirect_to groups_url, notice: "Group was successfully created."
26 | else
27 | render :new
28 | end
29 | end
30 |
31 | # PATCH/PUT /groups/1
32 | def update
33 | if @group.update(group_params)
34 | redirect_to groups_url, notice: "Group was successfully updated."
35 | else
36 | render :edit
37 | end
38 | end
39 |
40 | # DELETE /groups/1
41 | def destroy
42 | @group.destroy
43 | redirect_to groups_url, notice: "Group was successfully destroyed."
44 | end
45 |
46 | private
47 |
48 | # Use callbacks to share common setup or constraints between actions.
49 | def set_group
50 | @group = Group.find(params[:id])
51 | end
52 |
53 | # Only allow a trusted parameter "white list" through.
54 | def group_params
55 | params.require(:group).permit(:name, :parent_id)
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class SessionsController < ApplicationController
4 | def create
5 | session[:current_user_id] = params[:user_id]
6 | redirect_back fallback_location: root_url
7 | end
8 |
9 | def destroy
10 | session[:current_user_id] = nil
11 | redirect_to root_url
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class UsersController < ApplicationController
4 | before_action :set_user, only: %i[show edit update destroy]
5 |
6 | # GET /users
7 | def index
8 | @users = User.all.includes(:group)
9 | end
10 |
11 | # GET /users/new
12 | def new
13 | @user = User.new
14 | end
15 |
16 | # GET /users/1/edit
17 | def edit; end
18 |
19 | # POST /users
20 | def create
21 | @user = User.new(user_params)
22 |
23 | if @user.save
24 | redirect_to users_url, notice: "User was successfully created."
25 | else
26 | render :new
27 | end
28 | end
29 |
30 | # PATCH/PUT /users/1
31 | def update
32 | if @user.update(user_params)
33 | redirect_to users_url, notice: "User was successfully updated."
34 | else
35 | render :edit
36 | end
37 | end
38 |
39 | # DELETE /users/1
40 | def destroy
41 | @user.destroy
42 | redirect_to users_url, notice: "User was successfully destroyed."
43 | end
44 |
45 | private
46 |
47 | # Use callbacks to share common setup or constraints between actions.
48 | def set_user
49 | @user = User.find(params[:id])
50 | end
51 |
52 | # Only allow a trusted parameter "white list" through.
53 | def user_params
54 | params.require(:user).permit(:name, :group_id)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Workflows::ApplicationController < ApplicationController
4 | layout "workflows"
5 |
6 | before_action :set_workflow
7 |
8 | protected
9 |
10 | # Use callbacks to share common setup or constraints between actions.
11 | def set_workflow
12 | @workflow = Workflow.find(params[:workflow_id])
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/fields/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Fields::ApplicationController < ApplicationController
5 | before_action :set_field
6 |
7 | protected
8 |
9 | # Use callbacks to share common setup or constraints between actions.
10 | def set_field
11 | @field = @workflow.fields.find(params[:field_id])
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/fields/options_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Fields::OptionsController < Fields::ApplicationController
5 | before_action :set_options
6 |
7 | def edit; end
8 |
9 | def update
10 | @options.assign_attributes(options_params)
11 | if @options.valid? && @field.save(validate: false)
12 | redirect_to workflow_fields_url(@workflow), notice: "Field was successfully updated."
13 | else
14 | render :edit
15 | end
16 | end
17 |
18 | private
19 |
20 | def set_options
21 | @options = @field.options
22 | end
23 |
24 | def options_params
25 | params.fetch(:options, {}).permit!
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/fields/validations_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Fields::ValidationsController < Fields::ApplicationController
5 | before_action :set_validations
6 |
7 | def edit; end
8 |
9 | def update
10 | @validations.assign_attributes(validations_params)
11 | if @validations.valid? && @field.save(validate: false)
12 | redirect_to workflow_fields_url(@workflow), notice: "Field was successfully updated."
13 | else
14 | render :edit
15 | end
16 | end
17 |
18 | private
19 |
20 | def set_validations
21 | @validations = @field.validations
22 | end
23 |
24 | def validations_params
25 | params.fetch(:validations, {}).permit!
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/fields_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Workflows::FieldsController < Workflows::ApplicationController
4 | before_action :set_form
5 | before_action :set_field, only: %i[show edit update destroy]
6 |
7 | # GET /workflows/1/fields
8 | def index
9 | @fields = @form.fields.all
10 | end
11 |
12 | # GET /workflows/fields/new
13 | def new
14 | @field = @form.fields.build
15 | end
16 |
17 | # GET /workflows/1/fields/1/edit
18 | def edit; end
19 |
20 | # POST /workflows/1/fields
21 | def create
22 | @field = @form.fields.build(field_params)
23 |
24 | if @field.save!
25 | redirect_to workflow_fields_url(@workflow), notice: "Field was successfully created."
26 | else
27 | render :new
28 | end
29 | end
30 |
31 | # PATCH/PUT /workflows/1/fields/1
32 | def update
33 | if @field.update(field_params)
34 | redirect_to workflow_fields_url(@workflow), notice: "Field was successfully updated."
35 | else
36 | render :edit
37 | end
38 | end
39 |
40 | # DELETE /workflows/1/fields/1
41 | def destroy
42 | @field.destroy
43 | redirect_to workflow_fields_url(@workflow), notice: "Field was successfully destroyed."
44 | end
45 |
46 | private
47 |
48 | # Use callbacks to share common setup or constraints between actions.
49 | def set_form
50 | @form = @workflow.form
51 | end
52 |
53 | def set_field
54 | @field = @form.fields.find(params[:id])
55 | end
56 |
57 | # Only allow a trusted parameter "white list" through.
58 | def field_params
59 | params.fetch(:field, {}).permit(:name, :label, :hint, :type)
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/instances/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Instances::ApplicationController < ApplicationController
5 | layout "workflow_instances"
6 |
7 | before_action :require_signed_in
8 | before_action :set_instance
9 |
10 | protected
11 |
12 | # Use callbacks to share common setup or constraints between actions.
13 | def set_instance
14 | @instance = @workflow.instances.find(params[:instance_id])
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/instances/tokens_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Instances::TokensController < Instances::ApplicationController
5 | before_action :set_token, only: %i[show fire]
6 | before_action :set_form_model, only: %i[show fire]
7 |
8 | # GET /workflows/1/tokens
9 | def index
10 | @tokens = @instance.tokens.includes(place: :output_transition)
11 | end
12 |
13 | # POST /workflows/1/tokens/1/fire
14 | def show
15 | @transition_valid = @token.place.output_transition.options.valid?
16 | @form_record = @virtual_model.new(@instance.payload)
17 | end
18 |
19 | # POST /workflows/1/tokens/1/fire
20 | def fire
21 | form_params = form_record_params
22 | @token.payload.note = form_params[:_note]
23 | @token.payload.action = form_params[:_action]
24 |
25 | @form_record = @virtual_model.new(@instance.payload)
26 | @form_record.assign_attributes(form_params.except(:_note, :_action))
27 | @transition_valid = @token.place.output_transition.options.valid?
28 |
29 | if @form_record.valid? && @transition_valid
30 | @instance.update! payload: (@instance.payload || {}).merge(@form_record.serializable_hash)
31 | @token.place.output_transition.fire(@token)
32 |
33 | redirect_to workflow_instance_tokens_url(@workflow, @instance), notice: "Token was successfully fired."
34 | else
35 | render :show
36 | end
37 | end
38 |
39 | private
40 |
41 | # Use callbacks to share common setup or constraints between actions.
42 | def set_token
43 | @token = @instance.tokens.find(params[:id] || params[:token_id])
44 | end
45 |
46 | def set_form_model
47 | @form = @workflow.form
48 | overrides = @token.place.output_transition.options.field_overrides.map { |o| { o.name => { accessibility: o.accessibility } } }.reduce(&:merge) || {}
49 | @virtual_model = @form.to_virtual_model overrides: overrides
50 | end
51 |
52 | def form_record_params
53 | params.fetch(:form_record, {}).permit!
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/instances_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Workflows::InstancesController < Workflows::ApplicationController
4 | before_action :require_signed_in
5 | before_action :set_instance, only: %i[show]
6 |
7 | # GET /workflows/1/instances
8 | def index
9 | @instances = @workflow.instances.all
10 | end
11 |
12 | # GET /workflows/1/instances
13 | def show
14 | @form = @workflow.form
15 | @virtual_model = @form.to_virtual_model
16 | @form_record = @virtual_model.new(@instance.payload)
17 |
18 | render layout: "workflow_instances"
19 | end
20 |
21 | def new
22 | @form = @workflow.form
23 | overrides = @workflow.start_place.output_transition.options.field_overrides.map { |o| { o.name => { accessibility: o.accessibility } } }.reduce(&:merge) || {}
24 | @virtual_model = @form.to_virtual_model overrides: overrides
25 |
26 | @form_record = @virtual_model.new
27 | end
28 |
29 | # POST /workflows/1/instances
30 | def create
31 | @form = @workflow.form
32 | overrides = @workflow.start_place.output_transition.options.field_overrides.map { |o| { o.name => { accessibility: o.accessibility } } }.reduce(&:merge) || {}
33 | @virtual_model = @form.to_virtual_model overrides: overrides
34 |
35 | @form_record = @virtual_model.new form_record_params
36 | render :new unless @form_record.valid?
37 |
38 | @instance = @workflow.instances.create! type: "WorkflowInstance", creator: current_user
39 | @instance.update! payload: @form_record.serializable_hash
40 | start_token = @instance.tokens.first
41 | start_token.place.output_transition.fire(start_token)
42 |
43 | redirect_to workflow_instance_tokens_url(@workflow, @instance), notice: "instance was successfully created."
44 | end
45 |
46 | private
47 |
48 | # Use callbacks to share common setup or constraints between actions.
49 | def set_instance
50 | @instance = @workflow.instances.find(params[:id])
51 | end
52 |
53 | def form_record_params
54 | params.fetch(:form_record, {}).permit!
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/loads_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Workflows::LoadsController < Workflows::ApplicationController
4 | # GET /workflows/1/load
5 | def show; end
6 |
7 | # PATCH/PUT /workflows/1/load
8 | def update
9 | bpmn_xml = permitted_params[:bpmn_xml].presence || permitted_params[:bpmn_file]&.read
10 | @workflow.load_from_bpmn!(bpmn_xml)
11 |
12 | redirect_to workflow_url(@workflow), notice: "Workflow definition was successfully imported."
13 | end
14 |
15 | private
16 |
17 | # Only allow a trusted parameter "white list" through.
18 | def permitted_params
19 | params.permit(:bpmn_xml, :bpmn_file)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/nested_forms/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class NestedForms::ApplicationController < ApplicationController
5 | before_action :set_nested_form
6 |
7 | protected
8 |
9 | # Use callbacks to share common setup or constraints between actions.
10 | def set_nested_form
11 | @nested_form = NestedForm.find(params[:nested_form_id])
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/nested_forms/fields_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class NestedForms::FieldsController < NestedForms::ApplicationController
5 | before_action :set_field, only: %i[show edit update destroy]
6 |
7 | def index
8 | @fields = @nested_form.fields.all
9 | end
10 |
11 | def new
12 | @field = @nested_form.fields.build
13 | end
14 |
15 | def edit; end
16 |
17 | def create
18 | @field = @nested_form.fields.build(field_params)
19 |
20 | if @field.save!
21 | redirect_to workflow_nested_form_fields_url(@workflow, @nested_form), notice: "Field was successfully created."
22 | else
23 | render :new
24 | end
25 | end
26 |
27 | def update
28 | if @field.update(field_params)
29 | redirect_to workflow_nested_form_fields_url(@workflow, @nested_form), notice: "Field was successfully updated."
30 | else
31 | render :edit
32 | end
33 | end
34 |
35 | def destroy
36 | @field.destroy
37 | redirect_to workflow_nested_form_fields_url(@workflow, @nested_form), notice: "Field was successfully destroyed."
38 | end
39 |
40 | private
41 |
42 | # Use callbacks to share common setup or constraints between actions.
43 | def set_field
44 | @field = @nested_form.fields.find(params[:id])
45 | end
46 |
47 | # Only allow a trusted parameter "white list" through.
48 | def field_params
49 | params.fetch(:field, {}).permit(:name, :label, :hint, :accessibility, :type)
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/transitions/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Transitions::ApplicationController < ApplicationController
5 | before_action :set_transition
6 |
7 | protected
8 |
9 | # Use callbacks to share common setup or constraints between actions.
10 | def set_transition
11 | @transition = @workflow.transitions.find(params[:transition_id])
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/transitions/options_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Workflows
4 | class Transitions::OptionsController < Transitions::ApplicationController
5 | before_action :set_options
6 |
7 | def edit; end
8 |
9 | def update
10 | @options.assign_attributes(options_params)
11 | if @options.valid? && @transition.save(validate: false)
12 | redirect_to workflow_transitions_url(@workflow), notice: "Transition was successfully updated."
13 | else
14 | render :edit
15 | end
16 | end
17 |
18 | private
19 |
20 | def set_options
21 | @options = @transition.options
22 | end
23 |
24 | def options_params
25 | params.fetch(:options, {}).permit!
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows/transitions_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Workflows::TransitionsController < Workflows::ApplicationController
4 | before_action :set_transition, only: %i[edit update destroy]
5 |
6 | # GET /workflows/1/transitions
7 | def index
8 | @transitions = @workflow.transitions.all
9 | end
10 |
11 | # GET /workflows/transitions/new
12 | def new
13 | @transition = @workflow.transitions.build
14 | end
15 |
16 | # GET /workflows/1/transitions/1/edit
17 | def edit; end
18 |
19 | # POST /workflows/1/transitions
20 | def create
21 | @transition = @workflow.transitions.build(transition_params)
22 |
23 | if @transition.save
24 | redirect_to workflow_transitions_url(@workflow), notice: "transition was successfully created."
25 | else
26 | render :new
27 | end
28 | end
29 |
30 | # PATCH/PUT /workflows/1/transitions/1
31 | def update
32 | if @transition.update(transition_params)
33 | redirect_to workflow_transitions_url(@workflow), notice: "transition was successfully updated."
34 | else
35 | render :edit
36 | end
37 | end
38 |
39 | # DELETE /workflows/1/transitions/1
40 | def destroy
41 | @transition.destroy
42 | redirect_to workflow_transitions_url(@workflow), notice: "transition was successfully destroyed."
43 | end
44 |
45 | private
46 |
47 | # Use callbacks to share common setup or constraints between actions.
48 | def set_transition
49 | @transition = @workflow.transitions.find(params[:id])
50 | end
51 |
52 | # Only allow a trusted parameter "white list" through.
53 | def transition_params
54 | params.fetch(:transition, {}).permit(:name, :type)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/workflows_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class WorkflowsController < ApplicationController
4 | layout "application"
5 |
6 | before_action :set_workflow, only: %i[show edit update destroy]
7 |
8 | # GET /workflows
9 | def index
10 | @workflows = Workflow.all
11 | end
12 |
13 | # GET /workflows/new
14 | def new
15 | @workflow = Workflow.new
16 | end
17 |
18 | # GET /workflows/1
19 | def show
20 | render layout: "workflows"
21 | end
22 |
23 | # GET /workflows/1/edit
24 | def edit; end
25 |
26 | # POST /workflows
27 | def create
28 | @workflow = Workflow.new(workflow_params)
29 |
30 | if @workflow.save
31 | redirect_to workflow_url(@workflow), notice: "workflow was successfully created."
32 | else
33 | render :new
34 | end
35 | end
36 |
37 | # PATCH/PUT /workflows/1
38 | def update
39 | if @workflow.update(workflow_params)
40 | redirect_to workflow_url(@workflow), notice: "workflow was successfully updated."
41 | else
42 | render :edit
43 | end
44 | end
45 |
46 | # DELETE /workflows/1
47 | def destroy
48 | @workflow.destroy
49 | redirect_to workflows_url, notice: "workflow was successfully destroyed."
50 | end
51 |
52 | private
53 |
54 | # Use callbacks to share common setup or constraints between actions.
55 | def set_workflow
56 | @workflow = Workflow.find(params[:id])
57 | end
58 |
59 | # Only allow a trusted parameter "white list" through.
60 | def workflow_params
61 | params.fetch(:workflow, {}).permit(:name, :description)
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/test/dummy/app/decorators/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/app/decorators/.keep
--------------------------------------------------------------------------------
/test/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ApplicationHelper
4 | def options_for_enum_select(klass, attribute, selected = nil)
5 | container = klass.public_send(attribute.to_s.pluralize).map do |k, v|
6 | v ||= k
7 | [klass.human_enum_value(attribute, k), v]
8 | end
9 |
10 | options_for_select(container, selected)
11 | end
12 |
13 | def present(model, options = {})
14 | klass = options.delete(:presenter_class) || "#{model.class}Presenter".constantize
15 | presenter = klass.new(model, self, options)
16 |
17 | yield(presenter) if block_given?
18 |
19 | presenter
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/fields_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FieldsHelper
4 | def options_for_field_types(selected: nil)
5 | options_for_select(Field.descendants.map { |klass| [klass.model_name.human, klass.to_s] }, selected)
6 | end
7 |
8 | def field_label(form, field_name:)
9 | field_name = field_name.to_s.split(".").first.to_sym
10 |
11 | form.fields.select do |field|
12 | field.name == field_name
13 | end.first&.label
14 | end
15 |
16 | def smart_form_fields_path(workflow, form)
17 | case form
18 | when Form
19 | workflow_fields_path(workflow, form)
20 | when NestedForm
21 | workflow_nested_form_fields_path(workflow, form)
22 | else
23 | raise "Unknown form: #{form.class}"
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/transitions_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module TransitionsHelper
4 | def options_for_transition_types(selected: nil)
5 | options_for_select(Transition.descendants.map { |klass| [klass.model_name.human, klass.to_s] }, selected)
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationJob < ActiveJob::Base
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/app/lib/.keep
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/definition_container.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class DefinitionContainer
5 | attr_reader :collection
6 |
7 | def initialize(tokens)
8 | @collection = tokens.map { |t| { t.id => t } }.reduce(&:merge!)
9 | @start_id = tokens.first { |t| t.node_type == :start_event }.id
10 | end
11 |
12 | def start_event
13 | @collection[@start_id]
14 | end
15 |
16 | def [](id)
17 | @collection[id]
18 | end
19 |
20 | def slice(*ids)
21 | @collection.slice(*ids).values
22 | end
23 |
24 | def self.parse(bpmn_xml)
25 | tokens = Bpmn::Tokenizer.new.tokenize(bpmn_xml)
26 | return nil unless tokens
27 |
28 | new tokens
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokenizer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokenizer
5 | def tokenize(bpmn_xml)
6 | return nil if bpmn_xml.blank?
7 |
8 | doc = begin
9 | Nokogiri::XML(bpmn_xml)
10 | rescue StandardError
11 | nil
12 | end
13 | return nil unless doc && doc.errors.count.zero?
14 |
15 | process = begin
16 | doc.at_xpath("//bpmn:process")
17 | rescue StandardError
18 | nil
19 | end
20 | return nil unless process
21 |
22 | return if process.blank?
23 |
24 | process.elements.map { |el| factory(el) }.compact
25 | end
26 |
27 | private
28 |
29 | def factory(element)
30 | case element.name
31 | when "startEvent"
32 | Bpmn::Tokens::StartEvent.new(element)
33 | when "endEvent"
34 | Bpmn::Tokens::EndEvent.new(element)
35 | when "task"
36 | Bpmn::Tokens::Task.new(element)
37 | when "userTask"
38 | Bpmn::Tokens::UserTask.new(element)
39 | when "scriptTask"
40 | Bpmn::Tokens::ScriptTask.new(element)
41 | when "parallelGateway"
42 | Bpmn::Tokens::ParallelGateway.new(element)
43 | when "exclusiveGateway"
44 | Bpmn::Tokens::ExclusiveGateway.new(element)
45 | when "inclusiveGateway"
46 | Bpmn::Tokens::InclusiveGateway.new(element)
47 | when "sequenceFlow"
48 | Bpmn::Tokens::SequenceFlow.new(element)
49 | else
50 | raise NotImplementedError, "#{element.name} is unsupported yet."
51 | end
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/common_token.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::CommonToken < Bpmn::Tokens::Token
5 | attr_reader :incoming_ids, :outgoing_ids
6 |
7 | def initialize(element)
8 | super
9 |
10 | @incoming_ids = element.xpath("bpmn:incoming").map(&:content)
11 | @outgoing_ids = element.xpath("bpmn:outgoing").map(&:content)
12 | end
13 |
14 | def to_hash
15 | super.merge(
16 | incoming_ids: incoming_ids,
17 | outgoing_ids: outgoing_ids
18 | )
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/end_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::EndEvent < Bpmn::Tokens::CommonToken
5 | def event?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/exclusive_gateway.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::ExclusiveGateway < Bpmn::Tokens::CommonToken
5 | attr_reader :default_flow_id
6 |
7 | def initialize(element)
8 | super
9 |
10 | @default_flow_id = element["default"]
11 | end
12 |
13 | def gateway?
14 | true
15 | end
16 |
17 | def to_hash
18 | super.merge(
19 | default_flow_id: default_flow_id
20 | )
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/extensions/condition_expression.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::Extensions::ConditionExpression
5 | attr_reader :language, :condition, :type
6 |
7 | def initialize(element)
8 | @language = element["language"]
9 | @condition = element.content
10 | @type = element["xsi:type"]
11 | end
12 |
13 | def self.factory(xelement)
14 | ce = xelement.at_xpath("bpmn:conditionExpression")
15 | return nil unless ce
16 |
17 | new(ce)
18 | end
19 |
20 | def to_hash
21 | {
22 | language: language,
23 | condition: condition,
24 | type: type
25 | }
26 | end
27 | alias to_h to_hash
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/inclusive_gateway.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::InclusiveGateway < Bpmn::Tokens::CommonToken
5 | attr_reader :default_flow_id
6 |
7 | def initialize(element)
8 | super
9 |
10 | @default_flow_id = element["default"]
11 | end
12 |
13 | def gateway?
14 | true
15 | end
16 |
17 | def to_hash
18 | super.merge(
19 | default_flow_id: default_flow_id
20 | )
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/parallel_gateway.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::ParallelGateway < Bpmn::Tokens::CommonToken
5 | def gateway?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/script_task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::ScriptTask < Bpmn::Tokens::CommonToken
5 | attr_reader :script_format, :script
6 |
7 | def initialize(element)
8 | super
9 |
10 | @script_format = element["scriptFormat"]
11 | @script = element.at_xpath("bpmn:script").try(:content)
12 | end
13 |
14 | def task?
15 | true
16 | end
17 |
18 | def to_hash
19 | super.merge(
20 | extensions: {
21 | script_format: script_format,
22 | script: script
23 | }
24 | )
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/sequence_flow.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::SequenceFlow < Bpmn::Tokens::Token
5 | attr_reader :source_id, :target_id
6 | attr_reader :condition_expression
7 |
8 | def initialize(element)
9 | super
10 |
11 | @source_id = element["sourceRef"]
12 | @target_id = element["targetRef"]
13 |
14 | @condition_expression = Bpmn::Tokens::Extensions::ConditionExpression.factory(element)
15 | end
16 |
17 | def flow?
18 | true
19 | end
20 |
21 | def to_hash
22 | super.merge(
23 | source_id: source_id,
24 | target_id: target_id,
25 | extensions: {
26 | condition_expression: condition_expression.to_hash
27 | }
28 | )
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/start_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::StartEvent < Bpmn::Tokens::CommonToken
5 | def event?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::Task < Bpmn::Tokens::CommonToken
5 | def task?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/token.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::Token
5 | attr_reader :id, :name, :node_type
6 | attr_reader :documentation
7 |
8 | def initialize(element)
9 | # @element = element
10 | @id = element["id"]
11 | @name = element["name"] || ""
12 | @node_type = element.name.underscore.to_sym
13 |
14 | @documentation = element.at_xpath("bpmn:documentation")&.content || ""
15 | end
16 |
17 | def gateway?
18 | false
19 | end
20 |
21 | def event?
22 | false
23 | end
24 |
25 | def task?
26 | false
27 | end
28 |
29 | def flow?
30 | false
31 | end
32 |
33 | def to_hash
34 | {
35 | node_id: id,
36 | node_type: node_type,
37 | name: name
38 | }
39 | end
40 | alias to_h to_hash
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/bpmn/tokens/user_task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Bpmn
4 | class Tokens::UserTask < Bpmn::Tokens::CommonToken
5 | def task?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/script_engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ScriptEngine
4 | class << self
5 | def engine
6 | @engine ||= ScriptCore::Engine.new Rails.root.join("mruby", "bin")
7 | end
8 |
9 | def run(string, payload: nil, instruction_quota_start: nil)
10 | sources = [
11 | %w[preparing prepare],
12 | ["user", string],
13 | %w[packing_output pack_output]
14 | ]
15 |
16 | engine.eval sources,
17 | input: {
18 | configuration: {
19 | time_zone_offset: Time.zone.formatted_offset(false)
20 | },
21 | payload: payload
22 | },
23 | instruction_quota_start: instruction_quota_start,
24 | environment_variables: { "TZ" => Time.zone.name }
25 | end
26 |
27 | def run_inline(string, payload: nil, instruction_quota_start: nil)
28 | run "Output.value = module Main\n#{string}\nend",
29 | payload: payload,
30 | instruction_quota_start: instruction_quota_start
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/test/dummy/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationMailer < ActionMailer::Base
4 | default from: "from@example.com"
5 | layout "mailer"
6 | end
7 |
--------------------------------------------------------------------------------
/test/dummy/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationRecord < ActiveRecord::Base
4 | self.abstract_class = true
5 |
6 | include ActsAsDefaultValue
7 | include EnumAttributeLocalizable
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/app/models/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/enum_attribute_localizable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module EnumAttributeLocalizable
4 | extend ActiveSupport::Concern
5 |
6 | module ClassMethods
7 | def human_enum_value(attribute, value, options = {})
8 | parts = attribute.to_s.split(".")
9 | attribute = parts.pop.pluralize
10 | attributes_scope = "#{i18n_scope}.attributes"
11 |
12 | if parts.any?
13 | namespace = parts.join("/")
14 | defaults = lookup_ancestors.map do |klass|
15 | :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}.#{value}"
16 | end
17 | defaults << :"#{attributes_scope}.#{namespace}.#{attribute}.#{value}"
18 | else
19 | defaults = lookup_ancestors.map do |klass|
20 | :"#{attributes_scope}.#{klass.model_name.i18n_key}.#{attribute}.#{value}"
21 | end
22 | end
23 |
24 | defaults << :"attributes.#{attribute}.#{value}"
25 | defaults << options.delete(:default) if options[:default]
26 | defaults << value.to_s.humanize
27 |
28 | options[:default] = defaults
29 | I18n.translate(defaults.shift, **options)
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/acceptance.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Acceptance
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :acceptance, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless acceptance
14 |
15 | model.validates field_name, acceptance: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/confirmation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Confirmation
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :confirmation, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless confirmation
14 |
15 | model.validates field_name, confirmation: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/exclusion.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Exclusion
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :exclusion, class_name: "Fields::Validations::Exclusion::ExclusionOptions"
9 | accepts_nested_attributes_for :exclusion
10 |
11 | after_initialize do
12 | build_exclusion unless exclusion
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | exclusion&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class ExclusionOptions < FieldOptions
22 | attribute :message, :string, default: ""
23 | attribute :in, :string, default: [], array: true
24 |
25 | def interpret_to(model, field_name, _accessibility, _options = {})
26 | return if self.in.empty?
27 |
28 | options = { in: self.in }
29 | options[:message] = message if message.present?
30 |
31 | model.validates field_name, exclusion: options, allow_blank: true
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/format.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Format
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :format, class_name: "Fields::Validations::Format::FormatOptions"
9 | accepts_nested_attributes_for :format
10 |
11 | after_initialize do
12 | build_format unless format
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | format&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class FormatOptions < FieldOptions
22 | attribute :with, :string, default: ""
23 | attribute :message, :string, default: ""
24 |
25 | validate do
26 | Regexp.new(with) if with.present?
27 | rescue RegexpError
28 | errors.add :with, :invalid
29 | end
30 |
31 | def interpret_to(model, field_name, _accessibility, _options = {})
32 | return if with.blank?
33 |
34 | with = Regexp.new(self.with)
35 |
36 | options = { with: with }
37 | options[:message] = message if message.present?
38 |
39 | model.validates field_name, format: options, allow_blank: true
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/inclusion.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Inclusion
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :inclusion, class_name: "Fields::Validations::Inclusion::InclusionOptions"
9 | accepts_nested_attributes_for :inclusion
10 |
11 | after_initialize do
12 | build_inclusion unless inclusion
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | inclusion&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class InclusionOptions < FieldOptions
22 | attribute :message, :string, default: ""
23 | attribute :in, :string, default: [], array: true
24 |
25 | def interpret_to(model, field_name, _accessibility, _options = {})
26 | return if self.in.empty?
27 |
28 | options = { in: self.in }
29 | options[:message] = message if message.present?
30 |
31 | model.validates field_name, inclusion: options, allow_blank: true
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/length.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Length
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :length, class_name: "Fields::Validations::Length::LengthOptions"
9 | accepts_nested_attributes_for :length
10 |
11 | after_initialize do
12 | build_length unless length
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | length&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class LengthOptions < FieldOptions
22 | attribute :minimum, :integer, default: 0
23 | attribute :maximum, :integer, default: 0
24 | attribute :is, :integer, default: 0
25 |
26 | validates :minimum, :maximum, :is,
27 | numericality: {
28 | greater_than_or_equal_to: 0
29 | }
30 | validates :maximum,
31 | numericality: {
32 | greater_than: :minimum
33 | },
34 | if: proc { |record| record.maximum <= record.minimum && record.maximum.positive? }
35 |
36 | validates :is,
37 | numericality: {
38 | equal_to: 0
39 | },
40 | if: proc { |record| !record.maximum.zero? || !record.minimum.zero? }
41 |
42 | def interpret_to(model, field_name, _accessibility, _options = {})
43 | return if minimum.zero? && maximum.zero? && is.zero?
44 |
45 | if is.positive?
46 | model.validates field_name, length: { is: is }, allow_blank: true
47 | return
48 | end
49 |
50 | options = {}
51 | options[:minimum] = minimum if minimum.positive?
52 | options[:maximum] = maximum if maximum.positive?
53 | return if options.empty?
54 |
55 | model.validates field_name, length: options, allow_blank: true
56 | end
57 | end
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/numericality.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Numericality
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :numericality, class_name: "Fields::Validations::Numericality::NumericalityOptions"
9 | accepts_nested_attributes_for :numericality
10 |
11 | after_initialize do
12 | build_numericality unless numericality
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | numericality&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class NumericalityOptions < FieldOptions
22 | attribute :lower_bound_check, :string, default: "disabled"
23 | attribute :upper_bound_check, :string, default: "disabled"
24 |
25 | attribute :lower_bound_value, :float, default: 0.0
26 | attribute :upper_bound_value, :float, default: 0.0
27 |
28 | enum lower_bound_check: {
29 | disabled: "disabled",
30 | greater_than: "greater_than",
31 | greater_than_or_equal_to: "greater_than_or_equal_to"
32 | }, _prefix: :lower_bound_check
33 | enum upper_bound_check: {
34 | disabled: "disabled",
35 | less_than: "less_than",
36 | less_than_or_equal_to: "less_than_or_equal_to"
37 | }, _prefix: :upper_bound_check
38 |
39 | validates :upper_bound_value,
40 | numericality: {
41 | greater_than: :lower_bound_value
42 | },
43 | if: proc { upper_bound_check != "disabled" && lower_bound_check != "disabled" }
44 |
45 | def interpret_to(model, field_name, _accessibility, _options = {})
46 | options = {}
47 | options[lower_bound_check] = lower_bound_value unless lower_bound_check_disabled?
48 | options[upper_bound_check] = upper_bound_value unless upper_bound_check_disabled?
49 | return if options.empty?
50 |
51 | options.symbolize_keys!
52 | model.validates field_name, numericality: options, allow_blank: true
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/presence.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Presence
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :presence, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless presence
14 |
15 | model.validates field_name, presence: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/transitions/options/assignable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | module Assignable
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :assignee_user_ids, type: :string, array: true
9 | attribute :assign_to, type: :string, default: "creator"
10 |
11 | enum assign_to: {
12 | creator: "creator",
13 | specific: "specific",
14 | inherited: "inherited"
15 | }, _prefix: :assign_to
16 |
17 | validates :assign_to,
18 | presence: true
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/transitions/options/field_overridable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | module FieldOverridable
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_many :field_overrides, class_name: "Transitions::Options::FieldOverridable::FieldOverride"
9 | accepts_nested_attributes_for :field_overrides
10 | end
11 |
12 | class FieldOverride < FieldOptions
13 | attribute :name, :string
14 | attribute :accessibility, :integer, default: 0
15 |
16 | attr_readonly :name
17 | enum accessibility: { read_and_write: 0, readonly: 1, hidden: 2 },
18 | _prefix: :access
19 |
20 | validates :name,
21 | presence: true
22 |
23 | validates :accessibility,
24 | inclusion: { in: accessibilities.keys.map(&:to_sym) }
25 |
26 | def name
27 | self[:name]&.to_sym
28 | end
29 |
30 | def accessibility
31 | self[:accessibility]&.to_sym
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/transitions/options/votable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | module Votable
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :vote_rule, type: :string, default: "one_vote_pass"
9 |
10 | enum vote_rule: {
11 | one_vote_pass: "one_vote_pass"
12 | }
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/dummy/app/models/field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Field < ApplicationRecord
4 | include FormCore::Concerns::Models::Field
5 |
6 | self.table_name = "fields"
7 |
8 | belongs_to :form, class_name: "MetalForm", foreign_key: "form_id", touch: true
9 |
10 | has_one :nested_form, as: :attachable
11 |
12 | validates :label,
13 | presence: true
14 | validates :type,
15 | inclusion: {
16 | in: ->(_) { Field.descendants.map(&:to_s) }
17 | },
18 | allow_blank: false
19 |
20 | default_value_for :name,
21 | ->(_) { "field_#{SecureRandom.hex(3)}" },
22 | allow_nil: false
23 |
24 | def self.type_key
25 | model_name.name.split("::").last.underscore
26 | end
27 |
28 | def type_key
29 | self.class.type_key
30 | end
31 |
32 | def options_configurable?
33 | options.is_a?(FieldOptions) && options.attributes.any?
34 | end
35 |
36 | def validations_configurable?
37 | validations.is_a?(FieldOptions) && validations.attributes.any?
38 | end
39 |
40 | def attached_nested_form?
41 | false
42 | end
43 |
44 | protected
45 |
46 | def interpret_validations_to(model, accessibility, overrides = {})
47 | return unless accessibility == :read_and_write
48 |
49 | validations_overrides = overrides.fetch(:validations) { {} }
50 | validations =
51 | if validations_overrides.any?
52 | self.validations.dup.update(validations_overrides)
53 | else
54 | self.validations
55 | end
56 |
57 | validations.interpret_to(model, name, accessibility)
58 | end
59 |
60 | def interpret_extra_to(model, accessibility, overrides = {})
61 | options_overrides = overrides.fetch(:options) { {} }
62 | options =
63 | if options_overrides.any?
64 | self.options.dup.update(options_overrides)
65 | else
66 | self.options
67 | end
68 |
69 | options.interpret_to(model, name, accessibility)
70 | end
71 | end
72 |
73 | require_dependency "fields"
74 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | %w[
5 | text boolean decimal integer
6 | nested_form multiple_nested_form
7 | ].each do |type|
8 | require_dependency "fields/#{type}_field"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/boolean_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class BooleanField < Field
5 | serialize :validations, Validations::BooleanField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :boolean
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DecimalField < Field
5 | serialize :validations, Validations::DecimalField
6 | serialize :options, Options::DecimalField
7 |
8 | def stored_type
9 | :decimal
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class IntegerField < Field
5 | serialize :validations, Validations::IntegerField
6 | serialize :options, Options::IntegerField
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | protected
13 |
14 | def interpret_extra_to(model, accessibility, _overrides = {})
15 | return if accessibility != :read_and_write
16 |
17 | model.validates name, numericality: { only_integer: true }, allow_blank: true
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleNestedFormField < Field
5 | after_create do
6 | build_nested_form.save!
7 | end
8 |
9 | serialize :validations, Validations::MultipleNestedFormField
10 | serialize :options, NonConfigurable
11 |
12 | def attached_nested_form?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | overrides[:name] = name
23 |
24 | nested_model = nested_form.to_virtual_model(overrides: { _global: { accessibility: accessibility } })
25 |
26 | model.nested_models[name] = nested_model
27 |
28 | model.embeds_many name, anonymous_class: nested_model, validate: true
29 | model.accepts_nested_attributes_for name, reject_if: :all_blank
30 | model.attr_readonly name if accessibility == :readonly
31 |
32 | interpret_validations_to model, accessibility, overrides
33 | interpret_extra_to model, accessibility, overrides
34 |
35 | model
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class NestedFormField < Field
5 | after_create do
6 | build_nested_form.save!
7 | end
8 |
9 | serialize :validations, Validations::NestedFormField
10 | serialize :options, NonConfigurable
11 |
12 | def attached_nested_form?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | nested_model = nested_form.to_virtual_model(overrides: { _global: { accessibility: accessibility } })
23 |
24 | model.nested_models[name] = nested_model
25 |
26 | model.embeds_one name, anonymous_class: nested_model, validate: true
27 | model.accepts_nested_attributes_for name, reject_if: :all_blank
28 | model.attr_readonly name if accessibility == :readonly
29 |
30 | interpret_validations_to model, accessibility, overrides
31 | interpret_extra_to model, accessibility, overrides
32 |
33 | model
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class DecimalField < FieldOptions
5 | attribute :step, :decimal, default: 0.01
6 |
7 | validates :step,
8 | numericality: {
9 | greater_than_or_equal_to: 0.0
10 | }
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class IntegerField < FieldOptions
5 | attribute :step, :integer, default: 0
6 |
7 | validates :step,
8 | numericality: {
9 | only_integer: true,
10 | greater_than_or_equal_to: 0
11 | }
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class TextField < FieldOptions
5 | attribute :multiline, :boolean, default: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class TextField < Field
5 | serialize :validations, Validations::TextField
6 | serialize :options, Options::TextField
7 |
8 | def stored_type
9 | :string
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/boolean_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class BooleanField < FieldOptions
5 | prepend Fields::Validations::Acceptance
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DecimalField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Numericality
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class IntegerField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Numericality
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleNestedFormField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class NestedFormField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class TextField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | prepend Fields::Validations::Format
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/models/form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Form < MetalForm
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/models/group.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Group < ApplicationRecord
4 | has_many :users, dependent: :nullify
5 |
6 | validates :name,
7 | presence: true
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/metal_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class MetalForm < ApplicationRecord
4 | include FormCore::Concerns::Models::Form
5 |
6 | self.table_name = "forms"
7 |
8 | has_many :fields, foreign_key: "form_id", dependent: :destroy
9 |
10 | default_value_for :name,
11 | ->(_) { "field_#{SecureRandom.hex(3)}" },
12 | allow_nil: false
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/models/nested_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NestedForm < MetalForm
4 | belongs_to :attachable, polymorphic: true, touch: true
5 | end
6 |
--------------------------------------------------------------------------------
/test/dummy/app/models/non_configurable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NonConfigurable < FieldOptions
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/models/place.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Place < WorkflowCore::Place
4 | def builtin?
5 | false
6 | end
7 |
8 | def append_to_graph(g, prev: nil, arc_label: "", nodes: {})
9 | key = "p_#{id}"
10 | unless nodes[key]
11 | nodes[key] = Graphviz::Node.new("p.#{id}#{": #{name}" if name.present?}", shape: "box", style: "rounded")
12 | g << nodes[key]
13 | end
14 | current = nodes[key]
15 |
16 | prev.connect(current, label: arc_label) if prev && !prev.connected?(current)
17 |
18 | if output_transition
19 | next_node = nodes["t_#{output_transition.id}"]
20 | if !next_node
21 | output_transition.append_to_graph(g, prev: current, nodes: nodes)
22 | else
23 | current.connect(next_node, label: arc_label)
24 | end
25 | end
26 |
27 | g
28 | end
29 | end
30 |
31 | require_dependency "places"
32 |
--------------------------------------------------------------------------------
/test/dummy/app/models/places.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Places
4 | %w[
5 | start end
6 | ].each do |type|
7 | require_dependency "places/#{type}_place"
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/models/places/end_place.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Places::EndPlace < Place
4 | def builtin?
5 | true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/places/start_place.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Places::StartPlace < Place
4 | def builtin?
5 | true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/token.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Token < WorkflowCore::Token
4 | belongs_to :assignable, polymorphic: true, optional: true
5 | belongs_to :forwardable, polymorphic: true, optional: true
6 |
7 | serialize :payload, Payload
8 |
9 | class Payload < FieldOptions
10 | attribute :note, type: :string
11 | attribute :action, type: :string
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/models/token/payload.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Token
4 | class Payload < FieldOptions
5 | attribute :note, type: :string
6 | attribute :action, type: :string
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transition.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transition < WorkflowCore::Transition
4 | serialize :options, NonConfigurable
5 |
6 | def auto_forwardable?
7 | false
8 | end
9 |
10 | def options_configurable?
11 | options.attributes.any? || options.class.reflections.any?
12 | end
13 |
14 | def self.type_key
15 | model_name.name.split("::").last.underscore
16 | end
17 |
18 | def type_key
19 | self.class.type_key
20 | end
21 |
22 | def append_to_graph(g, prev: nil, arc_label: "", nodes: {})
23 | key = "t_#{id}"
24 | unless nodes[key]
25 | nodes[key] = Graphviz::Node.new("t.#{id}#{": #{name}" if name.present?}", shape: "box")
26 | g << nodes[key]
27 | end
28 | current = nodes[key]
29 |
30 | prev.connect(current, label: arc_label) if prev && !prev.connected?(current)
31 |
32 | output_places.each do |succ|
33 | succ.append_to_graph(g, prev: current, nodes: nodes)
34 | end
35 |
36 | g
37 | end
38 |
39 | protected
40 |
41 | def auto_forward(next_token, transaction_options, **options)
42 | transition = next_token.place.output_transition
43 | return unless transition
44 | return unless transition.auto_forwardable?
45 |
46 | transition.on_fire(next_token, transaction_options, options)
47 | end
48 | end
49 |
50 | require_dependency "transitions"
51 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions
4 | %w[
5 | sequence
6 | start end
7 | parallel_split synchronization
8 | exclusive_choice simple_merge
9 | ].each do |type|
10 | require_dependency "transitions/#{type}"
11 | end
12 |
13 | %w[
14 | user_task assigning_assignees decision
15 | ].each do |type|
16 | require_dependency "transitions/variants/#{type}"
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/end.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::End < Transition
4 | def on_fire(token, _transaction_options, **_options)
5 | token.completed!
6 | token.instance.completed!
7 | end
8 |
9 | def auto_forwardable?
10 | true
11 | end
12 |
13 | def options_configurable?
14 | false
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/exclusive_choice.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::ExclusiveChoice < Transition
4 | serialize :options, Transitions::Options::ExclusiveChoice
5 |
6 | def on_fire(token, transaction_options, **options)
7 | instance = token.instance
8 |
9 | next_place_id = self.options.conditions.select do |condition|
10 | r = ScriptEngine.run_inline condition.condition_expression, payload: instance.payload
11 | raise r.errors.map(&:message).join("; ") if r.errors.any?
12 |
13 | r.output
14 | end.first&.place_id || self.options.default_next_place_id
15 | next_place = workflow.places.find(next_place_id)
16 |
17 | token.completed!
18 |
19 | next_token = next_place.tokens.create! previous: token, type: "Token",
20 | instance: token.instance, workflow: workflow
21 | auto_forward(next_token, transaction_options, options)
22 | end
23 |
24 | def auto_forwardable?
25 | true
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/options/assigning_assignees.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | class AssigningAssignees < FieldOptions
5 | include Assignable
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/options/decision.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | class Decision < FieldOptions
5 | include FieldOverridable
6 | include Votable
7 |
8 | embeds_many :actions, class_name: "Transitions::Options::Decision::Action"
9 | accepts_nested_attributes_for :actions, allow_destroy: true
10 |
11 | class Action < FieldOptions
12 | attribute :text, :string
13 | attribute :value, :string
14 | attribute :place_id, :integer
15 |
16 | validates :text, :value, :place_id,
17 | presence: true
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/options/exclusive_choice.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | class ExclusiveChoice < FieldOptions
5 | attribute :default_next_place_id, :integer
6 |
7 | embeds_many :conditions, class_name: "Transitions::Options::ExclusiveChoice::Condition"
8 | accepts_nested_attributes_for :conditions
9 |
10 | validates :default_next_place_id,
11 | presence: true
12 |
13 | class Condition < FieldOptions
14 | attribute :condition_expression, :string
15 | attribute :place_id, :integer
16 |
17 | validates :condition_expression, :place_id,
18 | presence: true
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/options/user_task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Options
4 | class UserTask < FieldOptions
5 | include FieldOverridable
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/parallel_split.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::ParallelSplit < Transition
4 | def on_fire(token, transaction_options, **options)
5 | token.completed!
6 | output_places.each do |p|
7 | next_token = p.tokens.create! previous: token, type: "Token",
8 | instance: token.instance, workflow: workflow
9 | auto_forward(next_token, transaction_options, options)
10 | end
11 | end
12 |
13 | def auto_forwardable?
14 | true
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/sequence.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::Sequence < Transition
4 | def on_fire(token, transaction_options, **options)
5 | p = output_places.first # assume only one output place
6 |
7 | token.completed!
8 | next_token = p.tokens.create! previous: token, type: "Token",
9 | instance: token.instance, workflow: workflow
10 | auto_forward(next_token, transaction_options, options)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/simple_merge.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::SimpleMerge < Transition
4 | def on_fire(token, transaction_options, **options)
5 | p = output_places.first # assume only one output place
6 | # return unless p.tokens.size.zero?
7 |
8 | token.completed!
9 | # TODO: consider if status are not completed
10 | completed_tokens =
11 | input_places
12 | .includes(:tokens).where(workflow_tokens: { instance_id: token.instance_id })
13 | .map(&:tokens).flatten.select(&:completed?)
14 | if completed_tokens.size == 1
15 | next_token = p.tokens.create! previous: token, type: "Token",
16 | instance: token.instance, workflow: workflow
17 | auto_forward(next_token, transaction_options, options)
18 | end
19 | end
20 |
21 | def auto_forwardable?
22 | true
23 | end
24 |
25 | def options_configurable?
26 | false
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/start.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::Start < Transition
4 | # http://workflowpatterns.com/patterns/control/basic/wcp1.php
5 |
6 | def on_fire(token, transaction_options, **options)
7 | p = output_places.first # assume only one output place
8 |
9 | token.completed!
10 | next_token = p.tokens.create! previous: token, type: "Token",
11 | instance: token.instance, workflow: workflow
12 | auto_forward(next_token, transaction_options, options)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/synchronization.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Transitions::Synchronization < Transition
4 | def on_fire(token, transaction_options, **options)
5 | p = output_places.first # assume only one output place
6 | # return unless p.tokens.size.zero?
7 |
8 | token.completed!
9 | # TODO: consider if status are not completed
10 | completed_tokens =
11 | input_places
12 | .includes(:tokens).where(workflow_tokens: { instance_id: token.instance_id })
13 | .map(&:tokens).flatten.select(&:completed?)
14 | if completed_tokens.size == input_places.size
15 | next_token = p.tokens.create! previous: token, type: "Token",
16 | instance: token.instance, workflow: workflow
17 | auto_forward(next_token, transaction_options, options)
18 | end
19 | end
20 |
21 | def auto_forwardable?
22 | true
23 | end
24 |
25 | def options_configurable?
26 | false
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/variants/assigning_assignees.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Variants
4 | class AssigningAssignees < Transitions::Sequence
5 | serialize :options, Transitions::Options::AssigningAssignees
6 |
7 | def on_fire(token, transaction_options, **options)
8 | token.completed!
9 |
10 | place = output_places.first # assume only one output place
11 | if self.options.assign_to_creator?
12 | next_token = place.tokens.create! assignable: token.instance.creator,
13 | previous: token, type: "Token",
14 | instance: token.instance, workflow: workflow
15 | auto_forward(next_token, transaction_options, options)
16 | elsif self.options.assign_to_specific?
17 | assignees = User.where(id: self.options.assignee_user_ids).to_a
18 | assignees.each do |assignee|
19 | next_token = place.tokens.create! assignable: assignee,
20 | previous: token, type: "Token",
21 | instance: token.instance, workflow: workflow
22 | auto_forward(next_token, transaction_options, options)
23 | end
24 | elsif self.options.assign_to_inherited?
25 | next_token = place.tokens.create! assignable: token.assignable,
26 | previous: token, type: "Token",
27 | instance: token.instance, workflow: workflow
28 | auto_forward(next_token, transaction_options, options)
29 | else
30 | raise "Unsupported assign to #{options.assign_to}"
31 | end
32 | end
33 |
34 | def auto_forwardable?
35 | true
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/variants/decision.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Variants
4 | class Decision < Transitions::ExclusiveChoice
5 | serialize :options, Transitions::Options::Decision
6 |
7 | def on_fire(token, transaction_options, **options)
8 | token.completed!
9 |
10 | if self.options.one_vote_pass?
11 | token.instance.tokens.where(workflow: workflow, place_id: token.place, status: "processing").update_all status: :terminated
12 | end
13 |
14 | next_place_id = self.options.actions.select do |action|
15 | token.payload["action"] == action.value
16 | end.first&.place_id
17 | raise "No suitable place id for action #{token.payload['action']}" unless next_place_id
18 |
19 | next_place = workflow.places.find(next_place_id)
20 | next_token = next_place.tokens.create! previous: token, type: "Token",
21 | instance: token.instance, workflow: workflow,
22 | assignable: token.assignable
23 | auto_forward(next_token, transaction_options, options)
24 | end
25 |
26 | def auto_forwardable?
27 | false
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/test/dummy/app/models/transitions/variants/user_task.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Transitions::Variants
4 | class UserTask < Transitions::Sequence
5 | serialize :options, Transitions::Options::UserTask
6 |
7 | def on_fire(token, transaction_options, **options)
8 | token.completed!
9 | token.instance.tokens.where(workflow: workflow, place_id: token.place, status: "processing").update_all status: :terminated
10 |
11 | place = output_places.first # assume only one output place
12 | next_token = place.tokens.create! previous: token, type: "Token",
13 | instance: token.instance, workflow: workflow,
14 | assignable: token.assignable
15 | auto_forward(next_token, transaction_options, options)
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class User < ApplicationRecord
4 | belongs_to :group, optional: true
5 |
6 | validates :name,
7 | presence: true
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/virtual_model.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_dependency "concerns/enum_attribute_localizable"
4 |
5 | class VirtualModel < FormCore::VirtualModel
6 | include FormCore::ActsAsDefaultValue
7 |
8 | include EnumAttributeLocalizable
9 |
10 | def persisted?
11 | false
12 | end
13 |
14 | class << self
15 | def nested_models
16 | @nested_models ||= {}
17 | end
18 |
19 | def attr_readonly?(attr_name)
20 | readonly_attributes.include? attr_name.to_s
21 | end
22 |
23 | def metadata
24 | @metadata ||= {}
25 | end
26 |
27 | def _embeds_reflections
28 | _reflections.select { |_, v| v.is_a? ActiveEntity::Reflection::EmbeddedAssociationReflection }
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/app/models/workflow_instance.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class WorkflowInstance < WorkflowCore::WorkflowInstance
4 | belongs_to :creator, class_name: "User"
5 |
6 | after_create :auto_create_start_token!
7 |
8 | private
9 |
10 | def auto_create_start_token!
11 | tokens.create! place: workflow.start_place,
12 | workflow: workflow,
13 | type: "Token",
14 | assignable: creator
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/application_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationPresenter < SimpleDelegator
4 | def initialize(model, view, options = {})
5 | super(model)
6 |
7 | @model = model
8 | @view = view
9 | @options = options
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/concerns/fields/presenter_for_number_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Concerns::Fields
4 | module PresenterForNumberField
5 | extend ActiveSupport::Concern
6 |
7 | def min
8 | return if @model.validations.numericality.lower_bound_check_disabled?
9 |
10 | min = @model.validations.numericality.lower_bound_value
11 | integer_only? ? min.to_i : min
12 | end
13 |
14 | def max
15 | return if @model.validations.numericality.upper_bound_check_disabled?
16 |
17 | max = @model.validations.numericality.upper_bound_value
18 | integer_only? ? max.to_i : max
19 | end
20 |
21 | def step
22 | step = @model.options.step
23 | return if step.zero?
24 |
25 | integer_only? ? step.to_i : step
26 | end
27 |
28 | def integer_only?
29 | false
30 | end
31 |
32 | def to_builder_options
33 | { min: min, max: max, step: step, required: required? }.reject { |_, v| v.blank? }
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/boolean_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class BooleanFieldPresenter < FieldPresenter
5 | def required
6 | @model.validations&.acceptance
7 | end
8 |
9 | def value_for_preview
10 | super ? I18n.t("values.true") : I18n.t("values.false")
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/composite_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class CompositeFieldPresenter < FieldPresenter
5 | def value
6 | target&.send(@model.name)
7 | end
8 |
9 | def value_for_preview
10 | target&.send(@model.name)
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/decimal_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DecimalFieldPresenter < FieldPresenter
5 | include Concerns::Fields::PresenterForNumberField
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::FieldPresenter < ApplicationPresenter
4 | def required
5 | @model.validations&.presence
6 | end
7 | alias required? required
8 |
9 | def target
10 | @options[:target]
11 | end
12 |
13 | def value
14 | target&.read_attribute(@model.name)
15 | end
16 |
17 | def value_for_preview
18 | target&.read_attribute(@model.name)
19 | end
20 |
21 | def access_readonly?
22 | target.class.attr_readonly?(@model.name.to_s)
23 | end
24 |
25 | def access_hidden?
26 | target.class.attribute_names.exclude?(@model.name.to_s) && target.class._reflections.keys.exclude?(@model.name.to_s)
27 | end
28 |
29 | def access_read_and_write?
30 | !access_readonly? &&
31 | (target.class.attribute_names.include?(@model.name.to_s) || target.class._reflections.key?(@model.name.to_s))
32 | end
33 |
34 | def id
35 | "form_field_#{@model.id}"
36 | end
37 |
38 | def nested_form_field?
39 | false
40 | end
41 |
42 | def multiple_nested_form?
43 | false
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/integer_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class IntegerFieldPresenter < FieldPresenter
5 | include Concerns::Fields::PresenterForNumberField
6 |
7 | def integer_only?
8 | true
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_nested_form_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleNestedFormFieldPresenter < CompositeFieldPresenter
5 | def multiple_nested_form?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/nested_form_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class NestedFormFieldPresenter < CompositeFieldPresenter
5 | def nested_form_field?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/text_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class TextFieldPresenter < FieldPresenter
5 | def multiline
6 | @model.options.multiline
7 | end
8 | alias multiline? multiline
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_decimal_field.html.erb:
--------------------------------------------------------------------------------
1 |
Decimal field
2 |
3 |
4 | <%= f.label :step, class: "label" %>
5 |
6 | <%= f.number_field :step, class: "input", min: 0, step: 0.01 %>
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_integer_field.html.erb:
--------------------------------------------------------------------------------
1 | Integer field
2 |
3 |
4 | <%= f.label :step, class: "label" %>
5 |
6 | <%= f.number_field :step, class: "input", min: 0, step: 1 %>
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_text_field.html.erb:
--------------------------------------------------------------------------------
1 | Text field
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_boolean_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | <% if field.hint.present? %>
9 |
<%= field.hint %>
10 | <% end %>
11 |
12 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_decimal_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.number_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?, **field.to_builder_options %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_integer_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.number_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?, **field.to_builder_options %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_nested_form_field.html.erb:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_nested_form.html.erb:
--------------------------------------------------------------------------------
1 | <% nesting ||= false %>
2 |
3 |
40 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_nested_form_field.html.erb:
--------------------------------------------------------------------------------
1 |
25 |
26 | <% if field.access_read_and_write? %>
27 |
42 | <% end %>
43 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_text_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <% if field.options.multiline %>
5 | <%= f.text_area field.name, class: 'textarea', id: field.id, required: field.required, disabled: field.access_readonly? %>
6 | <% else %>
7 | <%= f.text_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly? %>
8 | <% end %>
9 |
10 | <% if field.hint.present? %>
11 |
<%= field.hint %>
12 | <% end %>
13 |
14 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/preview/_form.html.erb:
--------------------------------------------------------------------------------
1 | <% form.fields.map { |field| present(field, target: instance) }.each do |field| %>
2 | <% if field.nested_form_field? %>
3 | <% next unless field.value_for_preview %>
4 |
5 | <%= field.label %>:
6 | <%= render "_form_core/preview/nested_form", form: field.nested_form, instance: field.value_for_preview %>
7 | <% elsif field.multiple_nested_form? %>
8 | <% next if field.value_for_preview.empty? %>
9 |
10 | <%= field.label %>:
11 | <%= field.value_for_preview.map do |nested_instance| %>
12 | <% render "_form_core/preview/nested_form", form: field.nested_form, instance: nested_instance %>
13 | <% end.join("
").html_safe %>
14 | <% else %>
15 | <%= field.label %>: <%= field.value_for_preview %>
16 | <% end %>
17 | <% end %>
18 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/preview/_nested_form.html.erb:
--------------------------------------------------------------------------------
1 | <% fields = form.fields.map { |field| present(field, target: instance) }.reject(&:access_hidden?) %>
2 | <% return if fields.empty? %>
3 |
4 |
5 | <% fields.each do |field| %>
6 | <% if field.nested_form_field? %>
7 | <% next unless field.value_for_preview %>
8 |
9 |
<%= field.label %>:
10 | <%= render "_form_core/preview/nested_form", form: field.nested_form, instance: field.value_for_preview %>
11 | <% elsif field.multiple_nested_form? %>
12 | <% next if field.value_for_preview.empty? %>
13 |
14 |
<%= field.label %>:
15 | <%= field.value_for_preview.map do |nested_instance| %>
16 | <% render "_form_core/preview/nested_form", form: field.nested_form, instance: nested_instance %>
17 | <% end.join("
").html_safe %>
18 | <% else %>
19 |
<%= field.label %>: <%= field.value_for_preview %>
20 | <% end %>
21 | <% end %>
22 |
23 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/render/_form.html.erb:
--------------------------------------------------------------------------------
1 | <% options ||= {} %>
2 | <% back_url ||= url_for(:back) %>
3 |
4 | <%= form_with(model: instance, **options) do |f| %>
5 | <% if instance.errors.any? %>
6 |
7 |
12 |
13 |
14 | <% instance.errors.messages.each do |name, messages| %>
15 | <% messages.each do |message| %>
16 | - <%= "#{field_label(form, field_name: name)} #{message}" %>
17 | <% end %>
18 | <% end %>
19 |
20 |
21 |
22 | <% end %>
23 |
24 | <% form.fields.each do |field| %>
25 | <% field = present(field, target: instance) %>
26 | <% next if field.access_hidden? %>
27 |
28 | <%= render "_form_core/fields/#{field.type_key}", f: f, field: field %>
29 | <% end %>
30 |
31 |
32 |
33 | <%= f.submit "Submit", class: "button is-primary" %>
34 |
35 |
36 | <%= link_to "Back", back_url, class: "button is-link" %>
37 |
38 |
39 | <% end %>
40 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_acceptance.html.erb:
--------------------------------------------------------------------------------
1 | Acceptance
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_confirmation.html.erb:
--------------------------------------------------------------------------------
1 | Confirmation
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_exclusion.html.erb:
--------------------------------------------------------------------------------
1 | Exclusion
2 |
3 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_format.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_format unless validations.format %>
2 | <% format = validations.format %>
3 |
4 | Format
5 |
6 | <%= f.fields_for :format, format do |ff| %>
7 | <% if format.errors.any? %>
8 |
9 |
14 |
15 | <% format.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 | <%= ff.label :with %>
24 |
25 | <%= ff.text_field :with, class: "input" %>
26 |
27 |
28 |
29 |
30 | <%= ff.label :message %>
31 |
32 | <%= ff.text_field :message, class: "input" %>
33 |
34 |
35 | <% end %>
36 |
37 |
38 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_inclusion.html.erb:
--------------------------------------------------------------------------------
1 | Inclusion
2 |
3 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_length.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_length unless validations.length %>
2 | <% length = validations.length %>
3 |
4 | Length
5 |
6 | <%= f.fields_for :length, length do |ff| %>
7 | <% if length.errors.any? %>
8 |
9 |
14 |
15 | <% length.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 | <%= ff.label :minimum %>
24 |
25 | <%= ff.number_field :minimum, min: 0, step: 1, class: 'input' %>
26 |
27 |
28 |
29 |
30 | <%= ff.label :maximum %>
31 |
32 | <%= ff.number_field :maximum, min: 0, step: 1, class: 'input' %>
33 |
34 |
35 |
36 |
37 | <%= ff.label :is %>
38 |
39 | <%= ff.number_field :is, min: 0, step: 1, class: 'input' %>
40 |
41 |
42 | <% end %>
43 |
44 |
45 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_numericality.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_numericality unless validations.numericality %>
2 | <% numericality = validations.numericality %>
3 |
4 | Numericality
5 |
6 | <%= f.fields_for :numericality, numericality do |ff| %>
7 | <% if numericality.errors.any? %>
8 |
9 |
14 |
15 | <% numericality.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 |
24 |
25 | <%= ff.select :lower_bound_check, options_for_enum_select(numericality.class, :lower_bound_check, numericality.lower_bound_check), {}, class: "select" %>
26 |
27 |
28 |
29 | <%= ff.number_field :lower_bound_value, step: 0.01, class: "input" %>
30 |
31 |
32 |
33 |
34 |
35 |
36 | <%= ff.select :upper_bound_check, options_for_enum_select(numericality.class, :upper_bound_check, numericality.upper_bound_check), {}, class: "select" %>
37 |
38 |
39 |
40 | <%= ff.number_field :upper_bound_value, step: 0.01, class: "input" %>
41 |
42 |
43 | <% end %>
44 |
45 |
46 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_presence.html.erb:
--------------------------------------------------------------------------------
1 | Presence
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_action.html.erb:
--------------------------------------------------------------------------------
1 |
50 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_assignable.html.erb:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | <%= f.label :assignee_user_ids, class: "label" %>
15 |
16 |
17 | <%= f.select :assignee_user_ids, options_from_collection_for_select(User.all, :id, :name, f.object.assignee_user_ids), {}, multiple: true %>
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_assigning_assignees.html.erb:
--------------------------------------------------------------------------------
1 | <%= render "_workflow_core/transition_options/assignable", f: f, transition: transition, options: options %>
2 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_condition.html.erb:
--------------------------------------------------------------------------------
1 |
43 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_decision.html.erb:
--------------------------------------------------------------------------------
1 | <%= render "_workflow_core/transition_options/field_overridable", f: f, transition: transition, options: options %>
2 |
3 |
21 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_exclusive_choice.html.erb:
--------------------------------------------------------------------------------
1 | Exclusive choice options
2 |
3 |
4 | <%= f.label :default_next_place, class: "label" %>
5 |
6 |
7 | <%= f.collection_select :default_next_place_id, transition.output_places, :id, :id, include_blank: true %>
8 |
9 |
10 |
11 |
12 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_field_overridable.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
Field overrides
3 |
4 | <% @workflow.form.fields.each do |field| %>
5 | <% field_override = options.field_overrides.find { |r| r.name == field.name } || options.field_overrides.build(name: field.name, accessibility: field.accessibility) %>
6 | <%= f.fields_for :field_overrides, field_override do |ff| %>
7 | <%= ff.hidden_field :name %>
8 |
9 | <%= label_tag field.name, field.label, class: "label" %>
10 |
11 | <% Field.accessibilities.each do |k, _| %>
12 |
16 | <% end %>
17 |
18 |
19 | <% end %>
20 | <% end %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_workflow_core/transition_options/_user_task.html.erb:
--------------------------------------------------------------------------------
1 | <%= render "_workflow_core/transition_options/field_overridable", f: f, transition: transition, options: options %>
2 |
--------------------------------------------------------------------------------
/test/dummy/app/views/groups/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: group, local: true) do |f| %>
2 | <% if group.errors.any? %>
3 |
4 |
9 |
10 | <% group.errors.full_messages.each do |message| %>
11 |
<%= message %>
12 | <% end %>
13 |
14 |
15 | <% end %>
16 |
17 |
18 | <%= f.label :name, class: "label" %>
19 |
20 | <%= f.text_field :name, id: :user_name, class: 'input' %>
21 |
22 |
23 |
24 |
25 |
26 | <%= f.submit class: "button is-primary" %>
27 |
28 |
29 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
30 |
31 |
32 | <% end %>
33 |
--------------------------------------------------------------------------------
/test/dummy/app/views/groups/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing group
4 | <%= render "form", group: @group %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/groups/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New group", new_group_path, class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Id |
10 | Name |
11 | |
12 |
13 |
14 |
15 | <% @groups.each do |group| %>
16 |
17 | <%= group.id %> |
18 | <%= group.name %> |
19 |
20 | <%= link_to "Edit", edit_group_path(group) %> |
21 | <%= link_to "Destroy", group, method: :delete, data: {confirm: "Are you sure?"} %>
22 | |
23 |
24 | <% end %>
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/test/dummy/app/views/groups/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New group
4 | <%= render "form", group: @group %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_alert.html.erb:
--------------------------------------------------------------------------------
1 | <% return if alert.blank? %>
2 |
5 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_nav.html.erb:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_notice.html.erb:
--------------------------------------------------------------------------------
1 | <% return if notice.blank? %>
2 |
5 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Workflow Core
5 |
6 | <%= csrf_meta_tags %>
7 |
8 |
9 |
10 |
11 | <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
12 | <%= javascript_include_tag "application", "data-turbolinks-track": "reload" %>
13 |
14 |
15 | <%= render "layouts/notice" %>
16 | <%= render "layouts/alert" %>
17 | <%= render "layouts/nav" %>
18 |
19 |
20 | <%= content_for?(:content) ? yield(:content) : yield %>
21 |
22 |
23 | <%= render "layouts/footer" %>
24 |
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/workflow_instances.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :sub_content do %>
2 |
3 |
4 |
5 | <%= content_tag(:li, class: "#{"is-active" if controller_name == "instances"}") do %>
6 | <%= link_to "Payload", workflow_instance_path(@workflow, @instance) %>
7 | <% end %>
8 | <%= content_tag(:li, class: "#{"is-active" if controller_name.start_with?("tokens")}") do %>
9 | <%= link_to "Tokens", workflow_instance_tokens_path(@workflow, @instance) %>
10 | <% end %>
11 |
12 |
13 |
14 |
15 | <%= yield %>
16 | <% end %>
17 |
18 | <%= render template: "layouts/workflows" %>
19 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/workflows.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :content do %>
2 |
3 |
4 |
5 |
6 | <%= @workflow.name %>
7 |
8 |
9 | <%= @workflow.description %>
10 |
11 |
12 |
13 |
14 |
37 |
38 |
39 | <%= content_for?(:sub_content) ? yield(:sub_content) : yield %>
40 | <% end %>
41 |
42 | <%= render template: "layouts/application" %>
43 |
--------------------------------------------------------------------------------
/test/dummy/app/views/users/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: user, local: true) do |f| %>
2 | <% if user.errors.any? %>
3 |
4 |
9 |
10 | <% user.errors.full_messages.each do |message| %>
11 |
<%= message %>
12 | <% end %>
13 |
14 |
15 | <% end %>
16 |
17 |
18 | <%= f.label :name, class: "label" %>
19 |
20 | <%= f.text_field :name, id: :user_name, class: 'input' %>
21 |
22 |
23 |
24 |
25 | <%= f.label :group, class: "label" %>
26 |
27 |
28 | <%= f.collection_select :group_id, Group.all, :id, :name, include_blank: true %>
29 |
30 |
31 |
32 |
33 |
34 |
35 | <%= f.submit class: "button is-primary" %>
36 |
37 |
38 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
39 |
40 |
41 | <% end %>
42 |
--------------------------------------------------------------------------------
/test/dummy/app/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing user
4 | <%= render "form", user: @user %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New user", new_user_path, class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Id |
10 | Name |
11 | Group |
12 | |
13 |
14 |
15 |
16 | <% @users.each do |user| %>
17 |
18 | <%= user.id %> |
19 | <%= user.name %> |
20 | <%= user.group&.name %> |
21 |
22 | <% if current_user != user %>
23 | <%= link_to "Sign in", sessions_path(user_id: user.id), method: :post %> |
24 | <% end %>
25 | <%= link_to "Edit", edit_user_path(user) %> |
26 | <%= link_to "Destroy", user, method: :delete, data: {confirm: "Are you sure?"} %>
27 | |
28 |
29 | <% end %>
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/test/dummy/app/views/users/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New user
4 | <%= render "form", user: @user %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: workflow, local: true) do |f| %>
2 | <% if workflow.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% workflow.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :name, class: "label" %>
21 |
22 | <%= f.text_field :name, class: "input", placeholder: "Name" %>
23 |
24 |
25 |
26 |
27 | <%= f.label :description, class: "label" %>
28 |
29 | <%= f.text_area :description, class: "textarea", placeholder: "Description" %>
30 |
31 |
32 |
33 |
34 |
35 | <%= f.submit class: "button is-primary" %>
36 |
37 |
38 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
39 |
40 |
41 | <% end %>
42 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing workflow
4 | <%= render "form", workflow: @workflow %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: [@workflow, field.becomes(Field)], scope: :field, local: true) do |f| %>
2 | <% if field.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% field.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :name, class: "label" %>
21 |
22 | <%= f.text_field :name, class: "input", placeholder: "Name" %>
23 |
24 |
25 | The identifier of the field, the value must follow the pattern <%= Field::NAME_REGEX.source %>
and Ruby's variable naming rule.
26 |
27 |
28 |
29 |
30 | <%= f.label :label, class: "label" %>
31 |
32 | <%= f.text_field :label, class: "input", placeholder: "Label" %>
33 |
34 |
35 |
36 |
37 | <%= f.label :hint, class: "label" %>
38 |
39 | <%= f.text_field :hint, class: "input", placeholder: "Hint" %>
40 |
41 |
42 |
43 |
44 | <%= f.label :type, class: "label" %>
45 |
46 |
47 | <%= f.select :type, options_for_field_types(selected: field.class.to_s) %>
48 |
49 |
50 |
51 |
52 |
53 |
54 | <%= f.submit class: "button is-primary" %>
55 |
56 |
57 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
58 |
59 |
60 | <% end %>
61 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing field
4 | <%= render "form", field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New field", new_workflow_field_path(@workflow), class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Name |
10 | Label |
11 | Type |
12 | |
13 |
14 |
15 |
16 | <% @fields.each do |field| %>
17 |
18 | <%= field.name %> |
19 | <%= field.label %> |
20 | <%= field.class.model_name.human %> |
21 |
22 | <% if field.validations_configurable? %>
23 | <%= link_to "Validations", edit_workflow_field_validations_path(@workflow, field) %> |
24 | <% end %>
25 | <% if field.options_configurable? %>
26 | <%= link_to "Options", edit_workflow_field_options_path(@workflow, field) %> |
27 | <% end %>
28 | <% if field.attached_nested_form? %>
29 | <%= link_to "Fields", workflow_nested_form_fields_url(@workflow, field.nested_form) %> |
30 | <% end %>
31 | <%= link_to "Edit", edit_workflow_field_path(@workflow, field) %> |
32 | <%= link_to "Destroy", workflow_field_path(@workflow, field), method: :delete, data: {confirm: "Are you sure?"} %>
33 | |
34 |
35 | <% end %>
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New field
4 | <%= render "form", field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/options/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: options, scope: :options, url: workflow_field_options_path(@workflow, field), method: :patch, local: true) do |f| %>
2 | <% if options.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% options.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <%= render "_form_core/field_options/#{field.type_key}", f: f, options: options %>
20 |
21 |
22 |
23 | <%= f.submit "Update", class: 'button is-primary' %>
24 |
25 |
26 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
27 |
28 |
29 | <% end %>
30 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/options/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing options
4 | <%= render "form", field: @field, options: @options %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/validations/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: validations, scope: :validations, url: workflow_field_validations_path(@workflow, field), method: :patch, local: true) do |f| %>
2 | <% if validations.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% validations.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <% validations.class.attribute_names.each do |attribute_name| %>
20 | <%= render "_form_core/validations/#{attribute_name}", f: f, validations: validations %>
21 | <% end %>
22 | <% validations.class.reflections.keys.each do |attribute_name| %>
23 | <%= render "_form_core/validations/#{attribute_name}", f: f, validations: validations %>
24 | <% end %>
25 |
26 |
27 |
28 | <%= f.submit "Update", class: "button is-primary" %>
29 |
30 |
31 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
32 |
33 |
34 | <% end %>
35 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/fields/validations/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing validations
4 | <%= render "form", field: @field, validations: @validations %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New workflow", new_workflow_path, class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Name |
10 | Description |
11 | Updated at |
12 | |
13 |
14 |
15 |
16 | <% @workflows.each do |workflow| %>
17 |
18 | <%= workflow.name %> |
19 | <%= workflow.description %> |
20 | <%= workflow.updated_at %> |
21 |
22 | <%= link_to "Show", workflow_path(workflow) %> |
23 | <%= link_to "Edit", edit_workflow_path(workflow) %> |
24 | <%= link_to "Destroy", workflow, method: :delete, data: {confirm: "Are you sure?"} %>
25 | |
26 |
27 | <% end %>
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/instances/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New instance", new_workflow_instance_path(@workflow), class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Id |
10 | Status |
11 | Updated at |
12 | |
13 |
14 |
15 |
16 | <% @instances.each do |instance| %>
17 |
18 | <%= instance.id %> |
19 | <%= instance.status %> |
20 | <%= time_tag instance.updated_at %> |
21 |
22 | <%= link_to "Show", workflow_instance_path(@workflow, instance) %>
23 | |
24 |
25 | <% end %>
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/instances/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render "_form_core/render/form",
4 | form: @form, instance: @form_record,
5 | options: {scope: :form_record, url: workflow_instances_path(@workflow, @instance), local: true} %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/instances/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= render "_form_core/preview/form", form: @form, instance: @form_record %>
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/instances/tokens/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Id |
7 | Assignee |
8 | Status |
9 | Transition id |
10 | Transition name |
11 | Created at |
12 | |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Instance status: <%= @instance.status %>
20 | |
21 |
22 |
23 | <% @tokens.each do |token| %>
24 |
25 | <%= token.id %> |
26 | <%= token.assignable&.name %> |
27 | <%= token.status %> |
28 | <%= token.place&.output_transition&.id %> |
29 | <%= token.place&.output_transition&.name %> |
30 | <%= time_tag token.updated_at %> |
31 |
32 | <% if token.processing? && token.place&.output_transition %>
33 | <%= link_to "Fire", workflow_instance_token_path(@workflow, @instance, token) %>
34 | <% end %>
35 | |
36 |
37 | <% end %>
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/loads/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= form_with url: workflow_load_path(@workflow), method: :patch, local: true do |f| %>
4 |
5 |
6 | <%= f.text_area :bpmn_xml, class: "textarea", rows: 20 %>
7 |
8 |
9 |
10 |
11 |
12 | <%= f.file_field :bpmn_file %>
13 |
14 |
15 |
16 |
17 |
18 | <%= f.submit "Load from BPMN", class: "button is-primary" %>
19 |
20 |
21 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
22 |
23 |
24 | <% end %>
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/nested_forms/fields/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: [workflow, form, field.becomes(Field)], scope: :field, local: true) do |f| %>
2 | <% if field.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% field.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :name, class: "label" %>
21 |
22 | <%= f.text_field :name, class: "input", placeholder: "Name" %>
23 |
24 |
25 |
26 |
27 | <%= f.label :label, class: "label" %>
28 |
29 | <%= f.text_field :label, class: "input", placeholder: "Label" %>
30 |
31 |
32 |
33 |
34 | <%= f.label :hint, class: "label" %>
35 |
36 | <%= f.text_field :hint, class: "input", placeholder: "Hint" %>
37 |
38 |
39 |
40 |
41 | <%= f.label :type, class: "label" %>
42 |
43 |
44 | <%= f.select :type, options_for_field_types(selected: field.class.to_s) %>
45 |
46 |
47 |
48 |
49 |
50 |
51 | <% Field.accessibilities.each do |k, _| %>
52 |
56 | <% end %>
57 |
58 |
59 |
60 |
61 |
62 | <%= f.submit class: "button is-primary" %>
63 |
64 |
65 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
66 |
67 |
68 | <% end %>
69 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/nested_forms/fields/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing field
4 | <%= render "form", workflow: @workflow, form: @nested_form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/nested_forms/fields/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New field", new_workflow_nested_form_field_path(@workflow, @nested_form), class: "button is-primary" %>
5 | <%= link_to "Back", smart_form_fields_path(@workflow, @nested_form.attachable.form), class: "button is-link" %>
6 |
7 |
8 |
9 |
10 | Name |
11 | Label |
12 | Type |
13 | Accessibility |
14 | |
15 |
16 |
17 |
18 | <% @fields.each do |field| %>
19 |
20 | <%= field.name %> |
21 | <%= field.label %> |
22 | <%= field.class.model_name.human %> |
23 | <%= Field.human_enum_value(:accessibility, field.accessibility) %> |
24 |
25 | <% if field.validations_configurable? %>
26 | <%= link_to "Validations", edit_workflow_field_validations_path(@workflow, field) %> |
27 | <% end %>
28 | <% if field.options_configurable? %>
29 | <%= link_to "Options", edit_workflow_field_options_path(@workflow, field) %> |
30 | <% end %>
31 | <% if field.attached_nested_form? %>
32 | <%= link_to "Fields", workflow_nested_form_fields_url(@workflow, field.nested_form) %> |
33 | <% end %>
34 | <%= link_to "Edit", edit_workflow_nested_form_field_path(@workflow, @nested_form, field) %> |
35 | <%= link_to "Destroy", workflow_nested_form_field_path(@workflow, @nested_form, field), method: :delete, data: {confirm: "Are you sure?"} %>
36 | |
37 |
38 | <% end %>
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/nested_forms/fields/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New field
4 | <%= render "form", workflow: @workflow, form: @nested_form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New workflow
4 | <%= render "form", workflow: @workflow %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/show.html.erb:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: [@workflow, transition.becomes(Transition)], scope: :transition, local: true) do |f| %>
2 | <% if transition.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% transition.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :name, class: "label" %>
21 |
22 | <%= f.text_field :name, class: "input", placeholder: "Name" %>
23 |
24 |
25 |
26 |
27 | <%= f.label :type, class: "label" %>
28 |
29 |
30 | <%= f.select :type, options_for_transition_types(selected: transition.class.to_s) %>
31 |
32 |
33 |
34 |
35 |
36 |
37 | <%= f.submit class: "button is-primary" %>
38 |
39 |
40 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
41 |
42 |
43 | <% end %>
44 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing transition
4 | <%= render "form", transition: @transition %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Id |
7 | Name |
8 | Type |
9 | |
10 |
11 |
12 |
13 | <% @transitions.each do |transition| %>
14 |
15 | <%= transition.id %> |
16 | <%= transition.name %> |
17 | <%= transition.class.model_name.human %> |
18 |
19 | <% if transition.options_configurable? %>
20 | <%= link_to "Options", edit_workflow_transition_options_path(@workflow, transition) %> |
21 | <% end %>
22 | <%= link_to "Edit", edit_workflow_transition_path(@workflow, transition) %>
23 | |
24 |
25 | <% end %>
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New transition
4 | <%= render "form", transition: @transition %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/options/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: options, scope: :options, url: workflow_transition_options_path(@workflow, transition), method: :patch, local: true) do |f| %>
2 | <% if options.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% options.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <%= render "_workflow_core/transition_options/#{transition.type_key}", f: f, transition: transition, options: options %>
20 |
21 |
22 |
23 | <%= f.submit "Update", class: 'button is-primary' %>
24 |
25 |
26 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
27 |
28 |
29 | <% end %>
30 |
--------------------------------------------------------------------------------
/test/dummy/app/views/workflows/transitions/options/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing options
4 | <%= render "form", transition: @transition, options: @options %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | APP_PATH = File.expand_path("../config/application", __dir__)
5 | require_relative "../config/boot"
6 | require "rails/commands"
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require_relative "../config/boot"
5 | require "rake"
6 | Rake.application.run
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "fileutils"
5 | include FileUtils
6 |
7 | # path to your application root.
8 | APP_ROOT = File.expand_path("..", __dir__)
9 |
10 | def system!(*args)
11 | system(*args) || abort("\n== Command #{args} failed ==")
12 | end
13 |
14 | chdir APP_ROOT do
15 | # This script is a starting point to setup your application.
16 | # Add necessary setup steps to this file.
17 |
18 | puts "== Installing dependencies =="
19 | system! "gem install bundler --conservative"
20 | system("bundle check") || system!("bundle install")
21 |
22 | # Install JavaScript dependencies if using Yarn
23 | # system('bin/yarn')
24 |
25 | # puts "\n== Copying sample files =="
26 | # unless File.exist?('config/database.yml')
27 | # cp 'config/database.yml.sample', 'config/database.yml'
28 | # end
29 |
30 | puts "\n== Preparing database =="
31 | system! "bin/rails db:setup"
32 |
33 | puts "\n== Removing old logs and tempfiles =="
34 | system! "bin/rails log:clear tmp:clear"
35 |
36 | puts "\n== Restarting application server =="
37 | system! "bin/rails restart"
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "fileutils"
5 | include FileUtils
6 |
7 | # path to your application root.
8 | APP_ROOT = File.expand_path("..", __dir__)
9 |
10 | def system!(*args)
11 | system(*args) || abort("\n== Command #{args} failed ==")
12 | end
13 |
14 | chdir APP_ROOT do
15 | # This script is a way to update your development environment automatically.
16 | # Add necessary update steps to this file.
17 |
18 | puts "== Installing dependencies =="
19 | system! "gem install bundler --conservative"
20 | system("bundle check") || system!("bundle install")
21 |
22 | # Install JavaScript dependencies if using Yarn
23 | # system('bin/yarn')
24 |
25 | puts "\n== Updating database =="
26 | system! "bin/rails db:migrate"
27 |
28 | puts "\n== Removing old logs and tempfiles =="
29 | system! "bin/rails log:clear tmp:clear"
30 |
31 | puts "\n== Restarting application server =="
32 | system! "bin/rails restart"
33 | end
34 |
--------------------------------------------------------------------------------
/test/dummy/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | APP_ROOT = File.expand_path("..", __dir__)
5 | Dir.chdir(APP_ROOT) do
6 | begin
7 | exec "yarnpkg", *ARGV
8 | rescue Errno::ENOENT
9 | $stderr.puts "Yarn executable was not detected in the system."
10 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
11 | exit 1
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This file is used by Rack-based servers to start the application.
4 |
5 | require_relative "config/environment"
6 |
7 | run Rails.application
8 |
--------------------------------------------------------------------------------
/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "boot"
4 |
5 | require "rails/all"
6 |
7 | Bundler.require(*Rails.groups)
8 | require "workflow_core"
9 |
10 | Dir[Pathname.new(File.dirname(__FILE__)).realpath.parent.join("lib", "monkey_patches", "*.rb")].map do |file|
11 | require file
12 | end
13 |
14 | module Dummy
15 | class Application < Rails::Application
16 | # Initialize configuration defaults for originally generated Rails version.
17 | config.load_defaults 6.0
18 |
19 | # Settings in config/environments/* take precedence over those specified here.
20 | # Application configuration can go into files in config/initializers
21 | # -- all .rb files in that directory are automatically loaded after loading
22 | # the framework and any gems in your application.
23 |
24 | Rails.autoloaders.main.ignore(Rails.root.join("app", "overrides").to_s)
25 |
26 | config.to_prepare do
27 | Dir.glob(Rails.root + "app/decorators/**/*_decorator*.rb").each do |c|
28 | require_dependency(c)
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # tmp file for with_advisory_lock, see https://github.com/ClosureTree/with_advisory_lock/issues/3
4 | ENV["FLOCK_DIR"] ||= File.expand_path("../tmp/locks", __dir__)
5 |
6 | require "fileutils"
7 | FileUtils.mkdir_p ENV["FLOCK_DIR"]
8 |
9 | # Set up gems listed in the Gemfile.
10 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
11 |
12 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
13 | $LOAD_PATH.unshift File.expand_path("../../../lib", __dir__)
14 |
--------------------------------------------------------------------------------
/test/dummy/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: dummy_production
11 |
--------------------------------------------------------------------------------
/test/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/test/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Load the Rails application.
4 | require_relative "application"
5 |
6 | # Initialize the Rails application.
7 | Rails.application.initialize!
8 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # The test environment is used exclusively to run your application's
7 | # test suite. You never need to work with it otherwise. Remember that
8 | # your test database is "scratch space" for the test suite and is wiped
9 | # and recreated between test runs. Don't rely on the data there!
10 | config.cache_classes = true
11 |
12 | # Do not eager load code on boot. This avoids loading your whole application
13 | # just for the purpose of running a single test. If you are using a tool that
14 | # preloads Rails for running tests, you may have to set it to true.
15 | config.eager_load = false
16 |
17 | # Configure public file server for tests with Cache-Control for performance.
18 | config.public_file_server.enabled = true
19 | config.public_file_server.headers = {
20 | "Cache-Control" => "public, max-age=#{1.hour.to_i}"
21 | }
22 |
23 | # Show full error reports and disable caching.
24 | config.consider_all_requests_local = true
25 | config.action_controller.perform_caching = false
26 |
27 | # Raise exceptions instead of rendering exception templates.
28 | config.action_dispatch.show_exceptions = false
29 |
30 | # Disable request forgery protection in test environment.
31 | config.action_controller.allow_forgery_protection = false
32 |
33 | # Store uploaded files on the local file system in a temporary directory
34 | config.active_storage.service = :test
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Tell Action Mailer not to deliver emails to the real world.
39 | # The :test delivery method accumulates sent emails in the
40 | # ActionMailer::Base.deliveries array.
41 | config.action_mailer.delivery_method = :test
42 |
43 | # Print deprecation notices to the stderr.
44 | config.active_support.deprecation = :stderr
45 |
46 | # Raises error for missing translations
47 | # config.action_view.raise_on_missing_translations = true
48 | end
49 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # ActiveSupport::Reloader.to_prepare do
6 | # ApplicationController.renderer.defaults.merge!(
7 | # http_host: 'example.org',
8 | # https: false
9 | # )
10 | # end
11 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Version of your assets, change this if you want to expire all your assets.
6 | Rails.application.config.assets.version = "1.0"
7 |
8 | # Add additional assets to the asset load path.
9 | # Rails.application.config.assets.paths << Emoji.images_path
10 | # Add Yarn node_modules folder to the asset load path.
11 | Rails.application.config.assets.paths << Rails.root.join("node_modules")
12 |
13 | # Precompile additional assets.
14 | # application.js, application.css, and all non-JS/CSS in the app/assets
15 | # folder are already added.
16 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
17 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
6 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
7 |
8 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
9 | # Rails.backtrace_cleaner.remove_silencers!
10 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Define an application-wide content security policy
6 | # For further information see the following documentation
7 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
8 |
9 | # Rails.application.config.content_security_policy do |policy|
10 | # policy.default_src :self, :https
11 | # policy.font_src :self, :https, :data
12 | # policy.img_src :self, :https, :data
13 | # policy.object_src :none
14 | # policy.script_src :self, :https
15 | # policy.style_src :self, :https
16 |
17 | # # Specify URI for violation reports
18 | # # policy.report_uri "/csp-violation-report-endpoint"
19 | # end
20 |
21 | # If you are using UJS then enable automatic nonce generation
22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
23 |
24 | # Report CSP violations to a specified URI
25 | # For further information see the following documentation:
26 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
27 | # Rails.application.config.content_security_policy_report_only = true
28 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Specify a serializer for the signed and encrypted cookie jars.
6 | # Valid options are :json, :marshal, and :hybrid.
7 | Rails.application.config.action_dispatch.cookies_serializer = :json
8 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Configure sensitive parameters which will be filtered from the log file.
6 | Rails.application.config.filter_parameters += [:password]
7 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/form_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | FormCore.virtual_model_class = ::VirtualModel
4 | FormCore.virtual_model_coder_class = FormCore::HashCoder
5 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Add new inflection rules using the following format. Inflections
6 | # are locale specific, and you may define rules for as many different
7 | # locales as you wish. All of these examples are active by default:
8 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
9 | # inflect.plural /^(ox)$/i, '\1en'
10 | # inflect.singular /^(ox)en/i, '\1'
11 | # inflect.irregular 'person', 'people'
12 | # inflect.uncountable %w( fish sheep )
13 | # end
14 |
15 | # These inflection rules are supported but not enabled by default:
16 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
17 | # inflect.acronym 'RESTful'
18 | # end
19 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Add new mime types for use in respond_to blocks:
6 | # Mime::Type.register "text/richtext", :rtf
7 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # This file contains settings for ActionController::ParamsWrapper which
6 | # is enabled by default.
7 |
8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
9 | ActiveSupport.on_load(:action_controller) do
10 | wrap_parameters format: [:json]
11 | end
12 |
13 | # To enable root element in JSON for ActiveRecord objects.
14 | # ActiveSupport.on_load(:active_record) do
15 | # self.include_root_in_json = true
16 | # end
17 |
--------------------------------------------------------------------------------
/test/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | values:
34 | 'true': 'Yes'
35 | 'false': 'No'
36 |
--------------------------------------------------------------------------------
/test/dummy/config/puma.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Puma can serve each request in a thread from an internal thread pool.
4 | # The `threads` method setting takes two numbers: a minimum and maximum.
5 | # Any libraries that use thread pools should be configured to match
6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
7 | # and maximum; this matches the default thread size of Active Record.
8 | #
9 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
10 | threads threads_count, threads_count
11 |
12 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
13 | #
14 | port ENV.fetch("PORT") { 3000 }
15 |
16 | # Specifies the `environment` that Puma will run in.
17 | #
18 | environment ENV.fetch("RAILS_ENV") { "development" }
19 |
20 | # Specifies the number of `workers` to boot in clustered mode.
21 | # Workers are forked webserver processes. If using threads and workers together
22 | # the concurrency of the application would be max `threads` * `workers`.
23 | # Workers do not work on JRuby or Windows (both of which do not support
24 | # processes).
25 | #
26 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
27 |
28 | # Use the `preload_app!` method when specifying a `workers` number.
29 | # This directive tells Puma to first boot the application and load code
30 | # before forking the application. This takes advantage of Copy On Write
31 | # process behavior so workers use less memory.
32 | #
33 | # preload_app!
34 |
35 | # Allow puma to be restarted by `rails restart` command.
36 | plugin :tmp_restart
37 |
--------------------------------------------------------------------------------
/test/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.routes.draw do
4 | resources :users, except: %i[show]
5 | resources :groups, except: %i[show]
6 | resource :sessions, only: %i[create destroy]
7 |
8 | resources :workflows do
9 | scope module: :workflows do
10 | resources :fields, except: %i[show] do
11 | scope module: :fields do
12 | resource :validations, only: %i[edit update]
13 | resource :options, only: %i[edit update]
14 | end
15 | end
16 | resources :nested_forms, only: %i[] do
17 | scope module: :nested_forms do
18 | resources :fields, except: %i[show]
19 | end
20 | end
21 | resources :transitions, except: %i[show] do
22 | scope module: :transitions do
23 | resource :options, only: %i[edit update]
24 | end
25 | end
26 | resources :instances, only: %i[index show new create] do
27 | scope module: :instances do
28 | resources :tokens, only: %i[index show] do
29 | post "fire"
30 | end
31 | end
32 | end
33 |
34 | resource :load, only: %i[show update]
35 | end
36 | end
37 |
38 | root to: "workflows#index"
39 | end
40 |
--------------------------------------------------------------------------------
/test/dummy/config/spring.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | %w[
4 | .ruby-version
5 | .rbenv-vars
6 | tmp/restart.txt
7 | tmp/caching-dev.txt
8 | ].each { |path| Spring.watch(path) }
9 |
--------------------------------------------------------------------------------
/test/dummy/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916202025_create_forms.form_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This migration comes from form_core (originally 20170430190404)
4 | class CreateForms < ActiveRecord::Migration[6.0]
5 | def change
6 | create_table :forms do |t|
7 | t.string :name, null: false, index: { unique: true }
8 | t.string :type, null: false, index: true
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916202026_create_fields.form_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This migration comes from form_core (originally 20170430191336)
4 | class CreateFields < ActiveRecord::Migration[6.0]
5 | def change
6 | create_table :fields do |t|
7 | t.string :name, null: false
8 | t.integer :accessibility, null: false
9 | t.text :validations
10 | t.text :options
11 | t.string :type, null: false, index: true
12 | t.references :form, foreign_key: true
13 |
14 | t.timestamps
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916202027_add_attachable_to_forms.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddAttachableToForms < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :forms do |t|
6 | t.references :attachable, polymorphic: true, index: true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916202121_add_columns_to_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToFields < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :fields do |t|
6 | t.string :label, default: ""
7 | t.string :hint, default: ""
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916202124_add_position_to_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddPositionToFields < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :fields do |t|
6 | t.integer :position
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180916215022_add_columns_to_workflows.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToWorkflows < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflows do |t|
6 | t.references :form, foreign_key: true
7 |
8 | t.string :name, default: ""
9 | t.text :description, default: ""
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180917182517_create_groups.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateGroups < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :groups do |t|
6 | t.string :name
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180917184018_create_users.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateUsers < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :users do |t|
6 | t.string :name
7 | t.references :group, foreign_key: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180918202819_add_columns_to_transitions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToTransitions < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflow_transitions do |t|
6 | t.string :name
7 | t.string :uid
8 | t.text :options
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180918202827_add_columns_to_places.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToPlaces < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflow_places do |t|
6 | t.string :name
7 | t.string :uid
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180922095451_add_columns_to_workflow_instances.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToWorkflowInstances < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflow_instances do |t|
6 | t.string :type
7 |
8 | t.references :creator, polymorphic: true, index: true
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180922095933_add_columns_to_workflow_tokens.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToWorkflowTokens < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :workflow_tokens do |t|
6 | t.string :type
7 |
8 | t.text :payload
9 |
10 | t.references :assignable, polymorphic: true, index: true
11 | t.references :forwardable, polymorphic: true, index: true
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/lib/assets/.keep
--------------------------------------------------------------------------------
/test/dummy/lib/monkey_patches/active_support.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "active_support/concern+prependable"
4 |
--------------------------------------------------------------------------------
/test/dummy/lib/monkey_patches/active_support/concern+prependable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Cheated from https://gitlab.com/gitlab-org/gitlab-ee/blob/master/config/initializers/0_as_concern.rb
4 | # This module is based on: https://gist.github.com/bcardarella/5735987
5 |
6 | module Prependable
7 | def prepend_features(base)
8 | if base.instance_variable_defined?(:@_dependencies)
9 | base.instance_variable_get(:@_dependencies) << self
10 | false
11 | else
12 | return false if base < self
13 |
14 | super
15 | base.singleton_class.send(:prepend, const_get("ClassMethods")) if const_defined?(:ClassMethods)
16 | @_dependencies.each { |dep| base.send(:prepend, dep) }
17 | base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
18 | end
19 | end
20 | end
21 |
22 | module ActiveSupport
23 | module Concern
24 | prepend Prependable
25 |
26 | alias prepended included
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/lib/monkey_patches/big_decimal.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class BigDecimal
4 | # TODO: TEMP FIX BECAUSE SCRIPT_CORE NOT DONE YET.
5 | def to_msgpack(*args)
6 | to_f.to_msgpack(*args)
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/log/.keep
--------------------------------------------------------------------------------
/test/dummy/mruby/engine.gembox:
--------------------------------------------------------------------------------
1 | MRuby::GemBox.new do |conf|
2 | conf.gem(github: "jasl-lab/mruby-mpdecimal", branch: "master")
3 |
4 | conf.gem(core: "mruby-math")
5 | conf.gem(core: "mruby-time")
6 | conf.gem(core: "mruby-struct")
7 | conf.gem(core: "mruby-enum-ext")
8 | conf.gem(core: "mruby-string-ext")
9 | conf.gem(core: "mruby-numeric-ext")
10 | conf.gem(core: "mruby-array-ext")
11 | conf.gem(core: "mruby-hash-ext")
12 | conf.gem(core: "mruby-range-ext")
13 | conf.gem(core: "mruby-proc-ext")
14 | conf.gem(core: "mruby-symbol-ext")
15 | conf.gem(core: "mruby-object-ext")
16 | conf.gem(core: "mruby-toplevel-ext")
17 | conf.gem(core: "mruby-kernel-ext")
18 | conf.gem(core: "mruby-compiler")
19 | conf.gem(core: "mruby-metaprog")
20 | end
21 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/mruby/lib/.keep
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/core_ext.rb:
--------------------------------------------------------------------------------
1 | class FalseClass
2 | def dup
3 | self
4 | end
5 |
6 | def pack
7 | dup
8 | end
9 | end
10 |
11 | class TrueClass
12 | def dup
13 | self
14 | end
15 |
16 | def pack
17 | dup
18 | end
19 | end
20 |
21 | class Method
22 | def dup
23 | self
24 | end
25 | end
26 |
27 | class NilClass
28 | def dup
29 | self
30 | end
31 |
32 | def pack
33 | dup
34 | end
35 | end
36 |
37 | class String
38 | def pack
39 | dup
40 | end
41 | end
42 |
43 | class Numeric
44 | def dup
45 | self
46 | end
47 |
48 | def pack
49 | dup
50 | end
51 | end
52 |
53 | class Decimal
54 | def dup
55 | self
56 | end
57 |
58 | def pack
59 | to_s
60 | end
61 | end
62 |
63 | class Time
64 | class << self
65 | attr_accessor :formatted_offset
66 | end
67 |
68 | def pack
69 | "#{year}-#{month.to_s.rjust(2, "0")}-#{day.to_s.rjust(2, "0")} #{hour.to_s.rjust(2, "0")}:#{min.to_s.rjust(2, "0")}:#{sec.to_s.rjust(2, "0")} #{utc? ? "UTC" : Time.formatted_offset}".rstrip
70 | end
71 | end
72 |
73 | class Date < Time
74 | def pack
75 | "#{year}-#{month}-#{day}"
76 | end
77 | end
78 |
79 | class Symbol
80 | def dup
81 | self
82 | end
83 |
84 | def pack
85 | dup
86 | end
87 | end
88 |
89 | class Object
90 | def deep_dup
91 | dup
92 | end
93 |
94 | def pack
95 | raise NotImplementedError, "You need to implement #{self.class}#pack so that it can be output value"
96 | end
97 | end
98 |
99 | class Hash
100 | def deep_dup
101 | # Different with Shopify's
102 | each_with_object(dup) do |(key, value), hash|
103 | hash[key.deep_dup] = value.deep_dup
104 | end
105 | end
106 |
107 | def deep_pack
108 | each_with_object(dup) do |(key, value), hash|
109 | hash[key.pack] = value.pack
110 | end
111 | end
112 | alias pack deep_pack
113 | end
114 |
115 | class Array
116 | def deep_dup
117 | map(&:deep_dup)
118 | end
119 |
120 | def deep_pack
121 | map(&:pack)
122 | end
123 | alias pack deep_pack
124 | end
125 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/harden.rb:
--------------------------------------------------------------------------------
1 | Kernel.remove_method :object_id
2 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/input.rb:
--------------------------------------------------------------------------------
1 | module Input
2 | class << self
3 | def load(input)
4 | @input = input || {}
5 | @input.freeze
6 | end
7 |
8 | def value
9 | @input
10 | end
11 |
12 | def pack
13 | @input.pack
14 | end
15 |
16 | def [](key)
17 | @input[key]
18 | end
19 |
20 | def each(*args, &block)
21 | @input.each(*args, &block)
22 | end
23 |
24 | def map(*args, &block)
25 | @input.map(*args, &block)
26 | end
27 |
28 | def to_s
29 | @input.to_s
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/io.rb:
--------------------------------------------------------------------------------
1 | class << self
2 | attr_accessor :stdout_buffer
3 | end
4 |
5 | SCRIPT__TOP = self
6 | SCRIPT__TOP.stdout_buffer = ""
7 |
8 | module Kernel
9 | def puts(*args)
10 | if args.any?
11 | args.each do |arg|
12 | SCRIPT__TOP.stdout_buffer << "#{arg}\n"
13 | end
14 | else
15 | SCRIPT__TOP.stdout_buffer << "\n"
16 | end
17 |
18 | nil
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/output.rb:
--------------------------------------------------------------------------------
1 | module Output
2 | class << self
3 | attr_accessor :value
4 |
5 | def pack
6 | value.pack
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/mruby/lib/script_kernel.rb:
--------------------------------------------------------------------------------
1 | def prepare
2 | input = @input || {}
3 | remove_instance_variable "@input"
4 |
5 | configuration = input[:configuration] || {}
6 | Time.formatted_offset = configuration[:time_zone_offset] || 0
7 |
8 | Input.load input[:payload]
9 | end
10 |
11 | def pack_output
12 | instance_variable_set "@output", Output.pack
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dummy",
3 | "private": true,
4 | "dependencies": {}
5 | }
6 |
--------------------------------------------------------------------------------
/test/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/test/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/public/favicon.ico
--------------------------------------------------------------------------------
/test/dummy/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/dummy/storage/.keep
--------------------------------------------------------------------------------
/test/fixtures/workflow_core/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/fixtures/workflow_core/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/integration/.keep
--------------------------------------------------------------------------------
/test/models/workflow_core/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/workflow_core/c374337bc094dace0e41a556f1191f424949f052/test/models/workflow_core/.keep
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Configure Rails Environment
4 | ENV["RAILS_ENV"] = "test"
5 |
6 | require_relative "../test/dummy/config/environment"
7 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
8 | ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__)
9 | require "rails/test_help"
10 |
11 | # Filter out Minitest backtrace while allowing backtrace from other libraries
12 | # to be shown.
13 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new
14 |
15 | # Load fixtures from the engine
16 | if ActiveSupport::TestCase.respond_to?(:fixture_path=)
17 | ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__)
18 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
19 | ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
20 | ActiveSupport::TestCase.fixtures :all
21 | end
22 |
--------------------------------------------------------------------------------
/test/workflow_core_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | class WorkflowCore::Test < ActiveSupport::TestCase
6 | test "truth" do
7 | assert_kind_of Module, WorkflowCore
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/workflow_core.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "workflow_core/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "workflow_core"
11 | s.version = WorkflowCore::VERSION
12 | s.authors = ["jasl"]
13 | s.email = ["jasl9187@hotmail.com"]
14 | s.homepage = "https://github.com/rails-engine/workflow_core"
15 | s.summary = "A Rails engine which providing essential infrastructure of workflow. It's based on Workflow Nets."
16 | s.description = "A Rails engine which providing essential infrastructure of workflow. It's based on Workflow Nets."
17 | s.license = "MIT"
18 |
19 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
20 |
21 | s.add_dependency "rails", ">= 6.0.0.rc1", "< 7.0.0"
22 | end
23 |
--------------------------------------------------------------------------------