Pre-PR Discussion: Configurable user name order – "Lastname Firstname" (fully implemented)

Hi everyone,

I was already annoyed by the “Firstname Lastname” order, so I finally implemented it myself.

There have been several requests for this in the past:

Important: Nothing changes for anyone who leaves the new option at the default (false).

I only had to touch 4 files and made sure the change is UI-only (email recipient lines always stay “Firstname Lastname” – this is intentional and follows common email conventions).

1. New setting (db/seeds/settings.rb)

New option as string gives us the opportunity in the future to expand it for a format like “Smith, John”.

#Insert after the block pretty_date_format
Setting.create_or_update(
  title:       __('User Name Format'),
  name:        'ui_user_name_format',
  area:        'System::Branding',
  description: __('Defines how user names are displayed in dropdowns, overviews and selection fields.'),
  options:     {
    form: [
      {
        display: '',
        null:    false,
        name:    'ui_user_name_format',
        tag:     'select',
        options: {
          first_last: __('John Smith'),
          last_first: __('Smith John'),
        },
		translate: true,
      },
    ],
  },
  preferences: {
    render:     true,
    prio:       11,
    permission: ['admin.branding'],
  },
  state:        'first_last',
  frontend:     true
)

2. app/models/user.rb

Used in the new desktop view and for formatting of the e-mail recipient. However, the usual format “First Name Last Name” is retained when sending emails.

Change this line:

#Old code
    name = "#{firstname} #{lastname}".strip

to this:

#New code
    format = Setting.get('ui_user_name_format')
	
    if recipient_line
      # Email sending: always first name last name (regardless of setting)
      name = "#{firstname} #{lastname}".strip
    elsif format == 'last_first'
      # UI display: Lastname Firstname
      name = "#{lastname} #{firstname}".strip
    else
	  # UI display: Firstname Lastname
      name = "#{firstname} #{lastname}".strip
    end

3. app/assets/javascripts/app/models/user.coffee

This code is used in the current desktop view. I replaced the following block, which is primarily for the dropdown menu and general name displays…

#Old code
  displayName: ->
    if !_.isEmpty(@firstname)
      name = @firstname
    if !_.isEmpty(@lastname)
      if _.isEmpty(name)
        name = ''
      else
        name = name + ' '
      name = name + @lastname
    return name if !_.isEmpty(name)
    if @email
      return @email
    if @phone
      return @phone
    if @mobile
      return @mobile
    if @login
      return @login
    return '-'

to this:

#New code
  displayName: ->
    format = App.Config.get('ui_user_name_format') or 'first_last'
    parts =
      if format == 'last_first'
        [@lastname, @firstname]
      else
        [@firstname, @lastname]
    name = _.compact(parts).join(' ')
    return name   if name
    return @email if @email
    return @phone if @phone
    return @mobile if @mobile
    return @login if @login
    '-'

The next section is primarily used for overviews. I replaced the following block…

#Old code
  displayNameLong: ->
    if !_.isEmpty(@firstname)
      name = @firstname
    if !_.isEmpty(@lastname)
      if _.isEmpty(name)
        name = ''
      else
        name = name + ' '
      name = name + @lastname
    if !_.isEmpty(name)
      if !_.isEmpty(@organization)
        if typeof @organization is 'object'
          name = "#{name} (#{@organization.name})"
        else
          name = "#{name} (#{@organization})"
      else if !_.isEmpty(@department)
        name = "#{name} (#{@department})"
    return name if !_.isEmpty(name)
    if @email
      return @email
    if @phone
      return @phone
    if @mobile
      return @mobile
    if @login
      return @login
    return '-'

with this:

#New code
  displayNameLong: ->
    format = App.Config.get('ui_user_name_format') or 'first_last'
    parts =
      if format == 'last_first'
        [@lastname, @firstname]
      else
        [@firstname, @lastname]
    name = _.compact(parts).join(' ')
    if name
      if @organization
        org =
          if typeof @organization is 'object'
            @organization.name
          else
            @organization
        name = "#{name} (#{org})"
      else if @department
        name = "#{name} (#{@department})"
      return name
    return @email  if @email
    return @phone  if @phone
    return @mobile if @mobile
    return @login  if @login
    '-'

4. app/assets/javascripts/app/controllers/_ui_element/_application_action.coffee

This is for the list of e-mail recipients, a.e., in triggers. Here I changed it to use the function instead, which also resolves the problem of displaying “null” if firstname or lastname is null.

After the change:

Changed this line

#Old code
      columnSelectRecipientUserOptions.push({ value: key, name: "#{user.firstname} #{user.lastname}", selected: selected })

to this

#New code
      u = if user instanceof App.User then user else new App.User(user)
      columnSelectRecipientUserOptions.push
        value: key
        name: u.displayName()
        selected: selected
    columnSelectRecipientUserOptions = _.sortBy(columnSelectRecipientUserOptions, 'name')

After making these changes, I executed the following commands:

sudo rm -rf /opt/zammad/tmp/cache/webpacker
sudo zammad run rake assets:precompile
sudo systemctl restart zammad
sudo zammad run rake db:seed

Go to Settings, Settings, Branding and change the setting to “Smith John”:

Now the owner dropdown looks like this:

Question to the team:
Is the approach OK (one setting + explicit email exception in fullname)? Or would you prefer a second setting for email recipient lines?
Would love to hear your thoughts before I open a PR.

PS for the devs of the new desktop view: In the current desktop view, the “Organization” or “Department” is displayed next to the name in the overviews. This is not yet present in the new desktop view.

1 Like

Can’t speak for the team, but I like this elegant solution with a single setting to just swap the two names with each other consistently. Not sure how well this approach works for instances that cover several different areas and locales though.

PS for the devs of the new desktop view: In the current desktop view, the “Organization” or “Department” is displayed next to the name in the overviews. This is not yet present in the new desktop view.

This output was dropped in the new desktop view, because in this case you can activate the organization column.

In my tests I found out, when I create a ticket as agent and choose “E-Mail” in the interface, when I choose the customer “John Smith j.smith@company.com”, in the mails from-header is written “Smith John j.smith@company.com”.

When I add an mail-article and choose the same customer, there’s only the mail-address in the from-header.

I will figure this out and will create a pull request after.