vault/ui/app/components/clients/activity.ts
claire bontempo 009702cae0
UI: Convert client count utils to typescript (#26262)
* cleanup namespaceArrayToObject method

* WIP typescript conversion

* WIP typescripted destructured block

* slowly making progress....

* WIP move all types to util type file, separate returns in formatByMonths

* namespaceArrayToObject is working?!?

* fix mirage handler not generating months when queries are after upgrade

* wow, the types are actually working omg

* add comments and update client-count-utils test

* delete old js file

* remove types from activity model

* remove comment

* reuse totalclients type to minimize places we add types

* commit file with type changes for git diff

* delete util file again

* address PR feedback and move type declarations to util file

* remove unused types

* update tests, use client helper in dashboard clients test

* remove typo

* make modifications with updated combined activity response from the backend
2024-04-09 20:53:16 +00:00

170 lines
5.2 KiB
TypeScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
// base component for counts child routes that can be extended as needed
// contains getters that filter and extract data from activity model for use in charts
import Component from '@glimmer/component';
import { isSameMonth, fromUnixTime } from 'date-fns';
import { parseAPITimestamp } from 'core/utils/date-formatters';
import { calculateAverage } from 'vault/utils/chart-helpers';
import { filterVersionHistory, hasMountsKey, hasNamespacesKey } from 'core/utils/client-count-utils';
import type ClientsActivityModel from 'vault/models/clients/activity';
import type ClientsVersionHistoryModel from 'vault/models/clients/version-history';
import type {
ByMonthNewClients,
MountNewClients,
NamespaceByKey,
NamespaceNewClients,
} from 'core/utils/client-count-utils';
interface Args {
isSecretsSyncActivated?: boolean;
activity: ClientsActivityModel;
versionHistory: ClientsVersionHistoryModel[];
startTimestamp: number;
endTimestamp: number;
namespace: string;
mountPath: string;
}
export default class ClientsActivityComponent extends Component<Args> {
average = (
data:
| (ByMonthNewClients | NamespaceNewClients | MountNewClients | undefined)[]
| (NamespaceByKey | undefined)[],
key: string
) => {
return calculateAverage(data, key);
};
get startTimeISO() {
return fromUnixTime(this.args.startTimestamp).toISOString();
}
get endTimeISO() {
return fromUnixTime(this.args.endTimestamp).toISOString();
}
get byMonthActivityData() {
const { activity, namespace } = this.args;
return namespace ? this.filteredActivityByMonth : activity.byMonth;
}
get byMonthNewClients() {
return this.byMonthActivityData ? this.byMonthActivityData?.map((m) => m?.new_clients) : [];
}
get filteredActivityByMonth() {
const { namespace, mountPath, activity } = this.args;
if (!namespace && !mountPath) {
return activity.byMonth;
}
const namespaceData = activity.byMonth
?.map((m) => m.namespaces_by_key[namespace])
.filter((d) => d !== undefined);
if (!mountPath) {
return namespaceData || [];
}
const mountData = namespaceData
?.map((namespace) => namespace?.mounts_by_key[mountPath])
.filter((d) => d !== undefined);
return mountData || [];
}
get filteredActivityByNamespace() {
const { namespace, activity } = this.args;
return activity.byNamespace.find((ns) => ns.label === namespace);
}
get filteredActivityByAuthMount() {
return this.filteredActivityByNamespace?.mounts?.find((mount) => mount.label === this.args.mountPath);
}
get filteredActivity() {
return this.args.mountPath ? this.filteredActivityByAuthMount : this.filteredActivityByNamespace;
}
get isCurrentMonth() {
const { activity } = this.args;
const current = parseAPITimestamp(activity.responseTimestamp) as Date;
const start = parseAPITimestamp(activity.startTime) as Date;
const end = parseAPITimestamp(activity.endTime) as Date;
return isSameMonth(start, current) && isSameMonth(end, current);
}
get isDateRange() {
const { activity } = this.args;
return !isSameMonth(
parseAPITimestamp(activity.startTime) as Date,
parseAPITimestamp(activity.endTime) as Date
);
}
// (object) top level TOTAL client counts for given date range
get totalUsageCounts() {
const { namespace, activity } = this.args;
return namespace ? this.filteredActivity : activity.total;
}
get upgradesDuringActivity() {
const { versionHistory, activity } = this.args;
return filterVersionHistory(versionHistory, activity.startTime, activity.endTime);
}
// (object) single month new client data with total counts and array of
// either namespaces or mounts
get newClientCounts() {
if (this.isDateRange || this.byMonthActivityData.length === 0) {
return null;
}
return this.byMonthActivityData[0]?.new_clients;
}
// total client data for horizontal bar chart in attribution component
get totalClientAttribution() {
const { namespace, activity } = this.args;
if (namespace) {
return this.filteredActivityByNamespace?.mounts || null;
} else {
return activity.byNamespace || null;
}
}
// new client data for horizontal bar chart
get newClientAttribution() {
// new client attribution only available in a single, historical month (not a date range or current month)
if (this.isDateRange || this.isCurrentMonth || !this.newClientCounts) return null;
const newCounts = this.newClientCounts;
if (this.args.namespace && hasMountsKey(newCounts)) return newCounts?.mounts;
if (hasNamespacesKey(newCounts)) return newCounts?.namespaces;
return null;
}
get hasAttributionData() {
const { mountPath, namespace } = this.args;
if (!mountPath) {
if (namespace) {
const mounts = this.filteredActivityByNamespace?.mounts?.map((mount) => ({
id: mount.label,
name: mount.label,
}));
return mounts && mounts.length > 0;
}
return !!this.totalClientAttribution && this.totalUsageCounts && this.totalUsageCounts.clients !== 0;
}
return false;
}
}