Fixes #3302 - Representation of inactive customers and orgnizations.
This commit is contained in:
parent
8a42ec4f7b
commit
7f9c477cf4
25 changed files with 248 additions and 41 deletions
|
@ -14,10 +14,15 @@ class App.OrganizationProfile extends App.Controller
|
||||||
|
|
||||||
if App.Organization.exists(@organization_id)
|
if App.Organization.exists(@organization_id)
|
||||||
organization = App.Organization.find(@organization_id)
|
organization = App.Organization.find(@organization_id)
|
||||||
|
icon = organization.icon()
|
||||||
|
|
||||||
|
if organization.active is false
|
||||||
|
icon = 'inactive-' + icon
|
||||||
|
|
||||||
meta.head = organization.displayName()
|
meta.head = organization.displayName()
|
||||||
meta.title = organization.displayName()
|
meta.title = organization.displayName()
|
||||||
meta.iconClass = organization.icon()
|
meta.iconClass = icon
|
||||||
|
meta.active = organization.active
|
||||||
meta
|
meta
|
||||||
|
|
||||||
url: =>
|
url: =>
|
||||||
|
|
|
@ -15,10 +15,15 @@ class App.UserProfile extends App.Controller
|
||||||
|
|
||||||
if App.User.exists(@user_id)
|
if App.User.exists(@user_id)
|
||||||
user = App.User.find(@user_id)
|
user = App.User.find(@user_id)
|
||||||
|
icon = user.icon()
|
||||||
|
|
||||||
|
if user.active is false
|
||||||
|
icon = 'inactive-' + icon
|
||||||
|
|
||||||
meta.head = user.displayName()
|
meta.head = user.displayName()
|
||||||
meta.title = user.displayName()
|
meta.title = user.displayName()
|
||||||
meta.iconClass = user.icon()
|
meta.iconClass = icon
|
||||||
|
meta.active = user.active
|
||||||
meta
|
meta
|
||||||
|
|
||||||
url: =>
|
url: =>
|
||||||
|
|
|
@ -9,7 +9,6 @@ class App.GlobalSearch extends App.Controller
|
||||||
|
|
||||||
search: (params) =>
|
search: (params) =>
|
||||||
query = params.query
|
query = params.query
|
||||||
|
|
||||||
# use cache for search result
|
# use cache for search result
|
||||||
currentTime = new Date
|
currentTime = new Date
|
||||||
if @searchResultCache[query] && @searchResultCache[query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
if @searchResultCache[query] && @searchResultCache[query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||||
|
|
|
@ -20,7 +20,10 @@ class App.SingleObjectPopoverProvider extends App.PopoverProvider
|
||||||
|
|
||||||
buildTitleFor: (elem) ->
|
buildTitleFor: (elem) ->
|
||||||
object = @constructor.klass.find(@objectIdFor(elem))
|
object = @constructor.klass.find(@objectIdFor(elem))
|
||||||
App.Utils.htmlEscape(@displayTitleUsing(object))
|
title = App.Utils.htmlEscape(@displayTitleUsing(object))
|
||||||
|
if object.active is false
|
||||||
|
title = '<span class="is-inactive">' + title + '</span>'
|
||||||
|
title
|
||||||
|
|
||||||
buildContentFor: (elem) ->
|
buildContentFor: (elem) ->
|
||||||
id = @objectIdFor(elem)
|
id = @objectIdFor(elem)
|
||||||
|
|
|
@ -240,8 +240,9 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
@invisiblePart.text('')
|
@invisiblePart.text('')
|
||||||
|
|
||||||
selectItem: (event) ->
|
selectItem: (event) ->
|
||||||
return if !event.currentTarget.textContent
|
currentText = event.currentTarget.querySelector('span.searchableSelect-option-text').textContent.trim()
|
||||||
@input.val event.currentTarget.textContent.trim()
|
return if !currentText
|
||||||
|
@input.val currentText
|
||||||
@input.trigger('change')
|
@input.trigger('change')
|
||||||
@shadowInput.val event.currentTarget.getAttribute('data-value')
|
@shadowInput.val event.currentTarget.getAttribute('data-value')
|
||||||
@shadowInput.trigger('change')
|
@shadowInput.trigger('change')
|
||||||
|
@ -351,7 +352,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if @currentItem || !@attribute.unknown
|
if @currentItem || !@attribute.unknown
|
||||||
valueName = @currentItem.text().trim()
|
valueName = @currentItem.children('span.searchableSelect-option-text').text().trim()
|
||||||
value = @currentItem.attr('data-value')
|
value = @currentItem.attr('data-value')
|
||||||
@input.val valueName
|
@input.val valueName
|
||||||
@shadowInput.val value
|
@shadowInput.val value
|
||||||
|
@ -427,7 +428,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
@currentItem.addClass 'is-active'
|
@currentItem.addClass 'is-active'
|
||||||
|
|
||||||
if autocomplete
|
if autocomplete
|
||||||
@autocomplete @currentItem.attr('data-value'), @currentItem.text().trim()
|
@autocomplete @currentItem.attr('data-value'), @currentItem.children('span.searchableSelect-option-text').text().trim()
|
||||||
|
|
||||||
highlightItem: (event) =>
|
highlightItem: (event) =>
|
||||||
@unhighlightCurrentItem()
|
@unhighlightCurrentItem()
|
||||||
|
|
|
@ -1311,6 +1311,14 @@ class App.Utils
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
source: source
|
source: source
|
||||||
minLength: 2
|
minLength: 2
|
||||||
|
create: ->
|
||||||
|
$(@).data('ui-autocomplete')._renderItem = (ul, item) ->
|
||||||
|
option_html = App.Utils.htmlEscape(item.label)
|
||||||
|
additional_class = ''
|
||||||
|
if item.inactive
|
||||||
|
option_html += '<span style="float: right;">' + App.i18n.translateContent('inactive') + '</span>'
|
||||||
|
additional_class = 'is-inactive'
|
||||||
|
return $('<li>').addClass(additional_class).append(option_html).appendTo(ul)
|
||||||
},
|
},
|
||||||
).on('tokenfield:createtoken', (e) ->
|
).on('tokenfield:createtoken', (e) ->
|
||||||
if type is 'email' && !e.attrs.value.match(/@/) || e.attrs.value.match(/\s/)
|
if type is 'email' && !e.attrs.value.match(/@/) || e.attrs.value.match(/\s/)
|
||||||
|
|
|
@ -38,7 +38,6 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
# cache search result
|
# cache search result
|
||||||
@searchResultCache[cacheKey] = data
|
@searchResultCache[cacheKey] = data
|
||||||
|
|
||||||
@renderResponse(data, query)
|
@renderResponse(data, query)
|
||||||
|
|
||||||
# if delegate is given and provides getAjaxAttributes method, try to extend ajax call
|
# if delegate is given and provides getAjaxAttributes method, try to extend ajax call
|
||||||
|
@ -81,7 +80,6 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||||
category = undefined
|
category = undefined
|
||||||
if result.type is 'KnowledgeBase::Answer::Translation' && result.subtitle
|
if result.type is 'KnowledgeBase::Answer::Translation' && result.subtitle
|
||||||
category = result.subtitle
|
category = result.subtitle
|
||||||
|
|
||||||
if result
|
if result
|
||||||
{
|
{
|
||||||
category: category
|
category: category
|
||||||
|
@ -103,6 +101,7 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||||
{
|
{
|
||||||
name: name
|
name: name
|
||||||
value: object.id
|
value: object.id
|
||||||
|
inactive: object.active == false
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoader: =>
|
showLoader: =>
|
||||||
|
|
|
@ -41,11 +41,18 @@ Using **Organisations** you can **group** customers. This has among others two i
|
||||||
data
|
data
|
||||||
|
|
||||||
searchResultAttributes: ->
|
searchResultAttributes: ->
|
||||||
|
classList = ['organization', 'organization-popover' ]
|
||||||
|
icon = 'organization'
|
||||||
|
|
||||||
|
if @active is false
|
||||||
|
classList.push 'is-inactive'
|
||||||
|
icon = 'inactive-' + icon
|
||||||
|
|
||||||
display: "#{@displayName()}"
|
display: "#{@displayName()}"
|
||||||
id: @id
|
id: @id
|
||||||
class: 'organization organization-popover'
|
class: classList.join(' ')
|
||||||
url: @uiUrl()
|
url: @uiUrl()
|
||||||
icon: 'organization'
|
icon: icon
|
||||||
|
|
||||||
activityMessage: (item) ->
|
activityMessage: (item) ->
|
||||||
return if !item
|
return if !item
|
||||||
|
|
|
@ -156,11 +156,18 @@ class App.User extends App.Model
|
||||||
data
|
data
|
||||||
|
|
||||||
searchResultAttributes: ->
|
searchResultAttributes: ->
|
||||||
|
classList = ['user', 'user-popover']
|
||||||
|
icon = 'user'
|
||||||
|
|
||||||
|
if @active is false
|
||||||
|
classList.push 'is-inactive'
|
||||||
|
icon = 'inactive-' + icon
|
||||||
|
|
||||||
display: "#{@displayName()}"
|
display: "#{@displayName()}"
|
||||||
id: @id
|
id: @id
|
||||||
class: 'user user-popover'
|
class: classList.join(' ')
|
||||||
url: @uiUrl()
|
url: @uiUrl()
|
||||||
icon: 'user'
|
icon: icon
|
||||||
|
|
||||||
activityMessage: (item) ->
|
activityMessage: (item) ->
|
||||||
return if !item
|
return if !item
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<li class="recipientList-entry js-object" data-object-id="<%= @object.id %>">
|
<li class="recipientList-entry js-object<% if @object.active is false: %> is-inactive<% end %>" data-object-id="<%= @object.id %>">
|
||||||
<div class="recipientList-iconSpacer">
|
<div class="recipientList-iconSpacer">
|
||||||
<%- @Icon(@icon, 'recipientList-icon') %>
|
<%- @Icon(@icon, 'recipientList-icon') %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,10 +9,10 @@
|
||||||
<%= @object.displayName() %>
|
<%= @object.displayName() %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @object.organization: %>
|
<% if @object.organization: %>
|
||||||
<span class="recipientList-detail">- <%= @object.organization.displayName() %></span>
|
<span class="recipientList-detail<% if @object.organization.active is false: %> is-inactive<% end %>">- <%= @object.organization.displayName() %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if @object.active is false: %>
|
<% if @object.active is false: %>
|
||||||
<div class="recipientList-status"><%- @Ti('inactive') %></div>
|
<div class="recipientList-status"><%- @Ti('inactive') %></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<li class="recipientList-entry js-organization" data-organization-id="<%- @organization.id %>">
|
<li class="recipientList-entry js-organization<% if @organization.active is false: %> is-inactive<% end %>" data-organization-id="<%- @organization.id %>">
|
||||||
<div class="recipientList-iconSpacer">
|
<div class="recipientList-iconSpacer">
|
||||||
<% if @organization.active is false: %>
|
<% if @organization.active is false: %>
|
||||||
<%- @Icon('inactive-organization', 'recipientList-icon') %>
|
<%- @Icon('inactive-organization', 'recipientList-icon') %>
|
||||||
|
@ -14,4 +14,4 @@
|
||||||
<div class="recipientList-status"><%- @Ti('inactive') %></div>
|
<div class="recipientList-status"><%- @Ti('inactive') %></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%- @Icon('arrow-right', 'recipientList-arrow') %>
|
<%- @Icon('arrow-right', 'recipientList-arrow') %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
<li role="presentation" class="<%= @class %>" data-value="<%= @option.value %>" title="<%= @option.name %><% if @detail: %><%= @detail %><% end %>">
|
<li role="presentation" class="<%= @class %>" data-value="<%= @option.value %>" title="<%= @option.name %><% if @detail: %><%= @detail %><% end %>">
|
||||||
<% if @option.category: %><small><%= @option.category %></small><br><% end %>
|
<% if @option.category: %><small><%= @option.category %></small><br><% end %>
|
||||||
<span class="searchableSelect-option-text">
|
<span class="searchableSelect-option-text<% if @option.inactive is true: %> is-inactive<% end %>">
|
||||||
<%= @option.name %><% if @detail: %><span class="dropdown-detail"><%= @detail %></span><% end %>
|
<%= @option.name %><% if @detail: %><span class="dropdown-detail"><%= @detail %></span><% end %>
|
||||||
</span>
|
</span>
|
||||||
<% if @option.children: %>
|
<% if @option.children: %>
|
||||||
<%- @Icon('arrow-right', 'recipientList-arrow') %>
|
<%- @Icon('arrow-right', 'recipientList-arrow') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if @option.inactive is true: %>
|
||||||
|
<span>
|
||||||
|
<%- @Ti('inactive') %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -11,4 +11,4 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
<div class="profile-section vertical centered">
|
<div class="profile-section vertical centered">
|
||||||
<div class="align-right profile-action js-action"></div>
|
<div class="align-right profile-action js-action"></div>
|
||||||
<div class="profile-organizationIcon">
|
<div class="profile-organizationIcon">
|
||||||
<%- @Icon('organization') %>
|
<% if @organization.active is true: %>
|
||||||
|
<%- @Icon('organization') %>
|
||||||
|
<% else: %>
|
||||||
|
<%- @Icon('inactive-organization') %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="js-name"></h1>
|
<h1 class="js-name"></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="js-object-container"></div>
|
<div class="js-object-container"></div>
|
||||||
<div class="profile-section js-ticket-stats"></div>
|
<div class="profile-section js-ticket-stats"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="popover-block">
|
<div class="popover-block">
|
||||||
<label><%- @T('Members') %></label>
|
<label><%- @T('Members') %></label>
|
||||||
<% for user in @object.members: %>
|
<% for user in @object.members: %>
|
||||||
<div class="person"><%= user.displayName() %></div>
|
<div class="person<% if user.active is false: %> is-inactive<% end %>"><%= user.displayName() %></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<% if @object['organization']: %>
|
<% if @object['organization']: %>
|
||||||
<div class="user-organization"><a href="<%- @object.organization.uiUrl() %>"><%= @object.organization.displayName() %></a></div>
|
<div class="user-organization<% if @object.organization.active is false: %> is-inactive<% end %>"><a href="<%- @object.organization.uiUrl() %>"><%= @object.organization.displayName() %></a></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%- @V('popover/single_object_generic', object: @object, attributes: @attributes) %>
|
<%- @V('popover/single_object_generic', object: @object, attributes: @attributes) %>
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<div class="sidebar-block">
|
<div class="sidebar-block">
|
||||||
<div class="avatar organizationInfo-avatar size-50">
|
<div class="avatar organizationInfo-avatar size-50">
|
||||||
<a href="<%- @organization.uiUrl() %>">
|
<a href="<%- @organization.uiUrl() %>">
|
||||||
<%- @Icon('organization') %>
|
<% if @organization.active is true: %>
|
||||||
|
<%- @Icon('organization') %>
|
||||||
|
<% else: %>
|
||||||
|
<%- @Icon('inactive-organization') %>
|
||||||
|
<% end %>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h3 title="<%- @Ti( 'Name') %>"><%= @organization.displayName() %></h3>
|
<h3 title="<%- @Ti( 'Name') %>"><%= @organization.displayName() %></h3>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<%- @Icon(@item.meta.iconClass) %>
|
<%- @Icon(@item.meta.iconClass) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-tab-name u-textTruncate flex"><%= @item.meta.head %></div>
|
<div class="nav-tab-name u-textTruncate flex<% if @item.meta.active is false: %> is-inactive<% end %>"><%= @item.meta.head %></div>
|
||||||
<div class="nav-tab-close js-close" title="<%- @Ti('close') %>">
|
<div class="nav-tab-close js-close" title="<%- @Ti('close') %>">
|
||||||
<div class="nav-tab-close-inner">
|
<div class="nav-tab-close-inner">
|
||||||
<%- @Icon('diagonal-cross') %>
|
<%- @Icon('diagonal-cross') %>
|
||||||
|
|
|
@ -4285,6 +4285,12 @@ footer {
|
||||||
|
|
||||||
.navigation .nav-tab-name {
|
.navigation .nav-tab-name {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: .73;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tasks-navigation .nav-tab-icon .error {
|
.tasks-navigation .nav-tab-icon .error {
|
||||||
|
@ -4314,6 +4320,11 @@ footer {
|
||||||
.nav-tab.nav-tab--search {
|
.nav-tab.nav-tab--search {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
padding-top: 9px;
|
padding-top: 9px;
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: .73;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tab-icon {
|
.nav-tab-icon {
|
||||||
|
@ -5353,6 +5364,11 @@ footer {
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
padding: 21px 17px 4px;
|
padding: 21px 17px 4px;
|
||||||
|
|
||||||
|
.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-content {
|
.popover-content {
|
||||||
|
@ -5411,10 +5427,22 @@ footer {
|
||||||
color: #a1a4a7;
|
color: #a1a4a7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popover .person {
|
||||||
|
&.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.popover .user-organization {
|
.popover .user-organization {
|
||||||
@extend .u-textTruncate;
|
@extend .u-textTruncate;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
margin-top: -4px;
|
margin-top: -4px;
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-block {
|
.popover-block {
|
||||||
|
@ -5555,6 +5583,11 @@ footer {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-popover.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: .73;
|
||||||
|
}
|
||||||
|
|
||||||
.btn.js-newTicket {
|
.btn.js-newTicket {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -7996,6 +8029,11 @@ footer {
|
||||||
padding: 9px 15px;
|
padding: 9px 15px;
|
||||||
list-style-image: none;
|
list-style-image: none;
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: .73;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
||||||
}
|
}
|
||||||
|
@ -8566,6 +8604,13 @@ footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@extend .u-clickable;
|
@extend .u-clickable;
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
.recipientList-name {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: .73;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.recipientList-entry .recipientList-iconSpacer {
|
.recipientList-entry .recipientList-iconSpacer {
|
||||||
|
@ -8620,6 +8665,10 @@ footer {
|
||||||
|
|
||||||
.recipientList-detail {
|
.recipientList-detail {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
||||||
|
&.is-inactive > span {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.recipientList-icon.plus {
|
.recipientList-icon.plus {
|
||||||
|
@ -10354,6 +10403,11 @@ output {
|
||||||
& + .icon {
|
& + .icon {
|
||||||
@include bidi-style(margin-left, 10px, margin-right, 0);
|
@include bidi-style(margin-left, 10px, margin-right, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-inactive {
|
||||||
|
opacity: .73;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dropdown li {
|
&.dropdown li {
|
||||||
|
|
|
@ -282,7 +282,7 @@ class UsersController < ApplicationController
|
||||||
realname = "#{realname} <#{user.email}>"
|
realname = "#{realname} <#{user.email}>"
|
||||||
end
|
end
|
||||||
a = if params[:term]
|
a = if params[:term]
|
||||||
{ id: user.id, label: realname, value: user.email }
|
{ id: user.id, label: realname, value: user.email, inactive: !user.active }
|
||||||
else
|
else
|
||||||
{ id: user.id, label: realname, value: realname }
|
{ id: user.id, label: realname, value: realname }
|
||||||
end
|
end
|
||||||
|
|
|
@ -65,6 +65,18 @@ RSpec.describe 'User', type: :request do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let!(:customer_inactive) do
|
||||||
|
create(
|
||||||
|
:customer,
|
||||||
|
organization: organization,
|
||||||
|
login: 'rest-customer_inactive@example.com',
|
||||||
|
firstname: 'Rest',
|
||||||
|
lastname: 'CustomerInactive',
|
||||||
|
email: 'rest-customer_inactive@example.com',
|
||||||
|
active: false,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
configure_elasticsearch(rebuild: true)
|
configure_elasticsearch(rebuild: true)
|
||||||
end
|
end
|
||||||
|
@ -224,7 +236,7 @@ RSpec.describe 'User', type: :request do
|
||||||
get '/api/v1/users/me', params: {}, as: :json
|
get '/api/v1/users/me', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect('rest-admin@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-admin@example.com')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/users', params: {}, as: :json
|
get '/api/v1/users', params: {}, as: :json
|
||||||
|
@ -243,13 +255,13 @@ RSpec.describe 'User', type: :request do
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect(Hash).to eq(json_response.class)
|
expect(Hash).to eq(json_response.class)
|
||||||
expect('rest-agent@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-agent@example.com')
|
||||||
|
|
||||||
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect(Hash).to eq(json_response.class)
|
expect(Hash).to eq(json_response.class)
|
||||||
expect('rest-customer1@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-customer1@example.com')
|
||||||
|
|
||||||
# create user with admin role
|
# create user with admin role
|
||||||
role = Role.lookup(name: 'Admin')
|
role = Role.lookup(name: 'Admin')
|
||||||
|
@ -332,7 +344,7 @@ RSpec.describe 'User', type: :request do
|
||||||
get '/api/v1/users/me', params: {}, as: :json
|
get '/api/v1/users/me', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect('rest-agent@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-agent@example.com')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/users', params: {}, as: :json
|
get '/api/v1/users', params: {}, as: :json
|
||||||
|
@ -442,9 +454,15 @@ RSpec.describe 'User', type: :request do
|
||||||
expect(json_response[0]['id']).to eq(json_response1['id'])
|
expect(json_response[0]['id']).to eq(json_response1['id'])
|
||||||
expect(json_response[0]['label']).to eq("Customer#{firstname} Customer Last <new_customer_by_agent@example.com>")
|
expect(json_response[0]['label']).to eq("Customer#{firstname} Customer Last <new_customer_by_agent@example.com>")
|
||||||
expect(json_response[0]['value']).to eq('new_customer_by_agent@example.com')
|
expect(json_response[0]['value']).to eq('new_customer_by_agent@example.com')
|
||||||
|
expect(json_response[0]['inactive']).to eq(false)
|
||||||
expect(json_response[0]['role_ids']).to be_falsey
|
expect(json_response[0]['role_ids']).to be_falsey
|
||||||
expect(json_response[0]['roles']).to be_falsey
|
expect(json_response[0]['roles']).to be_falsey
|
||||||
|
|
||||||
|
get "/api/v1/users/search?term=#{CGI.escape('CustomerInactive')}", params: {}, as: :json
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(json_response).to be_a_kind_of(Array)
|
||||||
|
expect(json_response[0]['inactive']).to eq(true)
|
||||||
|
|
||||||
# Regression test for issue #2539 - search pagination broken in users_controller.rb
|
# Regression test for issue #2539 - search pagination broken in users_controller.rb
|
||||||
# Get the total number of users N, then search with one result per page, so there should N pages with one result each
|
# Get the total number of users N, then search with one result per page, so there should N pages with one result each
|
||||||
get '/api/v1/users/search', params: { query: '*' }, as: :json
|
get '/api/v1/users/search', params: { query: '*' }, as: :json
|
||||||
|
@ -494,19 +512,19 @@ RSpec.describe 'User', type: :request do
|
||||||
get '/api/v1/users/me', params: {}, as: :json
|
get '/api/v1/users/me', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect('rest-customer1@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-customer1@example.com')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/users', params: {}, as: :json
|
get '/api/v1/users', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(Array).to eq(json_response.class)
|
expect(Array).to eq(json_response.class)
|
||||||
expect(1).to eq(json_response.length)
|
expect(json_response.length).to eq(1)
|
||||||
|
|
||||||
# show/:id
|
# show/:id
|
||||||
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(Hash).to eq(json_response.class)
|
expect(Hash).to eq(json_response.class)
|
||||||
expect('rest-customer1@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-customer1@example.com')
|
||||||
|
|
||||||
get "/api/v1/users/#{customer2.id}", params: {}, as: :json
|
get "/api/v1/users/#{customer2.id}", params: {}, as: :json
|
||||||
expect(response).to have_http_status(:forbidden)
|
expect(response).to have_http_status(:forbidden)
|
||||||
|
@ -536,19 +554,19 @@ RSpec.describe 'User', type: :request do
|
||||||
get '/api/v1/users/me', params: {}, as: :json
|
get '/api/v1/users/me', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response).to be_truthy
|
expect(json_response).to be_truthy
|
||||||
expect('rest-customer2@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-customer2@example.com')
|
||||||
|
|
||||||
# index
|
# index
|
||||||
get '/api/v1/users', params: {}, as: :json
|
get '/api/v1/users', params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(Array).to eq(json_response.class)
|
expect(Array).to eq(json_response.class)
|
||||||
expect(1).to eq(json_response.length)
|
expect(json_response.length).to eq(1)
|
||||||
|
|
||||||
# show/:id
|
# show/:id
|
||||||
get "/api/v1/users/#{customer2.id}", params: {}, as: :json
|
get "/api/v1/users/#{customer2.id}", params: {}, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(Hash).to eq(json_response.class)
|
expect(Hash).to eq(json_response.class)
|
||||||
expect('rest-customer2@example.com').to eq(json_response['email'])
|
expect(json_response['email']).to eq('rest-customer2@example.com')
|
||||||
|
|
||||||
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
get "/api/v1/users/#{customer.id}", params: {}, as: :json
|
||||||
expect(response).to have_http_status(:forbidden)
|
expect(response).to have_http_status(:forbidden)
|
||||||
|
|
|
@ -69,8 +69,25 @@ RSpec.describe 'Manage > Users', type: :system do
|
||||||
|
|
||||||
expect(page).to have_css('table.user-list td', text: 'NewTestUserFirstName')
|
expect(page).to have_css('table.user-list td', text: 'NewTestUserFirstName')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'select an Organization' do
|
||||||
|
before do
|
||||||
|
create(:organization, name: 'Example Inc.', active: true)
|
||||||
|
create(:organization, name: 'Inactive Inc.', active: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check for inactive Organizations in Organization selection' do
|
||||||
|
visit '#manage/users'
|
||||||
|
|
||||||
|
within(:active_content) do
|
||||||
|
find('[data-type=new]').click
|
||||||
|
|
||||||
|
find('[name=organization_id] ~ .searchableSelect-main').fill_in with: '**'
|
||||||
|
expect(page).to have_css('ul.js-optionsList > li.js-option', minimum: 2)
|
||||||
|
expect(page).to have_css('ul.js-optionsList > li.js-option .is-inactive', count: 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,4 +16,37 @@ RSpec.describe 'Search', type: :system, searchindex: true do
|
||||||
expect(page).to have_text '"Welcome"'
|
expect(page).to have_text '"Welcome"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'inactive user and organizations' do
|
||||||
|
before do
|
||||||
|
create(:organization, name: 'Example Inc.', active: true)
|
||||||
|
create(:organization, name: 'Example Inactive Inc.', active: false)
|
||||||
|
create(:customer, firstname: 'Firstname', lastname: 'Active', active: true)
|
||||||
|
create(:customer, firstname: 'Firstname', lastname: 'Inactive', active: false)
|
||||||
|
|
||||||
|
configure_elasticsearch(rebuild: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check that inactive organizations are marked correctly' do
|
||||||
|
fill_in id: 'global-search', with: '"Example"'
|
||||||
|
|
||||||
|
expect(page).to have_css('.nav-tab--search.organization', minimum: 2)
|
||||||
|
expect(page).to have_css('.nav-tab--search.organization.is-inactive', count: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check that inactive users are marked correctly' do
|
||||||
|
fill_in id: 'global-search', with: '"Firstname"'
|
||||||
|
|
||||||
|
expect(page).to have_css('.nav-tab--search.user', minimum: 2)
|
||||||
|
expect(page).to have_css('.nav-tab--search.user.is-inactive', count: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check that inactive users are also marked in the popover for the quick search result' do
|
||||||
|
fill_in id: 'global-search', with: '"Firstname"'
|
||||||
|
|
||||||
|
popover_on_hover(find('.nav-tab--search.user.is-inactive'))
|
||||||
|
|
||||||
|
expect(page).to have_css('.popover-title .is-inactive', count: 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -456,4 +456,21 @@ RSpec.describe 'Ticket Create', type: :system do
|
||||||
expect(page).to have_no_selector(:task_with, task_key)
|
expect(page).to have_no_selector(:task_with, task_key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'customer selection to check the field search' do
|
||||||
|
before do
|
||||||
|
create(:customer, active: true)
|
||||||
|
create(:customer, active: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check for inactive customer in customer/organization selection' do
|
||||||
|
visit 'ticket/create'
|
||||||
|
|
||||||
|
within(:active_content) do
|
||||||
|
find('[name=customer_id] ~ .user-select.token-input').fill_in with: '**'
|
||||||
|
expect(page).to have_css('ul.recipientList > li.recipientList-entry', minimum: 2)
|
||||||
|
expect(page).to have_css('ul.recipientList > li.recipientList-entry.is-inactive', count: 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -208,10 +208,14 @@ RSpec.describe 'Ticket zoom', type: :system do
|
||||||
|
|
||||||
context 'to inbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
|
context 'to inbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
|
||||||
let(:agent) { create(:agent, groups: [Group.first]) }
|
let(:agent) { create(:agent, groups: [Group.first]) }
|
||||||
let(:customer) { create(:agent) }
|
let(:customer) { create(:customer) }
|
||||||
let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
|
let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
|
||||||
let!(:article) { create(:ticket_article, :inbound_phone, ticket: ticket) }
|
let!(:article) { create(:ticket_article, :inbound_phone, ticket: ticket) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:customer, active: false)
|
||||||
|
end
|
||||||
|
|
||||||
it 'goes to customer email' do
|
it 'goes to customer email' do
|
||||||
visit "ticket/zoom/#{ticket.id}"
|
visit "ticket/zoom/#{ticket.id}"
|
||||||
|
|
||||||
|
@ -225,11 +229,28 @@ RSpec.describe 'Ticket zoom', type: :system do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'check active and inactive user in TO-field' do
|
||||||
|
visit "ticket/zoom/#{ticket.id}"
|
||||||
|
|
||||||
|
within :active_ticket_article, article do
|
||||||
|
click '.js-ArticleAction[data-type=emailReply]'
|
||||||
|
end
|
||||||
|
|
||||||
|
within :active_content do
|
||||||
|
within '.article-new' do
|
||||||
|
find('[name=to] ~ .ui-autocomplete-input').fill_in with: '**'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_css('ul.ui-autocomplete > li.ui-menu-item', minimum: 2)
|
||||||
|
expect(page).to have_css('ul.ui-autocomplete > li.ui-menu-item.is-inactive', count: 1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'to outbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
|
context 'to outbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
|
||||||
let(:agent) { create(:agent, groups: [Group.first]) }
|
let(:agent) { create(:agent, groups: [Group.first]) }
|
||||||
let(:customer) { create(:agent) }
|
let(:customer) { create(:customer) }
|
||||||
let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
|
let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
|
||||||
let!(:article) { create(:ticket_article, :outbound_phone, ticket: ticket) }
|
let!(:article) { create(:ticket_article, :outbound_phone, ticket: ticket) }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue