diff --git a/ui/app/models/clients/activity.js b/ui/app/models/clients/activity.js index f4edac595bbc..2462336989e2 100644 --- a/ui/app/models/clients/activity.js +++ b/ui/app/models/clients/activity.js @@ -1,10 +1,12 @@ import Model, { attr } from '@ember-data/model'; export default class Activity extends Model { - @attr('string') responseTimestamp; + @attr('array') byMonthTotalClients; + @attr('array') byMonthNewClients; @attr('array') byNamespace; + @attr('object') total; @attr('array') formattedEndTime; @attr('array') formattedStartTime; @attr('string') startTime; @attr('string') endTime; - @attr('object') total; + @attr('string') responseTimestamp; } diff --git a/ui/app/serializers/clients/activity.js b/ui/app/serializers/clients/activity.js index 1b1926ed138c..c831f8b9f86f 100644 --- a/ui/app/serializers/clients/activity.js +++ b/ui/app/serializers/clients/activity.js @@ -11,14 +11,17 @@ export default class ActivitySerializer extends ApplicationSerializer { Object.keys(ns['counts']).forEach((key) => (flattenedNs[key] = ns['counts'][key])); flattenedNs = this.homogenizeClientNaming(flattenedNs); - // TODO CMB check how this works with actual API endpoint // if no mounts, mounts will be an empty array flattenedNs.mounts = ns.mounts ? ns.mounts.map((mount) => { let flattenedMount = {}; - flattenedMount.label = mount['mount_path']; + let label = mount['mount_path']; Object.keys(mount['counts']).forEach((key) => (flattenedMount[key] = mount['counts'][key])); - return flattenedMount; + flattenedMount = this.homogenizeClientNaming(flattenedMount); + return { + label, + ...flattenedMount, + }; }) : []; @@ -29,22 +32,59 @@ export default class ActivitySerializer extends ApplicationSerializer { }); } - // For 1.10 release naming changed from 'distinct_entities' to 'entity_clients' and + // for vault usage - vertical bar chart + flattenByMonths(payload, isNewClients = false) { + if (isNewClients) { + return payload.map((m) => { + return { + month: m.timestamp, + entity_clients: m.new_clients.counts.entity_clients, + non_entity_clients: m.new_clients.counts.non_entity_clients, + total: m.new_clients.counts.clients, + namespaces: this.flattenDataset(m.new_clients.namespaces), + }; + }); + } else { + return payload.map((m) => { + return { + month: m.timestamp, + entity_clients: m.counts.entity_clients, + non_entity_clients: m.counts.non_entity_clients, + total: m.counts.clients, + namespaces: this.flattenDataset(m.namespaces), + new_clients: { + entity_clients: m.new_clients.counts.entity_clients, + non_entity_clients: m.new_clients.counts.non_entity_clients, + total: m.new_clients.counts.clients, + namespaces: this.flattenDataset(m.new_clients.namespaces), + }, + }; + }); + } + } + + // In 1.10 'distinct_entities' changed to 'entity_clients' and // 'non_entity_tokens' to 'non_entity_clients' - // accounting for deprecated API keys here and updating to latest nomenclature homogenizeClientNaming(object) { - // TODO CMB check with API payload, latest draft includes both new and old key names - // TODO CMB Delete old key names IF correct ones exist? - if (Object.keys(object).includes('distinct_entities', 'non_entity_tokens')) { - let entity_clients = object.distinct_entities; - let non_entity_clients = object.non_entity_tokens; - let { clients } = object; + // if new key names exist, only return those key/value pairs + if (Object.keys(object).includes('entity_clients')) { + let { clients, entity_clients, non_entity_clients } = object; return { clients, entity_clients, non_entity_clients, }; } + // if object only has outdated key names, update naming + if (Object.keys(object).includes('distinct_entities')) { + let { clients, distinct_entities, non_entity_tokens } = object; + return { + clients, + entity_clients: distinct_entities, + non_entity_clients: non_entity_tokens, + }; + } + // TODO CMB: test what to return if neither key exists return object; } @@ -64,11 +104,14 @@ export default class ActivitySerializer extends ApplicationSerializer { ...payload, response_timestamp, by_namespace: this.flattenDataset(payload.data.by_namespace), + by_month_total_clients: this.flattenByMonths(payload.data.months), + by_month_new_clients: this.flattenByMonths(payload.data.months, { isNewClients: true }), total: this.homogenizeClientNaming(payload.data.total), formatted_end_time: this.parseRFC3339(payload.data.end_time), formatted_start_time: this.parseRFC3339(payload.data.start_time), }; delete payload.data.by_namespace; + delete payload.data.months; delete payload.data.total; return super.normalizeResponse(store, primaryModelClass, transformedPayload, id, requestType); } diff --git a/ui/mirage/handlers/clients.js b/ui/mirage/handlers/clients.js index 32ad86621efa..fda9813f0098 100644 --- a/ui/mirage/handlers/clients.js +++ b/ui/mirage/handlers/clients.js @@ -187,7 +187,651 @@ export default function (server) { }, ], end_time: end_time || formatISO(sub(new Date(), { months: 1 })), - months: [], + months: [ + { + timestamp: '2021-05-01T00:00:00Z', + counts: { + distinct_entities: 0, + entity_clients: 13, + non_entity_tokens: 0, + non_entity_clients: 12, + clients: 25, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 8, + non_entity_tokens: 0, + non_entity_clients: 7, + clients: 15, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 8, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 8, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 7, + clients: 7, + }, + }, + ], + }, + { + namespace_id: 's07UR', + namespace_path: 'ns1/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 5, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 5, + }, + }, + ], + }, + ], + new_clients: { + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 3, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 2, + }, + }, + ], + }, + ], + }, + }, + { + timestamp: '2021-04-01T00:00:00Z', + counts: { + distinct_entities: 0, + entity_clients: 10, + non_entity_tokens: 0, + non_entity_clients: 10, + clients: 20, + }, + namespaces: [ + { + namespace_id: 'oImjk', + namespace_path: 'ns2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 5, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 5, + }, + }, + ], + }, + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + { + namespace_id: 's07UR', + namespace_path: 'ns1/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 3, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 2, + }, + }, + ], + }, + ], + new_clients: { + counts: { + distinct_entities: 0, + entity_clients: 10, + non_entity_tokens: 0, + non_entity_clients: 10, + clients: 20, + }, + namespaces: [ + { + namespace_id: 'oImjk', + namespace_path: 'ns2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 5, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 5, + }, + }, + ], + }, + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + { + namespace_id: 's07UR', + namespace_path: 'ns1/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 3, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 2, + }, + }, + ], + }, + ], + }, + }, + { + timestamp: '2021-03-01T00:00:00Z', + counts: { + distinct_entities: 0, + entity_clients: 7, + non_entity_tokens: 0, + non_entity_clients: 8, + clients: 15, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 5, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 5, + }, + }, + ], + }, + { + namespace_id: 's07UR', + namespace_path: 'ns1/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + ], + new_clients: { + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + namespaces: [ + { + namespace_id: 's07UR', + namespace_path: 'ns1/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + ], + }, + }, + { + timestamp: '2021-02-01T00:00:00Z', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 10, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 5, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 5, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 5, + clients: 5, + }, + }, + ], + }, + ], + new_clients: { + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 3, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 3, + }, + }, + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 2, + clients: 2, + }, + }, + ], + }, + ], + }, + }, + { + timestamp: '2021-01-01T00:00:00Z', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + ], + new_clients: { + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 5, + }, + mounts: [ + { + mount_path: 'auth/up1/', + counts: { + distinct_entities: 0, + entity_clients: 0, + non_entity_tokens: 0, + non_entity_clients: 3, + clients: 3, + }, + }, + { + mount_path: 'auth/up2/', + counts: { + distinct_entities: 0, + entity_clients: 2, + non_entity_tokens: 0, + non_entity_clients: 0, + clients: 2, + }, + }, + ], + }, + ], + }, + }, + ], start_time: isBefore(new Date(start_time), new Date(counts_start)) ? counts_start : start_time, total: { distinct_entities: 37389, diff --git a/ui/tests/acceptance/client-current-test.js b/ui/tests/acceptance/client-current-test.js index 00cc5bd2cc16..db4a3a3e83e3 100644 --- a/ui/tests/acceptance/client-current-test.js +++ b/ui/tests/acceptance/client-current-test.js @@ -151,10 +151,11 @@ module('Acceptance | clients current', function (hooks) { assert.dom(SELECTORS.attributionBlock).doesNotExist('Does not show attribution block'); // Delete auth filter goes back to filtered only on namespace await click('#auth-method-search-select [data-test-selected-list-button="delete"]'); - await waitUntil(() => find('[data-test-horizontal-bar-chart]')); assert.dom('[data-test-stat-text="total-clients"] .stat-value').hasText('15'); assert.dom('[data-test-stat-text="entity-clients"] .stat-value').hasText('5'); assert.dom('[data-test-stat-text="non-entity-clients"] .stat-value').hasText('10'); + await settled(); + await waitUntil(() => find('[data-test-horizontal-bar-chart]')); assert.dom('[data-test-horizontal-bar-chart]').exists('Still shows attribution bar chart'); await clickTrigger(); await searchSelect.options.objectAt(0).click(); diff --git a/ui/tests/acceptance/client-history-test.js b/ui/tests/acceptance/client-history-test.js index d56c390f14e9..5adc61ef2892 100644 --- a/ui/tests/acceptance/client-history-test.js +++ b/ui/tests/acceptance/client-history-test.js @@ -191,13 +191,12 @@ module('Acceptance | clients history tab', function (hooks) { // FILTER BY NAMESPACE await clickTrigger(); await searchSelect.options.objectAt(0).click(); - await waitUntil(() => { - return find('[data-test-horizontal-bar-chart]'); - }); + await settled(); assert.ok(true, 'Filter by first namespace'); assert.dom('[data-test-stat-text="total-clients"] .stat-value').hasText('15'); assert.dom('[data-test-stat-text="entity-clients"] .stat-value').hasText('5'); assert.dom('[data-test-stat-text="non-entity-clients"] .stat-value').hasText('10'); + await waitUntil(() => find('[data-test-horizontal-bar-chart]')); assert.dom('[data-test-horizontal-bar-chart]').exists('Shows attribution bar chart'); assert.dom('[data-test-top-attribution]').includesText('Top auth method'); diff --git a/ui/tests/helpers/clients.js b/ui/tests/helpers/clients.js index 37271d4a3fec..1acc6a0a4ff3 100644 --- a/ui/tests/helpers/clients.js +++ b/ui/tests/helpers/clients.js @@ -82,20 +82,18 @@ function generateNamespaceBlock(idx = 0, skipMounts = false) { if (!skipMounts) { mountCount = Math.floor((Math.random() + idx) * 20); let mounts = []; - if (!skipMounts) { - Array.from(Array(mountCount)).forEach((v, index) => { - mounts.push({ - mount_path: `auth/authid${index}`, - counts: { - clients: 5, - entity_clients: 3, - non_entity_clients: 2, - distinct_entities: 3, - non_entity_tokens: 2, - }, - }); + Array.from(Array(mountCount)).forEach((v, index) => { + mounts.push({ + mount_path: `auth/authid${index}`, + counts: { + clients: 5, + entity_clients: 3, + non_entity_clients: 2, + distinct_entities: 3, + non_entity_tokens: 2, + }, }); - } + }); nsBlock.mounts = mounts; } return nsBlock; @@ -124,7 +122,7 @@ export function generateActivityResponse(nsCount = 1, startDate, endDate) { }, }, ], - // months: [], + months: [], }, }; } @@ -142,7 +140,7 @@ export function generateActivityResponse(nsCount = 1, startDate, endDate) { non_entity_clients: 333, }, by_namespace: namespaces, - // months: [], + months: [], }, }; }