Full Code of hooopo/petri_flow for AI

master a36ba91c24dc cached
294 files
242.8 KB
76.4k tokens
493 symbols
1 requests
Download .txt
Showing preview only (307K chars total). Download the full file or copy to clipboard to get everything.
Repository: hooopo/petri_flow
Branch: master
Commit: a36ba91c24dc
Files: 294
Total size: 242.8 KB

Directory structure:
gitextract_22cx_jl_/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── gempush.yml
├── .gitignore
├── .rubocop.yml
├── FormSpec.md
├── Gemfile
├── Guard.md
├── LICENSE
├── MIT-LICENSE
├── README.md
├── Rakefile
├── acts_as_party.md
├── app/
│   ├── assets/
│   │   ├── config/
│   │   │   └── wf_manifest.js
│   │   ├── images/
│   │   │   └── wf/
│   │   │       └── .keep
│   │   ├── javascripts/
│   │   │   └── wf/
│   │   │       └── application.js
│   │   └── stylesheets/
│   │       └── wf/
│   │           ├── application.scss
│   │           ├── arcs.css
│   │           ├── cases.css
│   │           ├── comments.css
│   │           ├── fields.css
│   │           ├── forms.css
│   │           ├── guards.css
│   │           ├── places.css
│   │           ├── static_assignments.css
│   │           ├── transitions.css
│   │           ├── uikit/
│   │           │   ├── _colors.scss
│   │           │   ├── _variables.scss
│   │           │   ├── alert.scss
│   │           │   ├── button.scss
│   │           │   ├── card.scss
│   │           │   ├── index.scss
│   │           │   ├── navbar.scss
│   │           │   └── table.scss
│   │           ├── workflows.css
│   │           ├── workitem_assignments.css
│   │           └── workitems.css
│   ├── controllers/
│   │   └── wf/
│   │       ├── application_controller.rb
│   │       ├── arcs_controller.rb
│   │       ├── cases_controller.rb
│   │       ├── comments_controller.rb
│   │       ├── fields_controller.rb
│   │       ├── forms_controller.rb
│   │       ├── guards_controller.rb
│   │       ├── places_controller.rb
│   │       ├── static_assignments_controller.rb
│   │       ├── transitions_controller.rb
│   │       ├── workflows_controller.rb
│   │       ├── workitem_assignments_controller.rb
│   │       └── workitems_controller.rb
│   ├── helpers/
│   │   └── wf/
│   │       ├── application_helper.rb
│   │       ├── arcs_helper.rb
│   │       ├── cases_helper.rb
│   │       ├── comments_helper.rb
│   │       ├── fields_helper.rb
│   │       ├── forms_helper.rb
│   │       ├── guards_helper.rb
│   │       ├── places_helper.rb
│   │       ├── static_assignments_helper.rb
│   │       ├── transitions_helper.rb
│   │       ├── workflows_helper.rb
│   │       ├── workitem_assignments_helper.rb
│   │       └── workitems_helper.rb
│   ├── jobs/
│   │   └── wf/
│   │       ├── application_job.rb
│   │       └── fire_timed_workitem_job.rb
│   ├── mailers/
│   │   └── wf/
│   │       └── application_mailer.rb
│   ├── models/
│   │   └── wf/
│   │       ├── acts_as_party.rb
│   │       ├── application_record.rb
│   │       ├── arc.rb
│   │       ├── callbacks/
│   │       │   ├── assignment_default.rb
│   │       │   ├── deadline_default.rb
│   │       │   ├── enable_default.rb
│   │       │   ├── fire_default.rb
│   │       │   ├── hold_timeout_default.rb
│   │       │   ├── notification_default.rb
│   │       │   ├── time_default.rb
│   │       │   └── unassignment_default.rb
│   │       ├── case.rb
│   │       ├── case_assignment.rb
│   │       ├── case_command/
│   │       │   ├── add_comment.rb
│   │       │   ├── add_manual_assignment.rb
│   │       │   ├── add_token.rb
│   │       │   ├── add_workitem_assignment.rb
│   │       │   ├── begin_workitem_action.rb
│   │       │   ├── cancel.rb
│   │       │   ├── cancel_workitem.rb
│   │       │   ├── clear_manual_assignments.rb
│   │       │   ├── clear_workitem_assignments.rb
│   │       │   ├── consume_token.rb
│   │       │   ├── create_entry.rb
│   │       │   ├── enable_transitions.rb
│   │       │   ├── end_workitem_action.rb
│   │       │   ├── finish_workitem.rb
│   │       │   ├── finished_p.rb
│   │       │   ├── fire_message_transition.rb
│   │       │   ├── fire_transition_internal.rb
│   │       │   ├── lock_token.rb
│   │       │   ├── new.rb
│   │       │   ├── release_token.rb
│   │       │   ├── remove_manual_assignment.rb
│   │       │   ├── remove_workitem_assignment.rb
│   │       │   ├── resume.rb
│   │       │   ├── set_workitem_assignments.rb
│   │       │   ├── start_case.rb
│   │       │   ├── start_workitem.rb
│   │       │   ├── suspend.rb
│   │       │   ├── sweep_automatic_transitions.rb
│   │       │   ├── sweep_timed_transitions.rb
│   │       │   └── workitem_action.rb
│   │       ├── comment.rb
│   │       ├── demo_target.rb
│   │       ├── entry.rb
│   │       ├── field.rb
│   │       ├── field_value.rb
│   │       ├── form.rb
│   │       ├── group.rb
│   │       ├── guard.rb
│   │       ├── lola.rb
│   │       ├── multiple_instances/
│   │       │   └── all_finish.rb
│   │       ├── party.rb
│   │       ├── place.rb
│   │       ├── token.rb
│   │       ├── transition.rb
│   │       ├── transition_static_assignment.rb
│   │       ├── user.rb
│   │       ├── workflow.rb
│   │       ├── workitem.rb
│   │       └── workitem_assignment.rb
│   └── views/
│       ├── layouts/
│       │   └── wf/
│       │       ├── _alert.html.erb
│       │       ├── _footer.html.erb
│       │       ├── _nav.html.erb
│       │       ├── _notice.html.erb
│       │       └── application.html.erb
│       └── wf/
│           ├── arcs/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── cases/
│           │   ├── _form.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── comments/
│           │   └── new.html.erb
│           ├── fields/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── forms/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── guards/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── places/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── static_assignments/
│           │   ├── _form.html.erb
│           │   └── new.html.erb
│           ├── transitions/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── workflows/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── workitem_assignments/
│           │   └── new.html.erb
│           └── workitems/
│               ├── index.html.erb
│               ├── pre_finish.html.erb
│               └── show.html.erb
├── bin/
│   └── rails
├── config/
│   └── routes.rb
├── db/
│   └── migrate/
│       ├── 20200130201043_init.rb
│       ├── 20200130201641_init_some_data.rb
│       ├── 20200131200455_create_wf_entries.rb
│       ├── 20200201001543_add_target_field_name_for_guard.rb
│       ├── 20200212120019_remove_targetable_from_workitem.rb
│       ├── 20200213085258_add_formable.rb
│       ├── 20200213125753_add_form_id_for_entry.rb
│       ├── 20200213130900_remove_workflow_id_from_form_related.rb
│       ├── 20200220070839_remove_unused_column.rb
│       ├── 20200220072512_add_sub_workflow.rb
│       ├── 20200222150432_add_multi_instance.rb
│       └── 20200226195134_add_dynamic_assign_by.rb
├── lib/
│   ├── tasks/
│   │   └── wf_tasks.rake
│   ├── wf/
│   │   ├── engine.rb
│   │   └── version.rb
│   └── wf.rb
├── lola.md
├── screenshots/
│   └── .keep
├── test/
│   ├── controllers/
│   │   └── wf/
│   │       ├── arcs_controller_test.rb
│   │       ├── cases_controller_test.rb
│   │       ├── comments_controller_test.rb
│   │       ├── fields_controller_test.rb
│   │       ├── forms_controller_test.rb
│   │       ├── guards_controller_test.rb
│   │       ├── places_controller_test.rb
│   │       ├── static_assignments_controller_test.rb
│   │       ├── transitions_controller_test.rb
│   │       ├── workflows_controller_test.rb
│   │       ├── workitem_assignments_controller_test.rb
│   │       └── workitems_controller_test.rb
│   ├── dummy/
│   │   ├── .ruby-version
│   │   ├── Rakefile
│   │   ├── app/
│   │   │   ├── assets/
│   │   │   │   ├── config/
│   │   │   │   │   └── manifest.js
│   │   │   │   ├── images/
│   │   │   │   │   └── .keep
│   │   │   │   └── stylesheets/
│   │   │   │       └── application.css
│   │   │   ├── channels/
│   │   │   │   └── application_cable/
│   │   │   │       ├── channel.rb
│   │   │   │       └── connection.rb
│   │   │   ├── controllers/
│   │   │   │   ├── application_controller.rb
│   │   │   │   └── concerns/
│   │   │   │       └── .keep
│   │   │   ├── helpers/
│   │   │   │   └── application_helper.rb
│   │   │   ├── javascript/
│   │   │   │   └── packs/
│   │   │   │       └── application.js
│   │   │   ├── jobs/
│   │   │   │   └── application_job.rb
│   │   │   ├── mailers/
│   │   │   │   └── application_mailer.rb
│   │   │   ├── models/
│   │   │   │   ├── application_record.rb
│   │   │   │   ├── concerns/
│   │   │   │   │   └── .keep
│   │   │   │   ├── entry.rb
│   │   │   │   ├── field.rb
│   │   │   │   ├── field_value.rb
│   │   │   │   └── form.rb
│   │   │   └── views/
│   │   │       └── layouts/
│   │   │           ├── application.html.erb
│   │   │           ├── mailer.html.erb
│   │   │           └── mailer.text.erb
│   │   ├── bin/
│   │   │   ├── rails
│   │   │   ├── rake
│   │   │   └── setup
│   │   ├── 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
│   │   │   │   ├── inflections.rb
│   │   │   │   ├── mime_types.rb
│   │   │   │   ├── my_assignment_callback.rb
│   │   │   │   ├── wf_config.rb
│   │   │   │   └── wrap_parameters.rb
│   │   │   ├── locales/
│   │   │   │   └── en.yml
│   │   │   ├── mysql_database.yml
│   │   │   ├── puma.rb
│   │   │   ├── routes.rb
│   │   │   ├── spring.rb
│   │   │   └── storage.yml
│   │   ├── config.ru
│   │   ├── db/
│   │   │   ├── migrate/
│   │   │   │   ├── 20200213081814_new_form.rb
│   │   │   │   ├── 20200213133942_add_form_id_in_entry1.rb
│   │   │   │   └── 20200214005535_add_entry_id_for_field_values1.rb
│   │   │   ├── schema.rb
│   │   │   └── seeds.rb
│   │   ├── lib/
│   │   │   └── assets/
│   │   │       └── .keep
│   │   ├── log/
│   │   │   └── .keep
│   │   ├── public/
│   │   │   ├── 404.html
│   │   │   ├── 422.html
│   │   │   └── 500.html
│   │   └── storage/
│   │       └── .keep
│   ├── fixtures/
│   │   └── wf/
│   │       ├── case_assignments.yml
│   │       ├── comments.yml
│   │       ├── demo_targets.yml
│   │       ├── entries.yml
│   │       ├── field_values.yml
│   │       ├── fields.yml
│   │       ├── forms.yml
│   │       ├── guards.yml
│   │       ├── parties.yml
│   │       ├── transition_static_assignments.yml
│   │       ├── users.yml
│   │       └── workitem_assignments.yml
│   ├── integration/
│   │   └── navigation_test.rb
│   ├── models/
│   │   └── wf/
│   │       ├── case_assignment_test.rb
│   │       ├── comment_test.rb
│   │       ├── demo_target_test.rb
│   │       ├── entry_test.rb
│   │       ├── field_test.rb
│   │       ├── field_value_test.rb
│   │       ├── form_test.rb
│   │       ├── guard_test.rb
│   │       ├── party_test.rb
│   │       ├── transition_static_assignment_test.rb
│   │       ├── user_test.rb
│   │       ├── wf_test.rb
│   │       └── workitem_assignment_test.rb
│   └── test_helper.rb
└── wf.gemspec

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

root = true

[*]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
end_of_line = lf


================================================
FILE: .gitattributes
================================================
*.rb diff=ruby
*.gemspec diff=ruby



================================================
FILE: .github/workflows/ci.yml
================================================
name: Testing

on: [push, pull_request]

jobs:
  build:

    runs-on: ubuntu-latest

    services:
      db:
        image: postgres:11
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: postgres
        ports: ['5432:5432']
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby 2.6
      uses: actions/setup-ruby@v1
      with:
        ruby-version: "2.6"
    - name: Build and test with Rake
      env:
        DATABASE_URL: "postgresql://postgres:postgres@127.0.0.1:5432/postgres"
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: postgres
        POSTGRES_DB: postgres
        RAILS_ENV: test
      run: |
        sudo apt-get -yqq install libpq-dev
        sudo apt-get install libmysqlclient-dev
        sudo apt-get install graphviz
        gem install bundler
        bundle install --jobs 4 --retry 3
        bundle exec rake app:wf
        bundle exec rails app:db:create && bundle exec rails app:db:migrate  && bundle exec rails test


================================================
FILE: .github/workflows/gempush.yml
================================================
name: Ruby Gem

on:
  push:
    tags:
      - v*

jobs:
  build:
    name: Build + Publish
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby 2.6
      uses: actions/setup-ruby@v1
      with:
        ruby-version: "2.6.x"

    - name: Publish to RubyGems
      run: |
        mkdir -p $HOME/.gem
        touch $HOME/.gem/credentials
        chmod 0600 $HOME/.gem/credentials
        printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
        gem build *.gemspec
        gem push *.gem
      env:
        GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
#   git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config.
/.idea
.bundle/

# Ignore the default SQLite database.
test/dummy/db/*.sqlite3
test/dummy/db/*.sqlite3-journal

# Ignore all logfiles and tempfiles.
log/*.log
!test/dummy/log/.keep
!test/dummy/tmp/.keep
test/dummy/log/*.log
test/dummy/tmp/

# Ignore uploaded files in development
test/dummy/storage/*
!test/dummy/storage/.keep

# Ignore compiled mruby in dummy app
/test/dummy/mruby/bin

pkg/
.byebug_history

node_modules/
test/dummy/public/packs
test/dummy/node_modules/
yarn-error.log

*.gem

.env


================================================
FILE: .rubocop.yml
================================================
require:
  - rubocop-performance
  - rubocop-rails

AllCops:
  TargetRubyVersion: 2.5
  Exclude:
    - bin/**/*
    - test/dummy/bin/**/*
    - test/dummy/db/schema.rb

Rails:
  Enabled: true

Layout/LineLength:
  Max: 150

Metrics/MethodLength:
  Max: 100

Metrics/BlockLength:
  Max: 50

Metrics/ClassLength:
  Enabled: false

Style/GuardClause:
  Enabled: false

Style/Documentation:
  Enabled: false

Style/ClassAndModuleChildren:
  Enabled: false

Naming/AccessorMethodName:
  Enabled: false

Naming/MemoizedInstanceVariableName:
  Enabled: false

# Prefer assert_not over assert !
Rails/AssertNot:
  Include:
    - 'test/**/*'

# Prefer assert_not_x over refute_x
Rails/RefuteMethods:
  Include:
    - 'test/**/*'

# Prefer &&/|| over and/or.
Style/AndOr:
  Enabled: true

# Do not use braces for hash literals when they are the last argument of a
# method call.
Style/BracesAroundHashParameters:
  Enabled: true
  EnforcedStyle: context_dependent

# Align `when` with `case`.
Layout/CaseIndentation:
  Enabled: true

# Align comments with method definitions.
Layout/CommentIndentation:
  Enabled: true

Layout/ElseAlignment:
  Enabled: true

# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Layout/EndAlignment:
  Enabled: true
  EnforcedStyleAlignWith: variable
  AutoCorrect: true

Layout/EmptyLineAfterMagicComment:
  Enabled: true

Layout/EmptyLinesAroundBlockBody:
  Enabled: true

# In a regular class definition, no empty lines around the body.
Layout/EmptyLinesAroundClassBody:
  Enabled: true

# In a regular method definition, no empty lines around the body.
Layout/EmptyLinesAroundMethodBody:
  Enabled: true

# In a regular module definition, no empty lines around the body.
Layout/EmptyLinesAroundModuleBody:
  Enabled: true

Layout/FirstArgumentIndentation:
  Enabled: true

# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
  Enabled: true

# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Layout/IndentationConsistency:
  Enabled: true
  EnforcedStyle: indented_internal_methods

# Two spaces, no tabs (for indentation).
Layout/IndentationWidth:
  Enabled: true

Layout/LeadingCommentSpace:
  Enabled: true

Layout/SpaceAfterColon:
  Enabled: true

Layout/SpaceAfterComma:
  Enabled: true

Layout/SpaceAfterSemicolon:
  Enabled: true

Layout/SpaceAroundEqualsInParameterDefault:
  Enabled: true

Layout/SpaceAroundKeyword:
  Enabled: true

Layout/SpaceAroundOperators:
  Enabled: true

Layout/SpaceBeforeComma:
  Enabled: true

Layout/SpaceBeforeFirstArg:
  Enabled: true

Style/DefWithParentheses:
  Enabled: true

# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
  Enabled: true

Style/FrozenStringLiteralComment:
  Enabled: true
  EnforcedStyle: always

Style/RedundantFreeze:
  Enabled: true

# Use `foo {}` not `foo{}`.
Layout/SpaceBeforeBlockBraces:
  Enabled: true

# Use `foo { bar }` not `foo {bar}`.
Layout/SpaceInsideBlockBraces:
  Enabled: true
  EnforcedStyleForEmptyBraces: space

# Use `{ a: 1 }` not `{a:1}`.
Layout/SpaceInsideHashLiteralBraces:
  Enabled: true

Layout/SpaceInsideParens:
  Enabled: true

# Check quotes usage according to lint rule below.
Style/StringLiterals:
  Enabled: true
  EnforcedStyle: double_quotes

# Detect hard tabs, no hard tabs.
Layout/Tab:
  Enabled: true

# Blank lines should not have any spaces.
Layout/TrailingEmptyLines:
  Enabled: true

# No trailing whitespace.
Layout/TrailingWhitespace:
  Enabled: true

# Use quotes for string literals when they are enough.
Style/RedundantPercentQ:
  Enabled: true

Lint/AmbiguousOperator:
  Enabled: true

Lint/AmbiguousRegexpLiteral:
  Enabled: true

Lint/ErbNewArguments:
  Enabled: true

# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
  Enabled: true

Lint/ShadowingOuterLocalVariable:
  Enabled: true

Lint/RedundantStringCoercion:
  Enabled: true

Lint/UriEscapeUnescape:
  Enabled: true

Lint/UselessAssignment:
  Enabled: true

Lint/DeprecatedClassMethods:
  Enabled: true

Style/ParenthesesAroundCondition:
  Enabled: true

Style/RedundantBegin:
  Enabled: true

Style/RedundantReturn:
  Enabled: true
  AllowMultipleReturnValues: true

Style/Semicolon:
  Enabled: true
  AllowAsExpressionSeparator: true

# Prefer Foo.method over Foo::method
Style/ColonMethodCall:
  Enabled: true

Style/TrivialAccessors:
  Enabled: true

Performance/FlatMap:
  Enabled: true

Performance/RedundantMerge:
  Enabled: true

Performance/StartWith:
  Enabled: true

Performance/EndWith:
  Enabled: true

Performance/RegexpMatch:
  Enabled: true

Performance/ReverseEach:
  Enabled: true

Performance/UnfreezeString:
  Enabled: true


================================================
FILE: FormSpec.md
================================================
## Why

