Просмотр исходного кода

Fixes #2102 - Read-only custom objects.

Rolf Schmidt 3 лет назад
Родитель
Сommit
d5d5b3b7b8

+ 31 - 0
app/assets/javascripts/app/controllers/_application_controller/form.coffee

@@ -371,6 +371,9 @@ class App.ControllerForm extends App.Controller
   @fieldIsRemoved: (field) ->
     return field.closest('.form-group').hasClass('is-removed')
 
+  @fieldIsReadonly: (field) ->
+    return field.closest('.form-group').hasClass('is-readonly')
+
   attributeIsMandatory: (name) ->
     field_by_name = @constructor.findFieldByName(name, @form)
     if field_by_name.length > 0
@@ -438,6 +441,34 @@ class App.ControllerForm extends App.Controller
         field_by_data.parents('.form-group').find('label span').html('')
         field_by_data.closest('.form-group').removeClass('is-required')
 
+  readonly: (name, el = @form) ->
+    if !_.isArray(name)
+      name = [name]
+    for key in name
+      field_by_name = @constructor.findFieldByName(key, el)
+      field_by_data = @constructor.findFieldByData(key, el)
+
+      if !@constructor.fieldIsReadonly(field_by_name)
+        field_by_name.closest('.form-group').find('input, select').attr('readonly', true)
+        field_by_name.closest('.form-group').addClass('is-readonly')
+      if !@constructor.fieldIsReadonly(field_by_data)
+        field_by_data.closest('.form-group').find('input, select').attr('readonly', true)
+        field_by_data.closest('.form-group').addClass('is-readonly')
+
+  changeable: (name, el = @form) ->
+    if !_.isArray(name)
+      name = [name]
+    for key in name
+      field_by_name = @constructor.findFieldByName(key, el)
+      field_by_data = @constructor.findFieldByData(key, el)
+
+      if @constructor.fieldIsReadonly(field_by_name)
+        field_by_name.closest('.form-group').find('input, select').attr('readonly', false)
+        field_by_name.closest('.form-group').removeClass('is-readonly')
+      if @constructor.fieldIsReadonly(field_by_data)
+        field_by_data.closest('.form-group').find('input, select').attr('readonly', false)
+        field_by_data.closest('.form-group').removeClass('is-readonly')
+
   validate: (params) ->
     App.Model.validate(
       model:  @model

+ 9 - 9
app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee

@@ -37,17 +37,17 @@ class App.UiElement.core_workflow_perform extends App.UiElement.ApplicationSelec
         delete groups[key]
 
     operatorsType =
-      'boolean$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to']
-      'integer$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional']
-      '^select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
-      '^tree_select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
-      '^input$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'fill_in', 'fill_in_empty']
+      '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']
+      '^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']
 
     operatorsName =
-      '_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
-      '_ids$': ['show', 'hide', 'set_mandatory', 'set_optional']
-      'organization_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'add_option', 'remove_option']
-      'owner_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'select', 'auto_select']
+      '_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
+      '_ids$': ['show', 'hide', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly']
+      'organization_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option']
+      'owner_id$': ['show', 'hide', 'set_mandatory', 'set_optional', 'set_readonly', 'unset_readonly', 'add_option', 'remove_option', 'select', 'auto_select']
 
     # merge config
     elements = {}

+ 11 - 0
app/assets/javascripts/app/controllers/ticket_zoom/form_handler_core_workflow.coffee

@@ -205,6 +205,16 @@ class App.FormHandlerCoreWorkflow
       else
         ui.optional(field, form)
 
+  # changes the mandatory flag of form elements
+  @changeReadonly: (form, ui, data) ->
+    return if _.isEmpty(data)
+
+    for field, state of data
+      if state
+        ui.readonly(field, form)
+      else
+        ui.changeable(field, form)
+
   # executes individual js commands of the Core Workflow engine
   @executeEval: (form, ui, data) ->
     return if _.isEmpty(data)
@@ -226,6 +236,7 @@ class App.FormHandlerCoreWorkflow
     App.FormHandlerCoreWorkflow.fillIn(classname, form, ui, attributes, params, data.fill_in)
     App.FormHandlerCoreWorkflow.changeVisibility(form, ui, data.visibility)
     App.FormHandlerCoreWorkflow.changeMandatory(form, ui, data.mandatory, data.visibility)
+    App.FormHandlerCoreWorkflow.changeReadonly(form, ui, data.readonly)
     App.FormHandlerCoreWorkflow.executeEval(form, ui, data.eval)
     App.FormHandlerCoreWorkflow.runCallbacks(ui)
 

+ 6 - 1
app/assets/stylesheets/zammad.scss

