diff --git a/ui/app/components/clients/charts/vertical-bar-basic.ts b/ui/app/components/clients/charts/vertical-bar-basic.ts index 5b6dc33232..0929e3f6af 100644 --- a/ui/app/components/clients/charts/vertical-bar-basic.ts +++ b/ui/app/components/clients/charts/vertical-bar-basic.ts @@ -9,8 +9,8 @@ import { BAR_WIDTH, numericalAxisLabel } from 'vault/utils/chart-helpers'; import { formatNumber } from 'core/helpers/format-number'; import { parseAPITimestamp } from 'core/utils/date-formatters'; -import type { MonthlyChartData } from 'vault/vault/charts/client-counts'; -import type { TotalClients } from 'core/utils/client-count-utils'; +import type { MonthlyChartData } from 'vault/vault/client-counts/charts'; +import type { TotalClients } from 'vault/vault/client-counts/activity-api'; interface Args { data: MonthlyChartData[]; diff --git a/ui/app/components/clients/charts/vertical-bar-stacked.ts b/ui/app/components/clients/charts/vertical-bar-stacked.ts index b513d7cb42..be168ce288 100644 --- a/ui/app/components/clients/charts/vertical-bar-stacked.ts +++ b/ui/app/components/clients/charts/vertical-bar-stacked.ts @@ -9,8 +9,9 @@ import { BAR_WIDTH, numericalAxisLabel } from 'vault/utils/chart-helpers'; import { formatNumber } from 'core/helpers/format-number'; import { parseAPITimestamp } from 'core/utils/date-formatters'; import { flatGroup } from 'd3-array'; -import type { MonthlyChartData } from 'vault/vault/charts/client-counts'; -import type { ClientTypes } from 'core/utils/client-count-utils'; + +import type { MonthlyChartData } from 'vault/vault/client-counts/charts'; +import type { ClientTypes } from 'vault/vault/client-counts/activity-api'; interface Args { chartHeight?: number; diff --git a/ui/app/components/clients/filter-toolbar.ts b/ui/app/components/clients/filter-toolbar.ts index ca573419c8..5b79ff9607 100644 --- a/ui/app/components/clients/filter-toolbar.ts +++ b/ui/app/components/clients/filter-toolbar.ts @@ -9,13 +9,13 @@ import { action } from '@ember/object'; import { debounce } from '@ember/runloop'; import { capitalize } from '@ember/string'; import { buildISOTimestamp, parseAPITimestamp } from 'core/utils/date-formatters'; +import { ClientFilters } from 'core/utils/client-count-utils'; -import { +import type { ActivityExportData, - ClientFilters, + ClientFilterTypes, MountClients, - type ClientFilterTypes, -} from 'core/utils/client-count-utils'; +} from 'vault/vault/client-counts/activity-api'; import type { HTMLElementEvent } from 'vault/forms'; interface Args { diff --git a/ui/app/components/clients/page/client-list.ts b/ui/app/components/clients/page/client-list.ts index fec80ea72a..f1df17913b 100644 --- a/ui/app/components/clients/page/client-list.ts +++ b/ui/app/components/clients/page/client-list.ts @@ -7,15 +7,12 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { HTMLElementEvent } from 'vault/forms'; -import { - filterIsSupported, - filterTableData, - type ClientFilterTypes, - type ActivityExportData, -} from 'core/utils/client-count-utils'; +import { filterIsSupported, filterTableData } from 'core/utils/client-count-utils'; import { service } from '@ember/service'; import FlagsService from 'vault/services/flags'; +import type { ActivityExportData, ClientFilterTypes } from 'vault/vault/client-counts/activity-api'; + // Define the base mapping to derive types from const CLIENT_TYPE_MAP = { entity: 'Entity', diff --git a/ui/app/components/clients/page/overview.ts b/ui/app/components/clients/page/overview.ts index 0c58b9bdde..e3268fdfee 100644 --- a/ui/app/components/clients/page/overview.ts +++ b/ui/app/components/clients/page/overview.ts @@ -6,9 +6,10 @@ import Component from '@glimmer/component'; import { cached, tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; -import { filterTableData, flattenMounts, type ClientFilterTypes } from 'core/utils/client-count-utils'; +import { filterTableData, flattenMounts } from 'core/utils/client-count-utils'; import type ClientsActivityModel from 'vault/vault/models/clients/activity'; +import type { ClientFilterTypes } from 'vault/vault/client-counts/activity-api'; export interface Args { activity: ClientsActivityModel; diff --git a/ui/app/components/clients/running-total.ts b/ui/app/components/clients/running-total.ts index b3a04ce19d..2feb478af6 100644 --- a/ui/app/components/clients/running-total.ts +++ b/ui/app/components/clients/running-total.ts @@ -7,7 +7,7 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { service } from '@ember/service'; -import type { ByMonthNewClients, TotalClients } from 'core/utils/client-count-utils'; +import type { ByMonthNewClients, TotalClients } from 'vault/vault/client-counts/activity-api'; import type FlagsService from 'vault/services/flags'; interface Args { diff --git a/ui/app/components/clients/table.ts b/ui/app/components/clients/table.ts index eee2afb9a8..b9fb4b7bec 100644 --- a/ui/app/components/clients/table.ts +++ b/ui/app/components/clients/table.ts @@ -8,10 +8,10 @@ import { action } from '@ember/object'; import { cached, tracked } from '@glimmer/tracking'; import { paginate } from 'core/utils/paginate-list'; import { next } from '@ember/runloop'; - -import type { ClientFilterTypes } from 'core/utils/client-count-utils'; import { service } from '@ember/service'; -import VersionService from 'vault/services/version'; + +import type VersionService from 'vault/services/version'; +import type { ClientFilterTypes } from 'vault/vault/client-counts/activity-api'; /** * @module ClientsTable diff --git a/ui/lib/core/addon/utils/client-count-utils.ts b/ui/lib/core/addon/utils/client-count-utils.ts index 33e2372044..dd09d539b9 100644 --- a/ui/lib/core/addon/utils/client-count-utils.ts +++ b/ui/lib/core/addon/utils/client-count-utils.ts @@ -9,6 +9,21 @@ import { ROOT_NAMESPACE } from 'vault/services/namespace'; import { sanitizePath } from './sanitize-path'; import type ClientsVersionHistoryModel from 'vault/vault/models/clients/version-history'; +import type { + ActivityExportData, + ActivityMonthBlock, + ActivityMonthEmpty, + ActivityMonthStandard, + ByMonthNewClients, + ByNamespaceClients, + ClientFilterTypes, + ClientTypes, + Counts, + MountClients, + MountNewClients, + NamespaceNewClients, + NamespaceObject, +} from 'vault/vault/client-counts/activity-api'; /* The client count utils are responsible for serializing the sys/internal/counters/activity API response @@ -17,7 +32,7 @@ The initial API response shape and serialized types are defined below. To help visualize there are sample responses in ui/tests/helpers/clients.js */ -// add new types here +// Add new sys/activity/counters client count types here export const CLIENT_TYPES = [ 'acme_clients', 'clients', // summation of total clients @@ -26,8 +41,6 @@ export const CLIENT_TYPES = [ 'secret_syncs', ] as const; -export type ClientTypes = (typeof CLIENT_TYPES)[number]; - // map to dropdowns for filtering client count tables export enum ClientFilters { NAMESPACE = 'namespace_path', @@ -37,14 +50,10 @@ export enum ClientFilters { MONTH = 'month', } -export type ClientFilterTypes = (typeof ClientFilters)[keyof typeof ClientFilters]; - // client_type in the exported activity data differs slightly from the types of client keys // returned by sys/internal/counters/activity endpoint (: export const EXPORT_CLIENT_TYPES = ['non-entity-token', 'pki-acme', 'secret-sync', 'entity'] as const; -export type ActivityExportClientTypes = (typeof EXPORT_CLIENT_TYPES)[number]; - // returns array of VersionHistoryModels for noteworthy upgrades: 1.9, 1.10 // that occurred between timestamps (i.e. queried activity data) export const filterVersionHistory = ( @@ -239,133 +248,3 @@ export function hasNamespacesKey( ): obj is ByMonthNewClients { return 'namespaces' in obj; } - -// TYPES RETURNED BY UTILS (serialized) -export interface TotalClients { - clients: number; - entity_clients: number; - non_entity_clients: number; - secret_syncs: number; - 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[]; -} - -export interface MountClients extends TotalClients { - label: string; - mount_path: string; - mount_type: string; - namespace_path: string; -} - -export interface ByMonthClients extends TotalClients { - timestamp: string; - namespaces: ByNamespaceClients[]; - new_clients: ByMonthNewClients; -} - -export interface ByMonthNewClients extends TotalClientsSometimes { - timestamp: string; - namespaces: ByNamespaceClients[]; -} - -export interface NamespaceByKey extends TotalClients { - timestamp: string; - new_clients: NamespaceNewClients; -} - -export interface NamespaceNewClients extends TotalClientsSometimes { - timestamp: string; - label: string; - mounts: MountClients[]; -} - -export interface MountByKey extends TotalClients { - timestamp: string; - label: string; - new_clients: MountNewClients; -} - -export interface MountNewClients extends TotalClientsSometimes { - timestamp: string; - label: string; -} - -// Serialized data from activity/export API -export interface ActivityExportData { - client_id: string; - client_type: ActivityExportClientTypes; - namespace_id: string; - namespace_path: string; - mount_accessor: string; - mount_type: string; - mount_path: string; - token_creation_time: string; - client_first_used_time: string; -} -export interface EntityClients extends ActivityExportData { - entity_name: string; - entity_alias_name: string; - local_entity_alias: boolean; - policies: string[]; - entity_metadata: Record; - entity_alias_metadata: Record; - entity_alias_custom_metadata: Record; - entity_group_ids: string[]; -} - -// API RESPONSE SHAPE (prior to serialization) - -export interface NamespaceObject { - namespace_id: string; - namespace_path: string; - counts: Counts; - mounts: { mount_path: string; counts: Counts; mount_type: string }[]; -} - -type ActivityMonthStandard = { - timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month) - counts: Counts; - namespaces: NamespaceObject[]; - new_clients: { - counts: Counts; - namespaces: NamespaceObject[]; - timestamp: string; - }; -}; -type ActivityMonthNoNewClients = { - timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month) - counts: Counts; - namespaces: NamespaceObject[]; - new_clients: { - counts: null; - namespaces: null; - }; -}; -type ActivityMonthEmpty = { - timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month) - counts: null; - namespaces: null; - new_clients: null; -}; -export type ActivityMonthBlock = ActivityMonthEmpty | ActivityMonthNoNewClients | ActivityMonthStandard; - -export interface Counts { - acme_clients: number; - clients: number; - entity_clients: number; - non_entity_clients: number; - secret_syncs: number; -} diff --git a/ui/types/vault/client-counts/activity-api.ts b/ui/types/vault/client-counts/activity-api.ts new file mode 100644 index 0000000000..c71f50fb62 --- /dev/null +++ b/ui/types/vault/client-counts/activity-api.ts @@ -0,0 +1,127 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { CLIENT_TYPES, ClientFilters, EXPORT_CLIENT_TYPES } from 'core/utils/client-count-utils'; + +// At time of writing ClientTypes are: 'acme_clients' | 'clients' | 'entity_clients' | 'non_entity_clients' | 'secret_syncs' +export type ClientTypes = (typeof CLIENT_TYPES)[number]; + +// 'namespace_path' | 'mount_path' | 'mount_type' | 'month' +export type ClientFilterTypes = (typeof ClientFilters)[keyof typeof ClientFilters]; + +// client_type in the exported activity data differs slightly from the types of client keys +// returned by sys/internal/counters/activity endpoint (: +// 'non-entity-token' | 'pki-acme' | 'secret-sync' | 'entity' +type ActivityExportClientTypes = (typeof EXPORT_CLIENT_TYPES)[number]; + +export interface TotalClients { + clients: number; + entity_clients: number; + non_entity_clients: number; + secret_syncs: number; + 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[]; +} + +export interface MountClients extends TotalClients { + label: string; + mount_path: string; + mount_type: string; + namespace_path: string; +} + +export interface ByMonthClients extends TotalClients { + timestamp: string; + namespaces: ByNamespaceClients[]; + new_clients: ByMonthNewClients; +} + +export interface ByMonthNewClients extends TotalClientsSometimes { + timestamp: string; + namespaces: ByNamespaceClients[]; +} + +export interface NamespaceNewClients extends TotalClientsSometimes { + timestamp: string; + label: string; + mounts: MountClients[]; +} + +export interface MountNewClients extends TotalClientsSometimes { + timestamp: string; + label: string; +} + +// SERIALIZED RESPONSE DATA from activity/export API +export interface ActivityExportData { + client_id: string; + client_type: ActivityExportClientTypes; + namespace_id: string; + namespace_path: string; + mount_accessor: string; + mount_type: string; + mount_path: string; + token_creation_time: string; + client_first_used_time: string; +} + +// API RESPONSE SHAPE (prior to serialization) +export interface NamespaceObject { + namespace_id: string; + namespace_path: string; + counts: Counts; + mounts: { mount_path: string; counts: Counts; mount_type: string }[]; +} + +export type ActivityMonthStandard = { + timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month) + counts: Counts; + namespaces: NamespaceObject[]; + new_clients: { + counts: Counts; + namespaces: NamespaceObject[]; + timestamp: string; + }; +}; + +export type ActivityMonthNoNewClients = { + 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 type ActivityMonthEmpty = { + timestamp: string; // YYYY-MM-01T00:00:00Z (always the first day of the month) + counts: null; + namespaces: null; + new_clients: null; +}; + +export type ActivityMonthBlock = ActivityMonthEmpty | ActivityMonthNoNewClients | ActivityMonthStandard; + +export interface Counts { + acme_clients: number; + clients: number; + entity_clients: number; + non_entity_clients: number; + secret_syncs: number; +} diff --git a/ui/types/vault/charts/client-counts.d.ts b/ui/types/vault/client-counts/charts.ts similarity index 87% rename from ui/types/vault/charts/client-counts.d.ts rename to ui/types/vault/client-counts/charts.ts index c3ca2a922c..34e9b371ed 100644 --- a/ui/types/vault/charts/client-counts.d.ts +++ b/ui/types/vault/client-counts/charts.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import type { TotalClients } from 'core/utils/client-count-utils'; +import type { TotalClients } from './activity-api'; // TotalClients and EmptyCount are mutually exclusive // but that's hard to represent in an interface diff --git a/ui/types/vault/models/clients/activity.d.ts b/ui/types/vault/models/clients/activity.d.ts index 58e7123777..f8952ce468 100644 --- a/ui/types/vault/models/clients/activity.d.ts +++ b/ui/types/vault/models/clients/activity.d.ts @@ -4,8 +4,11 @@ */ import type { Model } from 'vault/app-types'; - -import type { ByMonthClients, ByNamespaceClients, TotalClients } from 'core/utils/client-count-utils'; +import type { + ByMonthClients, + ByNamespaceClients, + TotalClients, +} from 'vault/vault/client-counts/activity-api'; export default interface ClientsActivityModel extends Model { byMonth: ByMonthClients[];