From 405b80cbe2ee2f876bc1efc200b1b58d8c6af3d3 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Thu, 14 Oct 2021 08:31:04 +0200 Subject: [PATCH 1/3] Fixes #3808 - Regression of #3797 causes installation of new instances from package to fail. --- contrib/packager.io/functions | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/packager.io/functions b/contrib/packager.io/functions index a8d9dcae2..8f3f91983 100644 --- a/contrib/packager.io/functions +++ b/contrib/packager.io/functions @@ -273,10 +273,11 @@ function elasticsearch_searchindex_rebuild () { function update_or_install () { - echo "# Clear cache..." - zammad run rails r Cache.clear - if [ -f ${ZAMMAD_DIR}/config/database.yml ]; then + + echo "# Clear cache..." + zammad run rails r Cache.clear + update_database update_translations From fc4ab53c1ab7bf72c7c20bbb3c3d07a032df16ca Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Thu, 14 Oct 2021 10:56:50 +0200 Subject: [PATCH 2/3] Follow up - b125b3603e01c9c79a40701153e97db332c25bb4 - Maintenance: Docker Chat build image misses yarn installation of dependencies. --- public/assets/chat/docker-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/assets/chat/docker-entrypoint.sh b/public/assets/chat/docker-entrypoint.sh index 3760633d3..fb15472f9 100755 --- a/public/assets/chat/docker-entrypoint.sh +++ b/public/assets/chat/docker-entrypoint.sh @@ -2,4 +2,6 @@ cd "${GULP_DIR}" || exit +yarn + gulp js css no-jquery From 4b0fa96cc9260c90025985cad1040cc58d0ca403 Mon Sep 17 00:00:00 2001 From: Rolf Schmidt Date: Thu, 14 Oct 2021 13:00:42 +0200 Subject: [PATCH 3/3] Fixes #3790 - Support workflow mechanism to do pending reminder state hide pending time use case. --- .../_ui_element/core_workflow_perform.coffee | 6 +- spec/factories/core_workflow.rb | 2 +- .../system/examples/core_workflow_examples.rb | 268 ++++++++++++++++++ spec/system/ticket/create_spec.rb | 55 ++++ 4 files changed, 328 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee b/app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee index b20780c62..1e1969ff7 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee @@ -39,6 +39,7 @@ class App.UiElement.core_workflow_perform extends App.UiElement.ApplicationSelec operatorsType = 'boolean$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option', 'set_fixed_to'] 'integer$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly'] + '^date': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly'] '^select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select'] '^tree_select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select'] '^input$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'fill_in', 'fill_in_empty'] @@ -63,8 +64,9 @@ class App.UiElement.core_workflow_perform extends App.UiElement.ApplicationSelec continue for row in App[groupMeta.model].configure_attributes - continue if !_.contains(['input', 'select', 'integer', 'boolean', 'tree_select'], row.tag) - continue if groupKey is 'ticket' && _.contains(['number', 'organization_id', 'title'], row.name) + continue if !_.contains(['input', 'select', 'integer', 'boolean', 'tree_select', 'date', 'datetime'], row.tag) + continue if _.contains(['created_at', 'updated_at'], row.name) + continue if groupKey is 'ticket' && _.contains(['number', 'organization_id', 'title', 'escalation_at', 'first_response_escalation_at', 'update_escalation_at', 'close_escalation_at', 'last_contact_at', 'last_contact_agent_at', 'last_contact_customer_at', 'first_response_at', 'close_at'], row.name) # ignore passwords and relations if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' && row.searchable isnt false diff --git a/spec/factories/core_workflow.rb b/spec/factories/core_workflow.rb index 02c327f7d..d4755d542 100644 --- a/spec/factories/core_workflow.rb +++ b/spec/factories/core_workflow.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :core_workflow do - sequence(:name) { |n| "test - workflow #{n}" } + sequence(:name) { |n| "test - workflow #{format '%07d', n}" } changeable { false } created_by_id { 1 } updated_by_id { 1 } diff --git a/spec/system/examples/core_workflow_examples.rb b/spec/system/examples/core_workflow_examples.rb index 5635bee28..424a59fa5 100644 --- a/spec/system/examples/core_workflow_examples.rb +++ b/spec/system/examples/core_workflow_examples.rb @@ -782,6 +782,274 @@ RSpec.shared_examples 'core workflow' do end end + describe 'modify date attribute', authenticated_as: :authenticate, db_strategy: :reset do + def authenticate + create(:object_manager_attribute_date, object_name: object_name, name: field_name, display: field_name, screens: screens) + ObjectManager::Attribute.migration_execute + true + end + + describe 'action - show' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'show', + show: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}']", wait: 10) + end + end + + describe 'action - hide' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'hide', + hide: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}'].is-hidden", visible: :hidden, wait: 10) + end + end + + describe 'action - remove' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'remove', + remove: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}'].is-removed", visible: :hidden, wait: 10) + end + end + + describe 'action - set_optional' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_optional', + set_optional: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page.find("div[data-attribute-name='#{field_name}'] div.formGroup-label label")).to have_no_text('*', wait: 10) + end + end + + describe 'action - set_mandatory' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_mandatory', + set_mandatory: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page.find("div[data-attribute-name='#{field_name}'] div.formGroup-label label")).to have_text('*', wait: 10) + end + end + + describe 'action - unset_readonly' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'unset_readonly', + unset_readonly: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_no_selector("div[data-attribute-name='#{field_name}'].is-readonly", wait: 10) + end + end + + describe 'action - set_readonly' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_readonly', + set_readonly: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector("div[data-attribute-name='#{field_name}'].is-readonly", wait: 10) + end + end + end + + describe 'modify datetime attribute', authenticated_as: :authenticate, db_strategy: :reset do + def authenticate + create(:object_manager_attribute_datetime, object_name: object_name, name: field_name, display: field_name, screens: screens) + ObjectManager::Attribute.migration_execute + true + end + + describe 'action - show' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'show', + show: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}']", wait: 10) + end + end + + describe 'action - hide' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'hide', + hide: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}'].is-hidden", visible: :hidden, wait: 10) + end + end + + describe 'action - remove' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'remove', + remove: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector(".form-group[data-attribute-name='#{field_name}'].is-removed", visible: :hidden, wait: 10) + end + end + + describe 'action - set_optional' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_optional', + set_optional: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page.find("div[data-attribute-name='#{field_name}'] div.formGroup-label label")).to have_no_text('*', wait: 10) + end + end + + describe 'action - set_mandatory' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_mandatory', + set_mandatory: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page.find("div[data-attribute-name='#{field_name}'] div.formGroup-label label")).to have_text('*', wait: 10) + end + end + + describe 'action - unset_readonly' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'unset_readonly', + unset_readonly: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_no_selector("div[data-attribute-name='#{field_name}'].is-readonly", wait: 10) + end + end + + describe 'action - set_readonly' do + before do + create(:core_workflow, + object: object_name, + perform: { + "#{object_name.downcase}.#{field_name}": { + operator: 'set_readonly', + set_readonly: 'true' + }, + }) + end + + it 'does perform' do + before_it.call + expect(page).to have_selector("div[data-attribute-name='#{field_name}'].is-readonly", wait: 10) + end + end + end + describe 'Unable to close tickets in certran cases if core workflow is used #3710', authenticated_as: :authenticate, db_strategy: :reset do def authenticate create(:object_manager_attribute_text, object_name: object_name, name: field_name, display: field_name, screens: screens) diff --git a/spec/system/ticket/create_spec.rb b/spec/system/ticket/create_spec.rb index 28ad4af66..5bc6a7de5 100644 --- a/spec/system/ticket/create_spec.rb +++ b/spec/system/ticket/create_spec.rb @@ -628,4 +628,59 @@ RSpec.describe 'Ticket Create', type: :system do end end end + + describe 'Support workflow mechanism to do pending reminder state hide pending time use case #3790', authenticated_as: :authenticate do + let(:template) { create(:template, :dummy_data) } + + def add_state + Ticket::State.create_or_update( + name: 'pending customer feedback', + state_type: Ticket::StateType.find_by(name: 'pending reminder'), + ignore_escalation: true, + created_by_id: 1, + updated_by_id: 1, + ) + end + + def update_screens + attribute = ObjectManager::Attribute.get( + object: 'Ticket', + name: 'state_id', + ) + attribute.data_option[:filter] = Ticket::State.by_category(:viewable).pluck(:id) + attribute.screens[:create_middle]['ticket.agent'][:filter] = Ticket::State.by_category(:viewable_agent_new).pluck(:id) + attribute.screens[:create_middle]['ticket.customer'][:filter] = Ticket::State.by_category(:viewable_customer_new).pluck(:id) + attribute.screens[:edit]['ticket.agent'][:filter] = Ticket::State.by_category(:viewable_agent_edit).pluck(:id) + attribute.screens[:edit]['ticket.customer'][:filter] = Ticket::State.by_category(:viewable_customer_edit).pluck(:id) + attribute.save! + end + + def create_flow + create(:core_workflow, + object: 'Ticket', + condition_selected: { 'ticket.state_id'=>{ 'operator' => 'is', 'value' => Ticket::State.find_by(name: 'pending customer feedback').id.to_s } }, + perform: { 'ticket.pending_time'=> { 'operator' => 'remove', 'remove' => 'true' } }) + end + + def authenticate + add_state + update_screens + create_flow + template + true + end + + before do + visit 'ticket/create' + use_template(template) + end + + it 'does make it possible to create pending states where the pending time is optional and not visible' do + select 'pending customer feedback', from: 'state_id' + click '.js-submit' + expect(current_url).to include('ticket/zoom') + expect(Ticket.last.state_id).to eq(Ticket::State.find_by(name: 'pending customer feedback').id) + expect(Ticket.last.pending_time).to be nil + end + end end