The core of Petri Flow is the workflow engine. 
However, workflow, dynamic forms, and organization systems are inseparable. Therefore, petri flow provides simple built-in dynamic form functions, but in practice dynamic forms require more complex features. 
Such as selecting data from other data sources, data validation, application-oriented data fields, UI customization, etc. 
Petri Flow abstracts the interface needed to integrate with dynamic forms, in order to integrate more complex dynamic forms systems, such as [form core](https://github.com/rails-engine/form_core).

## Core Entity

* Form
* Field
* Entry
* FieldValue

## Relations

* form has_many fields
* form has_many entries

* field belongs_to form

* field_value belongs_to form
* field_value belongs_to field
* field_value belongs_to entry

* entry belongs_to form
* entry belongs_to user
* entry belongs_to workitem
* entry has_many field_values

## Casting

* Field#cast(value)
* FieldValue#value_after_cast

## Setting

```ruby
# config/initializers/wf_config.rb
Wf.user_class   = "::Wf::User"
WF.form_class   = "::Form"
Wf.entry_class  = "::Entry"
Wf.field_class  = "::Field"
```


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

# Declare your gem's dependencies in wf.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec

# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.

# To use a debugger
# gem 'byebug', group: [:development, :test]
gem "annotate"
gem "bootstrap", "~> 4.4.1"
gem "bootstrap4-kaminari-views"
gem "jquery-rails"
gem "kaminari"
gem "pg"
gem "pry-rails"
gem "simple_command"

gem "loaf"
gem "mysql2"
gem "rubocop"
gem "rubocop-performance"
gem "rubocop-rails"
gem "ruby-graphviz", require: "graphviz"


================================================
FILE: Guard.md
================================================
## Guard Expression

There are two per-defined variables for your guard expression, `workitem`, `target`.

Schema for `workitem`:

```json
{
  "id":1,
  "case_id":1,
  "workflow_id":10,
  "transition_id":24,
  "state":"enabled",
  "enabled_at":"2020-02-24T12:37:28.459Z",
  "started_at":null,
  "canceled_at":null,
  "finished_at":null,
  "overridden_at":null,
  "deadline":null,
  "created_at":"2020-02-24T12:37:28.601Z",
  "updated_at":"2020-02-24T12:37:28.601Z",
  "trigger_time":null,
  "holding_user_id":null,
  "children_count":3,
  "children_finished_count":1,
  "forked":false,
  "parent_id":null,
  "holding_user":{

  },
  "form":{

  },
  "children":[
    {
      "id":3,
      "case_id":1,
      "workflow_id":10,
      "transition_id":24,
      "state":"enabled",
      "enabled_at":"2020-02-24T12:37:28.459Z",
      "started_at":null,
      "canceled_at":null,
      "finished_at":null,
      "overridden_at":null,
      "deadline":null,
      "created_at":"2020-02-24T12:37:28.757Z",
      "updated_at":"2020-02-24T12:37:28.757Z",
      "trigger_time":null,
      "holding_user_id":"7",
      "children_count":0,
      "children_finished_count":0,
      "forked":true,
      "parent_id":1,
      "holding_user":{
        "id":7,
        "name":"User6",
        "created_at":"2020-02-24T12:36:46.994Z",
        "updated_at":"2020-02-24T12:36:46.994Z",
        "group_id":2
      },
      "form":{

      },
      "children":[

      ]
    },
    {
      "id":4,
      "case_id":1,
      "workflow_id":10,
      "transition_id":24,
      "state":"enabled",
      "enabled_at":"2020-02-24T12:37:28.459Z",
      "started_at":null,
      "canceled_at":null,
      "finished_at":null,
      "overridden_at":null,
      "deadline":null,
      "created_at":"2020-02-24T12:37:28.788Z",
      "updated_at":"2020-02-24T12:37:28.788Z",
      "trigger_time":null,
      "holding_user_id":"5",
      "children_count":0,
      "children_finished_count":0,
      "forked":true,
      "parent_id":1,
      "holding_user":{
        "id":5,
        "name":"User4",
        "created_at":"2020-02-24T12:36:46.984Z",
        "updated_at":"2020-02-24T12:36:46.984Z",
        "group_id":1
      },
      "form":{

      },
      "children":[

      ]
    },
    {
      "id":2,
      "case_id":1,
      "workflow_id":10,
      "transition_id":24,
      "state":"finished",
      "enabled_at":"2020-02-24T12:37:28.459Z",
      "started_at":null,
      "canceled_at":null,
      "finished_at":"2020-02-24T12:37:46.221Z",
      "overridden_at":null,
      "deadline":null,
      "created_at":"2020-02-24T12:37:28.700Z",
      "updated_at":"2020-02-24T12:37:46.232Z",
      "trigger_time":null,
      "holding_user_id":"1",
      "children_count":0,
      "children_finished_count":0,
      "forked":true,
      "parent_id":1,
      "holding_user":{
        "id":1,
        "name":"User0",
        "created_at":"2020-02-24T12:36:46.963Z",
        "updated_at":"2020-02-24T12:36:46.963Z",
        "group_id":4
      },
      "form":{
        "score":90
      },
      "children":[

      ]
    }
  ]
}
```

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Hooopo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: MIT-LICENSE
================================================
Copyright 2020 Hooopo Wang

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# Petri Flow ![Ruby Gem](https://github.com/hooopo/petri_flow/workflows/Ruby%20Gem/badge.svg?event=push) ![Testing](https://github.com/hooopo/petri_flow/workflows/Testing/badge.svg?event=push)

Workflow engine for Rails.

## Features
* Full petri net features support (seq, parallel, iterative, timed, automitic etc.)
* Both approval workflow and business workflow.
* Simple web admin for workflow definition and case management.
* Build-in simple dynamic form.
* Replaceable dynamic form.
* Support sub workflow.
* Graph screen for workflow definition.
* Graph screen for case and token migration.
* Powerful guard expression.
* MySQL and Postgres Support.
* Powerful assignment management.
* Flexible integration of organizational structure system(role, group, position or department etc.)

## Docs

* [Petri-Nets and Workflows](https://hooopo.gitbook.io/petri-flow/)
* [Workflow Conceptual Guide](https://hooopo.gitbook.io/petri-flow/workflow-conceptual-guide)
* [Workflow Concepts Reference](https://hooopo.gitbook.io/petri-flow/workflow-concepts-reference)
* [Petri Flow ERD](https://hooopo.gitbook.io/petri-flow/erd)
* [Developer Doc](https://hooopo.gitbook.io/petri-flow/developer-document)

## Screenshots

###  iterative routing

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-M-GhlU_QaD6nbLAbaJI%2F-M-X0nIxUUBwJsNhY4FN%2F-M-XAAQJbxDdaxoaYVda%2Fimage.png?alt=media&token=e74d1ae7-fa16-47ab-83b5-ad73a382fa07)

### parallel_routing

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-M-GhlU_QaD6nbLAbaJI%2F-M-X0nIxUUBwJsNhY4FN%2F-M-XAKm9VN1MJxPZT9Xe%2Fimage.png?alt=media&token=c8beba84-72ec-470f-9987-81cf40762e15)

### guard

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-M-GhlU_QaD6nbLAbaJI%2F-M-X0nIxUUBwJsNhY4FN%2F-M-XAT8Ui_xjqy9Niccp%2Fimage.png?alt=media&token=de4298fb-14b9-40bc-ab75-92ef0b98a533)

### case state graph

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-M-GhlU_QaD6nbLAbaJI%2F-M-X0nIxUUBwJsNhY4FN%2F-M-XAeeR42ZRVIVKuUae%2Fimage.png?alt=media&token=90c96af9-d01f-4d6e-ae2b-445ea343a5ac)

### 
## Installation
Add this line to your application's Gemfile:

```ruby
gem 'petri_flow', require: 'wf'
```

And then execute:

```bash
$ bundle
```

Install graphviz

```
brew install graphviz
```

Migration:

```
bundle exec rake wf:install:migrations
bundle exec rails db:create
bundle exec rails db:migrate
bundle exec rails db:seed
```
## Usage

Add wf_config:

```ruby
# config/initializers/wf_config.rb
Wf.user_class = "::User"
Wf.org_classes = { group: "::Group" }
```

Set parties:

For normal org model, for example group or role etc.

```ruby
module Wf
  class Group < ApplicationRecord
    has_many :users 
    include Wf::ActsAsParty
    acts_as_party(user: false, party_name: :name)
  end
end
```

For user model:

```ruby
module Wf
  class User < ApplicationRecord
    belongs_to :group, optional: true
    include Wf::ActsAsParty
    acts_as_party(user: true, party_name: :name)
  end
end
```

then

```
bundle exec rails 
```

visit:

```
http://localhost:3000/wf
```

## Testing

* RAILS_ENV=test rake app:db:migrate && RAILS_ENV=test rake app:db:test:prepare && bundle exec rake test

## Contributing
Contribution directions go here.

## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).


================================================
FILE: Rakefile
================================================
# frozen_string_literal: true

begin
  require "bundler/setup"
rescue LoadError
  puts "You must `gem install bundler` and `bundle install` to run rake tasks"
end

require "rdoc/task"

RDoc::Task.new(:rdoc) do |rdoc|
  rdoc.rdoc_dir = "rdoc"
  rdoc.title    = "Wf"
  rdoc.options << "--line-numbers"
  rdoc.rdoc_files.include("README.md")
  rdoc.rdoc_files.include("lib/**/*.rb")
end

APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
load "rails/tasks/engine.rake"

load "rails/tasks/statistics.rake"

require "bundler/gem_tasks"

require "rake/testtask"

Rake::TestTask.new(:test) do |t|
  t.libs << "test"
  t.pattern = "test/**/*_test.rb"
  t.verbose = false
end

task default: :test


================================================
FILE: acts_as_party.md
================================================
## Usage


for normal org model, for example group or role etc.

```ruby
module Wf
  class Group < ApplicationRecord
    has_many :users 
    include Wf::ActsAsParty
    acts_as_party(user: false, party_name: :name)
  end
end
```

for user model:

```ruby
module Wf
  class User < ApplicationRecord
    belongs_to :group, optional: true
    include Wf::ActsAsParty
    acts_as_party(user: true, party_name: :name)
  end
end
```

================================================
FILE: app/assets/config/wf_manifest.js
================================================
//= link_directory ../stylesheets/wf .css
//= link_directory ../javascripts/wf .js


================================================
FILE: app/assets/images/wf/.keep
================================================


================================================
FILE: app/assets/javascripts/wf/application.js
================================================
//= require jquery3
//= require popper
//= require bootstrap
//= require rails-ujs
//= require select2-full


================================================
FILE: app/assets/stylesheets/wf/application.scss
================================================
/*
*= require select2
*= require select2-bootstrap4
*/

@import "uikit/index";

main{
  min-height: 80vh;
  h2 {
    margin-bottom: 1rem;
  }
}

.footer{
  text-align: center;
  .container{
    border-top: 1px solid rgb(245, 239, 228);
    padding-top: 1rem;
  }
  a{
    color: $gray-10;
  }
}


================================================
FILE: app/assets/stylesheets/wf/arcs.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/cases.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/comments.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/fields.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/forms.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/guards.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/places.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/static_assignments.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/transitions.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/uikit/_colors.scss
================================================
// fork from: https://github.com/oortcast/42page/blob/master/app/javascript/42design/
//
// inspired by https://github.com/ant-design/ant-design
//
// The [colorPalette] means that the color is
// generated by https://ant.design/docs/spec/colors#Palette-Generation-Tool

// Brand Color
$pagegreen-base: #00d192;
$pagegreen-1: #f6fdfb; // tint background color
$pagegreen-2: #cff5e8; // background color
$pagegreen-3: #77f7c4; // [colorPalette]
$pagegreen-4: #4bebb0; // [colorPalette]
$pagegreen-5: #20CF97; // hover
$pagegreen-6: $pagegreen-base; // normal
$pagegreen-7: #00ab74; // click
$pagegreen-8: #008566; // [colorPalette]
$pagegreen-9: #005e4b; // [colorPalette]
$pagegreen-10: #00382f; // [colorPalette]

// Neutral Color
$gray-1: #fff;
$gray-2: #f7f7f7; //
$gray-3: #f1f1f2; // table header
$gray-4: #d2d3d4; // disable background
$gray-5: #92989c; // border
$gray-6: #868b8f; // disable text
$gray-7: #7a7e81; // secondary text
$gray-8: #53585c;
$gray-9: #23292f; // primary text
$gray-10: #000; // title

// Color Palette

$red-base: #fa4a4a;
$red-1: #fff2f0; // [colorPalette]
$red-2: #fff2f0;
$red-3: #ffcdc7; // [colorPalette]
$red-4: #ffa59e; // [colorPalette]
$red-5: #ff7a75; // [colorPalette]
$red-6: $red-base;
$red-7: #d4353a; // [colorPalette]
$red-8: #ad232c; // [colorPalette]
$red-9: #871420; // [colorPalette]
$red-10: #610e19; // [colorPalette]

$yellow-base: #F9C84A;
$yellow-1: #fffdf0; // [colorPalette]
$yellow-2: #FFF3E0;
$yellow-3: #fff5c7; // [colorPalette]
$yellow-4: #ffea9e; // [colorPalette]
$yellow-5: #ffdd75; // mark
$yellow-6: $yellow-base;
$yellow-7: #d4a135; // [colorPalette]
$yellow-8: #ad7d23; // [colorPalette]
$yellow-9: #875b14; // [colorPalette]
$yellow-10: #613e0e; // [colorPalette]

$blue-base: #3d90eb;
$blue-1: #f0faff; // [colorPalette]
$blue-2: #e6f5ff;
$blue-3: #bde3ff; // [colorPalette]
$blue-4: #94cfff; // [colorPalette]
$blue-5: #68b2f7; // [colorPalette]
$blue-6: $blue-base;
$blue-7: #296fc4; // [colorPalette]
$blue-8: #19519e; // [colorPalette]
$blue-9: #0d3678; // [colorPalette]
$blue-10: #082252; // [colorPalette]

$cyan-base: #01C1B2;
$cyan-1: #e6fff9; // [colorPalette]
$cyan-2: #E3FFF8;
$cyan-3: #72e8d2; // [colorPalette]
$cyan-4: #48dbc5; // [colorPalette]
$cyan-5: #23cfbb; // [colorPalette]
$cyan-6: $cyan-base;
$cyan-7: #009c94; // [colorPalette]
$cyan-8: #007573; // [colorPalette]
$cyan-9: #004e4f; // [colorPalette]
$cyan-10: #002729; // [colorPalette]


================================================
FILE: app/assets/stylesheets/wf/uikit/_variables.scss
================================================
@import "colors";
@import "bootstrap/functions";
$blue:    $blue-base;
$red:     $red-base;
$yellow:  $yellow-base;
$green:   $pagegreen-base;
$cyan:    $cyan-base;
$primary: $green;

$gray-100: $gray-1;
$gray-200: $gray-2;
$gray-300: $gray-3; // table header
$gray-400: $gray-4; // disable background
$gray-500: $gray-5; // border
$gray-600: $gray-6; // disable text
$gray-700: $gray-7; // secondary text
$gray-800: $gray-8;
$gray-900: $gray-9; // primary text
$secondary: $gray-7;

$body-bg: #fffefd;

$link-color:                              $primary;
$link-hover-color:                        $pagegreen-5;

$font-family-sans-serif: system, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol";
$font-family-monospace: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;

$line-height-base:            1.6;

@import "bootstrap/variables";



================================================
FILE: app/assets/stylesheets/wf/uikit/alert.scss
================================================
@import "variables";

.alert{
  margin-bottom: 2rem;
  p{
    margin-bottom: 0;
  }

  &.alert-success{
    background: $pagegreen-1;
    border-color: $pagegreen-4;
    color: $gray-9;
  }
  &.alert-warning{
    background: $red-1;
    border-color: $red-5;
    color: $gray-9;
  }
}


================================================
FILE: app/assets/stylesheets/wf/uikit/button.scss
================================================
@import "_variables";

.btn-light{
  color: $gray-8;
  background: rgba(94, 94, 94, 0.2);
  border: rgb(94,94,94);
}


================================================
FILE: app/assets/stylesheets/wf/uikit/card.scss
================================================
.card{
  margin-bottom: 4rem;
  border: 1px solid rgba(230, 230, 230, 0.41);
  border-radius: 0.625rem;
  box-shadow: 0 2px 6px 0 rgba(0,0,0,0.05);
}


================================================
FILE: app/assets/stylesheets/wf/uikit/index.scss
================================================
@import "_variables";
@import "bootstrap";

//overwrite
@import "navbar";
@import "table";
@import "card";
@import "alert";
@import "button";


================================================
FILE: app/assets/stylesheets/wf/uikit/navbar.scss
================================================
@import "variables";

.navbar-petri{
  box-shadow: 0 12px 24px 0 rgba(0,0,0,0.05);
  margin-bottom: 2rem;
  background: $white;
  .navbar-brand a{
    color: $gray-9;
    &:hover{
      text-decoration: none;
      color: $gray-10;
    }
  }
  .navbar-end a{
    color: #7b7f82;
    margin: 0 20px;
    font-size: 18px;
    border-bottom: transparent solid 2px;
    &:hover{
      color: $gray-9;
      text-decoration: none;
    }
    &.is-active{
      color: $gray-9;
      border-bottom: $primary solid 2px;
    }
  }
}


================================================
FILE: app/assets/stylesheets/wf/uikit/table.scss
================================================
@import "variables";

.table-view{
  thead th{
    color: $gray-7;
    font-weight: 500;
    border-top: 0;
    border-bottom-width: 1px;
    border-color: $gray-3;
  }
  tbody tr:hover {
    background-color: $gray-2;
  }
  tbody td a:not(.btn) {
    color: $gray-10;
  }
}


================================================
FILE: app/assets/stylesheets/wf/workflows.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/workitem_assignments.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/assets/stylesheets/wf/workitems.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: app/controllers/wf/application_controller.rb
================================================
# frozen_string_literal: true

module Wf
  class ApplicationController < ::ApplicationController
    protect_from_forgery with: :exception
    helper_method :wf_current_user

    breadcrumb "Home", :root_path

    def wf_current_user
      current_user
    end
  end
end


================================================
FILE: app/controllers/wf/arcs_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class ArcsController < ApplicationController
    breadcrumb "Workflows", :workflows_path

    def new
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.new
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def create
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.new(arc_params)
      if @arc.save
        redirect_to workflow_path(@workflow), notice: "arc was successfully created."
      else
        render :new
      end
    end

    def destroy
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.find(params[:id])
      @arc.destroy
      render js: "window.location.reload()"
    end

    def show
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def edit
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
      breadcrumb @arc.name, workflow_arc_path(@workflow, @arc)
    end

    def update
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @arc = @workflow.arcs.find(params[:id])
      if @arc.update(arc_params)
        redirect_to workflow_path(@workflow), notice: "arc was successfully created."
      else
        render :edit
      end
    end

    private

      def arc_params
        params.fetch(:arc, {}).permit(:direction, :transition_id, :place_id)
      end
  end
end


================================================
FILE: app/controllers/wf/cases_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class CasesController < ApplicationController
    breadcrumb "Workflows", :workflows_path
    def new
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @wf_case = @workflow.cases.new
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def create
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @wf_case = Wf::CaseCommand::New.call(@workflow, GlobalID::Locator.locate(case_params[:targetable])).result
      Wf::CaseCommand::StartCase.call(@wf_case)
      redirect_to workflow_cases_path(@workflow), notice: "case created."
    end

    def index
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @cases = @workflow.cases.order("id DESC")
      @cases = @cases.where(state: params[:state].intern) if params[:state].present?
      @cases = @cases.page(params[:page])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def show
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @wf_case = @workflow.cases.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def destroy
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @case = @workflow.cases.find(params[:id])
      @case.destroy
      render js: "window.location.reload()"
    end

    private

      def case_params
        params.fetch(:case, {}).permit(:targetable, :target_id, :target_type)
      end
  end
end


================================================
FILE: app/controllers/wf/comments_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class CommentsController < ApplicationController
    breadcrumb "Workflows", :workflows_path

    def new
      @workitem = Wf::Workitem.find(params[:workitem_id])
      @comment = @workitem.comments.new
      breadcrumb @workitem.workflow.name, workflow_path(@workitem.workflow)
      breadcrumb @workitem.case.name, workflow_case_path(@workitem.workflow, @workitem.case)
      breadcrumb @workitem.name, workitem_path(@workitem)
    end

    def create
      @workitem = Wf::Workitem.find(params[:workitem_id])
      Wf::CaseCommand::AddComment.call(@workitem, params[:comment][:body], wf_current_user)
      redirect_to workitem_path(@workitem), notice: "Comment Added."
    end

    def destroy
      @workitem = Wf::Workitem.find(params[:workitem_id])
      @comment = @workitem.comments.find(params[:id])
      @comment.destroy
      render js: "window.location.reload()"
    end
  end
end


================================================
FILE: app/controllers/wf/fields_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class FieldsController < ApplicationController
    breadcrumb "Forms", :forms_path

    def new
      @form = Wf::Form.find(params[:form_id])
      @field = @form.fields.new
      breadcrumb @form.name, form_path(@form)
    end

    def create
      @form = Wf::Form.find(params[:form_id])
      @field = @form.fields.new(field_params)
      if @field.save
        redirect_to form_path(@form), notice: "field was successfully created."
      else
        render :new
      end
    end

    def destroy
      @form = Wf::Form.find(params[:form_id])
      @field = @form.fields.find(params[:id])
      @field.destroy
      render js: "window.location.reload()"
    end

    def edit
      @form = Wf::Form.find(params[:form_id])
      @field = @form.fields.find(params[:id])
      breadcrumb @form.name, form_path(@form)
    end

    def update
      @form = Wf::Form.find(params[:form_id])
      @field = @form.fields.find(params[:id])
      if @field.update(field_params)
        redirect_to form_path(@form), notice: "field was successfully created."
      else
        render :edit
      end
    end

    private

      def field_params
        params.fetch(:field, {}).permit(:name, :form_id, :field_type, :position, :default_value)
      end
  end
end


================================================
FILE: app/controllers/wf/forms_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class FormsController < ApplicationController
    breadcrumb "Forms", :forms_path

    def index
      @forms = Wf::Form.order("id DESC").page(params[:page])
    end

    def new
      @form = Wf::Form.new
    end

    def edit
      @form = Wf::Form.find(params[:id])
    end

    def show
      @form = Wf::Form.find(params[:id])
    end

    def destroy
      @form = Wf::Form.find(params[:id])
      @form.destroy
      respond_to do |format|
        format.html { redirect_to forms_path, notice: "form was successfully deleted." }
        format.js { render js: "window.location.reload();" }
      end
    end

    def update
      @form = Wf::Form.find(params[:id])
      if @form.update(form_params)
        redirect_to form_path(@form), notice: "form was successfully updated."
      else
        render :edit
      end
    end

    def create
      @form = Wf::Form.new(form_params)

      if @form.save
        redirect_to forms_path, notice: "form was successfully created."
      else
        render :new
      end
    end

    private

      def form_params
        params.fetch(:form, {}).permit(:name, :description)
      end
  end
end


================================================
FILE: app/controllers/wf/guards_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class GuardsController < ApplicationController
    breadcrumb "Workflows", :workflows_path
    def new
      @arc = Wf::Arc.find(params[:arc_id])
      @guard = @arc.guards.new
      breadcrumb @arc.workflow.name, workflow_path(@arc.workflow)
      breadcrumb @arc.name, workflow_arc_path(@arc.workflow, @arc)
    end

    def create
      @arc = Wf::Arc.find(params[:arc_id])
      gp = guard_params.merge(fieldable: GlobalID::Locator.locate(guard_params[:fieldable]))
      @guard = @arc.guards.new(gp.merge(workflow: @arc.workflow))
      redirect_to workflow_arc_path(@arc.workflow, @arc), notice: "only out direction arc can set guard!" unless @arc.out?
      if @guard.save
        redirect_to workflow_arc_path(@arc.workflow, @arc), notice: "guard was successfully created."
      else
        render :new
      end
    end

    def destroy
      @arc = Wf::Arc.find(params[:arc_id])
      @guard = @arc.guards.find(params[:id])
      @guard.destroy
      render js: "window.location.reload()"
    end

    def edit
      @arc = Wf::Arc.find(params[:arc_id])
      @guard = @arc.guards.find(params[:id])
      breadcrumb @arc.workflow.name, workflow_path(@arc.workflow)
      breadcrumb @arc.name, workflow_arc_path(@arc.workflow, @arc)
    end

    def update
      @arc = Wf::Arc.find(params[:arc_id])
      gp = guard_params.merge(fieldable: GlobalID::Locator.locate(guard_params[:fieldable]))
      @guard = @arc.guards.find(params[:id])
      if @guard.update(gp)
        redirect_to workflow_arc_path(@arc.workflow, @arc), notice: "guard was successfully created."
      else
        render :edit
      end
    end

    private

      def guard_params
        params.fetch(:guard, {}).permit(:fieldable, :fieldable_type, :fieldable_id, :op, :value, :exp)
      end
  end
end


================================================
FILE: app/controllers/wf/places_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class PlacesController < ApplicationController
    breadcrumb "Workflows", :workflows_path
    def new
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @place = @workflow.places.new
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def create
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @place = @workflow.places.new(place_params)
      if @place.save
        redirect_to workflow_path(@workflow), notice: "place was successfully created."
      else
        render :new
      end
    end

    def destroy
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @place = @workflow.places.find(params[:id])
      @place.destroy
      render js: "window.location.reload()"
    end

    def edit
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @place = @workflow.places.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def update
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @place = @workflow.places.find(params[:id])
      if @place.update(place_params)
        redirect_to workflow_path(@workflow), notice: "place was successfully created."
      else
        render :edit
      end
    end

    private

      def place_params
        params.fetch(:place, {}).permit(:name, :description, :place_type, :sort_order)
      end
  end
end


================================================
FILE: app/controllers/wf/static_assignments_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class StaticAssignmentsController < ApplicationController
    def new
      @transition = Wf::Transition.find(params[:transition_id])
      @static_assignment = @transition.transition_static_assignments.new
    end

    def create
      @transition = Wf::Transition.find(params[:transition_id])
      @party = Wf::Party.find(permit_params[:party_id])
      @static_assignment = @transition.transition_static_assignments.new(party: @party)
      if @static_assignment.save
        redirect_to workflow_transition_path(@transition.workflow, @transition), notice: "static assignment was successfully created."
      else
        render :new
      end
    end

    def destroy
      @transition = Wf::Transition.find(params[:transition_id])
      @static_assignment = @transition.transition_static_assignments.find(params[:id])
      @static_assignment.destroy
      render js: "window.location.reload()"
    end

    def permit_params
      params.fetch(:transition_static_assignment, {}).permit(:party_id)
    end
  end
end


================================================
FILE: app/controllers/wf/transitions_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class TransitionsController < ApplicationController
    breadcrumb "Workflows", :workflows_path

    def new
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @transition = @workflow.transitions.new
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def show
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @transition = @workflow.transitions.find(params[:id])
    end

    def create
      @workflow = Wf::Workflow.find(params[:workflow_id])
      tp = transition_params.merge(form: GlobalID::Locator.locate(transition_params[:form]))
      @transition = @workflow.transitions.new(tp)
      if @transition.save
        redirect_to workflow_path(@workflow), notice: "transition was successfully created."
      else
        render :new
      end
    end

    def edit
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @transition = @workflow.transitions.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def destroy
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @transition = @workflow.transitions.find(params[:id])
      @transition.destroy
      render js: "window.location.reload()"
    end

    def update
      @workflow = Wf::Workflow.find(params[:workflow_id])
      @transition = @workflow.transitions.find(params[:id])
      tp = transition_params.merge(form: GlobalID::Locator.locate(transition_params[:form]))
      if @transition.update(tp)
        redirect_to workflow_path(@workflow), notice: "transition was successfully updated."
      else
        render :edit
      end
    end

    private

      def transition_params
        params.fetch(:transition, {}).permit(
          :name,
          :description,
          :trigger_limit,
          :trigger_type,
          :sort_order,
          :form,
          :enable_callback,
          :fire_callback,
          :time_callback,
          :hold_timeout_callback,
          :assignment_callback,
          :unassignment_callback,
          :notification_callback,
          :deadline_callback,
          :sub_workflow_id,
          :multiple_instance,
          :finish_condition,
          :dynamic_assign_by_id
        )
      end
  end
end


================================================
FILE: app/controllers/wf/workflows_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class WorkflowsController < ApplicationController
    breadcrumb "Workflows", :workflows_path
    def index
      @workflows = Wf::Workflow.order("id DESC").page(params[:page])
    end

    def new
      @workflow = Wf::Workflow.new
    end

    def edit
      @workflow = Wf::Workflow.find(params[:id])
      breadcrumb @workflow.name, workflow_path(@workflow)
    end

    def show
      @workflow = Wf::Workflow.find(params[:id])
    end

    def destroy
      @workflow = Wf::Workflow.find(params[:id])
      @workflow.destroy
      respond_to do |format|
        format.html { redirect_to workflows_path, notice: "workflow was successfully deleted." }
        format.js { render js: "window.location.reload();" }
      end
    end

    def update
      @workflow = Wf::Workflow.find(params[:id])
      if @workflow.update(workflow_params)
        redirect_to workflow_path(@workflow), notice: "workflow was successfully updated."
      else
        render :edit
      end
    end

    def create
      @workflow = Wf::Workflow.new(workflow_params)

      if @workflow.save
        redirect_to workflows_path, notice: "workflow was successfully created."
      else
        render :new
      end
    end

    private

      def workflow_params
        params.fetch(:workflow, {}).permit(:name, :description)
      end
  end
end


================================================
FILE: app/controllers/wf/workitem_assignments_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class WorkitemAssignmentsController < ApplicationController
    breadcrumb "Workflows", :workflows_path
    def new
      @workitem = Wf::Workitem.find(params[:workitem_id])
      @workitem_assignment = @workitem.workitem_assignments.new(party_id: params[:party_id])
      breadcrumb @workitem.workflow.name, workflow_path(@workitem.workflow)
      breadcrumb @workitem.case.name, workflow_case_path(@workitem.workflow, @workitem.case)
      breadcrumb @workitem.name, workitem_path(@workitem)
    end

    def create
      @workitem = Wf::Workitem.find(params[:workitem_id])
      party = Wf::Party.find(params[:workitem_assignment][:party_id])
      Wf::CaseCommand::AddWorkitemAssignment.call(@workitem, party)
      redirect_to workitem_path(@workitem), notice: "assigned party to workitem."
    end

    def destroy
      @workitem = Wf::Workitem.find(params[:workitem_id])
      party = Wf::Party.find(params[:party_id])
      Wf::CaseCommand::RemoveWorkitemAssignment.call(@workitem, party)
      render js: "window.location.reload()"
    end
  end
end


================================================
FILE: app/controllers/wf/workitems_controller.rb
================================================
# frozen_string_literal: true

require_dependency "wf/application_controller"

module Wf
  class WorkitemsController < ApplicationController
    before_action :find_workitem, except: [:index]
    before_action :check_start, only: [:start]
    before_action :check_finish, only: %i[pre_finish finish]

    breadcrumb "Workflows", :workflows_path

    def index
      @workitems = Wf::Workitem.todo(wf_current_user)
      @workitems = @workitems.where(state: params[:state].intern) if params[:state]
      @workitems = @workitems.where(state: params[:state].intern) if params[:state].present?
      @workitems = @workitems.distinct.order("id desc").page(params[:page])
    end

    def show
      breadcrumb @workitem.workflow.name, workflow_path(@workitem.workflow)
      breadcrumb @workitem.case.name, workflow_case_path(@workitem.workflow, @workitem.case)
    end

    def start
      Wf::CaseCommand::StartWorkitem.call(@workitem, wf_current_user)
      breadcrumb @workitem.workflow.name, workflow_path(@workitem.workflow)
      breadcrumb @workitem.case.name, workflow_case_path(@workitem.workflow, @workitem.case)
      breadcrumb @workitem.name, workitem_path(@workitem)
      render :pre_finish
    end

    def pre_finish
      breadcrumb @workitem.workflow.name, workflow_path(@workitem.workflow)
      breadcrumb @workitem.case.name, workflow_case_path(@workitem.workflow, @workitem.case)
      breadcrumb @workitem.name, workitem_path(@workitem)
    end

    def finish
      if dynamic_assignments = params.dig(:workitem, :dynamic_assignments)
        dynamic_assignments.permit!.each do |t_id, party_id|
          Wf::CaseCommand::AddManualAssignment.call(@workitem.case, @workitem.workflow.transitions.find(t_id), Wf::Party.find(party_id))
        end
      end
      if @workitem.transition.form && params[:workitem][:entry]
        form = @workitem.transition.form
        cmd = Wf::CaseCommand::CreateEntry.call(form, @workitem, wf_current_user, params[:workitem][:entry].permit!)
        if cmd.success?
          Wf::CaseCommand::FinishWorkitem.call(@workitem)
          finish_and_redirect
        else
          redirect_to pre_finish_workitem_path(@workitem), notice: "Your input no OK."
        end
      else
        Wf::CaseCommand::FinishWorkitem.call(@workitem)
        finish_and_redirect
      end
    end

    def finish_and_redirect
      if @workitem.case.finished?
        if started_by = @workitem.case.started_by_workitem
          redirect_to workflow_case_path(started_by.workflow, started_by.case), notice: "workitem is done, and goto parent case."
        else
          redirect_to workflow_case_path(@workitem.workflow, @workitem.case), notice: "workitem is done, and the case is finished."
        end
      else
        redirect_to workitem_path(@workitem.case.workitems.enabled.first), notice: "workitem is done, and goto next fireable workitem."
      end
    end

    def find_workitem
      @workitem = Wf::Workitem.find(params[:id])
    end

    def check_start
      unless @workitem.started_by?(wf_current_user)
        redirect_to workitem_path(@workitem), notice: "You can not start this workitem, Please assign to youself first."
      end
    end

    def check_finish
      unless @workitem.finished_by?(wf_current_user)
        redirect_to workitem_path(@workitem), notice: "You can not the holding use of this workitem, Please assign to youself && start it first."
      end
    end
  end
end


================================================
FILE: app/helpers/wf/application_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module ApplicationHelper
  end
end


================================================
FILE: app/helpers/wf/arcs_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module ArcsHelper
  end
end


================================================
FILE: app/helpers/wf/cases_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module CasesHelper
  end
end


================================================
FILE: app/helpers/wf/comments_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module CommentsHelper
  end
end


================================================
FILE: app/helpers/wf/fields_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module FieldsHelper
  end
end


================================================
FILE: app/helpers/wf/forms_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module FormsHelper
  end
end


================================================
FILE: app/helpers/wf/guards_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module GuardsHelper
  end
end


================================================
FILE: app/helpers/wf/places_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module PlacesHelper
  end
end


================================================
FILE: app/helpers/wf/static_assignments_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module StaticAssignmentsHelper
  end
end


================================================
FILE: app/helpers/wf/transitions_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module TransitionsHelper
  end
end


================================================
FILE: app/helpers/wf/workflows_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module WorkflowsHelper
  end
end


================================================
FILE: app/helpers/wf/workitem_assignments_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module WorkitemAssignmentsHelper
  end
end


================================================
FILE: app/helpers/wf/workitems_helper.rb
================================================
# frozen_string_literal: true

module Wf
  module WorkitemsHelper
  end
end


================================================
FILE: app/jobs/wf/application_job.rb
================================================
# frozen_string_literal: true

module Wf
  class ApplicationJob < ActiveJob::Base
  end
end


================================================
FILE: app/jobs/wf/fire_timed_workitem_job.rb
================================================
# frozen_string_literal: true

module Wf
  class FireTimedWorkitemJob < ApplicationJob
    queue_as :default

    def perform(workitem_id)
      item = Wf::Workitem.find(workitem_id)
      if item.trigger_time && item.enabled? && item.case.active?
        CaseCommand::FireTransitionInternal.call(item)
        CaseCommand::SweepAutomaticTransitions.call(item.case)
      end
    end
  end
end


================================================
FILE: app/mailers/wf/application_mailer.rb
================================================
# frozen_string_literal: true

module Wf
  class ApplicationMailer < ActionMailer::Base
    default from: "from@example.com"
    layout "mailer"
  end
end


================================================
FILE: app/models/wf/acts_as_party.rb
================================================
# frozen_string_literal: true

require "active_support/concern"

module Wf
  module ActsAsParty
    extend ActiveSupport::Concern

    included do
      has_one :party, as: :partable
    end

    module ClassMethods
      def acts_as_party(options = { user: false, party_name: :name })
        cattr_accessor :yaffle_text_field
        has_many :users, foreign_key: :id if options[:user]
        after_create do
          create_party(party_name: options[:party_name])
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/application_record.rb
================================================
# frozen_string_literal: true

module Wf
  class ApplicationRecord < ActiveRecord::Base
    self.abstract_class = true
  end
end


================================================
FILE: app/models/wf/arc.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_arcs
#
#  id            :integer          not null, primary key
#  workflow_id   :integer
#  transition_id :integer
#  place_id      :integer
#  direction     :integer          default("0")
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#  guards_count  :integer          default("0")
#

module Wf
  class Arc < ApplicationRecord
    belongs_to :workflow, touch: true
    belongs_to :transition
    belongs_to :place

    has_many :guards, dependent: :destroy

    scope :with_guards, -> { where("guards_count > 0") }
    scope :without_guards, -> { where(guards_count: 0) }

    # direction is relative to the transition
    enum direction: {
      in: 0,
      out: 1
    }

    def name
      if in?
        [place&.name, transition&.name].join(" -> ")
      else
        [transition&.name, place&.name].join(" -> ")
      end
    end
  end
end


================================================
FILE: app/models/wf/callbacks/assignment_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class AssignmentDefault < ApplicationJob
    queue_as :default

    def perform(_workitem_id)
      # return Party array.
      []
    end
  end
end


================================================
FILE: app/models/wf/callbacks/deadline_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class DeadlineDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/enable_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class EnableDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/fire_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class FireDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/hold_timeout_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class HoldTimeoutDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/notification_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class NotificationDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/time_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class TimeDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/callbacks/unassignment_default.rb
================================================
# frozen_string_literal: true

module Wf::Callbacks
  class UnassignmentDefault < ApplicationJob
    queue_as :default

    def perform(*guests)
      $stdout.puts(guests.inspect)
    end
  end
end


================================================
FILE: app/models/wf/case.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_cases
#
#  id                     :integer          not null, primary key
#  workflow_id            :integer
#  targetable_type        :string
#  targetable_id          :string
#  state                  :integer          default("0")
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#  started_by_workitem_id :integer
#

module Wf
  class Case < ApplicationRecord
    belongs_to :workflow
    belongs_to :targetable, optional: true, polymorphic: true
    belongs_to :started_by_workitem, optional: true, class_name: "Wf::Workitem"
    has_many :workitems
    has_many :tokens
    has_many :case_assignments
    has_many :parties, through: :case_assignments, source: "party"

    enum state: {
      created: 0,
      active: 1,
      suspended: 2,
      canceled: 3,
      finished: 4
    }

    def can_fire?(transition)
      ins = transition.arcs.in.to_a
      return false if ins.blank?

      ins.all? { |arc| arc.place.tokens.where(case: self).where(state: :free).exists? }
    end

    def name
      "Case->#{id}"
    end
  end
end


================================================
FILE: app/models/wf/case_assignment.rb
================================================
# frozen_string_literal: true
# == Schema Information
#
# Table name: wf_case_assignments
#
#  id            :integer          not null, primary key
#  case_id       :integer
#  transition_id :integer
#  party_id      :integer
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#

# frozen_string_literal: true

module Wf
  class CaseAssignment < ApplicationRecord
    belongs_to :case
    belongs_to :transition
    belongs_to :party
  end
end


================================================
FILE: app/models/wf/case_command/add_comment.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class AddComment
    prepend SimpleCommand
    attr_reader :workitem, :comment, :user
    def initialize(workitem, comment, user)
      @workitem   = workitem
      @comment    = comment
      @user       = user
    end

    def call
      workitem.comments.create!(user: user, body: comment)
    end
  end
end


================================================
FILE: app/models/wf/case_command/add_manual_assignment.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class AddManualAssignment
    prepend SimpleCommand
    attr_reader :wf_case, :transition, :party
    def initialize(wf_case, transition, party)
      @wf_case = wf_case
      @transition = transition
      @party = party
    end

    def call
      wf_case.case_assignments.find_or_create_by!(transition: transition, party: party)
    end
  end
end


================================================
FILE: app/models/wf/case_command/add_token.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class AddToken
    prepend SimpleCommand
    attr_reader :wf_case, :place
    def initialize(wf_case, place)
      @wf_case = wf_case
      @place = place
    end

    def call
      wf_case.tokens.create!(
        workflow: wf_case.workflow,
        place: place,
        state: :free
      )
    end
  end
end


================================================
FILE: app/models/wf/case_command/add_workitem_assignment.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class AddWorkitemAssignment
    prepend SimpleCommand
    attr_reader :workitem, :party, :permanent
    def initialize(workitem, party, permanent = true)
      @workitem = workitem
      @party    = party
      @permanent = permanent
    end

    def call
      return if party.nil?

      Wf::ApplicationRecord.transaction do
        AddManualAssignment.call(workitem.case, workitem.transition, party) if permanent

        notified_users = workitem.parties.map do |p|
          p.partable.users.to_a
        end.flatten

        assign = workitem.workitem_assignments.where(party: party).first
        break if assign

        workitem.workitem_assignments.create!(party: party)
        new_users = party.partable.users.to_a
        to_notify = new_users - notified_users
        transition = workitem.transition
        to_notify.each do |user|
          # TODO: multiple instance + sub workflow
          if transition.multiple_instance? && !workitem.forked?
            next if workitem.children.where(holding_user: user).exists?

            child = workitem.children.create!(
              workflow_id: workitem.workflow_id,
              transition_id: workitem.transition_id,
              state: :enabled,
              trigger_time: workitem.trigger_time,
              forked: true,
              holding_user: user,
              case_id: workitem.case_id
            )
            workitem.transition.notification_callback.constantize.new(child, user.id).perform_now
          else
            workitem.transition.notification_callback.constantize.new(workitem, user.id).perform_now
          end
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/begin_workitem_action.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class BeginWorkitemAction
    prepend SimpleCommand
    attr_reader :workitem, :action, :user
    def initialize(workitem, user, action = :start)
      @workitem = workitem
      @action   = action
      @user     = user
    end

    def call
      if action == :start
        raise("Workitem is in state #{workitem.state}, but it must be in state enabled to be started.") unless workitem.enabled?
        raise("You are not assigned to this workitem.") unless workitem.owned_by?(user)
      elsif action == :finish || action == :cancel
        if workitem.started?
          raise("You are not the user currently working on this workitem.") if workitem.holding_user != user
        elsif workitem.enabled?
          raise("You can only cancel a workitem in state started, but this workitem is in state #{workitem.state}.") if action == :cancel
          raise("You are not assigned to this workitem.") unless workitem.owned_by?(user)

          workitem.update!(holding_user: user)
        else
          raise("Workitem is in state #{workitem.state}, but it must be in state enabled or started to be finished.")
        end
      elsif action == :comment
        # TODO
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/cancel.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class Cancel
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      raise("Only active or suspended cases can be canceled") unless wf_case.suspended? || wf_case.active?

      wf_case.canceled!
    end
  end
end


================================================
FILE: app/models/wf/case_command/cancel_workitem.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class CancelWorkitem
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      raise("The workitem is not in state #{workitem.state}") unless workitem.started?

      Wf::ApplicationRecord.transaction do
        workitem.update!(state: :canceled, canceled_at: Time.zone.now)
        ReleaseToken.call(workitem)
        SweepAutomaticTransitions.call(workitem.case)
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/clear_manual_assignments.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class ClearManualAssignments
    prepend SimpleCommand
    attr_reader :wf_case, :transition
    def initialize(wf_case, transition)
      @wf_case = wf_case
      @transition = transition
    end

    def call
      wf_case.case_assignments.where(transition: transition).find_each(&:destroy)
    end
  end
end


================================================
FILE: app/models/wf/case_command/clear_workitem_assignments.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class ClearWorkitemAssignments
    prepend SimpleCommand
    attr_reader :workitem, :permanent
    def initialize(workitem, permanent = true)
      @workitem = workitem
      @permanent = permanent
    end

    def call
      Wf::ApplicationRecord.transaction do
        ClearManualAssignments.call(workitem.case, workitem.transition) if permanent
        workitem.workitem_assignments.delete_all
        workitem.transition.unassignment_callback.constantize.new(workitem.id).perform
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/consume_token.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class ConsumeToken
    prepend SimpleCommand
    attr_reader :wf_case, :place, :locked_item
    def initialize(wf_case, place, locked_item = nil)
      @wf_case  = wf_case
      @place    = place
      @locked_item = locked_item
    end

    def call
      Wf::ApplicationRecord.transaction do
        if locked_item
          wf_case.tokens.where(place: place, state: :locked, locked_workitem_id: locked_item.id).update(consumed_at: Time.zone.now, state: :consumed)
        else
          wf_case.tokens.where(id: wf_case.tokens.where(place: place, state: :free).first&.id).update(consumed_at: Time.zone.now, state: :consumed)
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/create_entry.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class CreateEntry
    prepend SimpleCommand
    attr_reader :form, :workitem, :user, :params
    def initialize(form, workitem, user, params)
      @form       = form
      @workitem   = workitem
      @params     = params
      @user       = user
    end

    def call
      create_entry
    rescue StandardError
      binding.pry
      puts $ERROR_INFO
      # TODO: more detail
      errors.add(:base, :failure)
    end

    def create_entry
      Wf::ApplicationRecord.transaction do
        entry = form.entries.find_or_create_by!(user: user, workitem: workitem)
        params.each do |field_id, field_value|
          if field = entry.field_values.where(form: form, field_id: field_id).first
            field.update!(value: field_value)
          else
            entry.field_values.create!(form: form, field_id: field_id, value: field_value)
          end
        end
        entry.update_payload!
        entry
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/enable_transitions.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class EnableTransitions
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      Wf::ApplicationRecord.transaction do
        wf_case.workitems.enabled.each do |workitem|
          workitem.update!(state: :overridden, overridden_at: Time.zone.now) unless wf_case.can_fire?(workitem.transition)
        end
        wf_case.workflow.transitions.each do |transition|
          next unless wf_case.can_fire?(transition) && !transition.workitems.where(case: wf_case, state: %i[enabled started]).exists?

          trigger_time = Time.zone.now + transition.trigger_limit.minutes if transition.trigger_limit && transition.time?
          workitem = wf_case.workitems.create!(
            workflow: wf_case.workflow,
            transition: transition,
            state: :enabled,
            trigger_time: trigger_time
          )
          Wf::FireTimedWorkitemJob.set(wait: transition.trigger_limit.minutes).perform_later(workitem.id) if trigger_time
          SetWorkitemAssignments.call(workitem)
          workitem.transition.unassignment_callback.constantize.new(workitem.id).perform_now if workitem.workitem_assignments.count == 0
          if sub_workflow = transition.sub_workflow
            sub_case = Wf::CaseCommand::New.call(sub_workflow, nil, workitem).result
            Wf::CaseCommand::StartCase.call(sub_case)
          end
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/end_workitem_action.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class EndWorkitemAction
    prepend SimpleCommand
    attr_reader :workitem, :action, :user
    def initialize(workitem, user, action = :start)
      @workitem = workitem
      @action   = action
      @user     = user
    end

    def call
      if action == :start
        StartWorkitem.call(workitem, user)
      elsif action == :finish
        FinishWorkitem.call(workitem, user)
      elsif action == :cancel
        CancelWorkitem.call(workitem, user)
      elsif action == :comment
        raise("Unknown action #{action}")
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/finish_workitem.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class FinishWorkitem
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      Wf::ApplicationRecord.transaction do
        if workitem.forked?
          workitem.update!(finished_at: Time.zone.now, state: :finished)
          Wf::Workitem.increment_counter(:children_finished_count, workitem.parent_id)
          if parent = workitem.parent
            if (parent.children_finished_count >= parent.children_count) || workitem.transition.finish_condition.constantize.new.perform(workitem)
              parent.children.where(state: %i[started enabled]).find_each do |wi|
                wi.update!(overridden_at: Time.zone.now, state: :overridden)
              end
              FireTransitionInternal.call(parent)
              SweepAutomaticTransitions.call(parent.case)
            end
          end
        else
          FireTransitionInternal.call(workitem)
          SweepAutomaticTransitions.call(workitem.case)
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/finished_p.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class FinishedP
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      return true if wf_case.finished?

      end_place = wf_case.workflow.places.end.first
      end_place_token_num = Wf::ApplicationRecord.uncached { wf_case.tokens.where(place: end_place).count }
      if end_place_token_num == 0
        false
      else
        free_and_locked_token_num = wf_case.tokens.where(place: end_place).where(state: %i[free locked]).count
        raise("The workflow net is misconstructed: Some parallel executions have not finished.") if free_and_locked_token_num > 1

        ConsumeToken.call(wf_case, end_place)
        unless wf_case.finished?
          wf_case.finished!
          if started_by_workitem = wf_case.started_by_workitem
            Wf::CaseCommand::FinishWorkitem.call(started_by_workitem)
          end
        end
        true
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/fire_message_transition.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class FireMessageTransition
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      raise("Transition #{workitem.transition.name} is not message triggered") unless workitem.transition.message?

      Wf::ApplicationRecord.transaction do
        FireTransitionInternal.call(workitem)
        SweepAutomaticTransitions.call(workitem.case)
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/fire_transition_internal.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class FireTransitionInternal
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      if workitem.enabled?
        locked_item = nil
      elsif workitem.started?
        locked_item = workitem
      else
        raise("can not fire the transition if it is not in state enabled or started.")
      end
      Wf::ApplicationRecord.transaction do
        workitem.update!(finished_at: Time.zone.now, state: :finished)
        # TODO: only in?
        workitem.transition.arcs.each do |arc|
          ConsumeToken.call(workitem.case, arc.place, locked_item)
        end
        # last arc without guard -> pass
        has_passed = false
        workitem.transition.arcs.out.order("guards_count DESC").each do |arc|
          if workitem.transition.explicit_or_split?
            if workitem.pass_guard?(arc, has_passed)
              has_passed = true
              AddToken.call(workitem.case, arc.place)
            end
          else
            AddToken.call(workitem.case, arc.place)
          end
        end
        workitem.transition.fire_callback.constantize.new(workitem.id).perform_now
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/lock_token.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class LockToken
    prepend SimpleCommand
    attr_reader :wf_case, :place, :workitem
    def initialize(wf_case, place, workitem)
      @wf_case = wf_case
      @place = place
      @workitem = workitem
    end

    def call
      wf_case.tokens.free.where(place: place).limit(1).update_all(
        state: :locked,
        locked_at: Time.zone.now,
        locked_workitem_id: workitem.id
      )
    end
  end
end


================================================
FILE: app/models/wf/case_command/new.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class New
    prepend SimpleCommand
    attr_reader :workflow, :target, :started_by
    def initialize(workflow, target = nil, started_by = nil)
      @workflow = workflow
      @target = target
      @started_by = started_by
    end

    def call
      wf_case = workflow.cases.create!(targetable: target, started_by_workitem: started_by, state: :created)
      wf_case
    end
  end
end


================================================
FILE: app/models/wf/case_command/release_token.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class ReleaseToken
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      Wf::ApplicationRecord.transaction do
        Wf::Token.where(locked_workitem_id: workitem.id).locked.each do |token|
          AddToken.call(token.case, token.place)
          token.update!(state: :canceled, canceled_at: Time.zone.now)
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/remove_manual_assignment.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class RemoveManualAssignment
    prepend SimpleCommand
    attr_reader :wf_case, :transition, :party
    def initialize(wf_case, transition, party)
      @wf_case = wf_case
      @transition = transition
      @party = party
    end

    def call
      wf_case.case_assignments.where(transition: transition, party: party).find_each(&:destroy)
    end
  end
end


================================================
FILE: app/models/wf/case_command/remove_workitem_assignment.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class RemoveWorkitemAssignment
    prepend SimpleCommand
    attr_reader :workitem, :party, :permanent
    def initialize(workitem, party, permanent = true)
      @workitem = workitem
      @party    = party
      @permanent = permanent
    end

    def call
      return if party.nil?

      Wf::ApplicationRecord.transaction do
        RemoveManualAssignment.call(workitem.case, workitem.transition, party) if permanent
        workitem.workitem_assignments.where(party: party).first&.destroy

        workitem.transition.unassignment_callback.constantize.new(workitem.id).perform_now if workitem.workitem_assignments.count == 0
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/resume.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class Resume
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      raise("Only suspended or canceled cases can be resumed") unless wf_case.suspended? || wf_case.canceled?

      wf_case.active!
    end
  end
end


================================================
FILE: app/models/wf/case_command/set_workitem_assignments.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class SetWorkitemAssignments
    prepend SimpleCommand
    attr_reader :workitem
    def initialize(workitem)
      @workitem = workitem
    end

    def call
      Wf::ApplicationRecord.transaction do
        has_case_ass = false
        workitem.case.case_assignments.where(transition: workitem.transition).find_each do |case_ass|
          AddWorkitemAssignment.call(workitem, case_ass.party, false)
          has_case_ass = true
        end

        unless has_case_ass
          callback_parties = workitem.transition.assignment_callback.constantize.new.perform(workitem.id)
          if callback_parties.present?
            callback_parties.each do |party|
              AddWorkitemAssignment.call(workitem, party, false)
            end
          else
            workitem.transition.transition_static_assignments.each do |static_assignment|
              AddWorkitemAssignment.call(workitem, static_assignment.party, false)
            end
          end
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/start_case.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class StartCase
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      Wf::ApplicationRecord.transaction do
        wf_case.active!
        AddToken.call(wf_case, wf_case.workflow.places.start.first)
        SweepAutomaticTransitions.call(wf_case)
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/start_workitem.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class StartWorkitem
    prepend SimpleCommand
    attr_reader :workitem, :user
    def initialize(workitem, user)
      @workitem = workitem
      @user     = user
    end

    def call
      raise("The workitem can not run by user.") unless workitem.real?
      raise("The workitem is not in state #{workitem.state}") unless workitem.enabled?

      # TODO: holding timeout
      Wf::ApplicationRecord.transaction do
        workitem.update!(state: :started, holding_user: user)

        workitem.transition.arcs.in.each do |arc|
          LockToken.call(workitem.case, arc.place, workitem)
        end
      end
      workitem
    end
  end
end


================================================
FILE: app/models/wf/case_command/suspend.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class Suspend
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      raise("Only active or suspended cases can be canceled") unless wf_case.active?

      wf_case.suspended!
    end
  end
end


================================================
FILE: app/models/wf/case_command/sweep_automatic_transitions.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class SweepAutomaticTransitions
    prepend SimpleCommand
    attr_reader :wf_case
    def initialize(wf_case)
      @wf_case = wf_case
    end

    def call
      Wf::ApplicationRecord.transaction do
        EnableTransitions.call(wf_case)
        done = false
        until done
          done = true
          finished = FinishedP.call(wf_case).result
          next if finished

          Wf::ApplicationRecord.uncached do
            wf_case.workitems.joins(:transition).where(state: :enabled).where(Wf::Transition.table_name => { trigger_type: Wf::Transition.trigger_types[:automatic] }).find_each do |item|
              FireTransitionInternal.call(item)
              done = false
            end
          end
          EnableTransitions.call(wf_case)
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/sweep_timed_transitions.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class SweepTimedTransitions
    prepend SimpleCommand

    def call
      Wf::ApplicationRecord.transaction do
        Wf::Workitem.enabled.where("trigger_time <= ?", Time.zone.now).find_each do |item|
          FireTransitionInternal.call(item)
          SweepAutomaticTransitions.call(item.case)
        end
      end
    end
  end
end


================================================
FILE: app/models/wf/case_command/workitem_action.rb
================================================
# frozen_string_literal: true

module Wf::CaseCommand
  class WorkitemAction
    prepend SimpleCommand
    attr_reader :workitem, :action, :user
    def initialize(workitem, user, action = :start)
      @workitem = workitem
      @action   = action
      @user     = user
    end

    def call
      Wf::ApplicationRecord.transaction do
        BeginWorkitemAction.call(workitem, user, action)
        EndWorkitemAction.call(workitem, user, action)
      end
    end
  end
end


================================================
FILE: app/models/wf/comment.rb
================================================
# frozen_string_literal: true
# == Schema Information
#
# Table name: wf_comments
#
#  id          :integer          not null, primary key
#  workitem_id :integer
#  user_id     :string
#  body        :text
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

# frozen_string_literal: true

module Wf
  class Comment < ApplicationRecord
    belongs_to :workitem
    belongs_to :user, class_name: Wf.user_class.to_s
  end
end


================================================
FILE: app/models/wf/demo_target.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_demo_targets
#
#  id          :integer          not null, primary key
#  name        :string
#  description :string
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

module Wf
  class DemoTarget < ApplicationRecord
    has_many :cases, as: :targetable
  end
end


================================================
FILE: app/models/wf/entry.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_entries
#
#  id          :integer          not null, primary key
#  user_id     :string
#  workitem_id :integer
#  payload     :json             default("{}")
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#  form_id     :integer
#

module Wf
  class Entry < ApplicationRecord
    belongs_to :form
    belongs_to :user, class_name: Wf.user_class.to_s
    belongs_to :workitem
    has_many :field_values

    after_initialize do
      self.payload = {} if payload.blank?
    end

    def json
      field_values.includes(:field).map { |x| [x.field_id.to_i, { field_id: x.id.to_i, field_name: x.field.name, value: x.value_after_cast }] }.to_h
    end

    def for_mini_racer
      field_values.includes(:field).map { |x| [x.field.name, x.value_after_cast] }.to_h
    end

    def update_payload!
      update(payload: json)
    end
  end
end


================================================
FILE: app/models/wf/field.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_fields
#
#  id              :integer          not null, primary key
#  name            :string
#  form_id         :integer
#  position        :integer          default("0")
#  field_type      :integer          default("0")
#  field_type_name :string
#  default_value   :string
#  created_at      :datetime         not null
#  updated_at      :datetime         not null
#

module Wf
  class Field < ApplicationRecord
    belongs_to :form, touch: true

    enum field_type: {
      string: 0,
      integer: 1,
      boolean: 2,
      date: 3,
      datetime: 4,
      decimal: 5,
      float: 6,
      json: 7,
      text: 8,

      "string[]": 20,
      "integer[]": 21,
      "date[]": 23,
      "datetime[]": 24,
      "decimal[]": 25,
      "float[]": 26,
      "json[]": 27,
      "text[]": 28
    }

    # TODO: array type
    def field_type_for_view
      case field_type
      when "string"
        "text_field"
      when "integer"
        "number_field"
      when "date"
        "date_field"
      when "datetime"
        "datetime_field"
      when "boolean"
        "check_box"
      when "text"
        "text_area"
      else
        "text_field"
      end
    end

    def array?
      field_type.to_s.match(/^(\w+)(\[\])?$/)[2] == "[]"
    end

    def type_for_cast
      type = field_type.to_s.match(/^(\w+)(\[\])?$/)[1]
      if array?
        ActiveRecord::Type.lookup(type.to_sym, adapter: :postgresql, array: true)
      else
        ActiveRecord::Type.lookup(type.to_sym, adapter: :postgresql)
      end
    end

    delegate :cast, to: :type_for_cast
  end
end


================================================
FILE: app/models/wf/field_value.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_field_values
#
#  id         :integer          not null, primary key
#  form_id    :integer
#  field_id   :integer
#  value      :text
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  entry_id   :integer
#

module Wf
  class FieldValue < ApplicationRecord
    belongs_to :form
    belongs_to :field
    belongs_to :entry

    def value_after_cast
      ov = self[:value]
      if field.array? && !ov.is_a?(Array)
        v = begin
              JSON.parse(ov)
            rescue StandardError
              []
            end
        field.type_for_cast.cast(v)
      else
        field.type_for_cast.cast(ov)
      end
    end

    def value=(v)
      self[:value] = if field.array?
        Array(v.as_json)
      else
        v
      end
    end

    def value
      value_after_cast
    end
  end
end


================================================
FILE: app/models/wf/form.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_forms
#
#  id          :integer          not null, primary key
#  name        :string
#  description :text
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

module Wf
  class Form < ApplicationRecord
    has_many :fields, dependent: :destroy
    has_many :entries
  end
end


================================================
FILE: app/models/wf/group.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_groups
#
#  id         :integer          not null, primary key
#  name       :string
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

module Wf
  class Group < ApplicationRecord
    has_many :users
    include Wf::ActsAsParty
    acts_as_party(user: false, party_name: :name)
  end
end


================================================
FILE: app/models/wf/guard.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_guards
#
#  id             :integer          not null, primary key
#  arc_id         :integer
#  workflow_id    :integer
#  fieldable_type :string
#  fieldable_id   :string
#  op             :string
#  value          :string
#  exp            :string
#  created_at     :datetime         not null
#  updated_at     :datetime         not null
#

module Wf
  class Guard < ApplicationRecord
    belongs_to :workflow
    belongs_to :arc, touch: true, counter_cache: true
    belongs_to :fieldable, polymorphic: true, optional: true

    before_validation do
      self.workflow = arc.workflow
    end

    validate :validate_exp_and_fieldable

    OP = %w[
      =
      >
      <
      >=
      <=
      is_empty
    ].freeze

    def value_after_cast
      field = fieldable
      fieldable&.cast(value)
    end

    def pass?(entry, workitem)
      if exp
        check_exp(entry, workitem)
      else
        check_fieldable(entry)
      end
    end

    def check_exp(_entry, workitem)
      # 1000ms, 200mb
      context = MiniRacer::Context.new(timeout: 1000, max_memory: 200_000_000)
      context.eval("let target = #{target_hash.to_json};")
      context.eval("let workitem = #{workitem.to_json};")
      exp_value = context.eval(exp)
      yes_or_no?(exp_value, value)
    end

    def check_fieldable(entry)
      fv = entry.field_values.where(field_id: fieldable_id).first
      return unless fv

      yes_or_no?(fv.value_after_cast, value_after_cast)
    end

    def yes_or_no?(input_value, setting_value)
      if op == "="
        input_value == setting_value
      elsif op == ">"
        input_value > setting_value
      elsif op == "<"
        input_value < setting_value
      elsif op == ">="
        input_value >= setting_value
      elsif op == "<="
        input_value <= setting_value
      elsif op == "is_empty"
        input_value.blank?
      else
        false
      end
    end

    def inspect
      if exp
        %(eval(exp) #{op} #{value})
      else
        %(#{fieldable&.form&.name}.#{fieldable&.name} #{op} #{value})
      end
    end

    def validate_exp_and_fieldable
      if fieldable && exp.present?
        errors.add(:exp, "Exp and Fieldable can not be set at the same time.")
        return
      end

      errors.add(:exp, "Must set one of Exp and Fieldable.") unless fieldable || exp.present?
    end
  end
end


================================================
FILE: app/models/wf/lola.rb
================================================
# frozen_string_literal: true

module Wf
  class Lola
    attr_reader :end_p, :start_p, :workflow
    def initialize(workflow)
      @workflow = workflow
      @start_p  = workflow.places.start.first
      @end_p    = workflow.places.end.first
      generate_lola_file!
    end

    def to_text
      places      = workflow.places
      transitions = workflow.transitions

      places_text  = places.map(&:lola_id).join(",")
      marking_text = start_p.lola_id
      # TODO: with guard
      transitions_text = transitions.map do |t|
        consume = t.arcs.in.map { |arc| "#{arc.place.lola_id}:1" }.join(",")
        produce = t.arcs.out.map { |arc| "#{arc.place.lola_id}:1" }.join(",")
        [
          "TRANSITION #{t.lola_id}",
          "CONSUME #{consume};",
          "PRODUCE #{produce};"
        ].join("\n")
      end.join("\n\n")

      <<~LOLA
        PLACE #{places_text};

        MARKING #{marking_text};

        #{transitions_text}
      LOLA
    end

    def json_path(bucket)
      Rails.root.join("tmp", "#{workflow.id}-#{bucket}.json")
    end

    def lola_path
      Rails.root.join("tmp", "#{workflow.id}-#{workflow.updated_at.to_i}.lola")
    end

    def generate_lola_file!
      File.open(lola_path, "w") { |f| f.write(Wf::Lola.new(workflow).to_text) } unless File.exist?(lola_path)
    end

    def soundness?
      reachability_of_final_marking? && quasiliveness? && !deadlock?
    end

    def reachability_of_final_marking?
      formula = workflow.places.reject { |p| p == end_p }.map { |p| "#{p.lola_id} = 0" }.join(" AND ")
      formula += " AND #{end_p.lola_id} >= 1"
      formula = "AGEF(#{formula})"
      result = run_cmd(formula, "reachability_of_final_marking")
      result.dig("analysis", "result")
    end

    def quasiliveness?
      workflow.transitions.all? { |t| !dead_transition?(t) }
    end

    def deadlock?
      formula = "EF (DEADLOCK AND (#{end_p.lola_id} = 0))"
      result = run_cmd(formula, "deadlock")
      result.dig("analysis", "result")
    end

    private

      def dead_transition?(transition)
        formula = "AG NOT FIREABLE (#{transition.lola_id})"
        result = run_cmd(formula, "dead_transition_#{transition.id}")
        result.dig("analysis", "result")
      end

      def run_cmd(formula, bucket)
        cmd = %(lola #{lola_path} --markinglimit=1000 --timelimit=1 --formula="#{formula}" --json=#{json_path(bucket)})
        $stdout.puts cmd
        system(cmd)
        JSON.parse(File.read(json_path(bucket)))
      end
  end
end


================================================
FILE: app/models/wf/multiple_instances/all_finish.rb
================================================
# frozen_string_literal: true

module Wf
  module MultipleInstances
    class AllFinish
      def perform(_workitem)
        false
      end
    end
  end
end


================================================
FILE: app/models/wf/party.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_parties
#
#  id            :integer          not null, primary key
#  partable_type :string
#  partable_id   :string
#  party_name    :string
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#

module Wf
  class Party < ApplicationRecord
    # TODO: use acts_as_partable for sync group or role or user to party
    belongs_to :partable, polymorphic: true
    has_many :transition_static_assignments
    has_many :workitem_assignments
  end
end


================================================
FILE: app/models/wf/place.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_places
#
#  id          :integer          not null, primary key
#  workflow_id :integer
#  name        :string
#  description :text
#  sort_order  :integer          default("0")
#  place_type  :integer          default("0")
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

module Wf
  class Place < ApplicationRecord
    belongs_to :workflow, touch: true
    has_many :arcs
    has_many :tokens
    enum place_type: {
      start: 0,
      normal: 1,
      end: 2
    }

    def graph_id
      "#{name}/#{id}"
    end

    def lola_id
      "P#{id}"
    end
  end
end


================================================
FILE: app/models/wf/token.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_tokens
#
#  id                 :integer          not null, primary key
#  workflow_id        :integer
#  case_id            :integer
#  targetable_type    :string
#  targetable_id      :string
#  place_id           :integer
#  state              :integer          default("0")
#  locked_workitem_id :integer
#  produced_at        :datetime
#  locked_at          :datetime
#  canceled_at        :datetime
#  consumed_at        :datetime
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#

module Wf
  class Token < ApplicationRecord
    belongs_to :workflow
    belongs_to :case
    belongs_to :place
    belongs_to :locked_workitem, class_name: "Wf::Workitem", optional: true

    enum state: {
      free: 0,
      locked: 1,
      canceled: 2,
      consumed: 3
    }
  end
end


================================================
FILE: app/models/wf/transition.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_transitions
#
#  id                    :integer          not null, primary key
#  name                  :string
#  description           :text
#  workflow_id           :integer
#  sort_order            :integer          default("0")
#  trigger_limit         :integer
#  trigger_type          :integer          default("0")
#  created_at            :datetime         not null
#  updated_at            :datetime         not null
#  form_id               :integer
#  enable_callback       :string           default("Wf::Callbacks::EnableDefault")
#  fire_callback         :string           default("Wf::Callbacks::FireDefault")
#  notification_callback :string           default("Wf::Callbacks::NotificationDefault")
#  time_callback         :string           default("Wf::Callbacks::TimeDefault")
#  deadline_callback     :string           default("Wf::Callbacks::DeadlineDefault")
#  hold_timeout_callback :string           default("Wf::Callbacks::HoldTimeoutDefault")
#  assignment_callback   :string           default("Wf::Callbacks::AssignmentDefault")
#  unassignment_callback :string           default("Wf::Callbacks::UnassignmentDefault")
#  form_type             :string           default("Wf::Form")
#  sub_workflow_id       :integer
#  multiple_instance     :boolean          default("false")
#  finish_condition      :string           default("Wf::MultipleInstances::AllFinish")
#  dynamic_assign_by_id  :integer
#

module Wf
  class Transition < ApplicationRecord
    belongs_to :workflow, touch: true
    has_many :arcs
    has_many :transition_static_assignments
    has_many :static_parties, through: :transition_static_assignments, source: "party"
    has_many :workitems
    belongs_to :form, optional: true, polymorphic: true
    belongs_to :sub_workflow, optional: true, class_name: "Wf::Workflow"
    belongs_to :dynamic_assign_by, optional: true, class_name: "Wf::Transition"
    has_many :dynamic_assignments, class_name: "Wf::Transition", foreign_key: "dynamic_assign_by_id"

    enum trigger_type: {
      user: 0,
      automatic: 1,
      message: 2,
      time: 3
    }

    validate :validate_trigger_type_and_sub

    def is_sub_workflow?
      !!sub_workflow_id
    end

    def explicit_or_split?
      arcs.out.sum(:guards_count) >= 1
    end

    validates :name, presence: true

    def validate_trigger_type_and_sub
      errors.add(:trigger_type, "sub workflow must have trigger type: automatic, message and time.") if user? && is_sub_workflow?
    end

    def graph_id
      "#{name}/#{id}"
    end

    def lola_id
      "T#{id}"
    end
  end
end


================================================
FILE: app/models/wf/transition_static_assignment.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_transition_static_assignments
#
#  id            :integer          not null, primary key
#  party_id      :integer
#  transition_id :integer
#  workflow_id   :integer
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#

module Wf
  class TransitionStaticAssignment < ApplicationRecord
    belongs_to :workflow
    belongs_to :transition
    belongs_to :party

    validates :party_id, uniqueness: { scope: %i[workflow_id transition_id] }

    before_validation do
      self.workflow_id = transition&.workflow_id
    end
  end
end


================================================
FILE: app/models/wf/user.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_users
#
#  id         :integer          not null, primary key
#  name       :string
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  group_id   :integer
#

module Wf
  class User < ApplicationRecord
    belongs_to :group, optional: true
    include Wf::ActsAsParty
    acts_as_party(user: true, party_name: :name)
  end
end


================================================
FILE: app/models/wf/workflow.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_workflows
#
#  id          :integer          not null, primary key
#  name        :string
#  description :text
#  is_valid    :boolean          default("false")
#  creator_id  :string
#  error_msg   :text
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#
module Wf
  class Workflow < ApplicationRecord
    has_many :places, dependent: :destroy
    has_many :transitions, dependent: :destroy
    has_many :arcs, dependent: :destroy
    has_many :transition_static_assignments
    has_many :cases
    has_many :workitems
    has_many :tokens

    validates :name, presence: true

    scope :valid, -> { where(is_valid: true) }

    after_save do
      do_validate!
    end

    after_touch do
      do_validate!
    end

    # TODO: can from start place to end place
    # todo: remove color hex to const.
    def do_validate!
      msgs = []
      start_place = places.start.first
      end_place   = places.end.first
      msgs << "must have start place" if start_place.blank?
      msgs << "must have only one start place" if places.start.count > 1
      msgs << "must have end place" if end_place.blank?
      msgs << "must have only one end place" if places.end.count > 1
      msgs << "must not have discrete transition" if transitions.any? { |t| !t.arcs.in.exists? }
      if start_place && end_place
        rgl = to_rgl
        places.each do |p|
          msgs << "start place can not reach #{p.name}" unless rgl.path?(start_place.to_gid.to_s, p.to_gid.to_s)
          msgs << "#{p.name} can not reach end_place" unless rgl.path?(p.to_gid.to_s, end_place.to_gid.to_s)
        end

        transitions.each do |t|
          msgs << "start place can not reach #{t.name}" unless rgl.path?(start_place.to_gid.to_s, t.to_gid.to_s)
          msgs << "#{t.name} can not reach end_place" unless rgl.path?(t.to_gid.to_s, end_place.to_gid.to_s)
        end
      end

      if Wf.use_lola
        msgs << "has deadlock" if to_lola.deadlock?
        msgs << "has dead transition" unless to_lola.quasiliveness?
        msgs << "can not reach to the end place" unless to_lola.reachability_of_final_marking?
      end

      if msgs.present?
        update_columns(is_valid: false, error_msg: msgs.join("\n"))
      else
        update_columns(is_valid: true, error_msg: "")
      end
    end

    def to_graph(wf_case = nil, base = nil)
      fontfamily = "system, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, Segoe UI Symbol"
      fontfamily_monospace = "SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace"
      graph = base || GraphViz.new(name, type: :digraph, rankdir: "LR", splines: true, ratio: :auto)

      free_token_places = if wf_case
        wf_case.tokens.free.map(&:place_id)
      else
        []
      end
      pg_mapping = {}
      places.order("place_type ASC").each do |p|
        if p.start?
          fillcolor = "#ffe7ba"
          textcolor = "#fa8c16"
          shape     = :doublecircle
        elsif p.end?
          fillcolor = "#dff2ef"
          textcolor = "#29c0b1"
          shape     = :doublecircle
        else
          fillcolor = "#fbdbe1"
          textcolor = "#ff3366"
          shape     = :circle
        end

        token_count = free_token_places.count(p.id)
        if token_count >= 1
          label  = "&bull;"
          xlabel = nil
          fontsize = 25
        else
          label = p.name
          xlabel = nil
        end

        pg = graph.add_nodes(p.graph_id,
                             label: label,
                             xlabel: xlabel,
                             shape: shape,
                             fixedsize: true,
                             style: :filled,
                             fontname: fontfamily,
                             fontcolor: textcolor,
                             fontsize: fontsize,
                             color: fillcolor,
                             fillcolor: fillcolor,
                             href: Wf::Engine.routes.url_helpers.edit_workflow_place_path(self, p))
        pg_mapping[p] = pg
      end

      tg_mapping = {}
      transitions.each do |t|
        peripheries = if t.multiple_instance?
          3
        else
          1
        end
        tg = graph.add_nodes(t.graph_id, label: t.name, shape: :box, style: :filled, fillcolor: "#d6ddfa", color: "#d6ddfa",
                                         fontcolor: "#2c50ed", fontname: fontfamily, peripheries: peripheries,
                                         href: Wf::Engine.routes.url_helpers.edit_workflow_transition_path(self, t))
        tg_mapping[t] = tg
        # NOTICE: if sub_workflow is transition's workflow, then graph will loop infinite, this is valid for workflow definition.
        next unless t.is_sub_workflow? && t.sub_workflow != t.workflow

        sub_graph = graph.add_graph("cluster#{t.sub_workflow_id}", rankdir: "LR", splines: true, ratio: :auto)
        sub_graph[:label] = t.sub_workflow.name
        sub_graph[:style] = :dashed
        sub_graph[:color] = :lightgrey
        # TODO: detect related case for sub workflow.
        t.sub_workflow.to_graph(nil, sub_graph)
        graph.add_edges(tg, t.sub_workflow.places.start.first.graph_id, style: :dashed, dir: :both)
      end

      arcs.order("direction desc").each do |arc|
        label = if arc.guards_count > 0
          arc.guards.map(&:inspect).join(" & ")
        else
          ""
        end
        if arc.in?
          graph.add_edges(
            pg_mapping[arc.place],
            tg_mapping[arc.transition],
            label: label,
            weight: 1,
            labelfloat: false,
            labelfontcolor: :red,
            arrowhead: :vee,
            fontsize: 10,
            color: "#53585c",
            fontcolor: "#53585c",
            fontname: fontfamily_monospace,
            href: Wf::Engine.routes.url_helpers.edit_workflow_arc_path(self, arc)
          )
        else
          graph.add_edges(
            tg_mapping[arc.transition],
            pg_mapping[arc.place],
            label: label,
            weight: 1,
            labelfloat: false,
            labelfontcolor: :red,
            arrowhead: :vee,
            fontsize: 10,
            color: "#53585c",
            fontcolor: "#53585c",
            fontname: fontfamily_monospace,
            href: Wf::Engine.routes.url_helpers.edit_workflow_arc_path(self, arc)
          )
        end
      end
      graph
    end

    def render_graph(wf_case = nil)
      graph = to_graph(wf_case)
      path = Rails.root.join("tmp", "#{id}.svg")
      graph.output(svg: path)
      File.read(path)
    end

    def to_lola
      @lola ||= Wf::Lola.new(self)
    end

    def to_rgl
      graph = RGL::DirectedAdjacencyGraph.new
      places.order("place_type ASC").each do |p|
        graph.add_vertex(p.to_gid.to_s)
      end

      transitions.each do |t|
        graph.add_vertex(t.to_gid.to_s)
      end

      arcs.order("direction desc").each do |arc|
        if arc.in?
          graph.add_edge(arc.place.to_gid.to_s, arc.transition.to_gid.to_s)
        else
          graph.add_edge(arc.transition.to_gid.to_s, arc.place.to_gid.to_s)
        end
      end
      graph
    end
  end
end


================================================
FILE: app/models/wf/workitem.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_workitems
#
#  id                      :integer          not null, primary key
#  case_id                 :integer
#  workflow_id             :integer
#  transition_id           :integer
#  state                   :integer          default("0")
#  enabled_at              :datetime
#  started_at              :datetime
#  canceled_at             :datetime
#  finished_at             :datetime
#  overridden_at           :datetime
#  deadline                :datetime
#  created_at              :datetime         not null
#  updated_at              :datetime         not null
#  trigger_time            :datetime
#  holding_user_id         :string
#  children_count          :integer          default("0")
#  children_finished_count :integer          default("0")
#  forked                  :boolean          default("false")
#  parent_id               :integer
#

module Wf
  class Workitem < ApplicationRecord
    belongs_to :workflow
    belongs_to :transition
    belongs_to :case
    belongs_to :parent, class_name: "Wf::Workitem", optional: true, counter_cache: :children_count
    belongs_to :holding_user, foreign_key: :holding_user_id, class_name: Wf.user_class.to_s, optional: true
    has_many :workitem_assignments
    has_many :parties, through: :workitem_assignments, source: "party"
    has_many :comments
    has_many :entries, class_name: Wf.entry_class.to_s
    has_one :started_case, foreign_key: :started_by_workitem_id, class_name: "Wf::Case"

    has_many :children, foreign_key: :parent_id, class_name: "Wf::Workitem"

    enum state: {
      enabled: 0,
      started: 1,
      canceled: 2,
      finished: 3,
      overridden: 4
    }

    def self.todo(wf_current_user)
      current_party_ids = [
        wf_current_user,
        Wf.org_classes.map { |org, _org_class| wf_current_user&.public_send(org) }
      ].flatten.map { |x| x&.party&.id }.compact
      Wf::Workitem.where(forked: false).joins(:workitem_assignments).where(Wf::WorkitemAssignment.table_name => { party_id: current_party_ids })
    end

    def self.doing(wf_current_user)
      where(holding_user: wf_current_user).where(state: %i[started enabled])
    end

    def self.done(wf_current_user)
      where(holding_user: wf_current_user).where(state: [:finished])
    end

    def for_mini_racer
      attr = attributes
      attr = attr.merge(holding_user: holding_user&.attributes || {})
      attr = attr.merge(form: entries.to_a.first&.for_mini_racer || {})
      children_attrs = if forked?
        []
      else
        children.includes(:holding_user, entries: :field_values).map(&:for_mini_racer)
      end
      attr = attr.merge(children: children_attrs)
      attr
    end

    def parent?
      !forked
    end

    def name
      "Workitem -> #{id}"
    end

    def pass_guard?(arc, has_passed = false)
      if arc.guards_count == 0
        !has_passed
      else
        entry = entries.where(user: holding_user).first
        arc.guards.all? { |guard| guard.pass?(entry, self) }
      end
    end

    def real?
      return false if transition.multiple_instance? && parent_id.nil?
      return false if transition.sub_workflow_id.present?

      true
    end

    def started_by?(user)
      real? && enabled? && owned_by?(user)
    end

    def finished_by?(user)
      real? && started? && owned_by?(user) && holding_user == user
    end

    def owned_by?(user)
      Wf::Party.joins(workitem_assignments: { workitem: %i[transition case] })
               .where(Wf::Transition.table_name => { trigger_type: Wf::Transition.trigger_types[:user] })
               .where(Wf::Case.table_name => { state: Wf::Case.states[:active] })
               .where(Wf::Workitem.table_name => { state: Wf::Workitem.states.values_at(:started, :enabled) })
               .where(Wf::Workitem.table_name => { id: id }).map do |party|
        party.partable.users.to_a
      end.flatten.include?(user)
    end
  end
end


================================================
FILE: app/models/wf/workitem_assignment.rb
================================================
# frozen_string_literal: true

# == Schema Information
#
# Table name: wf_workitem_assignments
#
#  id          :integer          not null, primary key
#  party_id    :integer
#  workitem_id :integer
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

module Wf
  class WorkitemAssignment < ApplicationRecord
    belongs_to :party
    belongs_to :workitem
  end
end


================================================
FILE: app/views/layouts/wf/_alert.html.erb
================================================
<% return if alert.blank? %>
<div id="alert" class="alert alert-warning">
  <p>
    <svg viewBox="64 64 896 896" focusable="false" class="" data-icon="exclamation-circle" width="1em" height="1em" fill="#fa4a4a" aria-hidden="true"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"></path></svg> <%= alert %></p>
</div>


================================================
FILE: app/views/layouts/wf/_footer.html.erb
================================================
<footer class="footer">
  <div class="container">
    <p>
      <strong>
        <a href="https://github.com/hooopo/petri_flow" target="_blank" rel="nofollow">Petri Flow</a>
      </strong>
      crafted by <a href="https://github.com/hooopo" target="_blank" rel="nofollow">Hooopo</a>.
      The source code is licensed under <a href="http://opensource.org/licenses/mit-license.php">MIT license</a>.
    </p>
  </div>
</footer>


================================================
FILE: app/views/layouts/wf/_nav.html.erb
================================================
<nav class="navbar navbar-petri" role="navigation" aria-label="main navigation">
  <div class="container">
    <div class="navbar-brand">
      <%= link_to "👨‍💻Petri Flow", root_path, class: "navbar-item" %>
    </div>

    <div class="navbar-end">
      <%= link_to wf_current_user&.name, workitems_path %>
      <%= link_to 'Forms', forms_path, class: "navbar-item #{"is-active" if controller_name == "forms"}" %>
      <%= link_to 'Workflows', workflows_path, class: "navbar-item #{"is-active" if controller_name.start_with?("workflows")}" %>
    </div>
  </div>
</nav>


================================================
FILE: app/views/layouts/wf/_notice.html.erb
================================================
<% return if notice.blank? %>
<div id="notice" class="alert alert-success">
  <p>
    <svg viewBox="64 64 896 896" focusable="false" class="" data-icon="check-circle" width="1em" height="1em" fill="#00d192" aria-hidden="true"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg>  <%= notice %></p>
</div>


================================================
FILE: app/views/layouts/wf/application.html.erb
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Petri Flow</title>

  <%= csrf_meta_tags %>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>

  <%= stylesheet_link_tag    "wf/application", media: "all", "data-turbolinks-track": "reload" %>
  <%= javascript_include_tag "wf/application", "data-turbolinks-track": "reload" %>
</head>
<body>

<%= render "layouts/wf/nav" %>
<main class="container">
  <%= render "layouts/wf/notice" %>
  <%= render "layouts/wf/alert" %>
  <!--
  <nav aria-label="breadcrumb">
  <ol class='breadcrumb'>
    <% breadcrumb_trail do |crumb| %>
      <li class="breadcrumb-item <%= crumb.current? ? 'active' : '' %>">
        <%= link_to crumb.name, crumb.url, (crumb.current? ? {'aria-current' => 'page'} : {}) %>
      </li>
    <% end %>
  </ol>
</nav>
-->
  <%= content_for?(:content) ? yield(:content) : yield %>
</main>

<%= render "layouts/wf/footer" %>
</body>
</html>


================================================
FILE: app/views/wf/arcs/_form.html.erb
================================================
<%= form_with(model: arc, url: [@workflow, @arc], local: true) do |f| %>
  <% if arc.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(arc.errors.count, "error") %> prohibited this arc from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% arc.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :place, class: "label" %>
    <%= f.select :place_id, @workflow.places.map{|x| [x.name, x.id]}, {}, class: "form-control custom-select", placeholder: "Place" %>
  </div>

  <div class="form-group">
    <%= f.label :transition, class: "label" %>
    <%= f.select :transition_id, @workflow.transitions.map{|x| [x.name, x.id]}, {}, class: "custom-select", placeholder: "Transition" %>
  </div>

  <div class="form-group">
    <div id="notice" class="alert alert-success">
      Direction is base on transition, in: P->T, out: T->P.
    </div>
    <%= f.label :direction, class: "label" %>
    <%= f.select :direction, Wf::Arc.directions.keys, {}, class: "form-control custom-select", placeholder: "Direction" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/arcs/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, arc: @arc %>
</div>


================================================
FILE: app/views/wf/arcs/new.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, arc: @arc %>
</div>


================================================
FILE: app/views/wf/arcs/show.html.erb
================================================
<div class="card card-body">
<div class="float-right">
  <%= link_to 'Delete Arc', workflow_path(@workflow, @arc), data: {confirm: 'confirm?'}, method: :delete, class: 'btn btn-danger' %>
  <%= link_to 'Edit Arc', edit_workflow_arc_path(@workflow, @arc), class: 'btn btn-primary' %>
  <% if @arc.out? %>
    <%= link_to 'Create Guards', new_arc_guard_path(@arc), class: 'btn btn-primary' %>
  <% end %>
</div>
<div>
  <h2>Arc Detail</h2>
  <table class="table table-view">
    <tbody>
      <tr>
        <th scope="row">ID</th>
        <td><%= @arc.id %></td>
      </tr>
      <tr>
        <th scope="row">Name</th>
        <td><%= @arc.name %></td>
      </tr>
      <tr>
        <th scope="row">Transition</th>
        <td><%= @arc.transition.name %></td>
      </tr>
      <tr>
        <th scope="row">Place</th>
        <td><%= @arc.place.name %></td>
      </tr>
      <tr>
        <th scope="row">Guards</th>
        <td><%= @arc.guards.map {|x| x.inspect }.join(" & ") %></td>
      </tr>
      <tr>
        <th scope="row">Direction</th>
        <td><%= @arc.direction %></td>
      </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Guards</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Field</th>
        <th scope="col">Op</th>
        <th scope="col">Value</th>
        <th scope="col">Exp</th>
        <th scope="col">Actions</th>
      </tr>
    </thead>
    <tbody>
      <% @arc.guards.each do |guard| %>
        <tr>
          <td><%= guard.id %></td>
          <td><%= guard.fieldable&.form&.name %>/<%= guard.fieldable&.name %></td>
          <td><%= guard.op %></td>
          <td><%= guard.value %></td>
          <td>
            <pre>
              <%= guard.exp %>
            </pre>
          </td>
          <td><%= link_to 'Edit Guard', edit_arc_guard_path(@arc, guard), class: 'btn btn-sm btn-info' %></td>
          <td><%= link_to 'Delete Guard', [@arc, guard], remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-info' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
</div>


================================================
FILE: app/views/wf/cases/_form.html.erb
================================================
<%= form_with(model: wf_case, url: [@workflow, @wf_case], local: true) do |f| %>
  <% if wf_case.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(wf_case.errors.count, "error") %> prohibited this wf_case from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% wf_case.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :targetable, class: "label" %>
    <%= f.select :targetable, options_for_select(Wf::DemoTarget.all.map {|x| [x.name, x.to_global_id]} || []), {include_blank: true}, class: "form-control custom-select", placeholder: "targetable" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/cases/index.html.erb
================================================
<div class="card card-body">
  <div class="float-left"><h2>Cases</h2></div>
  <div class="float-right">
    <%= link_to 'New Case', new_workflow_case_path(@workflow), class: 'btn btn-primary' %>
  </div>
  <div>
    <table class="table table-view">
      <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">State</th>
        <th scope="col">Created At</th>
        <th scope="col">Targetable Type</th>
        <th scope="col">Targetable ID</th>
        <th scope="col">Action</th>
      </tr>
      </thead>
      <tbody>
      <% @cases.each do |wf_case| %>
        <tr>
          <td><%= wf_case.id %></td>
          <td><%= wf_case.state %></td>
          <td><%= wf_case.created_at %></td>
          <td><%= wf_case.targetable_type %></td>
          <td><%= wf_case.targetable_id %></td>
          <td>
            <%= link_to "Run", workflow_case_path(@workflow, wf_case), class: 'btn btn-success btn-sm' %>
          </td>
        </tr>
      <% end %>
      </tbody>
    </table>
  </div>
  <div>
    <%= paginate @cases, theme: 'twitter-bootstrap-4' %>
  </div>
</div>


================================================
FILE: app/views/wf/cases/new.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, wf_case: @wf_case %>
</div>


================================================
FILE: app/views/wf/cases/show.html.erb
================================================
<div class="card card-body">
<div>
  <h2>Case Detail</h2>
  <table class="table table-view">
    <tbody>
      <tr>
        <th scope="row">ID</th>
        <td><%= @wf_case.id %></td>
      </tr>
      <tr>
        <th scope="row">Workflow</th>
        <td><%= link_to @wf_case.workflow.name, workflow_path(@wf_case.workflow) %></td>
      </tr>
      <tr>
        <th scope="row">State</th>
        <td><%= @wf_case.state %></td>
      </tr>
      <tr>
        <th scope="row">Targetable Type</th>
        <td><%= @wf_case.targetable_type %></td>
      </tr>
      <tr>
        <th scope="row">Targetable ID</th>
        <td><%= @wf_case.targetable_id %></td>
      </tr>
      <tr>
        <th scope="row">Created At</th>
        <td><%= @wf_case.created_at %></td>
      </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Case Graph</h2>
  <div class="card">
    <div class="card-body">
      <%=raw @wf_case.workflow.render_graph(@wf_case) %>
    </div>
  </div>
</div>

<div>
  <h2>Tokens</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Place</th>
        <th scope="col">State</th>
        <th scope="col">Locked Workitem</th>
        <th scope="col">Produced At</th>
        <th scope="col">Locked At</th>
        <th scope="col">Canceled At</th>
        <th scope="col">Consumed At</th>
        <th scope="col">Created At</th>
      </tr>
    </thead>
    <tbody>
      <% @wf_case.tokens.each do |token| %>
        <tr>
          <td><%= token.id %></td>
          <td><%= link_to token.place.name, workflow_place_path(token.workflow, token.place) %> </td>
          <td><%= token.state %></td>
          <td><%= token.locked_workitem_id %></td>
          <td><%= token.produced_at %></td>
          <td><%= token.locked_at %></td>
          <td><%= token.canceled_at %></td>
          <td><%= token.consumed_at %></td>
          <td><%= token.created_at %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<div>
  <h2>Workitems</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Transition</th>
        <th scope="col">State</th>
        <th scope="col">Holding User</th>
        <th scope="col">Started At</th>
        <th scope="col">Enabled At</th>
        <th scope="col">Canceled At</th>
        <th scope="col">Finished At</th>
        <th scope="col">Overridden At</th>
        <th scope="col">Deadline</th>
        <th scope="col">Detail</th>
      </tr>
    </thead>
    <tbody>
      <% @wf_case.workitems.each do |workitem| %>
        <tr>
          <td><%= link_to workitem.id, workitem_path(workitem) %></td>
          <td>
            <%= link_to workitem.transition.name, workflow_transition_path(workitem.workflow, workitem.transition) %> </td>
          <td><%= workitem.state %></td>
          <td><%= workitem.holding_user_id %></td>
          <td><%= workitem.started_at %></td>
          <td><%= workitem.enabled_at %></td>
          <td><%= workitem.canceled_at %></td>
          <td><%= workitem.finished_at %></td>
          <td><%= workitem.overridden_at %></td>
          <td><%= workitem.deadline %></td>
          <td><%= link_to "Run", workitem_path(workitem), class: 'btn btn-sm btn-success' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
</div>


================================================
FILE: app/views/wf/comments/new.html.erb
================================================
<div class="card card-body">
<%= form_with(model: @comment, url: workitem_comments_path(@workitem), local: true) do |f| %>
  <% if @comment.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% @comment.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :body, class: "label" %>
    <%= f.text_area :body, class: "form-control", rows: 3, placeholder: "comment" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", value: "Comment", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>
</div>


================================================
FILE: app/views/wf/fields/_form.html.erb
================================================
<%= form_with(model: field, url: [@form, field], local: true) do |f| %>
  <% if field.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(field.errors.count, "error") %> prohibited this field from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% field.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :name, class: "label" %>
    <%= f.text_field :name, class: "form-control", fieldholder: "Name" %>
  </div>

  <div class="form-group">
    <%= f.label :position, class: "label" %>
    <%= f.text_field :position, class: "form-control", fieldholder: "Position" %>
  </div>

  <div class="form-group">
    <%= f.label :default_value, class: "label" %>
    <%= f.text_field :default_value, class: "form-control", fieldholder: "Default Value" %>
  </div>

  <div class="form-group">
    <%= f.label :field_type, class: "label" %>
    <%= f.select :field_type, Wf::Field.field_types.keys, {}, class: "form-control custom-select", fieldholder: "Field Type" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/fields/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", form: @form, field: @field %>
</div>


================================================
FILE: app/views/wf/fields/new.html.erb
================================================
<div class="card card-body">
<%= render "form", form: @form, field: @field %>
</div>


================================================
FILE: app/views/wf/forms/_form.html.erb
================================================
<%= form_with(model: form, local: true) do |f| %>
  <% if form.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(form.errors.count, "error") %> prohibited this form from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% form.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :name, class: "label" %>
    <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
  </div>

  <div class="form-group">
    <%= f.label :description, class: "label" %>
    <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/forms/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", form: @form %>
</div>


================================================
FILE: app/views/wf/forms/index.html.erb
================================================
<div class="card card-body">
 <div class="d-flex  justify-content-between">
   <div><h2>Forms</h2></div>
   <div><%= link_to '+  New Form', new_form_path, class: 'btn btn-primary' %></div>
 </div>
<div>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Description</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <% @forms.each do |form| %>
        <tr>
          <td><%= form.id %></td>
          <td><%= link_to form.name, form_path(form) %></td>
          <td><%= form.description %></td>
          <td class="text-right">
            <%= link_to 'Delete Form', form_path(form), method: :delete, data: {confirm: 'confirm?'}, class: 'btn-link btn btn-sm text-danger' %>
            <%= link_to 'Create Field', new_form_field_path(form), class: 'btn btn-link btn-sm' %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<div>
  <%= paginate @forms, theme: 'twitter-bootstrap-4' %>
</div>
</div>


================================================
FILE: app/views/wf/forms/new.html.erb
================================================
<div class="card card-body">
<%= render "form", form: @form %>
</div>


================================================
FILE: app/views/wf/forms/show.html.erb
================================================
<div class="card card-body">
<div class="d-flex  justify-content-end">
  <%= link_to 'Delete Form', form_path(@form), data: {confirm: 'confirm?'}, method: :delete, class: 'btn btn-danger mr-2' %>
  <%= link_to 'Edit Form', edit_form_path(@form), class: 'btn btn-light mr-2' %>
  <%= link_to 'Create Fields', new_form_field_path(@form), class: 'btn btn-light' %>
</div>
<div>
  <h2>Form Detail</h2>
  <table class="table table-view">
    <tbody>
      <tr>
        <th scope="row">ID</th>
        <td><%= @form.id %></td>
      </tr>
      <tr>
        <th scope="row">Name</th>
        <td><%= @form.name %></td>
      </tr>
      <tr>
        <th scope="row">Description</th>
        <td><%= @form.description %></td>
      </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Fields</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Position</th>
        <th scope="col">Field Type</th>
        <th scope="col">Default Value</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <% @form.fields.each do |field| %>
        <tr>
          <td><%= field.id %></td>
          <td><%= field.name %></td>
          <td><%= field.position %></td>
          <td><%= field.field_type %></td>
          <td><%= field.default_value %></td>
          <td class="text-right"><%= link_to 'Edit Field', edit_form_field_path(@form, field), class: 'btn btn-sm btn-link mr-2' %>
            <%= link_to 'Delete Field', [@form, field], remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-link text-danger' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
</div>


================================================
FILE: app/views/wf/guards/_form.html.erb
================================================
<%= form_with(model: guard, url: [@arc, @guard], local: true) do |f| %>
  <% if guard.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(guard.errors.count, "error") %> prohibited this guard from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% guard.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :fieldable, class: "label" %>
    <%= f.select :fieldable, options_for_select(@arc.transition.form&.fields&.map {|x| [x.name, x.to_global_id]} || [], selected: f.object&.fieldable&.to_global_id), {include_blank: "select a field"}, class: "form-control custom-select", placeholder: "fieldable" %>
  </div>

  <div class="form-group">
    <%= f.label :exp, class: "label" %> <small>JavaScript with build-in variable <span class="badge badge-danger">workitem</span>, <span class="badge badge-danger">target</span>.</small>
    <%= f.text_area :exp, class: "form-control", placeholder: "Exp", rows: 8 %>
  </div>

  <div class="form-group">
    <%= f.label :op, class: "label" %>
    <%= f.select :op, Wf::Guard::OP, {}, class: "form-control custom-select", placeholder: "Op" %>
  </div>


  <div class="form-group">
    <%= f.label :value, class: "label" %>
    <%= f.text_field :value, class: "form-control", placeholder: "Value" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/guards/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", arc: @arc, guard: @guard %>
</div>


================================================
FILE: app/views/wf/guards/new.html.erb
================================================
<div class="card card-body">
<%= render "form", arc: @arc, guard: @guard %>
</div>


================================================
FILE: app/views/wf/places/_form.html.erb
================================================
<%= form_with(model: place, url: [@workflow, @place], local: true) do |f| %>
  <% if place.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(place.errors.count, "error") %> prohibited this place from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% place.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :name, class: "label" %>
    <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
  </div>

  <div class="form-group">
    <%= f.label :description, class: "label" %>
    <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
  </div>


  <div class="form-group">
    <%= f.label :sort_order, class: "label" %>
    <%= f.text_field :sort_order, class: "form-control", placeholder: "Sort Order" %>
  </div>

  <div class="form-group">
    <%= f.label :place_type, class: "label" %>
    <%= f.select :place_type, Wf::Place.place_types.keys, {}, class: "form-control custom-select", placeholder: "Place Type" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/places/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, place: @place %>
</div>


================================================
FILE: app/views/wf/places/new.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, place: @place %>
</div>


================================================
FILE: app/views/wf/static_assignments/_form.html.erb
================================================
<%= form_with(model: static_assignment, url: transition_static_assignments_path(static_assignment.transition), local: true) do |f| %>
  <% if static_assignment.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(static_assignment.errors.count, "error") %> prohibited this static_assignment from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% static_assignment.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :party, class: "label" %>
    <%= f.select :party_id, Wf::Party.all.map{|x| [x.party_name, x.id]}, {}, class: "form-control custom-select", placeholder: "fieldable" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", value: 'Create Static Assignment', data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/static_assignments/new.html.erb
================================================
<div class="card card-body">
  <%= render "form", static_assignment: @static_assignment %>
</div>


================================================
FILE: app/views/wf/transitions/_form.html.erb
================================================
<%= form_with(model: transition, url: [@workflow, @transition], local: true) do |f| %>
  <% if transition.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(transition.errors.count, "error") %> prohibited this transition from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% transition.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="card">
  <h5 class="card-header">Basic Information</h5>
    <div class="card-body">
      <div class="form-group">
        <%= f.label :name, class: "label" %>
        <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
      </div>

      <div class="form-group">
        <%= f.label :description, class: "label" %>
        <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
      </div>

      <div class="form-group">
        <%= f.label :trigger_limit, class: "label" %>
        <%= f.text_field :trigger_limit, class: "form-control", placeholder: "Trigger Limit" %>
      </div>

      <div class="form-group">
        <%= f.label :trigger_type, class: "label" %>
        <%= f.select :trigger_type, Wf::Transition.trigger_types.keys, {}, class: "form-control custom-select", placeholder: "Trigger Type" %>
      </div>
    </div>
  </div>


  <div class="card">
  <h5 class="card-header">Sub Workflow</h5>
  <div class="card-body">
    <div class="form-group">
      <%= f.label :sub_workflow, class: "label" %>
      <%= f.select :sub_workflow_id, options_for_select(Wf::Workflow.valid.all.map{|x| [x.name, x.id]} || []), {include_blank: 'Start a sub workflow?'}, class: "form-control custom-select", placeholder: "Sub Workflow" %>
    </div>
  </div>
  </div>

  <div class="card">
  <h5 class="card-header">Dynimac Form</h5>
    <div class="card-body">
      <div class="form-group">
        <%= f.label :form, class: "label" %>
        <%= f.select :form, options_for_select(Wf.form_class.constantize.all.map{|x| [x.name, x.to_global_id]} || [], selected: f.object&.form&.to_global_id), {include_blank: 'user can input from custom form?'}, class: "form-control custom-select", placeholder: "Form" %>
      </div>
    </div>
  </div>

  <div class="card">
  <h5 class="card-header">Dynamic Assign By</h5>
  <div class="card-body">
    <div class="form-group">
      <%= f.label :dynamic_assign_by, class: "label" %>
      <%= f.select :dynamic_assign_by_id, options_for_select(@workflow.transitions.where("id != ?", @transition.id).all.map{|x| [x.name, x.id]} || []), {include_blank: 'What other transition you want to do the assignment for this transition?'}, class: "form-control custom-select" %>
    </div>
  </div>
  </div>

  <div class="card">
  <h5 class="card-header">Callbacks</h5>
    <div class="card-body">

      <div class="form-group">
        <%= f.label :enable_callback, class: "label" %>
        <%= f.select :enable_callback, Wf.enable_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :fire_callback, class: "label" %>
        <%= f.select :fire_callback, Wf.fire_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :deadline_callback, class: "label" %>
        <%= f.select :deadline_callback, Wf.deadline_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :time_callback, class: "label" %>
        <%= f.select :time_callback, Wf.time_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :hold_timeout_callback, class: "label" %>
        <%= f.select :hold_timeout_callback, Wf.hold_timeout_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :assignment_callback, class: "label" %>
        <%= f.select :assignment_callback, Wf.assignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :unassignment_callback, class: "label" %>
        <%= f.select :unassignment_callback, Wf.unassignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>

      <div class="form-group">
        <%= f.label :notification_callback, class: "label" %>
        <%= f.select :notification_callback, Wf.notification_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
      </div>
    </div>
  </div>

  <div class="card">
  <h5 class="card-header">Multiple Instances</h5>
    <div class="card-body">
      <div class="form-group">
        <%= f.label :multiple_instance, class: "label" %>
        <%= f.check_box :multiple_instance %>
      </div>
      <div class="form-group">
        <%= f.label :finish_condition, class: "label" %>
        <%= f.select :finish_condition, Wf.finish_conditions, {}, class: "form-control custom-select", placeholder: "Finish_condition" %>
      </div>
    </div>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/transitions/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, transition: @transition %>
</div>


================================================
FILE: app/views/wf/transitions/new.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow, transition: @transition %>
</div>


================================================
FILE: app/views/wf/transitions/show.html.erb
================================================
<div class="card card-body">
<div class="float-right">
  <%= link_to 'Edit Transition', edit_workflow_transition_path(@workflow, @transition), class: 'btn btn-primary' %>
  <%= link_to 'Create Static Assignments', new_transition_static_assignment_path(@transition), class: 'btn btn-primary' %>
</div>
<div>
  <h2>Transition Detail</h2>
  <table class="table table-view">
    <tbody>
      <tr>
        <th scope="row">ID</th>
        <td><%= @transition.id %></td>
      </tr>
      <tr>
        <th scope="row">Name</th>
        <td><%= @transition.name %></td>
      </tr>
      <tr>
        <th scope="row">Trigger Limit</th>
        <td><%= @transition.trigger_limit %></td>
      </tr>
      <tr>
        <th scope="row">Trigger Type</th>
        <td><%= @transition.trigger_type %></td>
      </tr>
      <tr>
        <th>Form</th>
        <td>
          <% if @transition.form %>
             <%= link_to @transition.form.name, form_path(@transition.form) %>
          <% else %>
             No Form
          <% end %>
        </td>
      </tr>

      <tr>
        <th>Sub Workflow</th>
        <td>
            <% if @transition.sub_workflow %>
              <%= link_to @transition.sub_workflow.name, workflow_path(@transition.sub_workflow_id) %>
            <% else %>
              No
            <% end %>
        </td>
      </tr>

      <tr>
        <th>Dynamic Assign By</th>
        <td>
            <% if @transition.dynamic_assign_by %>
              <%= link_to @transition.dynamic_assign_by.name, workflow_transition_path(@workflow, @transition.dynamic_assign_by_id) %>
            <% else %>
              No
            <% end %>
        </td>
      </tr>

      <tr>
        <th scope="row">Multiple Instance?</th>
        <td><%= @transition.multiple_instance %></td>
      </tr>
      <tr>
        <th scope="row">Finish Condition</th>
        <td><%= @transition.finish_condition %></td>
      </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Static Assignments</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Party Name</th>
        <th scope="col">Party Type</th>
        <th scope="col">Actions</th>
      </tr>
    </thead>
    <tbody>
      <% @transition.transition_static_assignments.each do |assign| %>
        <tr>
          <td><%= assign.id %></td>
          <td><%= assign.party.party_name %></td>
          <td><%= assign.party.partable_type %></td>
          <td><%= link_to 'Delete', transition_static_assignment_path(@transition, assign), remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-info' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
</div>


================================================
FILE: app/views/wf/workflows/_form.html.erb
================================================
<%= form_with(model: workflow, local: true) do |f| %>
  <% if workflow.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(workflow.errors.count, "error") %> prohibited this workflow from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% workflow.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :name, class: "label" %>
    <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
  </div>

  <div class="form-group">
    <%= f.label :description, class: "label" %>
    <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

================================================
FILE: app/views/wf/workflows/edit.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow %>
</div>


================================================
FILE: app/views/wf/workflows/index.html.erb
================================================
<div class="card card-body">
  <div class="d-flex  justify-content-between">

  <div><h2>Workflows</h2></div>
<div>
  <%= link_to 'New Workflow', new_workflow_path, class: 'btn btn-primary' %>
</div>
  </div>
<div>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Description</th>
        <th scope="col">Is Valid?</th>
        <th scope="col">Error Msg</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <% @workflows.each do |workflow| %>
        <tr>
          <td><%= workflow.id %></td>
          <td><%= link_to workflow.name, workflow_path(workflow) %></td>
          <td><%= workflow.description %></td>
          <td><%= workflow.is_valid? %></td>
          <td>
            <pre>
              <%= workflow.error_msg %>
            </pre>
          </td>
          <td class="text-right">
            <%= link_to 'Delete Workflow', workflow_path(workflow), remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-link btn-sm text-danger' %>
            <%= link_to 'Create Transition', new_workflow_transition_path(workflow), class: 'btn btn-link btn-sm' %>
            <%= link_to 'Create Place', new_workflow_place_path(workflow), class: 'btn btn-link btn-sm' %>
            <%= link_to 'Create Arc', new_workflow_arc_path(workflow), class: 'btn btn-link btn-sm' %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<div>
  <%= paginate @workflows, theme: 'twitter-bootstrap-4' %>
</div>
</div>


================================================
FILE: app/views/wf/workflows/new.html.erb
================================================
<div class="card card-body">
<%= render "form", workflow: @workflow %>
</div>


================================================
FILE: app/views/wf/workflows/show.html.erb
================================================
<div class="d-flex  justify-content-end">
<% if @workflow.is_valid? %>
    <%= link_to 'New Case', new_workflow_case_path(@workflow), class: 'btn btn-primary mr-2' %>
  <% end %>
  <%= link_to 'Delete Workflow', workflow_path(@workflow), data: {confirm: 'confirm?'}, method: :delete, class: 'btn btn-danger mr-2' %>
  <%= link_to 'Edit Workflow', edit_workflow_path(@workflow), class: 'btn btn-light mr-2' %>
  <%= link_to 'Create Transitions', new_workflow_transition_path(@workflow), class: 'btn btn-light mr-2' %>
  <%= link_to 'Create Places', new_workflow_place_path(@workflow), class: 'btn btn-light mr-2' %>
  <%= link_to 'Create Arcs', new_workflow_arc_path(@workflow), class: 'btn btn-light ' %>
</div>
<div class="card card-body">
  <h2 class="">Workflow Detail</h2>
  <table class="table table-view">
    <tbody>
      <tr>
        <th scope="row">ID</th>
        <td><%= @workflow.id %></td>
      </tr>
      <tr>
        <th scope="row">Name</th>
        <td><%= @workflow.name %></td>
      </tr>
      <tr>
        <th scope="row">Description</th>
        <td><%= @workflow.description %></td>
      </tr>
      <tr>
        <th scope="row">Is Valid?</th>
        <td><code><%= @workflow.is_valid? %></code></td>
      </tr>

      <tr>
        <th scope="row">Error Msg</th>
        <td>
          <pre>
            <%= @workflow.error_msg %>
          </pre>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<div class="card card-body">
  <h2>Graph Editor</h2>
  <div class="card">
    <div class="card-body">
      <%=raw @workflow.render_graph %>
    </div>
  </div>
</div>

<div class="card card-body">
  <h2 class="">Cases</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">All</th>
        <th scope="col">Created</th>
        <th scope="col">Active</th>
        <th scope="col">Suspended</th>
        <th scope="col">Canceled</th>
        <th scope="col">Finished</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= link_to @workflow.cases.count, workflow_cases_path(@workflow) %></td>
        <td><%= link_to @workflow.cases.created.count, workflow_cases_path(@workflow, state: :created) %></td>
        <td><%= link_to @workflow.cases.active.count, workflow_cases_path(@workflow, state: :active) %></td>
        <td><%= link_to @workflow.cases.suspended.count, workflow_cases_path(@workflow, state: :suspended) %></td>
        <td><%= link_to @workflow.cases.canceled.count, workflow_cases_path(@workflow, state: :canceled) %></td>
        <td><%= link_to @workflow.cases.finished.count, workflow_cases_path(@workflow, state: :finished) %></td>
      </tr>
    </tbody>
  </table>
</div>

<div class="card card-body">
  <h2>Places</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Description</th>
        <th scope="col">Place Type</th>
        <th scope="col">Sort Order</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <% @workflow.places.each do |place| %>
        <tr>
          <td><%= place.id %></td>
          <td><%= place.name %></td>
          <td><%= place.description %></td>
          <td><%= place.place_type %></td>
          <td><%= place.sort_order %></td>
          <td class="text-right">
            <%= link_to 'Edit Place', edit_workflow_place_path(@workflow, place), class: 'btn btn-sm btn-link mr-2' %>
            <%= link_to 'Delete Place', [@workflow, place], remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-link text-danger' %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<div class="card card-body">
  <h2>Transitions</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Description</th>
        <th scope="col">Trigger Limit</th>
        <th scope="col">Trigger Type</th>
        <th scope="col">Sort Order</th>
        <th scope="col">Custom Form</th>
        <th scope="col">Sub Workflow</th>
        <th scope='col'> </th>
      </tr>
    </thead>
    <tbody>
      <% @workflow.transitions.each do |transition| %>
        <tr>
          <td><%= transition.id %></td>
          <td><%= link_to transition.name, workflow_transition_path(@workflow, transition) %></td>
          <td><%= transition.description %></td>
          <td><%= transition.trigger_limit %></td>
          <td><%= transition.trigger_type %></td>
          <td><%= transition.sort_order %></td>

          <td>
            <% if transition.form %>
             <%= link_to transition.form.name, form_path(transition.form) %>
            <% else %>
             No Form
            <% end %>
          </td>
          <td>
            <% if transition.sub_workflow %>
              <%= link_to transition.sub_workflow.name, workflow_path(transition.sub_workflow_id) %>
            <% else %>
              No
            <% end %>
          </td> 
          <td><%= link_to 'Edit Transition', edit_workflow_transition_path(@workflow, transition), class: 'btn btn-sm btn-link mr-2' %>
            <%= link_to 'Delete Transition', [@workflow, transition], remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-link text-danger' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
<div class="card card-body">
  <h2>Arcs</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Direction</th>
        <th scope="col">Place</th>
        <th scope="col">Transition</th>
        <th scope="col">Arc Type</th>
        <th scope="col">Guards</th>
        <th scope='col'> </th>
      </tr>
    </thead>
    <tbody>
      <% @workflow.arcs.includes(:transition, :place).each do |arc| %>
        <tr>
          <td><%= link_to arc.id, workflow_arc_path(@workflow, arc) %></td>
          <td><%= link_to arc.name, workflow_arc_path(@workflow, arc) %></td>
          <td><%= arc.direction %></td>
          <td><%= arc.place&.name %></td>
          <td><%= arc.transition&.name %></td>
          <td><code><%= arc.guards.map(&:inspect).join(" & ") %></code></td>
          <td>
            <% if arc.out? %>
              <%= link_to 'Add Gruards', new_arc_guard_path(arc), class: 'btn btn-sm btn-outline-primary mr-2' %>
            <% end %>
          </td>
          <td class="text-right">
            <%= link_to 'Edit Arc', edit_workflow_arc_path(@workflow, arc), class: 'btn btn-sm btn-link mr-2' %>
            <%= link_to 'Delete Arc', [@workflow, arc], remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-link text-danger' %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>


================================================
FILE: app/views/wf/workitem_assignments/new.html.erb
================================================
<div class="card card-body">
<%= form_with(model: @workitem_assignment, url: workitem_workitem_assignments_path(@workitem), local: true) do |f| %>
  <% if @workitem_assignment.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(@workitem_assignment.errors.count, "error") %> prohibited this workitem_assignment from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% @workitem_assignment.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>

  <div class="form-group">
    <%= f.label :party_id, class: "label" %>
    <%= f.select :party_id, Wf::Party.all.map{|x| [x.party_name, x.id]}, {}, class: "form-control custom-select", placeholder: "party_id" %>
  </div>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", value: "Assign", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>
</div>


================================================
FILE: app/views/wf/workitems/index.html.erb
================================================
<div class="card card-body">
<div>
  <h2 class="">Stats</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">All</th>
        <th scope="col">Enabled</th>
        <th scope="col">Started</th>
        <th scope="col">Canceled</th>
        <th scope="col">Finished</th>
        <th scope="col">Overridden</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).count, workitems_path %></td>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).enabled.count, workitems_path(state: :enabled) %></td>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).started.count, workitems_path(state: :started) %></td>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).canceled.count, workitems_path(state: :canceled) %></td>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).finished.count, workitems_path(state: :finished) %></td>
        <td><%= link_to @workitems.unscope(:offset).unscope(:limit).unscope(:order).unscope(:select).overridden.count, workitems_path(state: :overridden) %></td>
      </tr>
    </tbody>
  </table>
