Skip to content

Add alternative organizations to user#1

Open
egorovdunice wants to merge 553 commits intodevelopfrom
change_to_organization_ids_for_user
Open

Add alternative organizations to user#1
egorovdunice wants to merge 553 commits intodevelopfrom
change_to_organization_ids_for_user

Conversation

@egorovdunice
Copy link
Owner

No description provided.

Copy link

@thorsteneckel thorsteneckel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @egorovdunice,

I just reviewed your changes and added some inline comments. There are two other broader topics I want to cover here because they are related to multiple files:

Changes in generic files

There are quite a lot of changes to frontend files which meant to be generic. They now contain special organization logic which is not the way we should solve this requirement. Here is a list of related files:

  • app/assets/javascripts/app/controllers/_application_controller_form.coffee
  • app/assets/javascripts/app/controllers/_ui_element/autocompletion_ajax.coffee
  • app/assets/javascripts/app/controllers/_ui_element/select.coffee
  • app/assets/javascripts/app/lib/app_post/searchable_select.coffee
  • app/assets/javascripts/app/lib/bootstrap/transition.js
  • app/assets/javascripts/app/views/agent_ticket_create.jst.eco
  • app/assets/javascripts/app/views/customer_ticket_create.jst.eco
  • app/assets/javascripts/app/views/generic/searchable_select.jst.eco
  • app/assets/stylesheets/zammad.scss

I think the issue here is that you changed the existing generic files instead of inheriting from them and create a new custom element for the organization requirements (like e.g. app/assets/javascripts/app/lib/app_post/z_searchable_ajax_select.coffee does). This should resolve all of those file conflicts.

Debugging code

There are some changes and added files that I think are related to debugging. To be honest I don't know which are and which are not. So I added comments to the ones where I'm not sure. Would be a great help if you could mark them with TODO: DEBUGGING or something so I can get an idea what your thoughts where while adding/changing things.

There are some other things we need to get straight before merging (e.g. only one migration) but it's ok for now.

To be honest I don't have tested it yet because I think the required changes I described above might solve/introduce some bugs. After you changed things I'm happy to start testing.

Feel free to ask any questions!

sender_id: sender.id
form_id: @form_id
content_type: 'text/html'
organization_id: +params.organization_id

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The + in front of params looks wrong to me.

js_shadow_ids.each( -> ids.push $(this).val() )
if !ids.includes(data_value) && $(".js-shadow[name='organization_id']").val() != data_value
newInput = @input.closest('.searchableSelect').find('div.items')
input = "<input class='searchableSelect-shadow form-control js-shadow-ids' name='organization_ids'>"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use templates for HTML structures and don't build them in JS.

{ name: 'title', display: 'Title', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'customer_id', display: 'Customer', tag: 'input', type: 'text', limit: 100, null: false, autocapitalize: false, relation: 'User' },
{ name: 'organization_id', display: 'Organization', tag: 'select', relation: 'Organization', readonly: 1 },
# { name: 'organization_id', display: 'Organization', tag: 'select', relation: 'Organization', readonly: 1 },

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A ticket should still be assigned to one Organization.

return
end
8.times do
28.times do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this increased value?


# overwrite params
if !current_user.permissions?('ticket.agent')
%i[owner owner_id customer customer_id organization organization_id preferences].each do |key|

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove the organization_id key?

