mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
UI/Client counts view if no license (#13964)
* adds date picker if no license start date found * handle permissions denied for license endpoint * handle permissions errors if no license start date * change empty state copy for OSS * fix tests and empty state view * update nav links * remove ternary Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> * simplify hbs boolean Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> * organize history file * organize current file * rerun tests * fix conditional to show attribution chart * match main Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
This commit is contained in:
@@ -4,32 +4,25 @@ import { formatRFC3339 } from 'date-fns';
|
|||||||
export default Application.extend({
|
export default Application.extend({
|
||||||
formatTimeParams(query) {
|
formatTimeParams(query) {
|
||||||
let { start_time, end_time } = query;
|
let { start_time, end_time } = query;
|
||||||
// do not query without start_time. Otherwise returns last year data, which is not reflective of billing data.
|
// check if it's an array, if it is, it's coming from an action like selecting a new startTime or new EndTime
|
||||||
if (start_time) {
|
if (Array.isArray(start_time)) {
|
||||||
// check if it's an array, if it is, it's coming from an action like selecting a new startTime or new EndTime
|
let startYear = Number(start_time[0]);
|
||||||
if (Array.isArray(start_time)) {
|
let startMonth = Number(start_time[1]);
|
||||||
let startYear = Number(start_time[0]);
|
start_time = formatRFC3339(new Date(startYear, startMonth));
|
||||||
let startMonth = Number(start_time[1]);
|
}
|
||||||
start_time = formatRFC3339(new Date(startYear, startMonth));
|
if (end_time) {
|
||||||
|
if (Array.isArray(end_time)) {
|
||||||
|
let endYear = Number(end_time[0]);
|
||||||
|
let endMonth = Number(end_time[1]);
|
||||||
|
end_time = formatRFC3339(new Date(endYear, endMonth));
|
||||||
}
|
}
|
||||||
if (end_time) {
|
|
||||||
if (Array.isArray(end_time)) {
|
|
||||||
let endYear = Number(end_time[0]);
|
|
||||||
let endMonth = Number(end_time[1]);
|
|
||||||
end_time = formatRFC3339(new Date(endYear, endMonth));
|
|
||||||
}
|
|
||||||
|
|
||||||
return { start_time, end_time };
|
return { start_time, end_time };
|
||||||
} else {
|
|
||||||
return { start_time };
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// did not have a start time, return null through to component.
|
return { start_time };
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ARG TODO current Month tab is hitting this endpoint. Need to amend so only hit on Monthly history (large payload)
|
|
||||||
// query comes in as either: {start_time: '2021-03-17T00:00:00Z'} or
|
// query comes in as either: {start_time: '2021-03-17T00:00:00Z'} or
|
||||||
// {start_time: Array(2), end_time: Array(2)}
|
// {start_time: Array(2), end_time: Array(2)}
|
||||||
// end_time: (2) ['2022', 0]
|
// end_time: (2) ['2022', 0]
|
||||||
@@ -44,9 +37,6 @@ export default Application.extend({
|
|||||||
response.id = response.request_id || 'no-data';
|
response.id = response.request_id || 'no-data';
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
// did not have a start time, return null through to component.
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,18 +7,28 @@ export default class Current extends Component {
|
|||||||
{ key: 'entity_clients', label: 'entity clients' },
|
{ key: 'entity_clients', label: 'entity clients' },
|
||||||
{ key: 'non_entity_clients', label: 'non-entity clients' },
|
{ key: 'non_entity_clients', label: 'non-entity clients' },
|
||||||
];
|
];
|
||||||
|
@tracked firstUpgradeVersion = this.args.model.versionHistory[0].id || null; // return 1.9.0 or earliest upgrade post 1.9.0
|
||||||
|
@tracked upgradeDate = this.args.model.versionHistory[0].timestampInstalled || null; // returns RFC3339 timestamp
|
||||||
|
|
||||||
@tracked selectedNamespace = null;
|
@tracked selectedNamespace = null;
|
||||||
@tracked namespaceArray = this.byNamespaceCurrent.map((namespace) => {
|
@tracked namespaceArray = this.byNamespaceCurrent.map((namespace) => {
|
||||||
return { name: namespace['label'], id: namespace['label'] };
|
return { name: namespace['label'], id: namespace['label'] };
|
||||||
});
|
});
|
||||||
@tracked firstUpgradeVersion = this.args.model.versionHistory[0].id || null; // return 1.9.0 or earliest upgrade post 1.9.0
|
|
||||||
@tracked upgradeDate = this.args.model.versionHistory[0].timestampInstalled || null; // returns RFC3339 timestamp
|
|
||||||
|
|
||||||
// API client count data by namespace for current/partial month
|
// Response client count data by namespace for current/partial month
|
||||||
get byNamespaceCurrent() {
|
get byNamespaceCurrent() {
|
||||||
return this.args.model.monthly?.byNamespace || [];
|
return this.args.model.monthly?.byNamespace || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isGatheringData() {
|
||||||
|
// return true if tracking IS enabled but no data collected yet
|
||||||
|
return this.args.model.config?.enabled === 'On' && this.byNamespaceCurrent.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAttributionData() {
|
||||||
|
return this.totalUsageCounts.clients !== 0 && this.totalClientsData.length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
get countsIncludeOlderData() {
|
get countsIncludeOlderData() {
|
||||||
let firstUpgrade = this.args.model.versionHistory[0];
|
let firstUpgrade = this.args.model.versionHistory[0];
|
||||||
if (!firstUpgrade) {
|
if (!firstUpgrade) {
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import { action } from '@ember/object';
|
|||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { isSameMonth, isAfter } from 'date-fns';
|
import { isSameMonth, isAfter } from 'date-fns';
|
||||||
|
|
||||||
export default class History extends Component {
|
export default class History extends Component {
|
||||||
// TODO CMB alphabetize and delete unused vars (particularly @tracked)
|
@service store;
|
||||||
|
@service version;
|
||||||
|
|
||||||
arrayOfMonths = [
|
arrayOfMonths = [
|
||||||
'January',
|
'January',
|
||||||
'February',
|
'February',
|
||||||
@@ -26,7 +27,7 @@ export default class History extends Component {
|
|||||||
{ key: 'non_entity_clients', label: 'non-entity clients' },
|
{ key: 'non_entity_clients', label: 'non-entity clients' },
|
||||||
];
|
];
|
||||||
|
|
||||||
// needed for startTime modal picker
|
// FOR START DATE EDIT & MODAL //
|
||||||
months = Array.from({ length: 12 }, (item, i) => {
|
months = Array.from({ length: 12 }, (item, i) => {
|
||||||
return new Date(0, i).toLocaleString('en-US', { month: 'long' });
|
return new Date(0, i).toLocaleString('en-US', { month: 'long' });
|
||||||
});
|
});
|
||||||
@@ -34,33 +35,43 @@ export default class History extends Component {
|
|||||||
return new Date().getFullYear() - i;
|
return new Date().getFullYear() - i;
|
||||||
});
|
});
|
||||||
|
|
||||||
@service store;
|
|
||||||
|
|
||||||
@tracked queriedActivityResponse = null;
|
|
||||||
@tracked barChartSelection = false;
|
|
||||||
@tracked isEditStartMonthOpen = false;
|
@tracked isEditStartMonthOpen = false;
|
||||||
@tracked responseRangeDiffMessage = null;
|
|
||||||
@tracked startTimeRequested = null;
|
|
||||||
@tracked startTimeFromResponse = this.args.model.startTimeFromLicense; // ex: ['2021', 3] is April 2021 (0 indexed)
|
|
||||||
@tracked endTimeFromResponse = this.args.model.endTimeFromResponse;
|
|
||||||
@tracked startMonth = null;
|
@tracked startMonth = null;
|
||||||
@tracked startYear = null;
|
@tracked startYear = null;
|
||||||
|
|
||||||
|
// FOR HISTORY COMPONENT //
|
||||||
|
|
||||||
|
// RESPONSE
|
||||||
|
@tracked endTimeFromResponse = this.args.model.endTimeFromResponse;
|
||||||
|
@tracked startTimeFromResponse = this.args.model.startTimeFromLicense; // ex: ['2021', 3] is April 2021 (0 indexed)
|
||||||
|
@tracked startTimeRequested = null;
|
||||||
|
@tracked queriedActivityResponse = null;
|
||||||
|
|
||||||
|
// VERSION/UPGRADE INFO
|
||||||
|
@tracked firstUpgradeVersion = this.args.model.versionHistory[0].id || null; // return 1.9.0 or earliest upgrade post 1.9.0
|
||||||
|
@tracked upgradeDate = this.args.model.versionHistory[0].timestampInstalled || null; // returns RFC3339 timestamp
|
||||||
|
|
||||||
|
// SEARCH SELECT
|
||||||
@tracked selectedNamespace = null;
|
@tracked selectedNamespace = null;
|
||||||
@tracked noActivityDate = '';
|
|
||||||
@tracked namespaceArray = this.getActivityResponse.byNamespace.map((namespace) => {
|
@tracked namespaceArray = this.getActivityResponse.byNamespace.map((namespace) => {
|
||||||
return { name: namespace['label'], id: namespace['label'] };
|
return { name: namespace['label'], id: namespace['label'] };
|
||||||
});
|
});
|
||||||
@tracked firstUpgradeVersion = this.args.model.versionHistory[0].id || null; // return 1.9.0 or earliest upgrade post 1.9.0
|
|
||||||
@tracked upgradeDate = this.args.model.versionHistory[0].timestampInstalled || null; // returns RFC3339 timestamp
|
// TEMPLATE MESSAGING
|
||||||
|
@tracked noActivityDate = '';
|
||||||
|
@tracked responseRangeDiffMessage = null;
|
||||||
|
|
||||||
// on init API response uses license start_date, getter updates when user queries dates
|
// on init API response uses license start_date, getter updates when user queries dates
|
||||||
get getActivityResponse() {
|
get getActivityResponse() {
|
||||||
return this.queriedActivityResponse || this.args.model.activity;
|
return this.queriedActivityResponse || this.args.model.activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasAttributionData() {
|
||||||
|
return this.totalUsageCounts.clients !== 0 && this.totalClientsData.length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
get startTimeDisplay() {
|
get startTimeDisplay() {
|
||||||
if (!this.startTimeFromResponse) {
|
if (!this.startTimeFromResponse) {
|
||||||
// otherwise will return date of new Date(null)
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let month = this.startTimeFromResponse[1];
|
let month = this.startTimeFromResponse[1];
|
||||||
@@ -70,7 +81,6 @@ export default class History extends Component {
|
|||||||
|
|
||||||
get endTimeDisplay() {
|
get endTimeDisplay() {
|
||||||
if (!this.endTimeFromResponse) {
|
if (!this.endTimeFromResponse) {
|
||||||
// otherwise will return date of new Date(null)
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let month = this.endTimeFromResponse[1];
|
let month = this.endTimeFromResponse[1];
|
||||||
@@ -120,7 +130,6 @@ export default class History extends Component {
|
|||||||
return isAfter(versionDate, startTimeFromResponseAsDateObject) ? versionDate : false;
|
return isAfter(versionDate, startTimeFromResponseAsDateObject) ? versionDate : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACTIONS
|
|
||||||
@action
|
@action
|
||||||
async handleClientActivityQuery(month, year, dateType) {
|
async handleClientActivityQuery(month, year, dateType) {
|
||||||
if (dateType === 'cancel') {
|
if (dateType === 'cancel') {
|
||||||
@@ -134,7 +143,7 @@ export default class History extends Component {
|
|||||||
// clicked "Edit" Billing start month in Dashboard which opens a modal.
|
// clicked "Edit" Billing start month in Dashboard which opens a modal.
|
||||||
if (dateType === 'startTime') {
|
if (dateType === 'startTime') {
|
||||||
let monthIndex = this.arrayOfMonths.indexOf(month);
|
let monthIndex = this.arrayOfMonths.indexOf(month);
|
||||||
this.startTimeRequested = [year.toString(), monthIndex]; // ['2021', 0] (e.g. January 2021) // TODO CHANGE TO ARRAY
|
this.startTimeRequested = [year.toString(), monthIndex]; // ['2021', 0] (e.g. January 2021)
|
||||||
this.endTimeRequested = null;
|
this.endTimeRequested = null;
|
||||||
}
|
}
|
||||||
// clicked "Custom End Month" from the calendar-widget
|
// clicked "Custom End Month" from the calendar-widget
|
||||||
@@ -173,7 +182,7 @@ export default class History extends Component {
|
|||||||
}
|
}
|
||||||
this.queriedActivityResponse = response;
|
this.queriedActivityResponse = response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ARG TODO handle error
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +197,7 @@ export default class History extends Component {
|
|||||||
this.selectedNamespace = value;
|
this.selectedNamespace = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FOR START DATE MODAL
|
||||||
@action
|
@action
|
||||||
selectStartMonth(month) {
|
selectStartMonth(month) {
|
||||||
this.startMonth = month;
|
this.startMonth = month;
|
||||||
@@ -198,7 +208,7 @@ export default class History extends Component {
|
|||||||
this.startYear = year;
|
this.startYear = year;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HELPERS
|
// HELPERS //
|
||||||
filterByNamespace(namespace) {
|
filterByNamespace(namespace) {
|
||||||
return this.getActivityResponse.byNamespace.find((ns) => ns.label === namespace);
|
return this.getActivityResponse.byNamespace.find((ns) => ns.label === namespace);
|
||||||
}
|
}
|
||||||
|
|||||||
37
ui/app/components/date-dropdown.js
Normal file
37
ui/app/components/date-dropdown.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module DateDropdown
|
||||||
|
* DateDropdown components are used to display a dropdown of months and years to handle date selection
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* <DateDropdown @handleDateSelection={this.actionFromParent} @name={{"startTime"}}/>
|
||||||
|
* ```
|
||||||
|
* @param {function} handleDateSelection - is the action from the parent that the date picker triggers
|
||||||
|
* @param {string} [name] - optional argument passed from date dropdown to parent function
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class DateDropdown extends Component {
|
||||||
|
@tracked startMonth = null;
|
||||||
|
@tracked startYear = null;
|
||||||
|
|
||||||
|
months = Array.from({ length: 12 }, (item, i) => {
|
||||||
|
return new Date(0, i).toLocaleString('en-US', { month: 'long' });
|
||||||
|
});
|
||||||
|
years = Array.from({ length: 5 }, (item, i) => {
|
||||||
|
return new Date().getFullYear() - i;
|
||||||
|
});
|
||||||
|
|
||||||
|
@action
|
||||||
|
selectStartMonth(month) {
|
||||||
|
this.startMonth = month;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
selectStartYear(year) {
|
||||||
|
this.startYear = year;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,19 +5,24 @@ import { action } from '@ember/object';
|
|||||||
export default class HistoryRoute extends Route {
|
export default class HistoryRoute extends Route {
|
||||||
async getActivity(start_time) {
|
async getActivity(start_time) {
|
||||||
try {
|
try {
|
||||||
return this.store.queryRecord('clients/activity', { start_time });
|
// on init ONLY make network request if we have a start time from the license
|
||||||
|
// otherwise user needs to manually input
|
||||||
|
return start_time
|
||||||
|
? await this.store.queryRecord('clients/activity', { start_time })
|
||||||
|
: { endTime: null };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ARG TODO handle
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLicense() {
|
async getLicenseStartTime() {
|
||||||
try {
|
try {
|
||||||
return this.store.queryRecord('license', {});
|
let license = await this.store.queryRecord('license', {});
|
||||||
|
// if license.startTime is 'undefined' return 'null' for consistency
|
||||||
|
return license.startTime || null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ARG TODO handle
|
// if error due to permission denied, return null so user can input date manually
|
||||||
return e;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,18 +53,18 @@ export default class HistoryRoute extends Route {
|
|||||||
|
|
||||||
async model() {
|
async model() {
|
||||||
let config = await this.store.queryRecord('clients/config', {}).catch((e) => {
|
let config = await this.store.queryRecord('clients/config', {}).catch((e) => {
|
||||||
console.debug(e);
|
|
||||||
// swallowing error so activity can show if no config permissions
|
// swallowing error so activity can show if no config permissions
|
||||||
|
console.debug(e);
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
let license = await this.getLicense();
|
let licenseStart = await this.getLicenseStartTime();
|
||||||
let activity = await this.getActivity(license.startTime);
|
let activity = await this.getActivity(licenseStart);
|
||||||
|
|
||||||
return RSVP.hash({
|
return RSVP.hash({
|
||||||
config,
|
config,
|
||||||
activity,
|
activity,
|
||||||
startTimeFromLicense: this.parseRFC3339(license.startTime),
|
startTimeFromLicense: this.parseRFC3339(licenseStart),
|
||||||
endTimeFromResponse: activity ? this.parseRFC3339(activity.endTime) : null,
|
endTimeFromResponse: this.parseRFC3339(activity?.endTime),
|
||||||
versionHistory: this.getVersionHistory(),
|
versionHistory: this.getVersionHistory(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,46 +13,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if (eq @totalUsageCounts.clients 0)}}
|
<div class="chart-container-wide">
|
||||||
<div class="chart-empty-state">
|
<Clients::HorizontalBarChart
|
||||||
<EmptyState
|
@dataset={{this.barChartTotalClients}}
|
||||||
@title="No data received"
|
@chartLegend={{@chartLegend}}
|
||||||
@message="Tracking is turned on and Vault is gathering data. It should appear here within 30 minutes."
|
@totalUsageCounts={{@totalUsageCounts}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
|
||||||
<div class="chart-container-wide">
|
|
||||||
<Clients::HorizontalBarChart
|
|
||||||
@dataset={{this.barChartTotalClients}}
|
|
||||||
@chartLegend={{@chartLegend}}
|
|
||||||
@totalUsageCounts={{@totalUsageCounts}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chart-subTitle">
|
<div class="chart-subTitle">
|
||||||
<p class="chart-subtext">{{this.chartText.totalCopy}}</p>
|
<p class="chart-subtext">{{this.chartText.totalCopy}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="data-details-top">
|
<div class="data-details-top">
|
||||||
<h3 class="data-details">Top {{this.attributionBreakdown}}</h3>
|
<h3 class="data-details">Top {{this.attributionBreakdown}}</h3>
|
||||||
<p class="data-details">{{this.topClientCounts.label}}</p>
|
<p class="data-details">{{this.topClientCounts.label}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="data-details-bottom">
|
<div class="data-details-bottom">
|
||||||
<h3 class="data-details">Clients in {{this.attributionBreakdown}}</h3>
|
<h3 class="data-details">Clients in {{this.attributionBreakdown}}</h3>
|
||||||
<p class="data-details">{{format-number this.topClientCounts.clients}}</p>
|
<p class="data-details">{{format-number this.topClientCounts.clients}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timestamp">
|
<div class="timestamp">
|
||||||
Updated
|
Updated
|
||||||
{{date-format @timestamp "MMM dd yyyy, h:mm:ss aaa"}}
|
{{date-format @timestamp "MMM dd yyyy, h:mm:ss aaa"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="legend-center">
|
<div class="legend-center">
|
||||||
<span class="light-dot"></span><span class="legend-label">{{capitalize @chartLegend.0.label}}</span>
|
<span class="light-dot"></span><span class="legend-label">{{capitalize @chartLegend.0.label}}</span>
|
||||||
<span class="dark-dot"></span><span class="legend-label">{{capitalize @chartLegend.1.label}}</span>
|
<span class="dark-dot"></span><span class="legend-label">{{capitalize @chartLegend.1.label}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{! MODAL FOR CSV DOWNLOAD }}
|
{{! MODAL FOR CSV DOWNLOAD }}
|
||||||
|
|||||||
@@ -13,6 +13,11 @@
|
|||||||
</LinkTo>
|
</LinkTo>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
|
{{else if this.isGatheringData}}
|
||||||
|
<EmptyState
|
||||||
|
@title="No data received"
|
||||||
|
@message="Tracking is turned on and Vault is gathering data. It should appear here within 30 minutes."
|
||||||
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="is-subtitle-gray has-bottom-margin-m">
|
<div class="is-subtitle-gray has-bottom-margin-m">
|
||||||
FILTERS
|
FILTERS
|
||||||
@@ -48,7 +53,7 @@
|
|||||||
@title={{date-format this.responseTimestamp "MMMM"}}
|
@title={{date-format this.responseTimestamp "MMMM"}}
|
||||||
@totalUsageCounts={{this.totalUsageCounts}}
|
@totalUsageCounts={{this.totalUsageCounts}}
|
||||||
/>
|
/>
|
||||||
{{#if this.totalClientsData}}
|
{{#if this.hasAttributionData}}
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientsData={{this.totalClientsData}}
|
@totalClientsData={{this.totalClientsData}}
|
||||||
@@ -59,8 +64,6 @@
|
|||||||
@timestamp={{this.responseTimestamp}}
|
@timestamp={{this.responseTimestamp}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
|
||||||
<EmptyState @title={{concat "No partial history"}} @message="There is no data in the current month yet." />
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -8,10 +8,14 @@
|
|||||||
Billing start month
|
Billing start month
|
||||||
</h1>
|
</h1>
|
||||||
<div data-test-start-date-editor class="is-flex-align-baseline">
|
<div data-test-start-date-editor class="is-flex-align-baseline">
|
||||||
<p class="is-size-6">{{this.startTimeDisplay}}</p>
|
{{#if this.startTimeDisplay}}
|
||||||
<button type="button" class="button is-link" {{on "click" (fn (mut this.isEditStartMonthOpen) true)}}>
|
<p class="is-size-6">{{this.startTimeDisplay}}</p>
|
||||||
Edit
|
<button type="button" class="button is-link" {{on "click" (fn (mut this.isEditStartMonthOpen) true)}}>
|
||||||
</button>
|
Edit
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
<DateDropdown @handleDateSelection={{this.handleClientActivityQuery}} @name={{"startTime"}} />
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<p class="is-8 has-text-grey has-bottom-margin-xl">
|
<p class="is-8 has-text-grey has-bottom-margin-xl">
|
||||||
This date comes from your license, and defines when client counting starts. Without this starting point, the data shown
|
This date comes from your license, and defines when client counting starts. Without this starting point, the data shown
|
||||||
@@ -106,7 +110,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
{{#if this.totalUsageCounts}}
|
{{#if this.totalUsageCounts}}
|
||||||
<Clients::UsageStats @title="Total usage" @totalUsageCounts={{this.totalUsageCounts}} />
|
<Clients::UsageStats @title="Total usage" @totalUsageCounts={{this.totalUsageCounts}} />
|
||||||
{{#if this.totalClientsData}}
|
{{#if this.hasAttributionData}}
|
||||||
<Clients::Attribution
|
<Clients::Attribution
|
||||||
@chartLegend={{this.chartLegend}}
|
@chartLegend={{this.chartLegend}}
|
||||||
@totalClientsData={{this.totalClientsData}}
|
@totalClientsData={{this.totalClientsData}}
|
||||||
@@ -123,10 +127,17 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
{{#if this.version.isEnterprise}}
|
||||||
@title="No billing start date found"
|
<EmptyState
|
||||||
@message="In order to get the most from this data, please enter your billing period start month. This will ensure that the resulting data is accurate."
|
@title="No billing start date found"
|
||||||
/>
|
@message="In order to get the most from this data, please enter your billing period start month. This will ensure that the resulting data is accurate."
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<EmptyState
|
||||||
|
@title="No start date found"
|
||||||
|
@message="In order to get the most from this data, please enter a start month above. Vault will calculate new clients starting from that month."
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@
|
|||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li class="action">
|
<li class="action">
|
||||||
{{! template-lint-disable no-unknown-arguments-for-builtin-components }}
|
{{! template-lint-disable no-unknown-arguments-for-builtin-components }}
|
||||||
<LinkTo @route="vault.cluster.clients" @query={{hash tab="current"}} @invokeAction={{@onLinkClick}}>
|
<LinkTo @route="vault.cluster.clients.index" @invokeAction={{@onLinkClick}}>
|
||||||
<div class="level is-mobile">
|
<div class="level is-mobile">
|
||||||
<span class="level-left">Client count</span>
|
<span class="level-left">Client count</span>
|
||||||
<Chevron class="has-text-grey-light level-right" />
|
<Chevron class="has-text-grey-light level-right" />
|
||||||
|
|||||||
54
ui/app/templates/components/date-dropdown.hbs
Normal file
54
ui/app/templates/components/date-dropdown.hbs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
|
||||||
|
<D.Trigger
|
||||||
|
data-test-popup-menu-trigger="true"
|
||||||
|
class={{concat "toolbar-link" (if D.isOpen " is-active")}}
|
||||||
|
@htmlTag="button"
|
||||||
|
>
|
||||||
|
{{or this.startMonth "Month"}}
|
||||||
|
<Chevron @direction="down" @isButton={{true}} />
|
||||||
|
</D.Trigger>
|
||||||
|
<D.Content class="popup-menu-content is-wide">
|
||||||
|
<nav class="box menu scroll">
|
||||||
|
<ul class="menu-list">
|
||||||
|
{{#each this.months as |month|}}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="link"
|
||||||
|
{{on "click" (queue (fn this.selectStartMonth month) (action D.actions.close))}}
|
||||||
|
>
|
||||||
|
{{month}}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</D.Content>
|
||||||
|
</BasicDropdown>
|
||||||
|
<BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
|
||||||
|
<D.Trigger
|
||||||
|
data-test-popup-menu-trigger="true"
|
||||||
|
class={{concat "toolbar-link" (if D.isOpen " is-active")}}
|
||||||
|
@htmlTag="button"
|
||||||
|
>
|
||||||
|
{{or this.startYear "Year"}}
|
||||||
|
<Chevron @direction="down" @isButton={{true}} />
|
||||||
|
</D.Trigger>
|
||||||
|
<D.Content class="popup-menu-content is-wide">
|
||||||
|
<nav class="box menu">
|
||||||
|
<ul class="menu-list">
|
||||||
|
{{#each this.years as |year|}}
|
||||||
|
<button type="button" class="link" {{on "click" (queue (fn this.selectStartYear year) (action D.actions.close))}}>
|
||||||
|
{{year}}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</D.Content>
|
||||||
|
</BasicDropdown>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="button is-primary"
|
||||||
|
disabled={{if (and this.startMonth this.startYear) false true}}
|
||||||
|
{{on "click" (fn @handleDateSelection this.startMonth this.startYear @name)}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
@@ -76,9 +76,8 @@
|
|||||||
{{! template-lint-configure no-curly-component-invocation "warn" }}
|
{{! template-lint-configure no-curly-component-invocation "warn" }}
|
||||||
{{! template-lint-configure no-link-to-positional-params "warn" }}
|
{{! template-lint-configure no-link-to-positional-params "warn" }}
|
||||||
{{#link-to
|
{{#link-to
|
||||||
"vault.cluster.clients"
|
"vault.cluster.clients.history"
|
||||||
(query-params tab="history")
|
current-when="vault.cluster.clients.history"
|
||||||
current-when="vault.cluster.clients"
|
|
||||||
data-test-navbar-item="metrics"
|
data-test-navbar-item="metrics"
|
||||||
}}
|
}}
|
||||||
Client count
|
Client count
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
<Clients::Dashboard @model={{@model}} />
|
<Clients::Dashboard @model={{@model}} />
|
||||||
|
|
||||||
<Clients::History @model={{@model}} @isLoading={{this.currentlyLoading}} />
|
<Clients::History @model={{@model}} @isLoading={{this.currentlyLoading}} />
|
||||||
@@ -32,12 +32,13 @@ module('Integration | Component | client count current', function (hooks) {
|
|||||||
<div id="modal-wormhole"></div>
|
<div id="modal-wormhole"></div>
|
||||||
<Clients::Current @model={{this.model}} />`);
|
<Clients::Current @model={{this.model}} />`);
|
||||||
assert.dom('[data-test-component="empty-state"]').exists('Empty state exists');
|
assert.dom('[data-test-component="empty-state"]').exists('Empty state exists');
|
||||||
assert.dom('[data-test-empty-state-title]').hasText('No partial history');
|
assert.dom('[data-test-empty-state-title]').hasText('No data received');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it shows zeroed data when enabled but no counts', async function (assert) {
|
test('it shows zeroed data when enabled but no counts', async function (assert) {
|
||||||
Object.assign(this.model.config, { queriesAvailable: true, enabled: 'On' });
|
Object.assign(this.model.config, { queriesAvailable: true, enabled: 'On' });
|
||||||
Object.assign(this.model.monthly, {
|
Object.assign(this.model.monthly, {
|
||||||
|
byNamespace: [{ label: 'root', clients: 0, entity_clients: 0, non_entity_clients: 0 }],
|
||||||
total: { clients: 0, entity_clients: 0, non_entity_clients: 0 },
|
total: { clients: 0, entity_clients: 0, non_entity_clients: 0 },
|
||||||
});
|
});
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
|
|||||||
Reference in New Issue
Block a user