</div>
</div>
<div class="card card-body">
<div>
  <h2>Workitems</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Transition</th>
        <th scope="col">State</th>
        <th scope="col">Holding User</th>
        <th scope="col">Started At</th>
        <th scope="col">Enabled At</th>
        <th scope="col">Canceled At</th>
        <th scope="col">Finished At</th>
        <th scope="col">Overridden At</th>
        <th scope="col">Deadline</th>
        <th scope="col">Detail</th>
      </tr>
    </thead>
    <tbody>
      <% @workitems.each do |workitem| %>
        <tr>
          <td><%= link_to workitem.id, workitem_path(workitem) %></td>
          <td>
            <%= link_to workitem.transition.name, workflow_transition_path(workitem.workflow, workitem.transition) %> </td>
          <td><%= workitem.state %></td>
          <td><%= workitem.holding_user_id %></td>
          <td><%= workitem.started_at %></td>
          <td><%= workitem.enabled_at %></td>
          <td><%= workitem.canceled_at %></td>
          <td><%= workitem.finished_at %></td>
          <td><%= workitem.overridden_at %></td>
          <td><%= workitem.deadline %></td>
          <td><%= link_to "Run", workitem_path(workitem), class: 'btn btn-sm btn-success' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<div>
  <%= paginate @workitems, theme: 'twitter-bootstrap-4' %>