filter: Ticket::State.by_category(:viewable_agent_new).pluck(:id),
},
'ticket.customer' => {
item_class: 'column',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this line removed?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's needed to fit 2 select (Ticket.state and Ticket.organization_id) in 1 row

class App.ControllerForm extends App.Controller
constructor: (params) ->
super
if params['screen'] == 'create_middle_org'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't introduce hard coded attribute logic into generic files.

@@ -0,0 +1,5 @@
class App.UiElement.select_organization extends App.UiElement.select
@render: (attribute, params) ->
if attribute['name'] == 'organization_id' && attribute['default'] == 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a check for the attribute name if the name of the class is already limited to the attribute?

el: @$('.ticket-form-organization')
form_id: @formId
model: App.Ticket
screen: 'create_middle_org'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

el: @el.find('.ticket-form-organization')
form_id: @form_id
model: App.Ticket
screen: 'create_middle_org'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

@shadowInput.val event.currentTarget.getAttribute('data-value')
@shadowInput.trigger('change')


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove empty lines.

include Organization::SearchIndex

has_many :members, class_name: 'User'
has_and_belongs_to_many :members, after_add: :cache_update, after_remove: :cache_update, class_name: 'User'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two associations with the same name members which looks wrong to me.

encoding: utf8
username: zammad
password:
password: No newline at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this changes.

active: true,

screens: {
create_middle_org: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See first comment.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uniq screen for new field as 'create_middle', 'create_top' and etc.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I would use generic hooks then on ticket create form there appear wrong additional fields with the same hooks.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we need to change the priority of those so that the order matches the expectations.

}

.dropdown-menu {
margin-top: -3px;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these changes required? Looks like they might break other parts of the application.

active: true,

screens: {
create_middle_org: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See first comment.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uniq screen for new field as 'create_middle', 'create_top' and etc.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments above regarding generic hooks.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I would use generic hooks then on ticket create form there appear wrong additional fields with the same hooks.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we need to change the priority of those so that the order matches the expectations.

ids = []
if js_shadow_ids.length > 0
js_shadow_ids.each( -> ids.push $(this).val() )
unless ids.includes(data_value) || $(".js-shadow[name='organization_id']").val() == data_value

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't introduce hard coded attribute logic into generic files (organization_id ).


<div class="formset-inset">
<div class="ticket-form-middle horizontal two-columns"></div>
<div class="ticket-form-organization horizontal two-columns"></div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field should use the existing generic hooks (ticket-form-middle in this case) as the other attributes do.

<div class="ticket-form-middle horizontal two-columns"></div>
<div class="two-columns horizontal">
<div class="ticket-form-middle column"></div>
<div class="ticket-form-organization column"></div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here (generic hooks).

<% if @attribute.value: %>
<% for value in @attribute.value: %>
<div>
<span class='selected_organization' onclick="$(this).closest('div').remove()">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't introduce hard coded attribute logic into generic files (organization).

@@ -0,0 +1,4 @@
<div>
<span class='selected_organization' onclick="$(this).closest('div').remove()"><%= @title %></span>
<input class='searchableSelect-shadow form-control js-shadow-ids' name='organization_ids' value=<%= @data_value %>>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't introduce hard coded attribute logic into generic files (organization_ids).

.searchableSelect {
position: relative;

.selected_organization {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is required for? There should be no hard coded attribute logic in generic files (selected_organization).

active: true,

screens: {
create_middle_org: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments above regarding generic hooks.

end
end

describe '#check_defaults' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't test private/internal methods because they should be easy to change. Instead test functionality. You might want to use run_callbacks instead.

active: true,

screens: {
create_middle_org: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we need to change the priority of those so that the order matches the expectations.

active: true,

screens: {
create_middle_org: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we need to change the priority of those so that the order matches the expectations.

@input.trigger('change')
@shadowInput.val event.currentTarget.getAttribute('data-value')
@shadowInput.trigger('change')
$(".js-shadow-ids[value=#{event.currentTarget.getAttribute('data-value')}]").closest('div').remove()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this line for?

If we keep it:
It's not really expressive. We should add a comment for it and extend the tests to cover the functionality.

'.js-input': 'input'
'.js-shadow': 'shadowInput'
'.js-optionsList': 'optionsList'
'.items': 'itemList'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used in a descendant of the class so there is no need to have it in the base class.

ids = []
if js_shadow_ids.length > 0
js_shadow_ids.each( -> ids.push $(this).val() )
unless ids.includes(data_value) || $(".js-shadow[name='"+@attribute.name+"']").val() == data_value

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use unless statements.

<% if @attribute.value: %>
<% for value in @attribute.value: %>
<div>
<span class='selected_item' onclick="$(this).closest('div').remove()">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use inline JS. Move it to the controller that handles the template.

@@ -0,0 +1,4 @@
<div>
<span class='selected_item' onclick="$(this).closest('div').remove()"><%= @title %></span>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use inline JS. Move it to the controller that handles the template.

return true if !customer
return true if organization_id == customer.organization_id
self.organization_id = customer.organization_id
return true if (customer.organization_ids.include?(organization_id) || customer.organization_id? && customer.organization_id == organization_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split this line/if statment if possible. It carries way to much complexity.

if !owner_id
self.owner_id = 1
end
self.owner_id = 1 unless owner_id

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use unless.

end

if local_attributes['organization_id']
unless data[:Organization] || data[:Organization]&[local_attributes['organization_id']]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use unless.

<% for value in @attribute.value: %>
<div>
<span class='selected_item'>
<%- App.Organization.findNative(value).name %>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use specific code in generic components.

martini and others added 30 commits September 19, 2018 09:22
Fixed typo in 404: Ressource -> resource
…Error: undefined method `match' for nil:NilClass>"`.
…eferences[:delivery_status_message] has no utf8 charset.
…eptions::UnprocessableEntity: Invalid email>"`.
… Also added hiding of empty string attribute fields.
…nt race conditions (if callback comes later).
…if file is corrupt in filesystem and remove it in case).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.