mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 12:07:54 +00:00
UI: Fix client counts bug when no new clients (#27352)
This commit is contained in:
3
changelog/27352.txt
Normal file
3
changelog/27352.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
ui: fix issue where a month without new clients breaks the client count dashboard
|
||||
```
|
||||
@@ -86,7 +86,9 @@ export const formatDateObject = (dateObj: { monthIdx: number; year: number }, is
|
||||
return getUnixTime(utc);
|
||||
};
|
||||
|
||||
export const formatByMonths = (monthsArray: ActivityMonthBlock[] | EmptyActivityMonthBlock[]) => {
|
||||
export const formatByMonths = (
|
||||
monthsArray: (ActivityMonthBlock | EmptyActivityMonthBlock | NoNewClientsActivityMonthBlock)[]
|
||||
) => {
|
||||
const sortedPayload = sortMonthsByTimestamp(monthsArray);
|
||||
return sortedPayload?.map((m) => {
|
||||
const month = parseAPITimestamp(m.timestamp, 'M/yy') as string;
|
||||
@@ -95,23 +97,28 @@ export const formatByMonths = (monthsArray: ActivityMonthBlock[] | EmptyActivity
|
||||
if (m.counts) {
|
||||
const totalClientsByNamespace = formatByNamespace(m.namespaces);
|
||||
const newClientsByNamespace = formatByNamespace(m.new_clients?.namespaces);
|
||||
|
||||
let newClients: ByMonthNewClients = { month, timestamp, namespaces: [] };
|
||||
if (m.new_clients?.counts) {
|
||||
newClients = {
|
||||
month,
|
||||
timestamp,
|
||||
...destructureClientCounts(m?.new_clients?.counts),
|
||||
namespaces: formatByNamespace(m.new_clients?.namespaces),
|
||||
};
|
||||
}
|
||||
return {
|
||||
month,
|
||||
timestamp,
|
||||
...destructureClientCounts(m.counts),
|
||||
namespaces: formatByNamespace(m.namespaces) || [],
|
||||
namespaces: formatByNamespace(m.namespaces),
|
||||
namespaces_by_key: namespaceArrayToObject(
|
||||
totalClientsByNamespace,
|
||||
newClientsByNamespace,
|
||||
month,
|
||||
m.timestamp
|
||||
),
|
||||
new_clients: {
|
||||
month,
|
||||
timestamp,
|
||||
...destructureClientCounts(m?.new_clients?.counts),
|
||||
namespaces: formatByNamespace(m.new_clients?.namespaces) || [],
|
||||
},
|
||||
new_clients: newClients,
|
||||
};
|
||||
}
|
||||
// empty month
|
||||
@@ -125,7 +132,8 @@ export const formatByMonths = (monthsArray: ActivityMonthBlock[] | EmptyActivity
|
||||
});
|
||||
};
|
||||
|
||||
export const formatByNamespace = (namespaceArray: NamespaceObject[]) => {
|
||||
export const formatByNamespace = (namespaceArray: NamespaceObject[] | null): ByNamespaceClients[] => {
|
||||
if (!Array.isArray(namespaceArray)) return [];
|
||||
return namespaceArray.map((ns) => {
|
||||
// i.e. 'namespace_path' is an empty string for 'root', so use namespace_id
|
||||
const label = ns.namespace_path === '' ? ns.namespace_id : ns.namespace_path;
|
||||
@@ -158,7 +166,9 @@ export const destructureClientCounts = (verboseObject: Counts | ByNamespaceClien
|
||||
);
|
||||
};
|
||||
|
||||
export const sortMonthsByTimestamp = (monthsArray: ActivityMonthBlock[] | EmptyActivityMonthBlock[]) => {
|
||||
export const sortMonthsByTimestamp = (
|
||||
monthsArray: (ActivityMonthBlock | EmptyActivityMonthBlock | NoNewClientsActivityMonthBlock)[]
|
||||
) => {
|
||||
const sortedPayload = [...monthsArray];
|
||||
return sortedPayload.sort((a, b) =>
|
||||
compareAsc(parseAPITimestamp(a.timestamp) as Date, parseAPITimestamp(b.timestamp) as Date)
|
||||
@@ -168,7 +178,7 @@ export const sortMonthsByTimestamp = (monthsArray: ActivityMonthBlock[] | EmptyA
|
||||
export const namespaceArrayToObject = (
|
||||
monthTotals: ByNamespaceClients[],
|
||||
// technically this arg (monthNew) is the same type as above, just nested inside monthly new clients
|
||||
monthNew: ByMonthClients['new_clients']['namespaces'],
|
||||
monthNew: ByMonthClients['new_clients']['namespaces'] | null,
|
||||
month: string,
|
||||
timestamp: string
|
||||
) => {
|
||||
@@ -176,36 +186,45 @@ export const namespaceArrayToObject = (
|
||||
// it's an object in each month data block where the keys are namespace paths
|
||||
// and values include new and total client counts for that namespace in that month
|
||||
const namespaces_by_key = monthTotals.reduce((nsObject: { [key: string]: NamespaceByKey }, ns) => {
|
||||
const keyedNs: NamespaceByKey = {
|
||||
...destructureClientCounts(ns),
|
||||
timestamp,
|
||||
month,
|
||||
mounts_by_key: {},
|
||||
new_clients: {
|
||||
month,
|
||||
timestamp,
|
||||
label: ns.label,
|
||||
mounts: [],
|
||||
},
|
||||
};
|
||||
const newNsClients = monthNew?.find((n) => n.label === ns.label);
|
||||
if (newNsClients) {
|
||||
// mounts_by_key is is used to filter further in a namespace and get monthly activity by mount
|
||||
// it's an object inside the namespace block where the keys are mount paths
|
||||
// and the values include new and total client counts for that mount in that month
|
||||
const mounts_by_key = ns.mounts.reduce(
|
||||
keyedNs.mounts_by_key = ns.mounts.reduce(
|
||||
(mountObj: { [key: string]: MountByKey }, mount) => {
|
||||
const newMountClients = newNsClients.mounts.find((m) => m.label === mount.label);
|
||||
|
||||
if (newMountClients) {
|
||||
const mountNewClients = newNsClients ? newNsClients.mounts.find((m) => m.label === mount.label) : {};
|
||||
mountObj[mount.label] = {
|
||||
...mount,
|
||||
timestamp,
|
||||
month,
|
||||
new_clients: { month, timestamp, ...newMountClients },
|
||||
new_clients: {
|
||||
timestamp,
|
||||
month,
|
||||
label: mount.label,
|
||||
...mountNewClients,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return mountObj;
|
||||
},
|
||||
{} as { [key: string]: MountByKey }
|
||||
);
|
||||
|
||||
nsObject[ns.label] = {
|
||||
...destructureClientCounts(ns),
|
||||
timestamp,
|
||||
month,
|
||||
new_clients: { month, timestamp, ...newNsClients },
|
||||
mounts_by_key,
|
||||
};
|
||||
if (newNsClients) {
|
||||
keyedNs.new_clients = { month, timestamp, ...newNsClients };
|
||||
}
|
||||
nsObject[ns.label] = keyedNs;
|
||||
return nsObject;
|
||||
}, {});
|
||||
|
||||
@@ -239,6 +258,15 @@ export interface TotalClients {
|
||||
acme_clients: number;
|
||||
}
|
||||
|
||||
// extend this type when the counts are optional (eg for new clients)
|
||||
interface TotalClientsSometimes {
|
||||
clients?: number;
|
||||
entity_clients?: number;
|
||||
non_entity_clients?: number;
|
||||
secret_syncs?: number;
|
||||
acme_clients?: number;
|
||||
}
|
||||
|
||||
export interface ByNamespaceClients extends TotalClients {
|
||||
label: string;
|
||||
mounts: MountClients[];
|
||||
@@ -255,7 +283,9 @@ export interface ByMonthClients extends TotalClients {
|
||||
namespaces_by_key: { [key: string]: NamespaceByKey };
|
||||
new_clients: ByMonthNewClients;
|
||||
}
|
||||
export interface ByMonthNewClients extends TotalClients {
|
||||
|
||||
// clients numbers are only returned if month is of type ActivityMonthBlock
|
||||
export interface ByMonthNewClients extends TotalClientsSometimes {
|
||||
month: string;
|
||||
timestamp: string;
|
||||
namespaces: ByNamespaceClients[];
|
||||
@@ -268,7 +298,7 @@ export interface NamespaceByKey extends TotalClients {
|
||||
new_clients: NamespaceNewClients;
|
||||
}
|
||||
|
||||
export interface NamespaceNewClients extends TotalClients {
|
||||
export interface NamespaceNewClients extends TotalClientsSometimes {
|
||||
month: string;
|
||||
timestamp: string;
|
||||
label: string;
|
||||
@@ -282,7 +312,7 @@ export interface MountByKey extends TotalClients {
|
||||
new_clients: MountNewClients;
|
||||
}
|
||||
|
||||
export interface MountNewClients extends TotalClients {
|
||||
export interface MountNewClients extends TotalClientsSometimes {
|
||||
month: string;
|
||||
timestamp: string;
|
||||
label: string;
|
||||
@@ -308,6 +338,16 @@ export interface ActivityMonthBlock {
|
||||
};
|
||||
}
|
||||
|
||||
export interface NoNewClientsActivityMonthBlock {
|
||||
timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month)
|
||||
counts: Counts;
|
||||
namespaces: NamespaceObject[];
|
||||
new_clients: {
|
||||
counts: null;
|
||||
namespaces: null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface EmptyActivityMonthBlock {
|
||||
timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month)
|
||||
counts: null;
|
||||
|
||||
@@ -40,7 +40,7 @@ export function assertBarChart(assert, chartName, byMonthData, isStacked = false
|
||||
}
|
||||
|
||||
export const ACTIVITY_RESPONSE_STUB = {
|
||||
start_time: '2023-08-01T00:00:00Z',
|
||||
start_time: '2023-06-01T00:00:00Z',
|
||||
end_time: '2023-09-30T23:59:59Z', // is always the last day and hour of the month queried
|
||||
by_namespace: [
|
||||
{
|
||||
@@ -148,11 +148,209 @@ export const ACTIVITY_RESPONSE_STUB = {
|
||||
],
|
||||
months: [
|
||||
{
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
timestamp: '2023-06-01T00:00:00Z',
|
||||
counts: null,
|
||||
namespaces: null,
|
||||
new_clients: null,
|
||||
},
|
||||
{
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
namespaces: [
|
||||
{
|
||||
namespace_id: 'root',
|
||||
namespace_path: '',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
mounts: [
|
||||
{
|
||||
mount_path: 'pki-engine-0',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'auth/authid/0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'kvv2-engine-0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
new_clients: {
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
namespaces: [
|
||||
{
|
||||
namespace_id: 'root',
|
||||
namespace_path: '',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
mounts: [
|
||||
{
|
||||
mount_path: 'pki-engine-0',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'auth/authid/0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'kvv2-engine-0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
namespaces: [
|
||||
{
|
||||
namespace_id: 'root',
|
||||
namespace_path: '',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 100,
|
||||
non_entity_tokens: 100,
|
||||
},
|
||||
mounts: [
|
||||
{
|
||||
mount_path: 'pki-engine-0',
|
||||
counts: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'auth/authid/0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
mount_path: 'kvv2-engine-0',
|
||||
counts: {
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
distinct_entities: 0,
|
||||
non_entity_tokens: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
new_clients: {
|
||||
counts: null,
|
||||
namespaces: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamp: '2023-09-01T00:00:00Z',
|
||||
counts: {
|
||||
@@ -646,10 +844,323 @@ export const SERIALIZED_ACTIVITY_RESPONSE = {
|
||||
],
|
||||
by_month: [
|
||||
{
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
month: '6/23',
|
||||
timestamp: '2023-06-01T00:00:00Z',
|
||||
namespaces: [],
|
||||
namespaces_by_key: {},
|
||||
new_clients: {
|
||||
month: '6/23',
|
||||
timestamp: '2023-06-01T00:00:00Z',
|
||||
namespaces: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
namespaces: [
|
||||
{
|
||||
label: 'root',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
mounts: [
|
||||
{
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
namespaces_by_key: {
|
||||
root: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
month: '7/23',
|
||||
new_clients: {
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
label: 'root',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
mounts: [
|
||||
{
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
mounts_by_key: {
|
||||
'pki-engine-0': {
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
month: '7/23',
|
||||
new_clients: {
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
},
|
||||
'auth/authid/0': {
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
month: '7/23',
|
||||
new_clients: {
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
},
|
||||
'kvv2-engine-0': {
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
month: '7/23',
|
||||
new_clients: {
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new_clients: {
|
||||
month: '7/23',
|
||||
timestamp: '2023-07-01T00:00:00Z',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
namespaces: [
|
||||
{
|
||||
label: 'root',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
mounts: [
|
||||
{
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
namespaces: [
|
||||
{
|
||||
label: 'root',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
mounts: [
|
||||
{
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
},
|
||||
{
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
namespaces_by_key: {
|
||||
root: {
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 100,
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
month: '8/23',
|
||||
new_clients: {
|
||||
label: 'root',
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
mounts: [],
|
||||
},
|
||||
mounts_by_key: {
|
||||
'pki-engine-0': {
|
||||
label: 'pki-engine-0',
|
||||
acme_clients: 100,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 0,
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
month: '8/23',
|
||||
new_clients: {
|
||||
label: 'pki-engine-0',
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
},
|
||||
},
|
||||
'auth/authid/0': {
|
||||
label: 'auth/authid/0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 100,
|
||||
non_entity_clients: 100,
|
||||
secret_syncs: 0,
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
month: '8/23',
|
||||
new_clients: {
|
||||
label: 'auth/authid/0',
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
},
|
||||
},
|
||||
'kvv2-engine-0': {
|
||||
label: 'kvv2-engine-0',
|
||||
acme_clients: 0,
|
||||
clients: 100,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
secret_syncs: 100,
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
month: '8/23',
|
||||
new_clients: {
|
||||
label: 'kvv2-engine-0',
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new_clients: {
|
||||
month: '8/23',
|
||||
timestamp: '2023-08-01T00:00:00Z',
|
||||
|
||||
@@ -43,7 +43,7 @@ module('Integration | Component | dashboard/client-count-card', function (hooks)
|
||||
assert
|
||||
.dom(CLIENT_COUNT.statText('Total'))
|
||||
.hasText(
|
||||
`Total The number of clients in this billing period (Aug 2023 - Sep 2023). ${formatNumber([
|
||||
`Total The number of clients in this billing period (Jun 2023 - Sep 2023). ${formatNumber([
|
||||
total.clients,
|
||||
])}`
|
||||
);
|
||||
|
||||
@@ -129,27 +129,29 @@ module('Integration | Util | client count utils', function (hooks) {
|
||||
});
|
||||
|
||||
test('formatByMonths: it formats the months array', async function (assert) {
|
||||
assert.expect(5);
|
||||
assert.expect(9);
|
||||
const original = [...RESPONSE.months];
|
||||
|
||||
const [formattedNoData, formattedWithActivity] = formatByMonths(RESPONSE.months);
|
||||
const [formattedNoData, formattedWithActivity, formattedNoNew] = formatByMonths(RESPONSE.months);
|
||||
|
||||
// instead of asserting the whole expected response, broken up so tests are easier to debug
|
||||
// but kept whole above to copy/paste updated response expectations in the future
|
||||
const [expectedNoData, expectedWithActivity] = SERIALIZED_ACTIVITY_RESPONSE.by_month;
|
||||
const { namespaces, new_clients } = expectedWithActivity;
|
||||
const [expectedNoData, expectedWithActivity, expectedNoNew] = SERIALIZED_ACTIVITY_RESPONSE.by_month;
|
||||
|
||||
assert.propEqual(formattedNoData, expectedNoData, 'it formats months without data');
|
||||
['namespaces', 'new_clients', 'namespaces_by_key'].forEach((key) => {
|
||||
assert.propEqual(
|
||||
formattedWithActivity.namespaces,
|
||||
namespaces,
|
||||
'it formats namespaces array for months with data'
|
||||
formattedWithActivity[key],
|
||||
expectedWithActivity[key],
|
||||
`it formats ${key} array for months with data`
|
||||
);
|
||||
assert.propEqual(
|
||||
formattedWithActivity.new_clients,
|
||||
new_clients,
|
||||
'it formats new_clients block for months with data'
|
||||
formattedNoNew[key],
|
||||
expectedNoNew[key],
|
||||
`it formats the ${key} array for months with no new clients`
|
||||
);
|
||||
});
|
||||
|
||||
assert.propEqual(RESPONSE.months, original, 'it does not modify original months array');
|
||||
assert.propEqual(formatByMonths([]), [], 'it returns an empty array if the months key is empty');
|
||||
});
|
||||
@@ -187,7 +189,7 @@ module('Integration | Util | client count utils', function (hooks) {
|
||||
test('sortMonthsByTimestamp: sorts timestamps chronologically, oldest to most recent', async function (assert) {
|
||||
assert.expect(2);
|
||||
// API returns them in order so this test is extra extra
|
||||
const unOrdered = [RESPONSE.months[1], RESPONSE.months[0]]; // mixup order
|
||||
const unOrdered = [RESPONSE.months[1], RESPONSE.months[0], RESPONSE.months[3], RESPONSE.months[2]]; // mixup order
|
||||
const original = [...RESPONSE.months];
|
||||
const expected = RESPONSE.months;
|
||||
assert.propEqual(sortMonthsByTimestamp(unOrdered), expected);
|
||||
@@ -195,32 +197,30 @@ module('Integration | Util | client count utils', function (hooks) {
|
||||
});
|
||||
|
||||
test('namespaceArrayToObject: it returns namespaces_by_key and mounts_by_key', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// month at 0-index has no data so use second month in array, empty month format covered by formatByMonths test above
|
||||
const original = { ...RESPONSE.months[1] };
|
||||
const expectedObject = SERIALIZED_ACTIVITY_RESPONSE.by_month[1].namespaces_by_key;
|
||||
const formattedTotal = formatByNamespace(RESPONSE.months[1].namespaces);
|
||||
|
||||
// namespaceArrayToObject only called when there are counts, so skip month 0 which has no counts
|
||||
for (let i = 1; i < RESPONSE.months.length; i++) {
|
||||
const original = { ...RESPONSE.months[i] };
|
||||
const expectedObject = SERIALIZED_ACTIVITY_RESPONSE.by_month[i].namespaces_by_key;
|
||||
const formattedTotal = formatByNamespace(RESPONSE.months[i].namespaces);
|
||||
const testObject = namespaceArrayToObject(
|
||||
formattedTotal,
|
||||
formatByNamespace(RESPONSE.months[1].new_clients.namespaces),
|
||||
'9/23',
|
||||
'2023-09-01T00:00:00Z'
|
||||
formatByNamespace(RESPONSE.months[i].new_clients.namespaces),
|
||||
`${i + 6}/23`,
|
||||
original.timestamp
|
||||
);
|
||||
|
||||
const { root } = testObject;
|
||||
const { root: expectedRoot } = expectedObject;
|
||||
assert.propEqual(root.new_clients, expectedRoot.new_clients, 'it formats namespaces new_clients');
|
||||
|
||||
assert.propEqual(
|
||||
root?.new_clients,
|
||||
expectedRoot?.new_clients,
|
||||
`it formats namespaces new_clients for ${original.timestamp}`
|
||||
);
|
||||
assert.propEqual(root.mounts_by_key, expectedRoot.mounts_by_key, 'it formats namespaces mounts_by_key');
|
||||
assert.propContains(root, expectedRoot, 'namespace has correct keys');
|
||||
|
||||
assert.propEqual(
|
||||
namespaceArrayToObject(formattedTotal, formatByNamespace([]), '9/23', '2023-09-01T00:00:00Z'),
|
||||
{},
|
||||
'returns an empty object when there are no new clients '
|
||||
);
|
||||
assert.propEqual(RESPONSE.months[1], original, 'it does not modify original month data');
|
||||
assert.propEqual(RESPONSE.months[i], original, 'it does not modify original month data');
|
||||
}
|
||||
});
|
||||
|
||||
// TESTS FOR COMBINED ACTIVITY DATA - no mount attribution < 1.10
|
||||
|
||||
Reference in New Issue
Block a user