</div>
</div>


================================================
FILE: app/views/wf/workitems/pre_finish.html.erb
================================================
<%= form_with(model: @workitem, url: finish_workitem_path(@workitem), method: :put, local: true) do |f| %>
  <% if @workitem.errors.any? %>
    <article class="message is-danger">
      <div class="message-header">
        <p>
          <%= pluralize(@workitem.errors.count, "error") %> prohibited this workitem from being saved:
        </p>
      </div>
      <div class="message-body content">
        <ul>
          <% @workitem.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    </article>
  <% end %>
  
  <% @workitem.transition.dynamic_assignments.each do |tt| %>
    <%= f.fields_for :dynamic_assignments do |ff| %>
       <div class="form-group">
         <%= ff.label "Assign #{tt.name}", class: "label" %>
         <%= ff.select tt.id, Wf::Party.all.map{|x| [x.party_name, x.id]}, {}, class: "form-control custom-select" %>
       </div>
    <% end %>
  <% end %>

  
  <% if @workitem.transition.form %>
    <%= f.fields_for :entry do |ff| %>
      <% @workitem.transition.form.fields.each do |field| %>
       <div class="form-group">
        <%= ff.label field.name, class: "label" %>
        <% if field.array?  %>
          <%= ff.select field.id, {}, {}, multiple: true, class: "form-control select2" %>
        <% else %>
          <%= ff.send(field.field_type_for_view, field.id, class: "form-control") %>
        <% end %>
        </div>
      <% end %>
    <% end %>
  <% end %>

  <div class="form-group">
    <%= f.submit class: "btn btn-primary", value: "Done", data: {disable_with: 'Waiting...'} %>
  </div>
