mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-22 07:01:09 +02:00
* increase bar width, show new clients only, add timestamp to header, update bar color * remove extra timestamps, switch to basic bar chart * update docs and styling * remove unneeded timestamp args * show new client running totatls * initial test updates * update test * clean up new client total calc into util fn * bits of clean up and todos * update tests * update to avoid activity call when in CE and missing either start or end time * update todos * update tests * tidying * move new client total onto payload for easier access * update more tests to align with copy changes and new client totals * remove addressed TODOs * Update comment * add changelog entry * revert to using total, update tests and clean up * Update ui/app/components/clients/page/counts.hbs Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * remove duplicate charts and update descriptions * update tests after removing extra charts * tidy * update instances of byMonthActivityData to use byMonthNewClients and update tests * Update ui/app/components/clients/running-total.ts Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * update chart styles --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
149 lines
5.2 KiB
JavaScript
149 lines
5.2 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import { action } from '@ember/object';
|
|
import { service } from '@ember/service';
|
|
import { waitFor } from '@ember/test-waiters';
|
|
import Component from '@glimmer/component';
|
|
import { tracked } from '@glimmer/tracking';
|
|
import { parseAPITimestamp } from 'core/utils/date-formatters';
|
|
import { sanitizePath } from 'core/utils/sanitize-path';
|
|
import { isSameMonth } from 'date-fns';
|
|
import { task } from 'ember-concurrency';
|
|
|
|
/**
|
|
* @module ClientsPageHeader
|
|
* ClientsPageHeader components are used to render a header and check for export capabilities before rendering an export button.
|
|
*
|
|
* @example
|
|
* ```js
|
|
* <Clients::PageHeader @startTimestamp="2022-06-01T23:00:11.050Z" @endTimestamp="2022-12-01T23:00:11.050Z" @namespace="foo" @upgradesDuringActivity={{array (hash version="1.10.1" previousVersion="1.9.1" timestampInstalled= "2021-11-18T10:23:16Z") }} />
|
|
* ```
|
|
* @param {string} [billingStartTime] - ISO timestamp of billing start date, to be passed to date picker
|
|
* @param {string} [activityTimestamp] - ISO timestamp created in serializer to timestamp the response to be displayed in page header
|
|
* @param {string} [startTimestamp] - ISO timestamp of start time, to be passed to export request
|
|
* @param {string} [endTimestamp] - ISO timestamp of end time, to be passed to export request
|
|
* @param {number} [retentionMonths = 48] - number of months for historical billing, to be passed to date picker
|
|
* @param {string} [namespace] - namespace filter. Will be appended to the current namespace in the export request.
|
|
* @param {string} [upgradesDuringActivity] - array of objects containing version history upgrade data
|
|
* @param {boolean} [noData = false] - when true, export button will hide regardless of capabilities
|
|
* @param {function} [onChange] - callback when a new date range is saved, to be passed to date picker
|
|
*/
|
|
export default class ClientsPageHeaderComponent extends Component {
|
|
@service download;
|
|
@service namespace;
|
|
@service store;
|
|
@service version;
|
|
|
|
@tracked canDownload = false;
|
|
@tracked showEditModal = false;
|
|
@tracked showExportModal = false;
|
|
@tracked exportFormat = 'csv';
|
|
@tracked downloadError = '';
|
|
|
|
constructor() {
|
|
super(...arguments);
|
|
this.getExportCapabilities(this.args.namespace);
|
|
}
|
|
|
|
get showExportButton() {
|
|
if (this.args.noData === true) return false;
|
|
return this.canDownload;
|
|
}
|
|
|
|
@waitFor
|
|
async getExportCapabilities(ns = '') {
|
|
try {
|
|
// selected namespace usually ends in /
|
|
const url = ns
|
|
? `${sanitizePath(ns)}/sys/internal/counters/activity/export`
|
|
: 'sys/internal/counters/activity/export';
|
|
const cap = await this.store.findRecord('capabilities', url);
|
|
this.canDownload = cap.canSudo;
|
|
} catch (e) {
|
|
// if we can't read capabilities, default to show
|
|
this.canDownload = true;
|
|
}
|
|
}
|
|
|
|
get formattedStartDate() {
|
|
if (!this.args.startTimestamp) return null;
|
|
return parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy');
|
|
}
|
|
|
|
get formattedEndDate() {
|
|
if (!this.args.endTimestamp) return null;
|
|
return parseAPITimestamp(this.args.endTimestamp, 'MMMM yyyy');
|
|
}
|
|
|
|
get showEndDate() {
|
|
// displays on CSV export modal, no need to display duplicate months and years
|
|
if (!this.args.endTimestamp) return false;
|
|
const startDateObject = parseAPITimestamp(this.args.startTimestamp);
|
|
const endDateObject = parseAPITimestamp(this.args.endTimestamp);
|
|
return !isSameMonth(startDateObject, endDateObject);
|
|
}
|
|
|
|
get formattedCsvFileName() {
|
|
const endRange = this.showEndDate ? `-${this.formattedEndDate}` : '';
|
|
const csvDateRange = this.formattedStartDate ? `_${this.formattedStartDate + endRange}` : '';
|
|
const ns = this.namespaceFilter ? `_${this.namespaceFilter}` : '';
|
|
return `clients_export${ns}${csvDateRange}`;
|
|
}
|
|
|
|
get namespaceFilter() {
|
|
const currentNs = this.namespace.path;
|
|
const { namespace } = this.args;
|
|
return namespace ? sanitizePath(`${currentNs}/${namespace}`) : sanitizePath(currentNs);
|
|
}
|
|
|
|
get showCommunity() {
|
|
return this.version.isCommunity && !!this.formattedStartDate && !!this.formattedEndDate;
|
|
}
|
|
|
|
async getExportData() {
|
|
const adapter = this.store.adapterFor('clients/activity');
|
|
const { startTimestamp, endTimestamp } = this.args;
|
|
return adapter.exportData({
|
|
// the API only accepts json or csv
|
|
format: this.exportFormat === 'jsonl' ? 'json' : 'csv',
|
|
start_time: startTimestamp,
|
|
end_time: endTimestamp,
|
|
namespace: this.namespaceFilter,
|
|
});
|
|
}
|
|
|
|
parseAPITimestamp = (timestamp, format) => {
|
|
return parseAPITimestamp(timestamp, format);
|
|
};
|
|
|
|
exportChartData = task({ drop: true }, async (filename) => {
|
|
try {
|
|
const contents = await this.getExportData();
|
|
this.download.download(filename, contents, this.exportFormat);
|
|
this.showExportModal = false;
|
|
} catch (e) {
|
|
this.downloadError = e.message;
|
|
}
|
|
});
|
|
|
|
@action
|
|
setExportFormat(evt) {
|
|
const { value } = evt.target;
|
|
this.exportFormat = value;
|
|
}
|
|
|
|
@action
|
|
resetModal() {
|
|
this.showExportModal = false;
|
|
this.downloadError = '';
|
|
}
|
|
|
|
@action
|
|
setEditModalVisible(visible) {
|
|
this.showEditModal = visible;
|
|
}
|
|
}
|