diff --git a/changelog/_10728.txt b/changelog/_10728.txt new file mode 100644 index 0000000000..ea7403ddc4 --- /dev/null +++ b/changelog/_10728.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui/activity (enterprise): Allow manual querying of client usage if there is a problem retrieving the license start time. +``` \ No newline at end of file diff --git a/ui/app/components/clients/date-range.hbs b/ui/app/components/clients/date-range.hbs index cd68b94cb2..5aef1d2db6 100644 --- a/ui/app/components/clients/date-range.hbs +++ b/ui/app/components/clients/date-range.hbs @@ -5,7 +5,8 @@
- {{#if this.version.isEnterprise}} + {{! Enterprise should always have a @billingStartTime but as a fallback allow the user to query dates manually }} + {{#if (and @billingStartTime this.version.isEnterprise)}} {{if this.flags.isHvdManaged "Change data period" "Change billing period"}} @@ -34,17 +35,15 @@ {{/each}} {{/if}} - {{else}} - {{! Hide if the user has made an initial query because dates can be updated by clicking "Edit" beside the date range }} - {{#unless (and @startTimestamp @endTimestamp)}} - - {{/unless}} + {{else if (not (and @startTimestamp @endTimestamp))}} + {{! Hide if the user has already made an initial query because dates can be updated by clicking "Edit" beside the date range }} + {{/if}}
@@ -54,62 +53,61 @@ Edit date range - + {{#if this.version.isCommunity}}

Use custom date ranges to query historic client count data. Query results do not include the current month.

-
    -
  • - Start - sets the month and year (inclusive) for the first month of client counting. -
  • -
  • - End - sets the month and year (inclusive) for the final month of client counting. -
  • -
-

- We recommend setting + {{/if}} +

    +
  • Start - to your Vault deploy date to get the most accurate new and total client count estimations.

    - -
    -
    - - Start - -
    -
    - - End - -
    + sets the month and year (inclusive) for the first month of client counting. +
  • +
  • + End + sets the month and year (inclusive) for the final month of client counting. +
  • +
+

+ We recommend setting + Start + to your Vault deploy date to get the most accurate client counts.

+
+
+ + Start +
- {{#if this.validationError}} - {{this.validationError}} - {{/if}} - +
+ + End + +
+
+ {{#if this.validationError}} + {{this.validationError}} + {{/if}}
diff --git a/ui/app/components/clients/date-range.ts b/ui/app/components/clients/date-range.ts index 407927f6d2..671b67115b 100644 --- a/ui/app/components/clients/date-range.ts +++ b/ui/app/components/clients/date-range.ts @@ -86,7 +86,8 @@ export default class ClientsDateRangeComponent extends Component { if (this.modalStart > this.modalEnd) { return 'Start date must be before end date.'; } - if (this.modalStart > this.previousMonth || this.modalEnd > this.previousMonth) { + 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; diff --git a/ui/app/components/clients/page-header.hbs b/ui/app/components/clients/page-header.hbs index 31f8213586..6a852880c8 100644 --- a/ui/app/components/clients/page-header.hbs +++ b/ui/app/components/clients/page-header.hbs @@ -23,22 +23,21 @@ /> {{/if}} - {{#if this.version.isEnterprise}} - -

- {{if this.flags.isHvdManaged "For data period:" "For billing period:"}} + + {{#if (and this.version.isEnterprise @billingStartTime)}} + {{! Enterprise should always have a @billingStartTime but as a fallback allow the user to query dates manually. }} + {{! A dropdown renders in Clients::DateRange to query specific dates if we have a @billingStartTime }} +

+ {{if this.flags.isHvdManaged "For data period: " "For billing period: "}} {{this.formattedStartDate}} - {{this.formattedEndDate}}

-
- {{/if}} - - {{#if this.showCommunity}} + {{else if (and @startTimestamp @endTimestamp)}} + {{! If these timestamps exist an initial query has already been made using the modal in Clients::DateRange }}
Client counting period - Specify a date range to view within that timeframe. Click 'Edit' to - choose a different date range. + Click 'Edit' to select a different date range. {{this.formattedStartDate}} - diff --git a/ui/app/components/clients/page-header.js b/ui/app/components/clients/page-header.js index 20204f28f6..f110c723b0 100644 --- a/ui/app/components/clients/page-header.js +++ b/ui/app/components/clients/page-header.js @@ -95,10 +95,6 @@ export default class ClientsPageHeaderComponent extends Component { return `clients_export${ns}${csvDateRange}`; } - get showCommunity() { - return this.version.isCommunity && !!this.formattedStartDate && !!this.formattedEndDate; - } - async getExportData() { const adapter = this.store.adapterFor('clients/activity'); const { startTimestamp, endTimestamp } = this.args; diff --git a/ui/app/components/clients/page/counts.ts b/ui/app/components/clients/page/counts.ts index 260eb395c7..fe60de6992 100644 --- a/ui/app/components/clients/page/counts.ts +++ b/ui/app/components/clients/page/counts.ts @@ -39,7 +39,10 @@ export default class ClientsCountsPageComponent extends Component { } get formattedBillingStartDate() { - return this.args.config.billingStartTimestamp.toISOString(); + if (this.args.config?.billingStartTimestamp) { + return this.args.config.billingStartTimestamp.toISOString(); + } + return null; } // passed into page-header for the export modal alert diff --git a/ui/app/components/clients/page/overview.ts b/ui/app/components/clients/page/overview.ts index ead01fd548..1fcbeba765 100644 --- a/ui/app/components/clients/page/overview.ts +++ b/ui/app/components/clients/page/overview.ts @@ -28,7 +28,7 @@ export default class ClientsOverviewPageComponent extends Component { get byMonthClients() { // HVD clusters are billed differently and the monthly total is the important metric. if (this.flags.isHvdManaged) { - return this.args.activity.byMonth; + return this.args.activity.byMonth || []; } // For self-managed clusters only the new_clients per month are relevant because clients accumulate over a billing period. // (Since "total" per month is not cumulative it's not a useful metric) @@ -36,6 +36,7 @@ export default class ClientsOverviewPageComponent extends Component { } // Supplies data passed to dropdown filters (except months which is computed below ) + @cached get activityData() { // If no month is selected the table displays all of the activity for the queried date range. const selectedMonth = this.args.filterQueryParams.month; @@ -49,9 +50,12 @@ export default class ClientsOverviewPageComponent extends Component { @cached get months() { - return this.byMonthClients.map((m) => m.timestamp).reverse(); + const timestamps = this.byMonthClients.map((m) => m.timestamp); + // display the most recent month at the top of the dropdown + return timestamps.reverse(); } + @cached get tableData() { if (this.activityData?.length) { // Reset the `month` query param because it determines which dataset (see this.activityData) diff --git a/ui/tests/integration/components/clients/date-range-test.js b/ui/tests/integration/components/clients/date-range-test.js index fb267af3a0..ac5633802b 100644 --- a/ui/tests/integration/components/clients/date-range-test.js +++ b/ui/tests/integration/components/clients/date-range-test.js @@ -18,6 +18,7 @@ module('Integration | Component | clients/date-range', function (hooks) { setupRenderingTest(hooks); hooks.beforeEach(function () { + this.version = this.owner.lookup('service:version'); Sinon.replace(timestamp, 'now', Sinon.fake.returns(new Date('2018-04-03T14:15:30'))); this.now = timestamp.now(); this.startTimestamp = '2018-01-01T14:15:30'; @@ -36,6 +37,11 @@ module('Integration | Component | clients/date-range', function (hooks) { }; }); + test('it does not render if a start and end timestamp are already provided', async function (assert) { + await this.renderComponent(); + assert.dom(DATE_RANGE.edit).doesNotExist('it does not render if timestamps are provided'); + }); + test('it formats modal inputs to ISO string timestamps', async function (assert) { this.startTimestamp = undefined; await this.renderComponent(); @@ -80,7 +86,7 @@ module('Integration | Component | clients/date-range', function (hooks) { }); test('it does not allow the current month to be selected as a start date or as an end date', async function (assert) { - this.owner.lookup('service:version').type = 'community'; + this.version.type = 'community'; this.endTimestamp = undefined; const currentMonth = format(timestamp.now(), 'yyyy-MM'); @@ -91,7 +97,7 @@ module('Integration | Component | clients/date-range', function (hooks) { assert.dom(DATE_RANGE.validation).hasText('You cannot select the current month or beyond.'); await click(GENERAL.submitButton); - assert.false(this.onChange.called); + assert.false(this.onChange.called, 'it does not call @onChange callback'); // This tests validation when the end date is the current month and start is valid. // If start is current month and end is a valid prior selection, it will run into the validation error of start being after end date @@ -99,7 +105,22 @@ module('Integration | Component | clients/date-range', function (hooks) { await fillIn(DATE_RANGE.editDate('start'), '2018-01'); await fillIn(DATE_RANGE.editDate('end'), currentMonth); await click(GENERAL.submitButton); - assert.false(this.onChange.called); + assert.false(this.onChange.called, 'it does not call @onChange callback'); + }); + + test('it allows the current month to be selected if enterprise and there is not a @billingStartTime', async function (assert) { + this.version.type = 'enterprise'; + this.endTimestamp = undefined; + const currentMonth = format(timestamp.now(), 'yyyy-MM'); + + await this.renderComponent(); + await click(DATE_RANGE.edit); + await fillIn(DATE_RANGE.editDate('start'), currentMonth); + await fillIn(DATE_RANGE.editDate('end'), currentMonth); + + assert.dom(DATE_RANGE.validation).doesNotExist(); + await click(GENERAL.submitButton); + assert.true(this.onChange.called, 'it calls @onChange callback'); }); module('enterprise', function (hooks) { @@ -126,6 +147,19 @@ module('Integration | Component | clients/date-range', function (hooks) { }); }); + test('it renders date range modal if there are no timestamps provided', async function (assert) { + this.billingStartTime = ''; + this.startTimestamp = ''; + this.endTimestamp = ''; + await this.renderComponent(); + assert + .dom(DATE_RANGE.edit) + .exists('it renders button to open date range modal') + .hasText('Set date range'); + await click(DATE_RANGE.edit); + assert.dom(DATE_RANGE.editModal).exists(); + }); + test('it updates toggle text when a new date is selected', async function (assert) { this.onChange = ({ start_time }) => this.set('startTimestamp', start_time); diff --git a/ui/tests/integration/components/clients/page-header-test.js b/ui/tests/integration/components/clients/page-header-test.js index 5928196217..184546d957 100644 --- a/ui/tests/integration/components/clients/page-header-test.js +++ b/ui/tests/integration/components/clients/page-header-test.js @@ -25,6 +25,7 @@ module('Integration | Component | clients/page-header', function (hooks) { this.downloadStub = Sinon.stub(this.owner.lookup('service:download'), 'download'); this.startTimestamp = '2022-06-01T23:00:11.050Z'; this.endTimestamp = '2022-12-01T23:00:11.050Z'; + this.billingStartTime = this.startTimestamp; this.upgradesDuringActivity = []; this.noData = undefined; this.server.post('/sys/capabilities-self', () => @@ -34,7 +35,7 @@ module('Integration | Component | clients/page-header', function (hooks) { this.renderComponent = async () => { return render(hbs`