<% end %>

<script>
  $(function() {
    $(".select2").select2({
      tags: [],
      theme: "bootstrap4",
      tokenSeparators: [',', ' ']
    });
  });
</script>

================================================
FILE: app/views/wf/workitems/show.html.erb
================================================
<div class="card card-body">
<div class="float-right">
  <%= link_to 'Back to Case', workflow_case_path(@workitem.workflow, @workitem.case), class: 'btn btn-primary' %>
</div>
<div>
  <h2>Transition</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Description</th>
        <th scope="col">Trigger Limit</th>
        <th scope="col">Trigger Type</th>
        <th scope="col">Sort Order</th>
        <th scope="col">Custom Form</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= @workitem.transition.id %></td>
        <td><%= @workitem.transition.name %></td>
        <td><%= @workitem.transition.description %></td>
        <td><%= @workitem.transition.trigger_limit %></td>
        <td><%= @workitem.transition.trigger_type %></td>
        <td><%= @workitem.transition.sort_order %></td>

        <td>
          <% if @workitem.transition.form %>
           <%= link_to @workitem.transition.form.name, form_path(@workitem.transition.form) %>
          <% else %>
           No Form
          <% end %>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Detail</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Transition</th>
        <th scope="col">State</th>
        <th scope="col">Holding User</th>
        <th scope="col">Started At</th>
        <th scope="col">Enabled At</th>
        <th scope="col">Canceled At</th>
        <th scope="col">Finished At</th>
        <th scope="col">Overridden At</th>
        <th scope="col">Deadline</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= @workitem.id %></td>
        <td>
          <%= link_to @workitem.transition.name, workflow_transition_path(@workitem.workflow, @workitem.transition) %> </td>
        <td><%= @workitem.state %></td>
        <td><%= @workitem.holding_user_id %></td>
        <td><%= @workitem.started_at %></td>
        <td><%= @workitem.enabled_at %></td>
        <td><%= @workitem.canceled_at %></td>
        <td><%= @workitem.finished_at %></td>
        <td><%= @workitem.overridden_at %></td>
        <td><%= @workitem.deadline %></td>
      </tr>
    </tbody>
  </table>
</div>

<% if @workitem.transition.form %>
  <div>
    <h2>Entries</h2>
    <table class="table table-view">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">User</th>
          <th scope="col">Payload</th>
        </tr>
      </thead>
      <tbody>
        <% @workitem.entries.each do |entry| %>
          <tr>
            <td><%= entry.id %></td>
            <td><%= entry.user_id %></td>
            <td>
              <pre>
                <%= JSON.pretty_generate(entry.payload) %>
              </pre>
            </td>
          </tr>
        <% end %>
      </tbody>
    </table>
  </div>
<% end %>

<div>
  <h2>Assignments</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Party ID</th>
        <th scope="col">Name</th>
        <th scope="col">Created At</th>
        <th scope="col">Action</th>
      </tr>
    </thead>
    <tbody>
      <% @workitem.workitem_assignments.includes(:party).each do |assignment|%>
        <tr>
          <td><%= assignment.id %></td>
          <td><%= assignment.party_id %></td>
          <td>
            <%= assignment.party.party_name %> </td>
          <td><%= assignment.created_at %></td>
          <td><%= link_to "Remove", workitem_workitem_assignment_path(@workitem, party_id: assignment.party_id), remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-info' %></td>
        </tr>
      <% end %>
      <tr>
         <td colspan="5">
          <% if @workitem.transition.user? && (@workitem.started? || @workitem.enabled?) %>
             <% if @workitem.finished_by?(wf_current_user) %>
               <%= link_to "Pre Finish Workitem", pre_finish_workitem_path(@workitem), class: 'btn btn-sm btn-dark' %>
             <% elsif @workitem.started_by?(wf_current_user)%>
               <%= link_to "Start Workitem", start_workitem_path(@workitem), method: :put, class: 'btn btn-sm btn-dark' %>
             <% else %>
               You can not start workitem, Please assign to youself.
             <% end %>
             <%= link_to "Re Assign", new_workitem_workitem_assignment_path(@workitem), class: 'btn btn-success btn-sm' %>
             <%= link_to "Assign Yourself", new_workitem_workitem_assignment_path(@workitem, party_id: wf_current_user.party&.id), class: 'btn btn-success btn-sm' %>
             <%= link_to "Add Comment", new_workitem_comment_path(@workitem), class: 'btn btn-success btn-sm' %>
            <% end %>
          </td>
        </tr>
    </tbody>
  </table>
</div>

<div>
  <h2>Comments</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Body</th>
        <th scope="col">User</th>
        <th scope="col">Created At</th>
        <th scope="col">Action</th>
      </tr>
    </thead>
    <tbody>
      <% @workitem.comments.order("id DESC").each do |comment| %>
        <tr>
          <td><%= comment.id %></td>
          <td>
            <%= comment.body %> </td>
          <td><%= comment.user_id %></td>
          <td><%= comment.created_at %></td>
          <td><%= link_to "Delete", workitem_comment_path(@workitem, comment), remote: true, method: :delete, data: {confirm: 'confirm?', disable_with: 'Waiting...'}, class: 'btn btn-sm btn-info' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<div>
  <h2>All Workitems</h2>
  <table class="table table-view">
    <thead>
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Transition</th>
        <th scope="col">State</th>
        <th scope="col">Trigger Type</th>
        <th scope="col">Holding User</th>
        <th scope="col">Started At</th>
        <th scope="col">Enabled At</th>
        <th scope="col">Canceled At</th>
        <th scope="col">Finished At</th>
        <th scope="col">Overridden At</th>
        <th scope="col">Deadline</th>
        <th scope="col">Action</th>
      </tr>
    </thead>
    <tbody>
      <% @workitem.case.workitems.includes(:transition).each do |workitem| %>
        <tr>
          <td><%= link_to workitem.id, workitem_path(workitem) %></td>
          <td>
            <%= workitem.transition.name %> </td>
          <td><%= workitem.state %></td>
          <td><%= workitem.transition.trigger_type %></td>
          <td><%= workitem.holding_user_id %></td>
          <td><%= workitem.started_at %></td>
          <td><%= workitem.enabled_at %></td>
          <td><%= workitem.canceled_at %></td>
          <td><%= workitem.finished_at %></td>
          <td><%= workitem.overridden_at %></td>
          <td><%= workitem.deadline %></td>
          <td><%= link_to "Run", workitem_path(workitem), class: 'btn btn-sm btn-success' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
</div>


================================================
FILE: bin/rails
================================================
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails gems
# installed from the root of your application.

ENGINE_ROOT = File.expand_path('..', __dir__)
ENGINE_PATH = File.expand_path('../lib/wf/engine', __dir__)
APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

require 'rails/all'
require 'rails/engine/commands'


================================================
FILE: config/routes.rb
================================================
# frozen_string_literal: true

Wf::Engine.routes.draw do
  resources :workflows do
    resources :transitions
    resources :places
    resources :arcs
    resources :cases
  end

  resources :arcs do
    resources :guards
  end

  resources :forms do
    resources :fields
  end

  resources :transitions do
    resources :static_assignments
  end

  resources :workitems do
    resources :workitem_assignments, only: %i[new create destroy]
    resources :comments, only: %i[new create destroy]
    member do
      put :start
      get :pre_finish
      put :finish
    end
  end

  root to: "workitems#index"
end


================================================
FILE: db/migrate/20200130201043_init.rb
================================================
# frozen_string_literal: true