@@ -1782,6 +1782,11 @@ fieldset > .form-group {
   &.form-group--inactive {
     opacity: 0.5;
   }
+
+  &.is-readonly {
+    pointer-events: none;
+    cursor: not-allowed !important;
+  }
 }
 
 .date.form-group .controls {
@@ -12960,7 +12965,7 @@ span.is-disabled {
     padding: 6px 5px 11px;
     display: flex;
     flex-wrap: wrap;
-    
+
     .tag {
       margin: 2px;
       display: inline-block;

+ 32 - 1
app/models/core_workflow/attributes.rb

@@ -71,8 +71,12 @@ class CoreWorkflow::Attributes
     attribute[:screens].dig(@payload['screen'], type)
   end
 
+  def request_id_default
+    payload['request_id']
+  end
+
   # dont cache this else the result object will work with references and cache bugs occur
-  def shown_default
+  def visibility_default
     object_elements.each_with_object({}) do |attribute, result|
       result[ attribute[:name] ] = if @payload['request_id'] == 'ChecksCoreWorkflow.validate_workflows'
                                      'show'
@@ -106,6 +110,33 @@ class CoreWorkflow::Attributes
     end
   end
 
+  # dont cache this else the result object will work with references and cache bugs occur
+  def readonly_default
+    object_elements.each_with_object({}) do |attribute, result|
+      result[ attribute[:name] ] = false
+    end
+  end
+
+  def select_default
+    @result_object.result[:select] || {}
+  end
+
+  def fill_in_default
+    @result_object.result[:fill_in] || {}
+  end
+
+  def eval_default
+    []
+  end
+
+  def matched_workflows_default
+    @result_object.result[:matched_workflows] || []
+  end
+
+  def rerun_count_default
+    @result_object.result[:rerun_count] || 0
+  end
+
   def options_array(options)
     result = []
 

+ 4 - 11
app/models/core_workflow/result.rb

@@ -28,17 +28,10 @@ class CoreWorkflow::Result
   def set_default
     @rerun = false
 
-    @result = {
-      request_id:        payload['request_id'],
-      restrict_values:   {},
-      visibility:        attributes.shown_default,
-      mandatory:         attributes.mandatory_default,
-      select:            @result[:select] || {},
-      fill_in:           @result[:fill_in] || {},
-      eval:              [],
-      matched_workflows: @result[:matched_workflows] || [],
-      rerun_count:       @result[:rerun_count] || 0,
-    }
+    @result[:restrict_values] = {}
+    %i[request_id visibility mandatory readonly select fill_in eval matched_workflows rerun_count].each do |group|
+      @result[group] = attributes.send(:"#{group}_default")
+    end
 
     # restrict init defaults to make sure param values to removed if not allowed
     attributes.restrict_values_default.each do |field, values|

+ 8 - 0
app/models/core_workflow/result/set_readonly.rb

@@ -0,0 +1,8 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+class CoreWorkflow::Result::SetReadonly < CoreWorkflow::Result::Backend
+  def run
+    @result_object.result[:readonly][field] = true
+    true
+  end
+end

+ 8 - 0
app/models/core_workflow/result/unset_readonly.rb

@@ -0,0 +1,8 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+class CoreWorkflow::Result::UnsetReadonly < CoreWorkflow::Result::Backend
+  def run
+    @result_object.result[:readonly][field] = false
+    true
+  end
+end

+ 2 - 3
spec/models/core_workflow/attributes_spec.rb

@@ -56,10 +56,9 @@ RSpec.describe CoreWorkflow::Attributes, type: :model do
     end
   end
 
-  describe '#shown_default' do
+  describe '#visibility_default' do
     it 'priority should be shown by default' do
-      expect(result.shown_default['priority_id']).to eq('show')
+      expect(result.visibility_default['priority_id']).to eq('show')
     end
   end
-
 end

+ 42 - 0
spec/models/core_workflow_spec.rb

@@ -1561,4 +1561,46 @@ RSpec.describe CoreWorkflow, type: :model do
       expect(result[:visibility]['priority_id']).to eq('hide')
     end
   end
+
+  describe '.perform - Readonly' do
+    let!(:workflow1) do
+      create(:core_workflow,
+             object:  'Ticket',
+             perform: {
+               'ticket.group_id': {
+                 operator:     'set_readonly',
+                 set_readonly: 'true'
+               },
+             })
+    end
+
+    it 'does match workflow' do
+      expect(result[:matched_workflows]).to include(workflow1.id)
+    end
+
+    it 'does set group readonly' do
+      expect(result[:readonly]['group_id']).to eq(true)
+    end
+
+    context 'when readonly unset' do
+      let!(:workflow2) do
+        create(:core_workflow,
+               object:  'Ticket',
+               perform: {
+                 'ticket.group_id': {
+                   operator:       'unset_readonly',
+                   unset_readonly: 'true'
+                 },
+               })
+      end
+
+      it 'does match workflows' do
+        expect(result[:matched_workflows]).to include(workflow1.id, workflow2.id)
+      end
+
+      it 'does set group readonly' do
+        expect(result[:readonly]['group_id']).to eq(false)
+      end
+    end
+  end
 end

Некоторые файлы не были показаны из-за большого количества измененных файлов