diff --git a/app/javascript/dashboard/api/slaReports.js b/app/javascript/dashboard/api/slaReports.js new file mode 100644 index 000000000..4dd72ff05 --- /dev/null +++ b/app/javascript/dashboard/api/slaReports.js @@ -0,0 +1,73 @@ +/* global axios */ +import ApiClient from './ApiClient'; + +class SLAReportsAPI extends ApiClient { + constructor() { + super('applied_slas', { accountScoped: true }); + } + + get({ + from, + to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + page, + } = {}) { + return axios.get(this.url, { + params: { + since: from, + until: to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + page, + }, + }); + } + + download({ + from, + to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + } = {}) { + return axios.get(`${this.url}/download`, { + params: { + since: from, + until: to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + }, + }); + } + + getMetrics({ + from, + to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + } = {}) { + // no ratings for metrics + return axios.get(`${this.url}/metrics`, { + params: { + since: from, + until: to, + assigned_agent_id, + inbox_id, + team_id, + sla_policy_id, + }, + }); + } +} + +export default new SLAReportsAPI(); diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/SLAReports.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/SLAReports.vue index f5dce84ed..d64000986 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/SLAReports.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/SLAReports.vue @@ -1,10 +1,20 @@ diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLAReportItem.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLAReportItem.vue new file mode 100644 index 000000000..4bb9ef5bf --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLAReportItem.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLATable.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLATable.vue index 8fb5df3dd..d2485da5d 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLATable.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/SLA/SLATable.vue @@ -1,60 +1,92 @@ - diff --git a/app/javascript/dashboard/store/index.js b/app/javascript/dashboard/store/index.js index 91b84ddd1..2f8a9c1e5 100755 --- a/app/javascript/dashboard/store/index.js +++ b/app/javascript/dashboard/store/index.js @@ -44,6 +44,7 @@ import teams from './modules/teams'; import userNotificationSettings from './modules/userNotificationSettings'; import webhooks from './modules/webhooks'; import draftMessages from './modules/draftMessages'; +import SLAReports from './modules/SLAReports'; import LogRocket from 'logrocket'; import createPlugin from 'logrocket-vuex'; @@ -111,6 +112,7 @@ export default new Vuex.Store({ webhooks, draftMessages, sla, + slaReports: SLAReports, }, plugins, }); diff --git a/app/javascript/dashboard/store/modules/SLAReports.js b/app/javascript/dashboard/store/modules/SLAReports.js new file mode 100644 index 000000000..750634302 --- /dev/null +++ b/app/javascript/dashboard/store/modules/SLAReports.js @@ -0,0 +1,99 @@ +import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers'; +import types from '../mutation-types'; +import SLAReportsAPI from '../../api/slaReports'; + +export const state = { + records: [], + metrics: { + numberOfSLABreaches: 0, + hitRate: '0%', + }, + uiFlags: { + isFetching: false, + isFetchingMetrics: false, + }, + meta: { + count: 0, + currentPage: 1, + }, +}; + +export const getters = { + getAll(_state) { + return _state.records; + }, + getMeta(_state) { + return _state.meta; + }, + getMetrics(_state) { + return _state.metrics; + }, + getUIFlags(_state) { + return _state.uiFlags; + }, +}; + +export const actions = { + get: async function getResponses({ commit }, params) { + commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetching: true }); + try { + const response = await SLAReportsAPI.get(params); + const { payload, meta } = response.data; + + commit(types.SET_SLA_REPORTS, payload); + commit(types.SET_SLA_REPORTS_META, meta); + } catch (error) { + // Ignore error + } finally { + commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetching: false }); + } + }, + getMetrics: async function getMetrics({ commit }, params) { + commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: true }); + try { + const response = await SLAReportsAPI.getMetrics(params); + commit(types.SET_SLA_REPORTS_METRICS, response.data); + } catch (error) { + // Ignore error + } finally { + commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: false }); + } + }, +}; + +export const mutations = { + [types.SET_SLA_REPORTS_UI_FLAG](_state, data) { + _state.uiFlags = { + ..._state.uiFlags, + ...data, + }; + }, + + [types.SET_SLA_REPORTS]: MutationHelpers.set, + [types.SET_SLA_REPORTS_METRICS]( + _state, + { number_of_sla_breaches: numberOfSLABreaches, hit_rate: hitRate } + ) { + _state.metrics = { + numberOfSLABreaches, + hitRate, + }; + }, + [types.SET_SLA_REPORTS_META]( + _state, + { total_applied_slas: totalAppliedSLAs, current_page: currentPage } + ) { + _state.meta = { + count: totalAppliedSLAs, + currentPage, + }; + }, +}; + +export default { + namespaced: true, + state, + getters, + actions, + mutations, +}; diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js index 6f7d36cf7..c21fb44e2 100644 --- a/app/javascript/dashboard/store/mutation-types.js +++ b/app/javascript/dashboard/store/mutation-types.js @@ -309,4 +309,10 @@ export default { ADD_SLA: 'ADD_SLA', EDIT_SLA: 'EDIT_SLA', DELETE_SLA: 'DELETE_SLA', + + // SLA Reports + SET_SLA_REPORTS_UI_FLAG: 'SET_SLA_REPORTS_UI_FLAG', + SET_SLA_REPORTS: 'SET_SLA_REPORTS', + SET_SLA_REPORTS_METRICS: 'SET_SLA_REPORTS_METRICS', + SET_SLA_REPORTS_META: 'SET_SLA_REPORTS_META', }; diff --git a/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb b/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb index 4ec27bbbb..e9825bff6 100644 --- a/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb @@ -6,12 +6,14 @@ class Api::V1::Accounts::AppliedSlasController < Api::V1::Accounts::EnterpriseAc before_action :set_applied_slas, only: [:index, :metrics, :download] before_action :set_current_page, only: [:index] - before_action :paginate_slas, only: [:index] before_action :check_admin_authorization? sort_on :created_at, type: :datetime - def index; end + def index + @total_applied_slas = total_applied_slas + @applied_slas = @applied_slas.page(@current_page).per(RESULTS_PER_PAGE) + end def metrics @total_applied_slas = total_applied_slas @@ -52,7 +54,7 @@ class Api::V1::Accounts::AppliedSlasController < Api::V1::Accounts::EnterpriseAc end def set_applied_slas - initial_query = Current.account.applied_slas.includes(:conversation) + initial_query = Current.account.applied_slas.includes(:conversation).includes(:sla_policy) @applied_slas = initial_query .filter_by_date_range(range) .filter_by_inbox_id(params[:inbox_id]) @@ -62,10 +64,6 @@ class Api::V1::Accounts::AppliedSlasController < Api::V1::Accounts::EnterpriseAc .filter_by_assigned_agent_id(params[:assigned_agent_id]) end - def paginate_slas - @applied_slas = @applied_slas.page(@current_page).per(RESULTS_PER_PAGE) - end - def set_current_page @current_page = params[:page] || 1 end diff --git a/enterprise/app/views/api/v1/accounts/applied_slas/index.json.jbuilder b/enterprise/app/views/api/v1/accounts/applied_slas/index.json.jbuilder index e9a905d56..cdfc87fc4 100644 --- a/enterprise/app/views/api/v1/accounts/applied_slas/index.json.jbuilder +++ b/enterprise/app/views/api/v1/accounts/applied_slas/index.json.jbuilder @@ -1,14 +1,26 @@ -json.array! @applied_slas do |applied_sla| - json.id applied_sla.id - json.sla_policy_id applied_sla.sla_policy_id - json.conversation_id applied_sla.conversation_id - json.sla_status applied_sla.sla_status - json.created_at applied_sla.created_at - json.updated_at applied_sla.updated_at - json.conversation do - json.partial! 'api/v1/models/conversation', conversation: applied_sla.conversation - end - json.sla_events applied_sla.sla_events do |sla_event| - json.partial! 'api/v1/models/sla_event', formats: [:json], sla_event: sla_event + + +json.payload do + json.array! @applied_slas do |applied_sla| + json.id applied_sla.id + json.sla_policy_id applied_sla.sla_policy_id + json.conversation_id applied_sla.conversation_id + json.sla_status applied_sla.sla_status + json.created_at applied_sla.created_at + json.updated_at applied_sla.updated_at + json.conversation do + json.partial! 'api/v1/models/conversation', conversation: applied_sla.conversation + end + json.sla_events applied_sla.sla_events do |sla_event| + json.partial! 'api/v1/models/sla_event', formats: [:json], sla_event: sla_event + end + json.sla_policy do + json.partial! 'api/v1/models/sla_policy', sla_policy: applied_sla.sla_policy + end end end + +json.meta do + json.total_applied_slas @total_applied_slas + json.current_page @current_page +end