class Init < ActiveRecord::Migration[6.0]
  def change
    create_table "wf_arcs", force: :cascade do |t|
      t.bigint "workflow_id"
      t.bigint "transition_id"
      t.bigint "place_id"
      t.integer "direction", default: 0, comment: "0-in, 1-out"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.integer "guards_count", default: 0
    end

    create_table "wf_case_assignments", comment: "Manual per-case assignments of transition to parties", force: :cascade do |t|
      t.bigint "case_id"
      t.bigint "transition_id"
      t.bigint "party_id"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index %w[case_id transition_id party_id], name: "wf_ctp_u", unique: true
    end

    create_table "wf_cases", force: :cascade do |t|
      t.bigint "workflow_id"
      t.string "targetable_type", comment: "point to target type of Application."
      t.string "targetable_id", comment: "point to target ID of Application."
      t.integer "state", default: 0, comment: "0-created, 1-active, 2-suspended, 3-canceled, 4-finished"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_comments", force: :cascade do |t|
      t.bigint "workitem_id"
      t.string "user_id"
      t.text "body"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index ["user_id"], name: "index_wf_comments_on_user_id"
      t.index ["workitem_id"], name: "index_wf_comments_on_workitem_id"
    end

    create_table "wf_demo_targets", comment: "For demo, useless.", force: :cascade do |t|
      t.string "name"
      t.string "description"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_field_values", force: :cascade do |t|
      t.bigint "workflow_id"
      t.bigint "transition_id"
      t.bigint "form_id"
      t.bigint "field_id"
      t.text "value"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index ["field_id"], name: "index_wf_field_values_on_field_id"
      t.index ["form_id"], name: "index_wf_field_values_on_form_id"
      t.index ["transition_id"], name: "index_wf_field_values_on_transition_id"
      t.index ["workflow_id"], name: "index_wf_field_values_on_workflow_id"
    end

    create_table "wf_fields", force: :cascade do |t|
      t.string "name"
      t.bigint "form_id"
      t.integer "position", default: 0
      t.integer "field_type", default: 0
      t.string "field_type_name"
      t.string "default_value"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index ["form_id"], name: "index_wf_fields_on_form_id"
    end

    create_table "wf_forms", force: :cascade do |t|
      t.string "name"
      t.text "description"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_groups", comment: "For demo", force: :cascade do |t|
      t.string "name"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_guards", force: :cascade do |t|
      t.bigint "arc_id"
      t.bigint "workflow_id"
      t.string "fieldable_type"
      t.string "fieldable_id"
      t.string "op"
      t.string "value"
      t.string "exp"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index ["arc_id"], name: "index_wf_guards_on_arc_id"
      t.index ["workflow_id"], name: "index_wf_guards_on_workflow_id"
    end

    create_table "wf_parties", comment: "for groups or roles or users or positions etc.", force: :cascade do |t|
      t.string "partable_type"
      t.string "partable_id"
      t.string "party_name"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index %w[partable_type partable_id], name: "index_wf_parties_on_partable_type_and_partable_id", unique: true
    end

    create_table "wf_places", force: :cascade do |t|
      t.bigint "workflow_id"
      t.string "name"
      t.text "description"
      t.integer "sort_order", default: 0
      t.integer "place_type", default: 0, comment: "类型:0-start,1-normal,2-end"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_tokens", force: :cascade do |t|
      t.bigint "workflow_id"
      t.bigint "case_id"
      t.string "targetable_type"
      t.string "targetable_id"
      t.bigint "place_id"
      t.integer "state", default: 0, comment: "0-free, 1-locked, 2-canceled, 3-consumed"
      t.bigint "locked_workitem_id"
      if /mysql/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.datetime "produced_at", default: -> { "current_timestamp" }
      elsif /postgre/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.datetime "produced_at", default: -> { "timezone('utc'::text, now())" }
      end
      t.datetime "locked_at"
      t.datetime "canceled_at"
      t.datetime "consumed_at"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_transition_static_assignments", comment: "pre assignment for transition", force: :cascade do |t|
      t.bigint "party_id"
      t.bigint "transition_id"
      t.bigint "workflow_id"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index %w[transition_id party_id], name: "wf_tp_u", unique: true
    end

    create_table "wf_transitions", force: :cascade do |t|
      t.string "name"
      t.text "description"
      t.bigint "workflow_id"
      t.integer "sort_order", default: 0
      t.integer "trigger_limit", comment: "use with timed trigger, after x minitues, trigger exec"
      t.integer "trigger_type", default: 0, comment: "0-user,1-automatic, 2-message,3-time"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.bigint "form_id"
      t.string "enable_callback", default: "Wf::Callbacks::EnableDefault"
      t.string "fire_callback", default: "Wf::Callbacks::FireDefault"
      t.string "notification_callback", default: "Wf::Callbacks::NotificationDefault"
      t.string "time_callback", default: "Wf::Callbacks::TimeDefault"
      t.string "deadline_callback", default: "Wf::Callbacks::DeadlineDefault"
      t.string "hold_timeout_callback", default: "Wf::Callbacks::HoldTimeoutDefault"
      t.string "assignment_callback", default: "Wf::Callbacks::AssignmentDefault"
      t.string "unassignment_callback", default: "Wf::Callbacks::UnassignmentDefault"
    end

    create_table "wf_users", comment: "For demo", force: :cascade do |t|
      t.string "name"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.bigint "group_id"
    end

    create_table "wf_workflows", force: :cascade do |t|
      t.string "name"
      t.text "description"
      t.boolean "is_valid", default: false
      t.string "creator_id"
      t.text "error_msg"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end

    create_table "wf_workitem_assignments", force: :cascade do |t|
      t.bigint "party_id"
      t.bigint "workitem_id"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.index %w[workitem_id party_id], name: "wf_wp_u", unique: true
    end

    create_table "wf_workitems", force: :cascade do |t|
      t.bigint "case_id"
      t.bigint "workflow_id"
      t.bigint "transition_id"
      t.string "targetable_type", comment: "point to type of Application target: Task or Issue or PullRequest or Project etc."
      t.string "targetable_id", comment: "point to id of Application target: task_id or issue_id or pull_request_id or project_id etc."
      t.integer "state", default: 0, comment: "0-enabled, 1-started, 2-canceled, 3-finished,4-overridden"
      if /mysql/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.datetime "enabled_at", default: -> { "current_timestamp" }
      elsif /postgre/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.datetime "enabled_at", default: -> { "timezone('utc'::text, now())" }
      end
      t.datetime "started_at"
      t.datetime "canceled_at"
      t.datetime "finished_at"
      t.datetime "overridden_at"
      t.datetime "deadline", comment: ""
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
      t.datetime "trigger_time", comment: "set when transition_trigger=TIME & trigger_limit present"
      t.string "holding_user_id", comment: "id of App user"
      if /mysql/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.json "payload", comment: "store user input payload for workitem."
      elsif /postgre/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.json "payload", default: {}, comment: "store user input payload for workitem."
      end

      t.index %w[state trigger_time], name: "index_wf_workitems_on_state_and_trigger_time"
    end
  end
end


================================================
FILE: db/migrate/20200130201641_init_some_data.rb
================================================
# frozen_string_literal: true

class InitSomeData < ActiveRecord::Migration[6.0]
  def change
    5.times do |i|
      Wf::Group.create(name: "Group#{i}")
    end

    10.times do |i|
      Wf::User.create(name: "User#{i}", group: Wf::Group.all.sample)
    end

    10.times { |i| Wf::DemoTarget.create(name: "target #{i}") }
  end
end


================================================
FILE: db/migrate/20200131200455_create_wf_entries.rb
================================================
# frozen_string_literal: true

class CreateWfEntries < ActiveRecord::Migration[6.0]
  def change
    create_table :wf_entries, comment: "user input data for workitem with form." do |t|
      t.string :user_id, index: true
      t.bigint :workitem_id, index: true
      if /mysql/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.json "payload"
      elsif /postgre/i.match?(ActiveRecord::Base.connection.adapter_name)
        t.json "payload", default: {}
      end
      t.timestamps
    end
    remove_column :wf_workitems, :payload
    add_column :wf_field_values, :entry_id, :bigint, index: true
    add_index :wf_entries, %i[workitem_id user_id], unique: true
  end
end


================================================
FILE: db/migrate/20200201001543_add_target_field_name_for_guard.rb
================================================
# frozen_string_literal: true

class AddTargetFieldNameForGuard < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_guards, :target_attr_name, :string, comment: "point to workflow targetable's attribute"
  end
end


================================================
FILE: db/migrate/20200212120019_remove_targetable_from_workitem.rb
================================================
# frozen_string_literal: true

class RemoveTargetableFromWorkitem < ActiveRecord::Migration[6.0]
  def change
    remove_column :wf_workitems, :targetable_id
    remove_column :wf_workitems, :targetable_type
  end
end


================================================
FILE: db/migrate/20200213085258_add_formable.rb
================================================
# frozen_string_literal: true

class AddFormable < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_transitions, :form_type, :string, default: "Wf::Form"
    add_index :wf_transitions, %i[form_type form_id]
  end
end


================================================
FILE: db/migrate/20200213125753_add_form_id_for_entry.rb
================================================
# frozen_string_literal: true

class AddFormIdForEntry < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_entries, :form_id, :bigint, index: true
  end
end


================================================
FILE: db/migrate/20200213130900_remove_workflow_id_from_form_related.rb
================================================
# frozen_string_literal: true

class RemoveWorkflowIdFromFormRelated < ActiveRecord::Migration[6.0]
  def change
    remove_column :wf_field_values, :transition_id
    remove_column :wf_field_values, :workflow_id
  end
end


================================================
FILE: db/migrate/20200220070839_remove_unused_column.rb
================================================
# frozen_string_literal: true

class RemoveUnusedColumn < ActiveRecord::Migration[6.0]
  def change
    remove_column :wf_guards, :target_attr_name
  end
end


================================================
FILE: db/migrate/20200220072512_add_sub_workflow.rb
================================================
# frozen_string_literal: true

class AddSubWorkflow < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_transitions, :sub_workflow_id, :bigint, index: true
    add_column :wf_cases, :started_by_workitem_id, :bigint, index: true, comment: "As a sub workflow instance, it is started by one workitem."
  end
end


================================================
FILE: db/migrate/20200222150432_add_multi_instance.rb
================================================
# frozen_string_literal: true

class AddMultiInstance < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_transitions, :multiple_instance, :boolean, default: false, comment: "multiple instance mode or not"
    add_column :wf_transitions, :finish_condition, :string, comment: "set finish condition for parent workitem.", default: "Wf::MultipleInstances::AllFinish"
    add_column :wf_workitems, :children_count, :integer, default: 0
    add_column :wf_workitems, :children_finished_count, :integer, default: 0
    add_column :wf_workitems, :forked, :boolean, default: false
    add_column :wf_workitems, :parent_id, :bigint, comment: "parent workitem id"
  end
end


================================================
FILE: db/migrate/20200226195134_add_dynamic_assign_by.rb
================================================
# frozen_string_literal: true

class AddDynamicAssignBy < ActiveRecord::Migration[6.0]
  def change
    add_column :wf_transitions, :dynamic_assign_by_id, :bigint, comment: "dynamic assign by other transition", index: true
  end
end


================================================
FILE: lib/tasks/wf_tasks.rake
================================================
# frozen_string_literal: true

desc "Wf tasks"

task wf: :environment do
  url = "http://service-technology.org/files/lola/lola-2.0.tar.gz"
  path = Rails.root.join("tmp", "lola.tar.gz").to_s
  puts "Downloading, wait!"
  puts `wget http://service-technology.org/files/lola/lola-2.0.tar.gz -v -t0 -O #{path}` unless File.exist?(path)
  puts `cd #{Rails.root.join("tmp")} && tar -zxvf lola.tar.gz`
  puts `cd #{Rails.root.join("tmp/lola-2.0")} && ./configure`
  puts `cd #{Rails.root.join("tmp/lola-2.0")} && make`
  puts `cd #{Rails.root.join("tmp/lola-2.0")} && sudo make install`
  puts `lola --help`
end


================================================
FILE: lib/wf/engine.rb
================================================
# frozen_string_literal: true

module Wf
  class Engine < ::Rails::Engine
    isolate_namespace Wf
    config.autoload_paths += %W[
      #{config.root}/app/models/wf/concerns
    ]

    config.to_prepare do
      require_dependency(Rails.root + "config/initializers/wf_config.rb")
    rescue LoadError
      puts("config/initializers/wf_config.rb not found.")
    end
  end
end

require "bootstrap"
require "bootstrap4-kaminari-views"
require "jquery-rails"
require "kaminari"
require "simple_command"
require "loaf"
require "graphviz"
require "rgl/adjacency"
require "rgl/dijkstra"
require "rgl/topsort"
require "rgl/traversal"
require "rgl/path"
require "active_record/connection_adapters/postgresql_adapter.rb"
require "select2-rails"
require "mini_racer"


================================================
FILE: lib/wf/version.rb
================================================
# frozen_string_literal: true

module Wf
  VERSION = "0.2.5"
end


================================================
FILE: lib/wf.rb
================================================
# frozen_string_literal: true

require "wf/engine"

module Wf
  class << self
    attr_accessor :enable_callbacks
    attr_accessor :fire_callbacks
    attr_accessor :assignment_callbacks
    attr_accessor :unassignment_callbacks
    attr_accessor :notification_callbacks
    attr_accessor :time_callbacks
    attr_accessor :deadline_callbacks
    attr_accessor :hold_timeout_callbacks

    attr_accessor :form_class
    attr_accessor :entry_class
    attr_accessor :field_class

    attr_accessor :user_class
    attr_accessor :org_classes

    attr_accessor :finish_conditions

    attr_accessor :use_lola
  end

  self.enable_callbacks          = ["Wf::Callbacks::EnableDefault"]
  self.fire_callbacks            = ["Wf::Callbacks::FireDefault"]
  self.assignment_callbacks      = ["Wf::Callbacks::AssignmentDefault"]
  self.unassignment_callbacks    = ["Wf::Callbacks::UnassignmentDefault"]
  self.notification_callbacks    = ["Wf::Callbacks::NotificationDefault"]
  self.deadline_callbacks        = ["Wf::Callbacks::DeadlineDefault"]
  self.time_callbacks            = ["Wf::Callbacks::TimeDefault"]
  self.hold_timeout_callbacks    = ["Wf::Callbacks::HoldTimeoutDefault"]
  self.form_class                = "::Wf::Form"
  self.entry_class               = "::Wf::Entry"
  self.field_class               = "::Wf::Field"
  self.user_class                = "::Wf::User"
  self.org_classes               = { group: "::Wf::Group" }
  self.finish_conditions         = ["Wf::MultipleInstances::AllFinish"]
  self.use_lola                  = false
end


================================================
FILE: lola.md
================================================
## LoLA

LoLA is a Petri nets model-checking tool. To install LoLA, download lola-2.0.tar.gz from http://home.gna.org
Download .txt
gitextract_22cx_jl_/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── gempush.yml
├── .gitignore
├── .rubocop.yml
├── FormSpec.md
├── Gemfile
├── Guard.md
├── LICENSE
├── MIT-LICENSE
├── README.md
├── Rakefile
├── acts_as_party.md
├── app/
│   ├── assets/
│   │   ├── config/
│   │   │   └── wf_manifest.js
│   │   ├── images/
│   │   │   └── wf/
│   │   │       └── .keep
│   │   ├── javascripts/
│   │   │   └── wf/
│   │   │       └── application.js
│   │   └── stylesheets/
│   │       └── wf/
│   │           ├── application.scss
│   │           ├── arcs.css
│   │           ├── cases.css
│   │           ├── comments.css
│   │           ├── fields.css
│   │           ├── forms.css
│   │           ├── guards.css
│   │           ├── places.css
│   │           ├── static_assignments.css
│   │           ├── transitions.css
│   │           ├── uikit/
│   │           │   ├── _colors.scss
│   │           │   ├── _variables.scss
│   │           │   ├── alert.scss
│   │           │   ├── button.scss
│   │           │   ├── card.scss
│   │           │   ├── index.scss
│   │           │   ├── navbar.scss
│   │           │   └── table.scss
│   │           ├── workflows.css
│   │           ├── workitem_assignments.css
│   │           └── workitems.css
│   ├── controllers/
│   │   └── wf/
│   │       ├── application_controller.rb
│   │       ├── arcs_controller.rb
│   │       ├── cases_controller.rb
│   │       ├── comments_controller.rb
│   │       ├── fields_controller.rb
│   │       ├── forms_controller.rb
│   │       ├── guards_controller.rb
│   │       ├── places_controller.rb
│   │       ├── static_assignments_controller.rb
│   │       ├── transitions_controller.rb
│   │       ├── workflows_controller.rb
│   │       ├── workitem_assignments_controller.rb
│   │       └── workitems_controller.rb
│   ├── helpers/
│   │   └── wf/
│   │       ├── application_helper.rb
│   │       ├── arcs_helper.rb
│   │       ├── cases_helper.rb
│   │       ├── comments_helper.rb
│   │       ├── fields_helper.rb
│   │       ├── forms_helper.rb
│   │       ├── guards_helper.rb
│   │       ├── places_helper.rb
│   │       ├── static_assignments_helper.rb
│   │       ├── transitions_helper.rb
│   │       ├── workflows_helper.rb
│   │       ├── workitem_assignments_helper.rb
│   │       └── workitems_helper.rb
│   ├── jobs/
│   │   └── wf/
│   │       ├── application_job.rb
│   │       └── fire_timed_workitem_job.rb
│   ├── mailers/
│   │   └── wf/
│   │       └── application_mailer.rb
│   ├── models/
│   │   └── wf/
│   │       ├── acts_as_party.rb
│   │       ├── application_record.rb
│   │       ├── arc.rb
│   │       ├── callbacks/
│   │       │   ├── assignment_default.rb
│   │       │   ├── deadline_default.rb
│   │       │   ├── enable_default.rb
│   │       │   ├── fire_default.rb
│   │       │   ├── hold_timeout_default.rb
│   │       │   ├── notification_default.rb
│   │       │   ├── time_default.rb
│   │       │   └── unassignment_default.rb
│   │       ├── case.rb
│   │       ├── case_assignment.rb
│   │       ├── case_command/
│   │       │   ├── add_comment.rb
│   │       │   ├── add_manual_assignment.rb
│   │       │   ├── add_token.rb
│   │       │   ├── add_workitem_assignment.rb
│   │       │   ├── begin_workitem_action.rb
│   │       │   ├── cancel.rb
│   │       │   ├── cancel_workitem.rb
│   │       │   ├── clear_manual_assignments.rb
│   │       │   ├── clear_workitem_assignments.rb
│   │       │   ├── consume_token.rb
│   │       │   ├── create_entry.rb
│   │       │   ├── enable_transitions.rb
│   │       │   ├── end_workitem_action.rb
│   │       │   ├── finish_workitem.rb
│   │       │   ├── finished_p.rb
│   │       │   ├── fire_message_transition.rb
│   │       │   ├── fire_transition_internal.rb
│   │       │   ├── lock_token.rb
│   │       │   ├── new.rb
│   │       │   ├── release_token.rb
│   │       │   ├── remove_manual_assignment.rb
│   │       │   ├── remove_workitem_assignment.rb
│   │       │   ├── resume.rb
│   │       │   ├── set_workitem_assignments.rb
│   │       │   ├── start_case.rb
│   │       │   ├── start_workitem.rb
│   │       │   ├── suspend.rb
│   │       │   ├── sweep_automatic_transitions.rb
│   │       │   ├── sweep_timed_transitions.rb
│   │       │   └── workitem_action.rb
│   │       ├── comment.rb
│   │       ├── demo_target.rb
│   │       ├── entry.rb
│   │       ├── field.rb
│   │       ├── field_value.rb
│   │       ├── form.rb
│   │       ├── group.rb
│   │       ├── guard.rb
│   │       ├── lola.rb
│   │       ├── multiple_instances/
│   │       │   └── all_finish.rb
│   │       ├── party.rb
│   │       ├── place.rb
│   │       ├── token.rb
│   │       ├── transition.rb
│   │       ├── transition_static_assignment.rb
│   │       ├── user.rb
│   │       ├── workflow.rb
│   │       ├── workitem.rb
│   │       └── workitem_assignment.rb
│   └── views/
│       ├── layouts/
│       │   └── wf/
│       │       ├── _alert.html.erb
│       │       ├── _footer.html.erb
│       │       ├── _nav.html.erb
│       │       ├── _notice.html.erb
│       │       └── application.html.erb
│       └── wf/
│           ├── arcs/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── cases/
│           │   ├── _form.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── comments/
│           │   └── new.html.erb
│           ├── fields/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── forms/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── guards/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── places/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   └── new.html.erb
│           ├── static_assignments/
│           │   ├── _form.html.erb
│           │   └── new.html.erb
│           ├── transitions/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── workflows/
│           │   ├── _form.html.erb
│           │   ├── edit.html.erb
│           │   ├── index.html.erb
│           │   ├── new.html.erb
│           │   └── show.html.erb
│           ├── workitem_assignments/
│           │   └── new.html.erb
│           └── workitems/
│               ├── index.html.erb
│               ├── pre_finish.html.erb
│               └── show.html.erb
├── bin/
│   └── rails
├── config/
│   └── routes.rb
├── db/
│   └── migrate/
│       ├── 20200130201043_init.rb
│       ├── 20200130201641_init_some_data.rb
│       ├── 20200131200455_create_wf_entries.rb
│       ├── 20200201001543_add_target_field_name_for_guard.rb
│       ├── 20200212120019_remove_targetable_from_workitem.rb
│       ├── 20200213085258_add_formable.rb
│       ├── 20200213125753_add_form_id_for_entry.rb
│       ├── 20200213130900_remove_workflow_id_from_form_related.rb
│       ├── 20200220070839_remove_unused_column.rb
│       ├── 20200220072512_add_sub_workflow.rb
│       ├── 20200222150432_add_multi_instance.rb
│       └── 20200226195134_add_dynamic_assign_by.rb
├── lib/
│   ├── tasks/
│   │   └── wf_tasks.rake
│   ├── wf/
│   │   ├── engine.rb
│   │   └── version.rb
│   └── wf.rb
├── lola.md
├── screenshots/
│   └── .keep
├── test/
│   ├── controllers/
│   │   └── wf/
│   │       ├── arcs_controller_test.rb
│   │       ├── cases_controller_test.rb
│   │       ├── comments_controller_test.rb
│   │       ├── fields_controller_test.rb
│   │       ├── forms_controller_test.rb
│   │       ├── guards_controller_test.rb
│   │       ├── places_controller_test.rb
│   │       ├── static_assignments_controller_test.rb
│   │       ├── transitions_controller_test.rb
│   │       ├── workflows_controller_test.rb
│   │       ├── workitem_assignments_controller_test.rb
│   │       └── workitems_controller_test.rb
│   ├── dummy/
│   │   ├── .ruby-version
│   │   ├── Rakefile
│   │   ├── app/
│   │   │   ├── assets/
│   │   │   │   ├── config/
│   │   │   │   │   └── manifest.js
│   │   │   │   ├── images/
│   │   │   │   │   └── .keep
│   │   │   │   └── stylesheets/
│   │   │   │       └── application.css
│   │   │   ├── channels/
│   │   │   │   └── application_cable/
│   │   │   │       ├── channel.rb
│   │   │   │       └── connection.rb
│   │   │   ├── controllers/
│   │   │   │   ├── application_controller.rb
│   │   │   │   └── concerns/
│   │   │   │       └── .keep
│   │   │   ├── helpers/
│   │   │   │   └── application_helper.rb
│   │   │   ├── javascript/
│   │   │   │   └── packs/
│   │   │   │       └── application.js
│   │   │   ├── jobs/
│   │   │   │   └── application_job.rb
│   │   │   ├── mailers/
│   │   │   │   └── application_mailer.rb
│   │   │   ├── models/
│   │   │   │   ├── application_record.rb
│   │   │   │   ├── concerns/
│   │   │   │   │   └── .keep
│   │   │   │   ├── entry.rb
│   │   │   │   ├── field.rb
│   │   │   │   ├── field_value.rb
│   │   │   │   └── form.rb
│   │   │   └── views/
│   │   │       └── layouts/
│   │   │           ├── application.html.erb
│   │   │           ├── mailer.html.erb
│   │   │           └── mailer.text.erb
│   │   ├── bin/
│   │   │   ├── rails
│   │   │   ├── rake
│   │   │   └── setup
│   │   ├── 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
│   │   │   │   ├── inflections.rb
│   │   │   │   ├── mime_types.rb
│   │   │   │   ├── my_assignment_callback.rb
│   │   │   │   ├── wf_config.rb
│   │   │   │   └── wrap_parameters.rb
│   │   │   ├── locales/
│   │   │   │   └── en.yml
│   │   │   ├── mysql_database.yml
│   │   │   ├── puma.rb
│   │   │   ├── routes.rb
│   │   │   ├── spring.rb
│   │   │   └── storage.yml
│   │   ├── config.ru
│   │   ├── db/
│   │   │   ├── migrate/
│   │   │   │   ├── 20200213081814_new_form.rb
│   │   │   │   ├── 20200213133942_add_form_id_in_entry1.rb
│   │   │   │   └── 20200214005535_add_entry_id_for_field_values1.rb
│   │   │   ├── schema.rb
│   │   │   └── seeds.rb
│   │   ├── lib/
│   │   │   └── assets/
│   │   │       └── .keep
│   │   ├── log/
│   │   │   └── .keep
│   │   ├── public/
│   │   │   ├── 404.html
│   │   │   ├── 422.html
│   │   │   └── 500.html
│   │   └── storage/
│   │       └── .keep
│   ├── fixtures/
│   │   └── wf/
│   │       ├── case_assignments.yml
│   │       ├── comments.yml
│   │       ├── demo_targets.yml
│   │       ├── entries.yml
│   │       ├── field_values.yml
│   │       ├── fields.yml
│   │       ├── forms.yml
│   │       ├── guards.yml
│   │       ├── parties.yml
│   │       ├── transition_static_assignments.yml
│   │       ├── users.yml
│   │       └── workitem_assignments.yml
│   ├── integration/
│   │   └── navigation_test.rb
│   ├── models/
│   │   └── wf/
│   │       ├── case_assignment_test.rb
│   │       ├── comment_test.rb
│   │       ├── demo_target_test.rb
│   │       ├── entry_test.rb
│   │       ├── field_test.rb
│   │       ├── field_value_test.rb
│   │       ├── form_test.rb
│   │       ├── guard_test.rb
│   │       ├── party_test.rb
│   │       ├── transition_static_assignment_test.rb
│   │       ├── user_test.rb
│   │       ├── wf_test.rb
│   │       └── workitem_assignment_test.rb
│   └── test_helper.rb
└── wf.gemspec
Download .txt
SYMBOL INDEX (493 symbols across 148 files)

FILE: app/controllers/wf/application_controller.rb
  type Wf (line 3) | module Wf
    class ApplicationController (line 4) | class ApplicationController < ::ApplicationController
      method wf_current_user (line 10) | def wf_current_user

FILE: app/controllers/wf/arcs_controller.rb
  type Wf (line 5) | module Wf
    class ArcsController (line 6) | class ArcsController < ApplicationController
      method new (line 9) | def new
      method create (line 15) | def create
      method destroy (line 25) | def destroy
      method show (line 32) | def show
      method edit (line 38) | def edit
      method update (line 45) | def update
      method arc_params (line 57) | def arc_params

FILE: app/controllers/wf/cases_controller.rb
  type Wf (line 5) | module Wf
    class CasesController (line 6) | class CasesController < ApplicationController
      method new (line 8) | def new
      method create (line 14) | def create
      method index (line 21) | def index
      method show (line 29) | def show
      method destroy (line 35) | def destroy
      method case_params (line 44) | def case_params

FILE: app/controllers/wf/comments_controller.rb
  type Wf (line 5) | module Wf
    class CommentsController (line 6) | class CommentsController < ApplicationController
      method new (line 9) | def new
      method create (line 17) | def create
      method destroy (line 23) | def destroy

FILE: app/controllers/wf/fields_controller.rb
  type Wf (line 5) | module Wf
    class FieldsController (line 6) | class FieldsController < ApplicationController
      method new (line 9) | def new
      method create (line 15) | def create
      method destroy (line 25) | def destroy
      method edit (line 32) | def edit
      method update (line 38) | def update
      method field_params (line 50) | def field_params

FILE: app/controllers/wf/forms_controller.rb
  type Wf (line 5) | module Wf
    class FormsController (line 6) | class FormsController < ApplicationController
      method index (line 9) | def index
      method new (line 13) | def new
      method edit (line 17) | def edit
      method show (line 21) | def show
      method destroy (line 25) | def destroy
      method update (line 34) | def update
      method create (line 43) | def create
      method form_params (line 55) | def form_params

FILE: app/controllers/wf/guards_controller.rb
  type Wf (line 5) | module Wf
    class GuardsController (line 6) | class GuardsController < ApplicationController
      method new (line 8) | def new
      method create (line 15) | def create
      method destroy (line 27) | def destroy
      method edit (line 34) | def edit
      method update (line 41) | def update
      method guard_params (line 54) | def guard_params

FILE: app/controllers/wf/places_controller.rb
  type Wf (line 5) | module Wf
    class PlacesController (line 6) | class PlacesController < ApplicationController
      method new (line 8) | def new
      method create (line 14) | def create
      method destroy (line 24) | def destroy
      method edit (line 31) | def edit
      method update (line 37) | def update
      method place_params (line 49) | def place_params

FILE: app/controllers/wf/static_assignments_controller.rb
  type Wf (line 5) | module Wf
    class StaticAssignmentsController (line 6) | class StaticAssignmentsController < ApplicationController
      method new (line 7) | def new
      method create (line 12) | def create
      method destroy (line 23) | def destroy
      method permit_params (line 30) | def permit_params

FILE: app/controllers/wf/transitions_controller.rb
  type Wf (line 5) | module Wf
    class TransitionsController (line 6) | class TransitionsController < ApplicationController
      method new (line 9) | def new
      method show (line 15) | def show
      method create (line 20) | def create
      method edit (line 31) | def edit
      method destroy (line 37) | def destroy
      method update (line 44) | def update
      method transition_params (line 57) | def transition_params

FILE: app/controllers/wf/workflows_controller.rb
  type Wf (line 5) | module Wf
    class WorkflowsController (line 6) | class WorkflowsController < ApplicationController
      method index (line 8) | def index
      method new (line 12) | def new
      method edit (line 16) | def edit
      method show (line 21) | def show
      method destroy (line 25) | def destroy
      method update (line 34) | def update
      method create (line 43) | def create
      method workflow_params (line 55) | def workflow_params

FILE: app/controllers/wf/workitem_assignments_controller.rb
  type Wf (line 5) | module Wf
    class WorkitemAssignmentsController (line 6) | class WorkitemAssignmentsController < ApplicationController
      method new (line 8) | def new
      method create (line 16) | def create
      method destroy (line 23) | def destroy

