Skip to content

Commit

Permalink
🦋 Alerts page (#3636)
Browse files Browse the repository at this point in the history
🦋 updates alerts index page
  • Loading branch information
josemigallas authored Nov 27, 2023
1 parent 735de46 commit 928f296
Show file tree
Hide file tree
Showing 31 changed files with 420 additions and 387 deletions.
13 changes: 0 additions & 13 deletions app/assets/stylesheets/provider/_messages.scss

This file was deleted.

20 changes: 14 additions & 6 deletions app/assets/stylesheets/provider/_tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,18 @@ td.StatsMethodsTable-name {
word-break: break-word;
}

// HACK: old tables that has a search form element get styled as a table-cell and it breaks the
// total colspan. This rule makes sure the form is never visible and instead a "td" element fills
// the colspan. Apparently this does not affect Chrome and Firefox.
// TODO: this won't be necessary once all legacy tables have been upgraded with Patternfly.
.pf-c-table form.search {
display: none;
.pf-c-table {
// HACK: old tables that has a search form element get styled as a table-cell and it breaks the
// total colspan. This rule makes sure the form is never visible and instead a "td" element fills
// the colspan. Apparently this does not affect Chrome and Firefox.
// TODO: this won't be necessary once all legacy tables have been upgraded with Patternfly.
form.search {
display: none;
}

tr.unread {
td[data-label] a {
font-weight: $font-weight-bold;
}
}
}
1 change: 0 additions & 1 deletion app/assets/stylesheets/provider/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
@import 'provider/links';
@import 'provider/footer';
@import 'provider/forum';
@import 'provider/messages';
@import 'provider/sidetabs';
@import 'provider/services';
@import 'provider/plans';
Expand Down
31 changes: 13 additions & 18 deletions app/controllers/api/alerts_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

class Api::AlertsController < FrontendController
activate_menu :serviceadmin, :monitoring, :alerts

Expand All @@ -6,20 +8,17 @@ class Api::AlertsController < FrontendController

before_action :find_service

helper_method :presenter

attr_reader :presenter

def index
activate_menu :audience, :applications, :alerts unless @service
@search = ThreeScale::Search.new(search_params)
@account_search = ThreeScale::Search.new(@search.account)

if @account_search.present?
# threescale/search would remove all blank entries (including empty array)
# so to prevent that, pass -1 as id (which never exists) to return no results
@search.account_id = current_account.buyers.scope_search(@account_search).pluck(:id).presence || -1
end

@alerts = collection
.order_by(params[:sort], params[:direction])
.scope_search(@search).paginate(page: params[:page])
@presenter = Api::AlertsIndexPresenter.new(raw_alerts: collection,
params: params,
service: @service,
current_account: current_account)
end

def all_read
Expand Down Expand Up @@ -67,11 +66,6 @@ def destroy

private

def search_params
# default to account_id and cinstance_id params if no search hash is passed
params.fetch(:search) { params.slice(:account_id, :cinstance_id) }
end

def find_service
if params[:service_id].present?
@service = current_user.accessible_services.find(params[:service_id])
Expand All @@ -82,8 +76,9 @@ def find_service

def collection
current_account.buyer_alerts
.by_service(@service).not_deleted
.with_associations
.by_service(@service)
.not_deleted
.with_associations
end

def resource
Expand Down
7 changes: 3 additions & 4 deletions app/javascript/src/Common/components/TableToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import type { Props as SearchInputProps } from 'Common/components/ToolbarSearch'
import type { BulkAction } from 'Common/components/BulkActionsDropdown'
import type { FunctionComponent } from 'react'

interface ToolbarAction extends ButtonProps {
label: string;
type ToolbarAction = Pick<ButtonProps, 'data' | 'href' | 'label' | 'variant'> & {
isPersistent?: boolean;
}

Expand Down Expand Up @@ -135,8 +134,8 @@ const TableToolbar: FunctionComponent<Props> = ({
<Dropdown
isFlipEnabled
isPlain
dropdownItems={overflow.map(({ label, href, isShared }) => (
<OverflowMenuDropdownItem key={label} component="a" href={href} isShared={isShared}>
dropdownItems={overflow.map(({ label, ...btnProps }) => (
<OverflowMenuDropdownItem key={label} component="a" {...btnProps}>
{label}
</OverflowMenuDropdownItem>
))}
Expand Down
91 changes: 91 additions & 0 deletions app/presenters/api/alerts_index_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

class Api::AlertsIndexPresenter
include ::Draper::ViewHelpers

def initialize(raw_alerts:, params:, service:, current_account:)
@raw_alerts = raw_alerts
@service = service

@pagination_params = { page: params[:page] || 1, per_page: params[:per_page] || 20 }
@sorting_params = [params[:sort], params[:direction]]
@search = new_search(params, current_account)
end

attr_reader :raw_alerts, :service, :pagination_params, :sorting_params, :search

delegate :total_entries, to: :alerts

def alerts
@alerts ||= raw_alerts.order_by(*sorting_params)
.scope_search(search)
.paginate(pagination_params)
end

def empty_state?
raw_alerts.empty?
end

def empty_search?
alerts.empty?
end

def toolbar_props # rubocop:disable Metrics/MethodLength
{
totalEntries: total_entries,
actions: [],
overflow: [{
href: h.polymorphic_path([:all_read, :admin, service, :alerts]),
label: t('.read_all_button.label'),
variant: :primary,
'data-method': :put,
'data-confirm': t('.read_all_button.confirm'),
isShared: true
}, {
href: h.polymorphic_path([:purge, :admin, service, :alerts]),
label: t('.purge_button.label'),
variant: :danger,
'data-method': :delete,
'data-confirm': t('.purge_button.confirm'),
isShared: true
}],
search: {
name: 'search[account][query]',
placeholder: t('.search_placeholder')
}
}
end

def page_title
service ? t('.page_title.service') : t('.page_title.all')
end

def link_to_account_for_alert(alert)
if (account = alert.cinstance.try(:user_account))
h.link_to account.org_name, h.admin_buyers_account_path(account)
else
h.tag.span('missing')
end
end

private

def new_search(params, current_account)
# default to account_id and cinstance_id params if no search hash is passed
search_params = params.fetch(:search) { params.slice(:account_id, :cinstance_id) }

search = ThreeScale::Search.new(search_params)

if (account = search.account.presence)
# HACK: threescale/search would remove all blank entries including empty array. To prevent
# that, pass -1 as id (which never exists) to return no results.
search.account_id = current_account.buyers.scope_search(account).pluck(:id).presence || -1
end

search
end

def t(string, opts = {})
I18n.t(string, opts.merge(scope: 'api.alerts.index'))
end
end
3 changes: 0 additions & 3 deletions app/views/api/alerts/all_read.js.erb

This file was deleted.

77 changes: 0 additions & 77 deletions app/views/api/alerts/index.html.erb

This file was deleted.

59 changes: 59 additions & 0 deletions app/views/api/alerts/index.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
- content_for :page_header_title, presenter.page_title

- if presenter.empty_state?
tr role="row"
td role="cell" colspan="100"
div class="pf-c-empty-state"
div class="pf-c-empty-state__content"
i class="fas fa-check-circle pf-c-empty-state__icon" aria-hidden="true"
h1 class="pf-c-title pf-m-lg"
= t('.empty_state.title')
div class="pf-c-empty-state__body"
= t('.empty_state.body')

- else
- content_for :javascripts do
= javascript_packs_with_chunks_tag 'table_toolbar'

table class="pf-c-table pf-m-grid-lg" role="grid" aria-label="Alerts table" data-toolbar-props=presenter.toolbar_props.to_json
thead
tr role="row"
th role="columnheader" scope="col" Account
th role="columnheader" scope="col" Application
th role="columnheader" scope="col" Message
= th_sortable 'level', 'Level'
= th_sortable 'timestamp', 'Time (UTC)'
td

tbody role="rowgroup"
- if presenter.empty_search?
= render partial: 'shared/empty_search_state', locals: { scope: 'api.alerts.index' }
- else
- confirm_delete = t('.delete_alert_confirmation')
- presenter.alerts.each do |alert|
- cinstance = alert.cinstance
tr id=dom_id(alert) role="row" class=alert.state
td role="cell" data-label="Account"
= presenter.link_to_account_for_alert(alert)
td role="cell" data-label="Application"
= link_to cinstance.name, provider_admin_application_path(cinstance)
td role="cell" data-label="Message"
= h alert.message
td role="cell" data-label="Level" class="utilization"
= colorize_utilization(alert.level)
td role="cell" data-label="Time (UTC)"
= l alert.timestamp
td role="cell" class="pf-c-table__action"
div class="pf-c-overflow-menu"
div class="pf-c-overflow-menu__content"
div class="pf-c-overflow-menu__group pf-m-button-group"
div class="pf-c-overflow-menu__item"
= delete_button_for polymorphic_path([:admin, @service, alert]), method: :delete,
data: { confirm: confirm_delete }
div class="pf-c-overflow-menu__item"
- if alert.unread?
= action_link_to :read, polymorphic_path([:read, :admin, @service, alert]),
remote: true,
method: :put,
data: { disable_with: 'Read' },
title: 'Mark as read'
3 changes: 0 additions & 3 deletions app/views/api/alerts/purge.js.erb

This file was deleted.

9 changes: 6 additions & 3 deletions app/views/api/alerts/read.js.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
$(function(){
$("<%= '#' << dom_id(@alert) %>").attr('data-state','read').find('.mark-as-read').fadeOut();
});
<%# frozen_string_literal: true %>

const row = document.getElementById("<%= dom_id(@alert) %>")
row.classList.replace('unread', 'read')
row.querySelector('td.pf-c-table__action .pf-c-overflow-menu__item:last-of-type')
.remove()
2 changes: 1 addition & 1 deletion app/views/buyers/accounts/index.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
tbody role="rowgroup"
- if presenter.empty_search_state?
= render partial: 'empty_state', locals: { colspan: can?(:see, :multiple_applications) ? 9 : 8,
body: t('.empty_search.body') }
body: t('.empty_search.body') }
- else
- accounts.each do |account|
tr role="row" id=dom_id(account)
Expand Down
Loading

0 comments on commit 928f296

Please sign in to comment.