mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-28 04:10:44 -04:00
* updates flags service to use api service * converts clients index route to ts * updates clients config workflows to use api service * updates clients date-range component to handle Date objects rather than ISO strings * updates clients page-header component to handle Date objects and use api and capabilities services * updates clients route to use api and capabilities services * updates types in client-counts helpers * updates client counts route to use api service * updates types for client-counts serializers * updates date handling in client counts page component * updates clients overview page component * converts clients page-header component to ts * fixes type errors in clients page-header component * updates client counts tests * updates client-count-card component to use api service * converts client-count-card component to ts * removes model-form-fields test that uses clients/config model * removes clients/version-history model usage from client-counts helpers tests * removes migrated models from adapter and model registries * removes clients ember data models, adapters and serializers * updates clients date-range component to format dates in time zone * cleans up references to activityError in client counts route * adds clients/activity mirage model * updates activation flags assertions in sync overview tests * fixes issue selecting current period in clients date-range component and adds test * fixes issues with enabled state for client counts * updates parseAPITimestamp to handle date object formatting * removes unnecesarry type casting for format return in parseAPITimestamp util * updates parseAPITimestamp to use formatInTimeZone for strings * updates parseAPITimestamp comment * updates enabled value in clients config component to boolean * adds date-fns-tz to core addon * removes parseISO from date-formatters util in favor of new Date * updates comments for client counts * updates retention months validation for client counts config * updates comment and min retention months default for client counts config Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
159 lines
5.3 KiB
TypeScript
159 lines
5.3 KiB
TypeScript
/**
|
|
* Copyright IBM Corp. 2016, 2025
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import { action } from '@ember/object';
|
|
import { service } from '@ember/service';
|
|
import Component from '@glimmer/component';
|
|
import { tracked } from '@glimmer/tracking';
|
|
import { buildISOTimestamp, parseAPITimestamp } from 'core/utils/date-formatters';
|
|
import timestamp from 'core/utils/timestamp';
|
|
import { format } from 'date-fns';
|
|
|
|
import type FlagsService from 'vault/services/flags';
|
|
import type VersionService from 'vault/services/version';
|
|
import type { HTMLElementEvent } from 'forms';
|
|
|
|
interface OnChangeParams {
|
|
start_time: string;
|
|
end_time: string;
|
|
}
|
|
|
|
interface Args {
|
|
onChange: (callback: OnChangeParams) => void;
|
|
setEditModalVisible: (visible: boolean) => void;
|
|
showEditModal: boolean;
|
|
startTimestamp: Date;
|
|
endTimestamp: Date;
|
|
billingStartTime: Date;
|
|
retentionMonths: number;
|
|
}
|
|
/**
|
|
* @module ClientsDateRange
|
|
* ClientsDateRange components are used to display the current date range and provide a modal interface for editing the date range.
|
|
*
|
|
* @example
|
|
*
|
|
* <Clients::DateRange @startTimestamp="2018-01-01T14:15:30Z" @endTimestamp="2019-01-31T14:15:30Z" @onChange={{this.handleDateChange}} />
|
|
*
|
|
* @param {function} onChange - callback when a new range is saved.
|
|
* @param {function} setEditModalVisible - callback to tell parent header when modal is opened/closed
|
|
* @param {boolean} showEditModal - boolean for when parent header triggers the modal open
|
|
* @param {string} [startTimestamp] - ISO string timestamp of the start date for the displayed client count data
|
|
* @param {string} [endTimestamp] - ISO string timestamp of the end date for the displayed client count data
|
|
* @param {int} [retentionMonths=48] - number of months for historical billing
|
|
* @param {string} [billingStartTime] - ISO string timestamp of billing start date
|
|
*/
|
|
|
|
export default class ClientsDateRangeComponent extends Component<Args> {
|
|
@service declare readonly flags: FlagsService;
|
|
@service declare readonly version: VersionService;
|
|
|
|
@tracked modalStart = ''; // format yyyy-MM
|
|
@tracked modalEnd = ''; // format yyyy-MM
|
|
|
|
currentMonth = timestamp.now();
|
|
previousMonth = format(
|
|
new Date(this.currentMonth.getUTCFullYear(), this.currentMonth.getUTCMonth() - 1, 1),
|
|
'yyyy-MM'
|
|
);
|
|
|
|
constructor(owner: unknown, args: Args) {
|
|
super(owner, args);
|
|
this.setTrackedFromArgs();
|
|
}
|
|
|
|
get historicalBillingPeriods() {
|
|
// we want whole billing periods
|
|
const { billingStartTime } = this.args;
|
|
const totalMonths = this.args.retentionMonths || 48;
|
|
const count = Math.floor(totalMonths / 12);
|
|
const periods: Date[] = [];
|
|
|
|
for (let i = 1; i <= count; i++) {
|
|
const startDate = new Date(billingStartTime);
|
|
const utcYear = startDate.getUTCFullYear() - i;
|
|
startDate.setUTCFullYear(utcYear);
|
|
periods.push(startDate);
|
|
}
|
|
return periods;
|
|
}
|
|
|
|
get validationError() {
|
|
if (!this.modalStart || !this.modalEnd) {
|
|
return 'You must supply both start and end dates.';
|
|
}
|
|
if (this.modalStart > this.modalEnd) {
|
|
return 'Start date must be before end date.';
|
|
}
|
|
const isCurrentMonth = this.modalStart > this.previousMonth || this.modalEnd > this.previousMonth;
|
|
if (this.version.isCommunity && isCurrentMonth) {
|
|
return 'You cannot select the current month or beyond.';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@action onClose() {
|
|
// since the component never gets torn down, we have to manually re-set this on close
|
|
this.setTrackedFromArgs();
|
|
this.args.setEditModalVisible(false);
|
|
}
|
|
|
|
@action updateDate(evt: HTMLElementEvent<HTMLInputElement>) {
|
|
const { name, value } = evt.target;
|
|
this[name as 'modalStart' | 'modalEnd'] = value;
|
|
}
|
|
|
|
// used for CE date picker
|
|
@action handleSave() {
|
|
if (this.validationError) return;
|
|
const params: OnChangeParams = { start_time: '', end_time: '' };
|
|
|
|
if (this.modalStart) {
|
|
params.start_time = this.formatModalTimestamp(this.modalStart, false);
|
|
}
|
|
|
|
if (this.modalEnd) {
|
|
params.end_time = this.formatModalTimestamp(this.modalEnd, true);
|
|
}
|
|
|
|
this.args.onChange(params);
|
|
this.onClose();
|
|
}
|
|
|
|
@action
|
|
updateEnterpriseDateRange(start: Date, close: CallableFunction) {
|
|
// We do not send an end_time so the backend handles computing the expected billing period
|
|
const start_time = start ? start.toISOString() : '';
|
|
this.args.onChange({ start_time, end_time: '' });
|
|
close();
|
|
}
|
|
|
|
// HELPERS
|
|
formatModalTimestamp(modalValue: string, isEndDate: boolean) {
|
|
const [yearString, month] = modalValue.split('-');
|
|
const monthIdx = Number(month) - 1;
|
|
const year = Number(yearString);
|
|
return buildISOTimestamp({ monthIdx, year, isEndDate });
|
|
}
|
|
|
|
setTrackedFromArgs() {
|
|
if (this.args.startTimestamp) {
|
|
this.modalStart = this.formatDate(this.args.startTimestamp, 'yyyy-MM');
|
|
}
|
|
if (this.args.endTimestamp) {
|
|
this.modalEnd = this.formatDate(this.args.endTimestamp, 'yyyy-MM');
|
|
}
|
|
}
|
|
|
|
// TEMPLATE HELPERS
|
|
formatDate = (date: Date, displayFormat = 'MMMM yyyy') => parseAPITimestamp(date, displayFormat);
|
|
|
|
isSelected = (dropdownTimestamp: Date) => {
|
|
// Compare against this.args.startTimestamp because it's from the URL query param
|
|
// which is used to query the client count activity API.
|
|
const selectedStart = this.formatDate(this.args.startTimestamp);
|
|
return this.formatDate(dropdownTimestamp) === selectedStart;
|
|
};
|
|
}
|