FILE: app/controllers/wf/workitems_controller.rb
  type Wf (line 5) | module Wf
    class WorkitemsController (line 6) | class WorkitemsController < ApplicationController
      method index (line 13) | def index
      method show (line 20) | def show
      method start (line 25) | def start
      method pre_finish (line 33) | def pre_finish
      method finish (line 39) | def finish
      method finish_and_redirect (line 60) | def finish_and_redirect
      method find_workitem (line 72) | def find_workitem
      method check_start (line 76) | def check_start
      method check_finish (line 82) | def check_finish

FILE: app/helpers/wf/application_helper.rb
  type Wf (line 3) | module Wf
    type ApplicationHelper (line 4) | module ApplicationHelper

FILE: app/helpers/wf/arcs_helper.rb
  type Wf (line 3) | module Wf
    type ArcsHelper (line 4) | module ArcsHelper

FILE: app/helpers/wf/cases_helper.rb
  type Wf (line 3) | module Wf
    type CasesHelper (line 4) | module CasesHelper

FILE: app/helpers/wf/comments_helper.rb
  type Wf (line 3) | module Wf
    type CommentsHelper (line 4) | module CommentsHelper

FILE: app/helpers/wf/fields_helper.rb
  type Wf (line 3) | module Wf
    type FieldsHelper (line 4) | module FieldsHelper

FILE: app/helpers/wf/forms_helper.rb
  type Wf (line 3) | module Wf
    type FormsHelper (line 4) | module FormsHelper

FILE: app/helpers/wf/guards_helper.rb
  type Wf (line 3) | module Wf
    type GuardsHelper (line 4) | module GuardsHelper

FILE: app/helpers/wf/places_helper.rb
  type Wf (line 3) | module Wf
    type PlacesHelper (line 4) | module PlacesHelper

FILE: app/helpers/wf/static_assignments_helper.rb
  type Wf (line 3) | module Wf
    type StaticAssignmentsHelper (line 4) | module StaticAssignmentsHelper

FILE: app/helpers/wf/transitions_helper.rb
  type Wf (line 3) | module Wf
    type TransitionsHelper (line 4) | module TransitionsHelper

FILE: app/helpers/wf/workflows_helper.rb
  type Wf (line 3) | module Wf
    type WorkflowsHelper (line 4) | module WorkflowsHelper

FILE: app/helpers/wf/workitem_assignments_helper.rb
  type Wf (line 3) | module Wf
    type WorkitemAssignmentsHelper (line 4) | module WorkitemAssignmentsHelper

FILE: app/helpers/wf/workitems_helper.rb
  type Wf (line 3) | module Wf
    type WorkitemsHelper (line 4) | module WorkitemsHelper

FILE: app/jobs/wf/application_job.rb
  type Wf (line 3) | module Wf
    class ApplicationJob (line 4) | class ApplicationJob < ActiveJob::Base

FILE: app/jobs/wf/fire_timed_workitem_job.rb
  type Wf (line 3) | module Wf
    class FireTimedWorkitemJob (line 4) | class FireTimedWorkitemJob < ApplicationJob
      method perform (line 7) | def perform(workitem_id)

FILE: app/mailers/wf/application_mailer.rb
  type Wf (line 3) | module Wf
    class ApplicationMailer (line 4) | class ApplicationMailer < ActionMailer::Base

FILE: app/models/wf/acts_as_party.rb
  type Wf (line 5) | module Wf
    type ActsAsParty (line 6) | module ActsAsParty
      type ClassMethods (line 13) | module ClassMethods
        function acts_as_party (line 14) | def acts_as_party(options = { user: false, party_name: :name })

FILE: app/models/wf/application_record.rb
  type Wf (line 3) | module Wf
    class ApplicationRecord (line 4) | class ApplicationRecord < ActiveRecord::Base

FILE: app/models/wf/arc.rb
  type Wf (line 17) | module Wf
    class Arc (line 18) | class Arc < ApplicationRecord
      method name (line 34) | def name

FILE: app/models/wf/callbacks/assignment_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class AssignmentDefault (line 4) | class AssignmentDefault < ApplicationJob
      method perform (line 7) | def perform(_workitem_id)

FILE: app/models/wf/callbacks/deadline_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class DeadlineDefault (line 4) | class DeadlineDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/enable_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class EnableDefault (line 4) | class EnableDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/fire_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class FireDefault (line 4) | class FireDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/hold_timeout_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class HoldTimeoutDefault (line 4) | class HoldTimeoutDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/notification_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class NotificationDefault (line 4) | class NotificationDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/time_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class TimeDefault (line 4) | class TimeDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/callbacks/unassignment_default.rb
  type Wf::Callbacks (line 3) | module Wf::Callbacks
    class UnassignmentDefault (line 4) | class UnassignmentDefault < ApplicationJob
      method perform (line 7) | def perform(*guests)

FILE: app/models/wf/case.rb
  type Wf (line 17) | module Wf
    class Case (line 18) | class Case < ApplicationRecord
      method can_fire? (line 35) | def can_fire?(transition)
      method name (line 42) | def name

FILE: app/models/wf/case_assignment.rb
  type Wf (line 16) | module Wf
    class CaseAssignment (line 17) | class CaseAssignment < ApplicationRecord

FILE: app/models/wf/case_command/add_comment.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class AddComment (line 4) | class AddComment
      method initialize (line 7) | def initialize(workitem, comment, user)
      method call (line 13) | def call

FILE: app/models/wf/case_command/add_manual_assignment.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class AddManualAssignment (line 4) | class AddManualAssignment
      method initialize (line 7) | def initialize(wf_case, transition, party)
      method call (line 13) | def call

FILE: app/models/wf/case_command/add_token.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class AddToken (line 4) | class AddToken
      method initialize (line 7) | def initialize(wf_case, place)
      method call (line 12) | def call

FILE: app/models/wf/case_command/add_workitem_assignment.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class AddWorkitemAssignment (line 4) | class AddWorkitemAssignment
      method initialize (line 7) | def initialize(workitem, party, permanent = true)
      method call (line 13) | def call

FILE: app/models/wf/case_command/begin_workitem_action.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class BeginWorkitemAction (line 4) | class BeginWorkitemAction
      method initialize (line 7) | def initialize(workitem, user, action = :start)
      method call (line 13) | def call

FILE: app/models/wf/case_command/cancel.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class Cancel (line 4) | class Cancel
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/cancel_workitem.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class CancelWorkitem (line 4) | class CancelWorkitem
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/clear_manual_assignments.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class ClearManualAssignments (line 4) | class ClearManualAssignments
      method initialize (line 7) | def initialize(wf_case, transition)
      method call (line 12) | def call

FILE: app/models/wf/case_command/clear_workitem_assignments.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class ClearWorkitemAssignments (line 4) | class ClearWorkitemAssignments
      method initialize (line 7) | def initialize(workitem, permanent = true)
      method call (line 12) | def call

FILE: app/models/wf/case_command/consume_token.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class ConsumeToken (line 4) | class ConsumeToken
      method initialize (line 7) | def initialize(wf_case, place, locked_item = nil)
      method call (line 13) | def call

FILE: app/models/wf/case_command/create_entry.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class CreateEntry (line 4) | class CreateEntry
      method initialize (line 7) | def initialize(form, workitem, user, params)
      method call (line 14) | def call
      method create_entry (line 23) | def create_entry

FILE: app/models/wf/case_command/enable_transitions.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class EnableTransitions (line 4) | class EnableTransitions
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/end_workitem_action.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class EndWorkitemAction (line 4) | class EndWorkitemAction
      method initialize (line 7) | def initialize(workitem, user, action = :start)
      method call (line 13) | def call

FILE: app/models/wf/case_command/finish_workitem.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class FinishWorkitem (line 4) | class FinishWorkitem
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/finished_p.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class FinishedP (line 4) | class FinishedP
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/fire_message_transition.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class FireMessageTransition (line 4) | class FireMessageTransition
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/fire_transition_internal.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class FireTransitionInternal (line 4) | class FireTransitionInternal
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/lock_token.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class LockToken (line 4) | class LockToken
      method initialize (line 7) | def initialize(wf_case, place, workitem)
      method call (line 13) | def call

FILE: app/models/wf/case_command/new.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class New (line 4) | class New
      method initialize (line 7) | def initialize(workflow, target = nil, started_by = nil)
      method call (line 13) | def call

FILE: app/models/wf/case_command/release_token.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class ReleaseToken (line 4) | class ReleaseToken
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/remove_manual_assignment.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class RemoveManualAssignment (line 4) | class RemoveManualAssignment
      method initialize (line 7) | def initialize(wf_case, transition, party)
      method call (line 13) | def call

FILE: app/models/wf/case_command/remove_workitem_assignment.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class RemoveWorkitemAssignment (line 4) | class RemoveWorkitemAssignment
      method initialize (line 7) | def initialize(workitem, party, permanent = true)
      method call (line 13) | def call

FILE: app/models/wf/case_command/resume.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class Resume (line 4) | class Resume
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/set_workitem_assignments.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class SetWorkitemAssignments (line 4) | class SetWorkitemAssignments
      method initialize (line 7) | def initialize(workitem)
      method call (line 11) | def call

FILE: app/models/wf/case_command/start_case.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class StartCase (line 4) | class StartCase
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/start_workitem.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class StartWorkitem (line 4) | class StartWorkitem
      method initialize (line 7) | def initialize(workitem, user)
      method call (line 12) | def call

FILE: app/models/wf/case_command/suspend.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class Suspend (line 4) | class Suspend
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/sweep_automatic_transitions.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class SweepAutomaticTransitions (line 4) | class SweepAutomaticTransitions
      method initialize (line 7) | def initialize(wf_case)
      method call (line 11) | def call

FILE: app/models/wf/case_command/sweep_timed_transitions.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class SweepTimedTransitions (line 4) | class SweepTimedTransitions
      method call (line 7) | def call

FILE: app/models/wf/case_command/workitem_action.rb
  type Wf::CaseCommand (line 3) | module Wf::CaseCommand
    class WorkitemAction (line 4) | class WorkitemAction
      method initialize (line 7) | def initialize(workitem, user, action = :start)
      method call (line 13) | def call

FILE: app/models/wf/comment.rb
  type Wf (line 16) | module Wf
    class Comment (line 17) | class Comment < ApplicationRecord

FILE: app/models/wf/demo_target.rb
  type Wf (line 14) | module Wf
    class DemoTarget (line 15) | class DemoTarget < ApplicationRecord

FILE: app/models/wf/entry.rb
  type Wf (line 16) | module Wf
    class Entry (line 17) | class Entry < ApplicationRecord
      method json (line 27) | def json
      method for_mini_racer (line 31) | def for_mini_racer
      method update_payload! (line 35) | def update_payload!

FILE: app/models/wf/field.rb
  type Wf (line 18) | module Wf
    class Field (line 19) | class Field < ApplicationRecord
      method field_type_for_view (line 44) | def field_type_for_view
      method array? (line 63) | def array?
      method type_for_cast (line 67) | def type_for_cast

FILE: app/models/wf/field_value.rb
  type Wf (line 16) | module Wf
    class FieldValue (line 17) | class FieldValue < ApplicationRecord
      method value_after_cast (line 22) | def value_after_cast
      method value= (line 36) | def value=(v)
      method value (line 44) | def value

FILE: app/models/wf/form.rb
  type Wf (line 14) | module Wf
    class Form (line 15) | class Form < ApplicationRecord

FILE: app/models/wf/group.rb
  type Wf (line 13) | module Wf
    class Group (line 14) | class Group < ApplicationRecord

FILE: app/models/wf/guard.rb
  type Wf (line 19) | module Wf
    class Guard (line 20) | class Guard < ApplicationRecord
      method value_after_cast (line 40) | def value_after_cast
      method pass? (line 45) | def pass?(entry, workitem)
      method check_exp (line 53) | def check_exp(_entry, workitem)
      method check_fieldable (line 62) | def check_fieldable(entry)
      method yes_or_no? (line 69) | def yes_or_no?(input_value, setting_value)
      method inspect (line 87) | def inspect
      method validate_exp_and_fieldable (line 95) | def validate_exp_and_fieldable

FILE: app/models/wf/lola.rb
  type Wf (line 3) | module Wf
    class Lola (line 4) | class Lola
      method initialize (line 6) | def initialize(workflow)
      method to_text (line 13) | def to_text
      method json_path (line 39) | def json_path(bucket)
      method lola_path (line 43) | def lola_path
      method generate_lola_file! (line 47) | def generate_lola_file!
      method soundness? (line 51) | def soundness?
      method reachability_of_final_marking? (line 55) | def reachability_of_final_marking?
      method quasiliveness? (line 63) | def quasiliveness?
      method deadlock? (line 67) | def deadlock?
      method dead_transition? (line 75) | def dead_transition?(transition)
      method run_cmd (line 81) | def run_cmd(formula, bucket)

FILE: app/models/wf/multiple_instances/all_finish.rb
  type Wf (line 3) | module Wf
    type MultipleInstances (line 4) | module MultipleInstances
      class AllFinish (line 5) | class AllFinish
        method perform (line 6) | def perform(_workitem)

FILE: app/models/wf/party.rb
  type Wf (line 15) | module Wf
    class Party (line 16) | class Party < ApplicationRecord

FILE: app/models/wf/place.rb
  type Wf (line 17) | module Wf
    class Place (line 18) | class Place < ApplicationRecord
      method graph_id (line 28) | def graph_id
      method lola_id (line 32) | def lola_id

FILE: app/models/wf/token.rb
  type Wf (line 23) | module Wf
    class Token (line 24) | class Token < ApplicationRecord

FILE: app/models/wf/transition.rb
  type Wf (line 32) | module Wf
    class Transition (line 33) | class Transition < ApplicationRecord
      method is_sub_workflow? (line 53) | def is_sub_workflow?
      method explicit_or_split? (line 57) | def explicit_or_split?
      method validate_trigger_type_and_sub (line 63) | def validate_trigger_type_and_sub
      method graph_id (line 67) | def graph_id
      method lola_id (line 71) | def lola_id

FILE: app/models/wf/transition_static_assignment.rb
  type Wf (line 15) | module Wf
    class TransitionStaticAssignment (line 16) | class TransitionStaticAssignment < ApplicationRecord

FILE: app/models/wf/user.rb
  type Wf (line 14) | module Wf
    class User (line 15) | class User < ApplicationRecord

FILE: app/models/wf/workflow.rb
  type Wf (line 16) | module Wf
    class Workflow (line 17) | class Workflow < ApplicationRecord
      method do_validate! (line 40) | def do_validate!
      method to_graph (line 75) | def to_graph(wf_case = nil, base = nil)
      method render_graph (line 190) | def render_graph(wf_case = nil)
      method to_lola (line 197) | def to_lola
      method to_rgl (line 201) | def to_rgl

FILE: app/models/wf/workitem.rb
  type Wf (line 28) | module Wf
    class Workitem (line 29) | class Workitem < ApplicationRecord
      method todo (line 51) | def self.todo(wf_current_user)
      method doing (line 59) | def self.doing(wf_current_user)
      method done (line 63) | def self.done(wf_current_user)
      method for_mini_racer (line 67) | def for_mini_racer
      method parent? (line 80) | def parent?
      method name (line 84) | def name
      method pass_guard? (line 88) | def pass_guard?(arc, has_passed = false)
      method real? (line 97) | def real?
      method started_by? (line 104) | def started_by?(user)
      method finished_by? (line 108) | def finished_by?(user)
      method owned_by? (line 112) | def owned_by?(user)

FILE: app/models/wf/workitem_assignment.rb
  type Wf (line 14) | module Wf
    class WorkitemAssignment (line 15) | class WorkitemAssignment < ApplicationRecord

FILE: db/migrate/20200130201043_init.rb
  class Init (line 3) | class Init < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200130201641_init_some_data.rb
  class InitSomeData (line 3) | class InitSomeData < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200131200455_create_wf_entries.rb
  class CreateWfEntries (line 3) | class CreateWfEntries < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200201001543_add_target_field_name_for_guard.rb
  class AddTargetFieldNameForGuard (line 3) | class AddTargetFieldNameForGuard < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200212120019_remove_targetable_from_workitem.rb
  class RemoveTargetableFromWorkitem (line 3) | class RemoveTargetableFromWorkitem < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200213085258_add_formable.rb
  class AddFormable (line 3) | class AddFormable < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200213125753_add_form_id_for_entry.rb
  class AddFormIdForEntry (line 3) | class AddFormIdForEntry < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200213130900_remove_workflow_id_from_form_related.rb
  class RemoveWorkflowIdFromFormRelated (line 3) | class RemoveWorkflowIdFromFormRelated < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200220070839_remove_unused_column.rb
  class RemoveUnusedColumn (line 3) | class RemoveUnusedColumn < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200220072512_add_sub_workflow.rb
  class AddSubWorkflow (line 3) | class AddSubWorkflow < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200222150432_add_multi_instance.rb
  class AddMultiInstance (line 3) | class AddMultiInstance < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: db/migrate/20200226195134_add_dynamic_assign_by.rb
  class AddDynamicAssignBy (line 3) | class AddDynamicAssignBy < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: lib/wf.rb
  type Wf (line 5) | module Wf

FILE: lib/wf/engine.rb
  type Wf (line 3) | module Wf
    class Engine (line 4) | class Engine < ::Rails::Engine

FILE: lib/wf/version.rb
  type Wf (line 3) | module Wf

FILE: test/controllers/wf/arcs_controller_test.rb
  type Wf (line 5) | module Wf
    class ArcsControllerTest (line 6) | class ArcsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/cases_controller_test.rb
  type Wf (line 5) | module Wf
    class CasesControllerTest (line 6) | class CasesControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/comments_controller_test.rb
  type Wf (line 5) | module Wf
    class CommentsControllerTest (line 6) | class CommentsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/fields_controller_test.rb
  type Wf (line 5) | module Wf
    class FieldsControllerTest (line 6) | class FieldsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/forms_controller_test.rb
  type Wf (line 5) | module Wf
    class FormsControllerTest (line 6) | class FormsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/guards_controller_test.rb
  type Wf (line 5) | module Wf
    class GuardsControllerTest (line 6) | class GuardsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/places_controller_test.rb
  type Wf (line 5) | module Wf
    class PlacesControllerTest (line 6) | class PlacesControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/static_assignments_controller_test.rb
  type Wf (line 5) | module Wf
    class StaticAssignmentsControllerTest (line 6) | class StaticAssignmentsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/transitions_controller_test.rb
  type Wf (line 5) | module Wf
    class TransitionsControllerTest (line 6) | class TransitionsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/workflows_controller_test.rb
  type Wf (line 5) | module Wf
    class WorkflowsControllerTest (line 6) | class WorkflowsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/workitem_assignments_controller_test.rb
  type Wf (line 5) | module Wf
    class WorkitemAssignmentsControllerTest (line 6) | class WorkitemAssignmentsControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/wf/workitems_controller_test.rb
  type Wf (line 5) | module Wf
    class WorkitemsControllerTest (line 6) | class WorkitemsControllerTest < ActionDispatch::IntegrationTest

FILE: test/dummy/app/channels/application_cable/channel.rb
  type ApplicationCable (line 3) | module ApplicationCable
    class Channel (line 4) | class Channel < ActionCable::Channel::Base

FILE: test/dummy/app/channels/application_cable/connection.rb
  type ApplicationCable (line 3) | module ApplicationCable
    class Connection (line 4) | class Connection < ActionCable::Connection::Base

FILE: test/dummy/app/controllers/application_controller.rb
  class ApplicationController (line 3) | class ApplicationController < ActionController::Base
    method current_user (line 4) | def current_user

FILE: test/dummy/app/helpers/application_helper.rb
  type ApplicationHelper (line 3) | module ApplicationHelper

FILE: test/dummy/app/jobs/application_job.rb
  class ApplicationJob (line 3) | class ApplicationJob < ActiveJob::Base

FILE: test/dummy/app/mailers/application_mailer.rb
  class ApplicationMailer (line 3) | class ApplicationMailer < ActionMailer::Base

FILE: test/dummy/app/models/application_record.rb
  class ApplicationRecord (line 3) | class ApplicationRecord < ActiveRecord::Base

FILE: test/dummy/app/models/entry.rb
  class Entry (line 15) | class Entry < ApplicationRecord
    method json (line 25) | def json
    method update_payload! (line 29) | def update_payload!

FILE: test/dummy/app/models/field.rb
  class Field (line 18) | class Field < ApplicationRecord
    method field_type_for_view (line 43) | def field_type_for_view
    method array? (line 62) | def array?
    method type_for_cast (line 68) | def type_for_cast

FILE: test/dummy/app/models/field_value.rb
  class FieldValue (line 18) | class FieldValue < ApplicationRecord
    method value_after_cast (line 23) | def value_after_cast
    method value= (line 37) | def value=(v)
    method value (line 45) | def value

FILE: test/dummy/app/models/form.rb
  class Form (line 14) | class Form < ApplicationRecord

FILE: test/dummy/config/application.rb
  type Dummy (line 10) | module Dummy
    class Application (line 11) | class Application < Rails::Application

FILE: test/dummy/config/initializers/my_assignment_callback.rb
  class MyAssignmentCallback (line 3) | class MyAssignmentCallback
    method perform (line 4) | def perform(_workitem_id)

FILE: test/dummy/db/migrate/20200213081814_new_form.rb
  class NewForm (line 3) | class NewForm < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: test/dummy/db/migrate/20200213133942_add_form_id_in_entry1.rb
  class AddFormIdInEntry1 (line 3) | class AddFormIdInEntry1 < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: test/dummy/db/migrate/20200214005535_add_entry_id_for_field_values1.rb
  class AddEntryIdForFieldValues1 (line 3) | class AddEntryIdForFieldValues1 < ActiveRecord::Migration[6.0]
    method change (line 4) | def change

FILE: test/integration/navigation_test.rb
  class NavigationTest (line 5) | class NavigationTest < ActionDispatch::IntegrationTest

FILE: test/models/wf/case_assignment_test.rb
  type Wf (line 18) | module Wf
    class CaseAssignmentTest (line 19) | class CaseAssignmentTest < ActiveSupport::TestCase

FILE: test/models/wf/comment_test.rb
  type Wf (line 18) | module Wf
    class CommentTest (line 19) | class CommentTest < ActiveSupport::TestCase

FILE: test/models/wf/demo_target_test.rb
  type Wf (line 16) | module Wf
    class DemoTargetTest (line 17) | class DemoTargetTest < ActiveSupport::TestCase

FILE: test/models/wf/entry_test.rb
  type Wf (line 18) | module Wf
    class EntryTest (line 19) | class EntryTest < ActiveSupport::TestCase

FILE: test/models/wf/field_test.rb
  type Wf (line 20) | module Wf
    class FieldTest (line 21) | class FieldTest < ActiveSupport::TestCase

FILE: test/models/wf/field_value_test.rb
  type Wf (line 18) | module Wf
    class FieldValueTest (line 19) | class FieldValueTest < ActiveSupport::TestCase

FILE: test/models/wf/form_test.rb
  type Wf (line 16) | module Wf
    class FormTest (line 17) | class FormTest < ActiveSupport::TestCase

FILE: test/models/wf/guard_test.rb
  type Wf (line 21) | module Wf
    class GuardTest (line 22) | class GuardTest < ActiveSupport::TestCase

FILE: test/models/wf/party_test.rb
  type Wf (line 17) | module Wf
    class PartyTest (line 18) | class PartyTest < ActiveSupport::TestCase

FILE: test/models/wf/transition_static_assignment_test.rb
  type Wf (line 17) | module Wf
    class TransitionStaticAssignmentTest (line 18) | class TransitionStaticAssignmentTest < ActiveSupport::TestCase

FILE: test/models/wf/user_test.rb
  type Wf (line 16) | module Wf
    class UserTest (line 17) | class UserTest < ActiveSupport::TestCase

FILE: test/models/wf/wf_test.rb
  type Wf (line 5) | module Wf
    class WfTest (line 6) | class WfTest < ActiveSupport::TestCase

FILE: test/models/wf/workitem_assignment_test.rb
  type Wf (line 16) | module Wf
    class WorkitemAssignmentTest (line 17) | class WorkitemAssignmentTest < ActiveSupport::TestCase
Condensed preview — 294 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (280K chars).
[
  {
    "path": ".editorconfig",
    "chars": 243,
    "preview": "# This file is for unifying the coding style for different editors and IDEs\n# editorconfig.org\n\nroot = true\n\n[*]\ncharset"
  },
  {
    "path": ".gitattributes",
    "chars": 36,
    "preview": "*.rb diff=ruby\n*.gemspec diff=ruby\n\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1170,
    "preview": "name: Testing\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    services:\n      db:\n        ima"
  },
  {
    "path": ".github/workflows/gempush.yml",
    "chars": 628,
    "preview": "name: Ruby Gem\n\non:\n  push:\n    tags:\n      - v*\n\njobs:\n  build:\n    name: Build + Publish\n    runs-on: ubuntu-latest\n\n "
  },
  {
    "path": ".gitignore",
    "chars": 829,
    "preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
  },
  {
    "path": ".rubocop.yml",
    "chars": 4798,
    "preview": "require:\n  - rubocop-performance\n  - rubocop-rails\n\nAllCops:\n  TargetRubyVersion: 2.5\n  Exclude:\n    - bin/**/*\n    - te"
  },
  {
    "path": "FormSpec.md",
    "chars": 1162,
    "preview": "## Why\n\nThe core of Petri Flow is the workflow engine. \nHowever, workflow, dynamic forms, and organization systems are i"
  },
  {
    "path": "Gemfile",
    "chars": 933,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\ngit_source(:github) { |repo| \"https://github.com/#{repo}.gi"
  },
  {
    "path": "Guard.md",
    "chars": 3091,
    "preview": "## Guard Expression\n\nThere are two per-defined variables for your guard expression, `workitem`, `target`.\n\nSchema for `w"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2020 Hooopo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "MIT-LICENSE",
    "chars": 1051,
    "preview": "Copyright 2020 Hooopo Wang\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this softwar"
  },
  {
    "path": "README.md",
    "chars": 3409,
    "preview": "# Petri Flow ![Ruby Gem](https://github.com/hooopo/petri_flow/workflows/Ruby%20Gem/badge.svg?event=push) ![Testing](http"
  },
  {
    "path": "Rakefile",
    "chars": 702,
    "preview": "# frozen_string_literal: true\n\nbegin\n  require \"bundler/setup\"\nrescue LoadError\n  puts \"You must `gem install bundler` a"
  },
  {
    "path": "acts_as_party.md",
    "chars": 427,
    "preview": "## Usage\n\n\nfor normal org model, for example group or role etc.\n\n```ruby\nmodule Wf\n  class Group < ApplicationRecord\n   "
  },
  {
    "path": "app/assets/config/wf_manifest.js",
    "chars": 83,
    "preview": "//= link_directory ../stylesheets/wf .css\n//= link_directory ../javascripts/wf .js\n"
  },
  {
    "path": "app/assets/images/wf/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/assets/javascripts/wf/application.js",
    "chars": 108,
    "preview": "//= require jquery3\n//= require popper\n//= require bootstrap\n//= require rails-ujs\n//= require select2-full\n"
  },
  {
    "path": "app/assets/stylesheets/wf/application.scss",
    "chars": 295,
    "preview": "/*\n*= require select2\n*= require select2-bootstrap4\n*/\n\n@import \"uikit/index\";\n\nmain{\n  min-height: 80vh;\n  h2 {\n    mar"
  },
  {
    "path": "app/assets/stylesheets/wf/arcs.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/cases.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/comments.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/fields.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/forms.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/guards.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/places.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/static_assignments.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/transitions.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/_colors.scss",
    "chars": 2437,
    "preview": "// fork from: https://github.com/oortcast/42page/blob/master/app/javascript/42design/\n//\n// inspired by https://github.c"
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/_variables.scss",
    "chars": 968,
    "preview": "@import \"colors\";\n@import \"bootstrap/functions\";\n$blue:    $blue-base;\n$red:     $red-base;\n$yellow:  $yellow-base;\n$gre"
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/alert.scss",
    "chars": 285,
    "preview": "@import \"variables\";\n\n.alert{\n  margin-bottom: 2rem;\n  p{\n    margin-bottom: 0;\n  }\n\n  &.alert-success{\n    background: "
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/button.scss",
    "chars": 117,
    "preview": "@import \"_variables\";\n\n.btn-light{\n  color: $gray-8;\n  background: rgba(94, 94, 94, 0.2);\n  border: rgb(94,94,94);\n}\n"
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/card.scss",
    "chars": 150,
    "preview": ".card{\n  margin-bottom: 4rem;\n  border: 1px solid rgba(230, 230, 230, 0.41);\n  border-radius: 0.625rem;\n  box-shadow: 0 "
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/index.scss",
    "chars": 142,
    "preview": "@import \"_variables\";\n@import \"bootstrap\";\n\n//overwrite\n@import \"navbar\";\n@import \"table\";\n@import \"card\";\n@import \"aler"
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/navbar.scss",
    "chars": 524,
    "preview": "@import \"variables\";\n\n.navbar-petri{\n  box-shadow: 0 12px 24px 0 rgba(0,0,0,0.05);\n  margin-bottom: 2rem;\n  background: "
  },
  {
    "path": "app/assets/stylesheets/wf/uikit/table.scss",
    "chars": 275,
    "preview": "@import \"variables\";\n\n.table-view{\n  thead th{\n    color: $gray-7;\n    font-weight: 500;\n    border-top: 0;\n    border-b"
  },
  {
    "path": "app/assets/stylesheets/wf/workflows.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/workitem_assignments.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/assets/stylesheets/wf/workitems.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "app/controllers/wf/application_controller.rb",
    "chars": 271,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class ApplicationController < ::ApplicationController\n    protect_from_forger"
  },
  {
    "path": "app/controllers/wf/arcs_controller.rb",
    "chars": 1665,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class ArcsController < Applic"
  },
  {
    "path": "app/controllers/wf/cases_controller.rb",
    "chars": 1503,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class CasesController < Appli"
  },
  {
    "path": "app/controllers/wf/comments_controller.rb",
    "chars": 987,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class CommentsController < Ap"
  },
  {
    "path": "app/controllers/wf/fields_controller.rb",
    "chars": 1348,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class FieldsController < Appl"
  },
  {
    "path": "app/controllers/wf/forms_controller.rb",
    "chars": 1242,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class FormsController < Appli"
  },
  {
    "path": "app/controllers/wf/guards_controller.rb",
    "chars": 1879,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class GuardsController < Appl"
  },
  {
    "path": "app/controllers/wf/places_controller.rb",
    "chars": 1465,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class PlacesController < Appl"
  },
  {
    "path": "app/controllers/wf/static_assignments_controller.rb",
    "chars": 1113,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class StaticAssignmentsContro"
  },
  {
    "path": "app/controllers/wf/transitions_controller.rb",
    "chars": 2321,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class TransitionsController <"
  },
  {
    "path": "app/controllers/wf/workflows_controller.rb",
    "chars": 1423,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class WorkflowsController < A"
  },
  {
    "path": "app/controllers/wf/workitem_assignments_controller.rb",
    "chars": 1151,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class WorkitemAssignmentsCont"
  },
  {
    "path": "app/controllers/wf/workitems_controller.rb",
    "chars": 3451,
    "preview": "# frozen_string_literal: true\n\nrequire_dependency \"wf/application_controller\"\n\nmodule Wf\n  class WorkitemsController < A"
  },
  {
    "path": "app/helpers/wf/application_helper.rb",
    "chars": 78,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module ApplicationHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/arcs_helper.rb",
    "chars": 71,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module ArcsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/cases_helper.rb",
    "chars": 72,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module CasesHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/comments_helper.rb",
    "chars": 75,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module CommentsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/fields_helper.rb",
    "chars": 73,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module FieldsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/forms_helper.rb",
    "chars": 72,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module FormsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/guards_helper.rb",
    "chars": 73,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module GuardsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/places_helper.rb",
    "chars": 73,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module PlacesHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/static_assignments_helper.rb",
    "chars": 84,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module StaticAssignmentsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/transitions_helper.rb",
    "chars": 78,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module TransitionsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/workflows_helper.rb",
    "chars": 76,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module WorkflowsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/workitem_assignments_helper.rb",
    "chars": 86,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module WorkitemAssignmentsHelper\n  end\nend\n"
  },
  {
    "path": "app/helpers/wf/workitems_helper.rb",
    "chars": 76,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module WorkitemsHelper\n  end\nend\n"
  },
  {
    "path": "app/jobs/wf/application_job.rb",
    "chars": 92,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class ApplicationJob < ActiveJob::Base\n  end\nend\n"
  },
  {
    "path": "app/jobs/wf/fire_timed_workitem_job.rb",
    "chars": 394,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class FireTimedWorkitemJob < ApplicationJob\n    queue_as :default\n\n    def pe"
  },
  {
    "path": "app/mailers/wf/application_mailer.rb",
    "chars": 155,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class ApplicationMailer < ActionMailer::Base\n    default from: \"from@example."
  },
  {
    "path": "app/models/wf/acts_as_party.rb",
    "chars": 509,
    "preview": "# frozen_string_literal: true\n\nrequire \"active_support/concern\"\n\nmodule Wf\n  module ActsAsParty\n    extend ActiveSupport"
  },
  {
    "path": "app/models/wf/application_record.rb",
    "chars": 129,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class ApplicationRecord < ActiveRecord::Base\n    self.abstract_class = true\n "
  },
  {
    "path": "app/models/wf/arc.rb",
    "chars": 963,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_arcs\n#\n#  id            :integer          not "
  },
  {
    "path": "app/models/wf/callbacks/assignment_default.rb",
    "chars": 203,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class AssignmentDefault < ApplicationJob\n    queue_as :default\n\n  "
  },
  {
    "path": "app/models/wf/callbacks/deadline_default.rb",
    "chars": 194,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class DeadlineDefault < ApplicationJob\n    queue_as :default\n\n    "
  },
  {
    "path": "app/models/wf/callbacks/enable_default.rb",
    "chars": 192,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class EnableDefault < ApplicationJob\n    queue_as :default\n\n    de"
  },
  {
    "path": "app/models/wf/callbacks/fire_default.rb",
    "chars": 190,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class FireDefault < ApplicationJob\n    queue_as :default\n\n    def "
  },
  {
    "path": "app/models/wf/callbacks/hold_timeout_default.rb",
    "chars": 197,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class HoldTimeoutDefault < ApplicationJob\n    queue_as :default\n\n "
  },
  {
    "path": "app/models/wf/callbacks/notification_default.rb",
    "chars": 198,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class NotificationDefault < ApplicationJob\n    queue_as :default\n\n"
  },
  {
    "path": "app/models/wf/callbacks/time_default.rb",
    "chars": 190,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class TimeDefault < ApplicationJob\n    queue_as :default\n\n    def "
  },
  {
    "path": "app/models/wf/callbacks/unassignment_default.rb",
    "chars": 198,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::Callbacks\n  class UnassignmentDefault < ApplicationJob\n    queue_as :default\n\n"
  },
  {
    "path": "app/models/wf/case.rb",
    "chars": 1171,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_cases\n#\n#  id                     :integer    "
  },
  {
    "path": "app/models/wf/case_assignment.rb",
    "chars": 482,
    "preview": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: wf_case_assignments\n#\n#  id            :integer   "
  },
  {
    "path": "app/models/wf/case_command/add_comment.rb",
    "chars": 367,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class AddComment\n    prepend SimpleCommand\n    attr_reader :work"
  },
  {
    "path": "app/models/wf/case_command/add_manual_assignment.rb",
    "chars": 406,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class AddManualAssignment\n    prepend SimpleCommand\n    attr_rea"
  },
  {
    "path": "app/models/wf/case_command/add_token.rb",
    "chars": 368,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class AddToken\n    prepend SimpleCommand\n    attr_reader :wf_cas"
  },
  {
    "path": "app/models/wf/case_command/add_workitem_assignment.rb",
    "chars": 1707,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class AddWorkitemAssignment\n    prepend SimpleCommand\n    attr_r"
  },
  {
    "path": "app/models/wf/case_command/begin_workitem_action.rb",
    "chars": 1256,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class BeginWorkitemAction\n    prepend SimpleCommand\n    attr_rea"
  },
  {
    "path": "app/models/wf/case_command/cancel.rb",
    "chars": 345,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class Cancel\n    prepend SimpleCommand\n    attr_reader :wf_case\n"
  },
  {
    "path": "app/models/wf/case_command/cancel_workitem.rb",
    "chars": 527,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class CancelWorkitem\n    prepend SimpleCommand\n    attr_reader :"
  },
  {
    "path": "app/models/wf/case_command/clear_manual_assignments.rb",
    "chars": 367,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class ClearManualAssignments\n    prepend SimpleCommand\n    attr_"
  },
  {
    "path": "app/models/wf/case_command/clear_workitem_assignments.rb",
    "chars": 568,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class ClearWorkitemAssignments\n    prepend SimpleCommand\n    att"
  },
  {
    "path": "app/models/wf/case_command/consume_token.rb",
    "chars": 724,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class ConsumeToken\n    prepend SimpleCommand\n    attr_reader :wf"
  },
  {
    "path": "app/models/wf/case_command/create_entry.rb",
    "chars": 1005,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class CreateEntry\n    prepend SimpleCommand\n    attr_reader :for"
  },
  {
    "path": "app/models/wf/case_command/enable_transitions.rb",
    "chars": 1508,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class EnableTransitions\n    prepend SimpleCommand\n    attr_reade"
  },
  {
    "path": "app/models/wf/case_command/end_workitem_action.rb",
    "chars": 615,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class EndWorkitemAction\n    prepend SimpleCommand\n    attr_reade"
  },
  {
    "path": "app/models/wf/case_command/finish_workitem.rb",
    "chars": 1095,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class FinishWorkitem\n    prepend SimpleCommand\n    attr_reader :"
  },
  {
    "path": "app/models/wf/case_command/finished_p.rb",
    "chars": 1006,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class FinishedP\n    prepend SimpleCommand\n    attr_reader :wf_ca"
  },
  {
    "path": "app/models/wf/case_command/fire_message_transition.rb",
    "chars": 501,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class FireMessageTransition\n    prepend SimpleCommand\n    attr_r"
  },
  {
    "path": "app/models/wf/case_command/fire_transition_internal.rb",
    "chars": 1259,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class FireTransitionInternal\n    prepend SimpleCommand\n    attr_"
  },
  {
    "path": "app/models/wf/case_command/lock_token.rb",
    "chars": 473,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class LockToken\n    prepend SimpleCommand\n    attr_reader :wf_ca"
  },
  {
    "path": "app/models/wf/case_command/new.rb",
    "chars": 445,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class New\n    prepend SimpleCommand\n    attr_reader :workflow, :"
  },
  {
    "path": "app/models/wf/case_command/release_token.rb",
    "chars": 487,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class ReleaseToken\n    prepend SimpleCommand\n    attr_reader :wo"
  },
  {
    "path": "app/models/wf/case_command/remove_manual_assignment.rb",
    "chars": 417,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class RemoveManualAssignment\n    prepend SimpleCommand\n    attr_"
  },
  {
    "path": "app/models/wf/case_command/remove_workitem_assignment.rb",
    "chars": 715,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class RemoveWorkitemAssignment\n    prepend SimpleCommand\n    att"
  },
  {
    "path": "app/models/wf/case_command/resume.rb",
    "chars": 346,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class Resume\n    prepend SimpleCommand\n    attr_reader :wf_case\n"
  },
  {
    "path": "app/models/wf/case_command/set_workitem_assignments.rb",
    "chars": 1059,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class SetWorkitemAssignments\n    prepend SimpleCommand\n    attr_"
  },
  {
    "path": "app/models/wf/case_command/start_case.rb",
    "chars": 409,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class StartCase\n    prepend SimpleCommand\n    attr_reader :wf_ca"
  },
  {
    "path": "app/models/wf/case_command/start_workitem.rb",
    "chars": 703,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class StartWorkitem\n    prepend SimpleCommand\n    attr_reader :w"
  },
  {
    "path": "app/models/wf/case_command/suspend.rb",
    "chars": 325,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class Suspend\n    prepend SimpleCommand\n    attr_reader :wf_case"
  },
  {
    "path": "app/models/wf/case_command/sweep_automatic_transitions.rb",
    "chars": 857,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class SweepAutomaticTransitions\n    prepend SimpleCommand\n    at"
  },
  {
    "path": "app/models/wf/case_command/sweep_timed_transitions.rb",
    "chars": 394,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class SweepTimedTransitions\n    prepend SimpleCommand\n\n    def c"
  },
  {
    "path": "app/models/wf/case_command/workitem_action.rb",
    "chars": 477,
    "preview": "# frozen_string_literal: true\n\nmodule Wf::CaseCommand\n  class WorkitemAction\n    prepend SimpleCommand\n    attr_reader :"
  },
  {
    "path": "app/models/wf/comment.rb",
    "chars": 459,
    "preview": "# frozen_string_literal: true\n# == Schema Information\n#\n# Table name: wf_comments\n#\n#  id          :integer          not"
  },
  {
    "path": "app/models/wf/demo_target.rb",
    "chars": 373,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_demo_targets\n#\n#  id          :integer        "
  },
  {
    "path": "app/models/wf/entry.rb",
    "chars": 951,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_entries\n#\n#  id          :integer          not"
  },
  {
    "path": "app/models/wf/field.rb",
    "chars": 1658,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_fields\n#\n#  id              :integer          "
  },
  {
    "path": "app/models/wf/field_value.rb",
    "chars": 914,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_field_values\n#\n#  id         :integer         "
  },
  {
    "path": "app/models/wf/form.rb",
    "chars": 385,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_forms\n#\n#  id          :integer          not n"
  },
  {
    "path": "app/models/wf/group.rb",
    "chars": 396,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_groups\n#\n#  id         :integer          not n"
  },
  {
    "path": "app/models/wf/guard.rb",
    "chars": 2436,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_guards\n#\n#  id             :integer          n"
  },
  {
    "path": "app/models/wf/lola.rb",
    "chars": 2524,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class Lola\n    attr_reader :end_p, :start_p, :workflow\n    def initialize(wor"
  },
  {
    "path": "app/models/wf/multiple_instances/all_finish.rb",
    "chars": 159,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  module MultipleInstances\n    class AllFinish\n      def perform(_workitem)\n   "
  },
  {
    "path": "app/models/wf/party.rb",
    "chars": 557,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_parties\n#\n#  id            :integer          n"
  },
  {
    "path": "app/models/wf/place.rb",
    "chars": 680,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_places\n#\n#  id          :integer          not "
  },
  {
    "path": "app/models/wf/token.rb",
    "chars": 903,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_tokens\n#\n#  id                 :integer       "
  },
  {
    "path": "app/models/wf/transition.rb",
    "chars": 2659,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_transitions\n#\n#  id                    :intege"
  },
  {
    "path": "app/models/wf/transition_static_assignment.rb",
    "chars": 643,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_transition_static_assignments\n#\n#  id         "
  },
  {
    "path": "app/models/wf/user.rb",
    "chars": 434,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_users\n#\n#  id         :integer          not nu"
  },
  {
    "path": "app/models/wf/workflow.rb",
    "chars": 7378,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_workflows\n#\n#  id          :integer          n"
  },
  {
    "path": "app/models/wf/workitem.rb",
    "chars": 3992,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_workitems\n#\n#  id                      :intege"
  },
  {
    "path": "app/models/wf/workitem_assignment.rb",
    "chars": 401,
    "preview": "# frozen_string_literal: true\n\n# == Schema Information\n#\n# Table name: wf_workitem_assignments\n#\n#  id          :integer"
  },
  {
    "path": "app/views/layouts/wf/_alert.html.erb",
    "chars": 507,
    "preview": "<% return if alert.blank? %>\n<div id=\"alert\" class=\"alert alert-warning\">\n  <p>\n    <svg viewBox=\"64 64 896 896\" focusab"
  },
  {
    "path": "app/views/layouts/wf/_footer.html.erb",
    "chars": 428,
    "preview": "<footer class=\"footer\">\n  <div class=\"container\">\n    <p>\n      <strong>\n        <a href=\"https://github.com/hooopo/petr"
  },
  {
    "path": "app/views/layouts/wf/_nav.html.erb",
    "chars": 573,
    "preview": "<nav class=\"navbar navbar-petri\" role=\"navigation\" aria-label=\"main navigation\">\n  <div class=\"container\">\n    <div clas"
  },
  {
    "path": "app/views/layouts/wf/_notice.html.erb",
    "chars": 551,
    "preview": "<% return if notice.blank? %>\n<div id=\"notice\" class=\"alert alert-success\">\n  <p>\n    <svg viewBox=\"64 64 896 896\" focus"
  },
  {
    "path": "app/views/layouts/wf/application.html.erb",
    "chars": 1072,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <title>Petri Flow</title>\n\n  <%= csrf_meta_tags %>\n  <meta http-equiv=\"Content"
  },
  {
    "path": "app/views/wf/arcs/_form.html.erb",
    "chars": 1417,
    "preview": "<%= form_with(model: arc, url: [@workflow, @arc], local: true) do |f| %>\n  <% if arc.errors.any? %>\n    <article class=\""
  },
  {
    "path": "app/views/wf/arcs/edit.html.erb",
    "chars": 89,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, arc: @arc %>\n</div>\n"
  },
  {
    "path": "app/views/wf/arcs/new.html.erb",
    "chars": 89,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, arc: @arc %>\n</div>\n"
  },
  {
    "path": "app/views/wf/arcs/show.html.erb",
    "chars": 2129,
    "preview": "<div class=\"card card-body\">\n<div class=\"float-right\">\n  <%= link_to 'Delete Arc', workflow_path(@workflow, @arc), data:"
  },
  {
    "path": "app/views/wf/cases/_form.html.erb",
    "chars": 963,
    "preview": "<%= form_with(model: wf_case, url: [@workflow, @wf_case], local: true) do |f| %>\n  <% if wf_case.errors.any? %>\n    <art"
  },
  {
    "path": "app/views/wf/cases/index.html.erb",
    "chars": 1101,
    "preview": "<div class=\"card card-body\">\n  <div class=\"float-left\"><h2>Cases</h2></div>\n  <div class=\"float-right\">\n    <%= link_to "
  },
  {
    "path": "app/views/wf/cases/new.html.erb",
    "chars": 97,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, wf_case: @wf_case %>\n</div>\n"
  },
  {
    "path": "app/views/wf/cases/show.html.erb",
    "chars": 3364,
    "preview": "<div class=\"card card-body\">\n<div>\n  <h2>Case Detail</h2>\n  <table class=\"table table-view\">\n    <tbody>\n      <tr>\n    "
  },
  {
    "path": "app/views/wf/comments/new.html.erb",
    "chars": 913,
    "preview": "<div class=\"card card-body\">\n<%= form_with(model: @comment, url: workitem_comments_path(@workitem), local: true) do |f| "
  },
  {
    "path": "app/views/wf/fields/_form.html.erb",
    "chars": 1369,
    "preview": "<%= form_with(model: field, url: [@form, field], local: true) do |f| %>\n  <% if field.errors.any? %>\n    <article class="
  },
  {
    "path": "app/views/wf/fields/edit.html.erb",
    "chars": 85,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", form: @form, field: @field %>\n</div>\n"
  },
  {
    "path": "app/views/wf/fields/new.html.erb",
    "chars": 85,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", form: @form, field: @field %>\n</div>\n"
  },
  {
    "path": "app/views/wf/forms/_form.html.erb",
    "chars": 960,
    "preview": "<%= form_with(model: form, local: true) do |f| %>\n  <% if form.errors.any? %>\n    <article class=\"message is-danger\">\n  "
  },
  {
    "path": "app/views/wf/forms/edit.html.erb",
    "chars": 70,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", form: @form %>\n</div>\n"
  },
  {
    "path": "app/views/wf/forms/index.html.erb",
    "chars": 1051,
    "preview": "<div class=\"card card-body\">\n <div class=\"d-flex  justify-content-between\">\n   <div><h2>Forms</h2></div>\n   <div><%= lin"
  },
  {
    "path": "app/views/wf/forms/new.html.erb",
    "chars": 70,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", form: @form %>\n</div>\n"
  },
  {
    "path": "app/views/wf/forms/show.html.erb",
    "chars": 1720,
    "preview": "<div class=\"card card-body\">\n<div class=\"d-flex  justify-content-end\">\n  <%= link_to 'Delete Form', form_path(@form), da"
  },
  {
    "path": "app/views/wf/guards/_form.html.erb",
    "chars": 1646,
    "preview": "<%= form_with(model: guard, url: [@arc, @guard], local: true) do |f| %>\n  <% if guard.errors.any? %>\n    <article class="
  },
  {
    "path": "app/views/wf/guards/edit.html.erb",
    "chars": 83,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", arc: @arc, guard: @guard %>\n</div>\n"
  },
  {
    "path": "app/views/wf/guards/new.html.erb",
    "chars": 83,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", arc: @arc, guard: @guard %>\n</div>\n"
  },
  {
    "path": "app/views/wf/places/_form.html.erb",
    "chars": 1374,
    "preview": "<%= form_with(model: place, url: [@workflow, @place], local: true) do |f| %>\n  <% if place.errors.any? %>\n    <article c"
  },
  {
    "path": "app/views/wf/places/edit.html.erb",
    "chars": 93,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, place: @place %>\n</div>\n"
  },
  {
    "path": "app/views/wf/places/new.html.erb",
    "chars": 93,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, place: @place %>\n</div>\n"
  },
  {
    "path": "app/views/wf/static_assignments/_form.html.erb",
    "chars": 1028,
    "preview": "<%= form_with(model: static_assignment, url: transition_static_assignments_path(static_assignment.transition), local: tr"
  },
  {
    "path": "app/views/wf/static_assignments/new.html.erb",
    "chars": 98,
    "preview": "<div class=\"card card-body\">\n  <%= render \"form\", static_assignment: @static_assignment %>\n</div>\n"
  },
  {
    "path": "app/views/wf/transitions/_form.html.erb",
    "chars": 5510,
    "preview": "<%= form_with(model: transition, url: [@workflow, @transition], local: true) do |f| %>\n  <% if transition.errors.any? %>"
  },
  {
    "path": "app/views/wf/transitions/edit.html.erb",
    "chars": 103,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, transition: @transition %>\n</div>\n"
  },
  {
    "path": "app/views/wf/transitions/new.html.erb",
    "chars": 103,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow, transition: @transition %>\n</div>\n"
  },
  {
    "path": "app/views/wf/transitions/show.html.erb",
    "chars": 2720,
    "preview": "<div class=\"card card-body\">\n<div class=\"float-right\">\n  <%= link_to 'Edit Transition', edit_workflow_transition_path(@w"
  },
  {
    "path": "app/views/wf/workflows/_form.html.erb",
    "chars": 980,
    "preview": "<%= form_with(model: workflow, local: true) do |f| %>\n  <% if workflow.errors.any? %>\n    <article class=\"message is-dan"
  },
  {
    "path": "app/views/wf/workflows/edit.html.erb",
    "chars": 78,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow %>\n</div>\n"
  },
  {
    "path": "app/views/wf/workflows/index.html.erb",
    "chars": 1580,
    "preview": "<div class=\"card card-body\">\n  <div class=\"d-flex  justify-content-between\">\n\n  <div><h2>Workflows</h2></div>\n<div>\n  <%"
  },
  {
    "path": "app/views/wf/workflows/new.html.erb",
    "chars": 78,
    "preview": "<div class=\"card card-body\">\n<%= render \"form\", workflow: @workflow %>\n</div>\n"
  },
  {
    "path": "app/views/wf/workflows/show.html.erb",
    "chars": 6866,
    "preview": "<div class=\"d-flex  justify-content-end\">\n<% if @workflow.is_valid? %>\n    <%= link_to 'New Case', new_workflow_case_pat"
  },
  {
    "path": "app/views/wf/workitem_assignments/new.html.erb",
    "chars": 1044,
    "preview": "<div class=\"card card-body\">\n<%= form_with(model: @workitem_assignment, url: workitem_workitem_assignments_path(@workite"
  },
  {
    "path": "app/views/wf/workitems/index.html.erb",
    "chars": 2815,
    "preview": "<div class=\"card card-body\">\n<div>\n  <h2 class=\"\">Stats</h2>\n  <table class=\"table table-view\">\n    <thead>\n      <tr>\n "
  },
  {
    "path": "app/views/wf/workitems/pre_finish.html.erb",
    "chars": 1777,
    "preview": "<%= form_with(model: @workitem, url: finish_workitem_path(@workitem), method: :put, local: true) do |f| %>\n  <% if @work"
  },
  {
    "path": "app/views/wf/workitems/show.html.erb",
    "chars": 7101,
    "preview": "<div class=\"card card-body\">\n<div class=\"float-right\">\n  <%= link_to 'Back to Case', workflow_case_path(@workitem.workfl"
  },
  {
    "path": "bin/rails",
    "chars": 544,
    "preview": "#!/usr/bin/env ruby\n# This command will automatically be run when you run \"rails\" with Rails gems\n# installed from the r"
  },
  {
    "path": "config/routes.rb",
    "chars": 615,
    "preview": "# frozen_string_literal: true\n\nWf::Engine.routes.draw do\n  resources :workflows do\n    resources :transitions\n    resour"
  },
  {
    "path": "db/migrate/20200130201043_init.rb",
    "chars": 9718,
    "preview": "# frozen_string_literal: true\n\nclass Init < ActiveRecord::Migration[6.0]\n  def change\n    create_table \"wf_arcs\", force:"
  },
  {
    "path": "db/migrate/20200130201641_init_some_data.rb",
    "chars": 336,
    "preview": "# frozen_string_literal: true\n\nclass InitSomeData < ActiveRecord::Migration[6.0]\n  def change\n    5.times do |i|\n      W"
  },
  {
    "path": "db/migrate/20200131200455_create_wf_entries.rb",
    "chars": 688,
    "preview": "# frozen_string_literal: true\n\nclass CreateWfEntries < ActiveRecord::Migration[6.0]\n  def change\n    create_table :wf_en"
  },
  {
    "path": "db/migrate/20200201001543_add_target_field_name_for_guard.rb",
    "chars": 225,
    "preview": "# frozen_string_literal: true\n\nclass AddTargetFieldNameForGuard < ActiveRecord::Migration[6.0]\n  def change\n    add_colu"
  },
  {
    "path": "db/migrate/20200212120019_remove_targetable_from_workitem.rb",
    "chars": 218,
    "preview": "# frozen_string_literal: true\n\nclass RemoveTargetableFromWorkitem < ActiveRecord::Migration[6.0]\n  def change\n    remove"
  },
  {
    "path": "db/migrate/20200213085258_add_formable.rb",
    "chars": 229,
    "preview": "# frozen_string_literal: true\n\nclass AddFormable < ActiveRecord::Migration[6.0]\n  def change\n    add_column :wf_transiti"
  },
  {
    "path": "db/migrate/20200213125753_add_form_id_for_entry.rb",
    "chars": 168,
    "preview": "# frozen_string_literal: true\n\nclass AddFormIdForEntry < ActiveRecord::Migration[6.0]\n  def change\n    add_column :wf_en"
  },
  {
    "path": "db/migrate/20200213130900_remove_workflow_id_from_form_related.rb",
    "chars": 223,
    "preview": "# frozen_string_literal: true\n\nclass RemoveWorkflowIdFromFormRelated < ActiveRecord::Migration[6.0]\n  def change\n    rem"
  },
  {
    "path": "db/migrate/20200220070839_remove_unused_column.rb",
    "chars": 158,
    "preview": "# frozen_string_literal: true\n\nclass RemoveUnusedColumn < ActiveRecord::Migration[6.0]\n  def change\n    remove_column :w"
  },
  {
    "path": "db/migrate/20200220072512_add_sub_workflow.rb",
    "chars": 320,
    "preview": "# frozen_string_literal: true\n\nclass AddSubWorkflow < ActiveRecord::Migration[6.0]\n  def change\n    add_column :wf_trans"
  },
  {
    "path": "db/migrate/20200222150432_add_multi_instance.rb",
    "chars": 675,
    "preview": "# frozen_string_literal: true\n\nclass AddMultiInstance < ActiveRecord::Migration[6.0]\n  def change\n    add_column :wf_tra"
  },
  {
    "path": "db/migrate/20200226195134_add_dynamic_assign_by.rb",
    "chars": 233,
    "preview": "# frozen_string_literal: true\n\nclass AddDynamicAssignBy < ActiveRecord::Migration[6.0]\n  def change\n    add_column :wf_t"
  },
  {
    "path": "lib/tasks/wf_tasks.rake",
    "chars": 607,
    "preview": "# frozen_string_literal: true\n\ndesc \"Wf tasks\"\n\ntask wf: :environment do\n  url = \"http://service-technology.org/files/lo"
  },
  {
    "path": "lib/wf/engine.rb",
    "chars": 760,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  class Engine < ::Rails::Engine\n    isolate_namespace Wf\n    config.autoload_p"
  },
  {
    "path": "lib/wf/version.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Wf\n  VERSION = \"0.2.5\"\nend\n"
  },
  {
    "path": "lib/wf.rb",
    "chars": 1549,
    "preview": "# frozen_string_literal: true\n\nrequire \"wf/engine\"\n\nmodule Wf\n  class << self\n    attr_accessor :enable_callbacks\n    at"
  },
  {
    "path": "lola.md",
    "chars": 2261,
    "preview": "## LoLA\n\nLoLA is a Petri nets model-checking tool. To install LoLA, download lola-2.0.tar.gz from http://home.gna.org/se"
  },
  {
    "path": "screenshots/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/controllers/wf/arcs_controller_test.rb",
    "chars": 230,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class ArcsControllerTest < ActionDispatch::Integration"
  },
  {
    "path": "test/controllers/wf/cases_controller_test.rb",
    "chars": 231,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class CasesControllerTest < ActionDispatch::Integratio"
  },
  {
    "path": "test/controllers/wf/comments_controller_test.rb",
    "chars": 234,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class CommentsControllerTest < ActionDispatch::Integra"
  },
  {
    "path": "test/controllers/wf/fields_controller_test.rb",
    "chars": 232,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class FieldsControllerTest < ActionDispatch::Integrati"
  },
  {
    "path": "test/controllers/wf/forms_controller_test.rb",
    "chars": 231,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class FormsControllerTest < ActionDispatch::Integratio"
  },
  {
    "path": "test/controllers/wf/guards_controller_test.rb",
    "chars": 232,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class GuardsControllerTest < ActionDispatch::Integrati"
  },
  {
    "path": "test/controllers/wf/places_controller_test.rb",
    "chars": 232,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class PlacesControllerTest < ActionDispatch::Integrati"
  },
  {
    "path": "test/controllers/wf/static_assignments_controller_test.rb",
    "chars": 243,
    "preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nmodule Wf\n  class StaticAssignmentsControllerTest < ActionDispatch"
  }
]

// ... and 94 more files (download for full content)

About this extraction

This page contains the full source code of the hooopo/petri_flow GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 294 files (242.8 KB), approximately 76.4k tokens, and a symbol index with 493 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!