mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
UI: fix undefined csv filename (#26485)
* fix undefined file name start date * add test coverage! * small copy changes * one last test! * add changelog;
This commit is contained in:
3
changelog/26485.txt
Normal file
3
changelog/26485.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
ui: fixes undefined start time in filename for downloaded client count attribution csv
|
||||||
|
```
|
||||||
@@ -99,13 +99,17 @@
|
|||||||
</p>
|
</p>
|
||||||
<p class="has-bottom-margin-s is-subtitle-gray">SELECTED DATE {{if this.formattedEndDate " RANGE"}}</p>
|
<p class="has-bottom-margin-s is-subtitle-gray">SELECTED DATE {{if this.formattedEndDate " RANGE"}}</p>
|
||||||
<p class="has-bottom-margin-s" data-test-export-date-range>
|
<p class="has-bottom-margin-s" data-test-export-date-range>
|
||||||
{{this.parseAPITimestamp @startTimestamp "MMMM yyyy"}}
|
{{this.formattedStartDate}}
|
||||||
{{if this.formattedEndDate "-"}}
|
{{if this.formattedEndDate "-"}}
|
||||||
{{this.formattedEndDate}}</p>
|
{{this.formattedEndDate}}</p>
|
||||||
</M.Body>
|
</M.Body>
|
||||||
<M.Footer as |F|>
|
<M.Footer as |F|>
|
||||||
<Hds::ButtonSet>
|
<Hds::ButtonSet>
|
||||||
<Hds::Button @text="Export" {{on "click" (fn this.exportChartData this.formattedCsvFileName)}} />
|
<Hds::Button
|
||||||
|
@text="Export"
|
||||||
|
{{on "click" (fn this.exportChartData this.formattedCsvFileName)}}
|
||||||
|
data-test-confirm-button
|
||||||
|
/>
|
||||||
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
<Hds::Button @text="Cancel" @color="secondary" {{on "click" F.close}} />
|
||||||
</Hds::ButtonSet>
|
</Hds::ButtonSet>
|
||||||
{{#if @upgradesDuringActivity}}
|
{{#if @upgradesDuringActivity}}
|
||||||
|
|||||||
@@ -43,11 +43,8 @@ import { format, isSameMonth } from 'date-fns';
|
|||||||
|
|
||||||
export default class Attribution extends Component {
|
export default class Attribution extends Component {
|
||||||
@service download;
|
@service download;
|
||||||
|
|
||||||
@tracked showCSVDownloadModal = false;
|
@tracked showCSVDownloadModal = false;
|
||||||
|
|
||||||
parseAPITimestamp = (time, format) => parseAPITimestamp(time, format);
|
|
||||||
|
|
||||||
get attributionLegend() {
|
get attributionLegend() {
|
||||||
const attributionLegend = [
|
const attributionLegend = [
|
||||||
{ key: 'entity_clients', label: 'entity clients' },
|
{ key: 'entity_clients', label: 'entity clients' },
|
||||||
@@ -60,6 +57,11 @@ export default class Attribution extends Component {
|
|||||||
return attributionLegend;
|
return attributionLegend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get formattedStartDate() {
|
||||||
|
if (!this.args.startTimestamp) return null;
|
||||||
|
return parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy');
|
||||||
|
}
|
||||||
|
|
||||||
get formattedEndDate() {
|
get formattedEndDate() {
|
||||||
if (!this.args.startTimestamp && !this.args.endTimestamp) return null;
|
if (!this.args.startTimestamp && !this.args.endTimestamp) return null;
|
||||||
// displays on CSV export modal, no need to display duplicate months and years
|
// displays on CSV export modal, no need to display duplicate months and years
|
||||||
@@ -73,9 +75,6 @@ export default class Attribution extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isSingleNamespace() {
|
get isSingleNamespace() {
|
||||||
if (!this.args.totalClientAttribution) {
|
|
||||||
return 'no data';
|
|
||||||
}
|
|
||||||
// if a namespace is selected, then we're viewing top 10 auth methods (mounts)
|
// if a namespace is selected, then we're viewing top 10 auth methods (mounts)
|
||||||
return !!this.args.selectedNamespace;
|
return !!this.args.selectedNamespace;
|
||||||
}
|
}
|
||||||
@@ -100,6 +99,9 @@ export default class Attribution extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get chartText() {
|
get chartText() {
|
||||||
|
if (!this.args.totalClientAttribution) {
|
||||||
|
return { description: 'There is a problem gathering data' };
|
||||||
|
}
|
||||||
const dateText = this.formattedEndDate ? 'date range' : 'month';
|
const dateText = this.formattedEndDate ? 'date range' : 'month';
|
||||||
switch (this.isSingleNamespace) {
|
switch (this.isSingleNamespace) {
|
||||||
case true:
|
case true:
|
||||||
@@ -121,10 +123,6 @@ export default class Attribution extends Component {
|
|||||||
}`,
|
}`,
|
||||||
totalCopy: `The total clients in the namespace for this ${dateText}. This number is useful for identifying overall usage volume.`,
|
totalCopy: `The total clients in the namespace for this ${dateText}. This number is useful for identifying overall usage volume.`,
|
||||||
};
|
};
|
||||||
case 'no data':
|
|
||||||
return {
|
|
||||||
description: 'There is a problem gathering data',
|
|
||||||
};
|
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -157,15 +155,15 @@ export default class Attribution extends Component {
|
|||||||
const csvData = [];
|
const csvData = [];
|
||||||
// added to clarify that the row of namespace totals without an auth method (blank) are not additional clients
|
// added to clarify that the row of namespace totals without an auth method (blank) are not additional clients
|
||||||
// but indicate the total clients for that ns, including its auth methods
|
// but indicate the total clients for that ns, including its auth methods
|
||||||
const upgrade = this.args.upgradesDuringActivity.length
|
const upgrade = this.args.upgradesDuringActivity?.length
|
||||||
? `\n **data contains an upgrade, mount summation may not equal namespace totals`
|
? `\n **data contains an upgrade, mount summation may not equal namespace totals`
|
||||||
: '';
|
: '';
|
||||||
const descriptionOfBlanks = this.isSingleNamespace
|
const descriptionOfBlanks = this.isSingleNamespace
|
||||||
? ''
|
? ''
|
||||||
: `\n *namespace totals, inclusive of mount clients ${upgrade}`;
|
: `\n *namespace totals, inclusive of mount clients${upgrade}`;
|
||||||
const csvHeader = [
|
const csvHeader = [
|
||||||
'Namespace path',
|
'Namespace path',
|
||||||
`"Mount path ${descriptionOfBlanks}"`,
|
`Mount path${descriptionOfBlanks}`,
|
||||||
'Total clients',
|
'Total clients',
|
||||||
'Entity clients',
|
'Entity clients',
|
||||||
'Non-entity clients',
|
'Non-entity clients',
|
||||||
@@ -216,10 +214,10 @@ export default class Attribution extends Component {
|
|||||||
|
|
||||||
get formattedCsvFileName() {
|
get formattedCsvFileName() {
|
||||||
const endRange = this.formattedEndDate ? `-${this.formattedEndDate}` : '';
|
const endRange = this.formattedEndDate ? `-${this.formattedEndDate}` : '';
|
||||||
const csvDateRange = this.formattedStartDate + endRange;
|
const csvDateRange = this.formattedStartDate ? `_${this.formattedStartDate + endRange}` : '';
|
||||||
return this.isSingleNamespace
|
return this.isSingleNamespace
|
||||||
? `clients_by_mount_path_${csvDateRange}`
|
? `clients_by_mount_path${csvDateRange}`
|
||||||
: `clients_by_namespace_${csvDateRange}`;
|
: `clients_by_namespace${csvDateRange}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get modalExportText() {
|
get modalExportText() {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { endOfMonth, formatRFC3339 } from 'date-fns';
|
|||||||
import { click } from '@ember/test-helpers';
|
import { click } from '@ember/test-helpers';
|
||||||
import subMonths from 'date-fns/subMonths';
|
import subMonths from 'date-fns/subMonths';
|
||||||
import timestamp from 'core/utils/timestamp';
|
import timestamp from 'core/utils/timestamp';
|
||||||
|
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||||
|
|
||||||
module('Integration | Component | clients/attribution', function (hooks) {
|
module('Integration | Component | clients/attribution', function (hooks) {
|
||||||
setupRenderingTest(hooks);
|
setupRenderingTest(hooks);
|
||||||
@@ -19,7 +20,9 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
hooks.before(function () {
|
hooks.before(function () {
|
||||||
sinon.stub(timestamp, 'now').callsFake(() => new Date('2018-04-03T14:15:30'));
|
sinon.stub(timestamp, 'now').callsFake(() => new Date('2018-04-03T14:15:30'));
|
||||||
});
|
});
|
||||||
|
|
||||||
hooks.beforeEach(function () {
|
hooks.beforeEach(function () {
|
||||||
|
this.csvDownloadStub = sinon.stub(this.owner.lookup('service:download'), 'csv');
|
||||||
const mockNow = timestamp.now();
|
const mockNow = timestamp.now();
|
||||||
this.mockNow = mockNow;
|
this.mockNow = mockNow;
|
||||||
this.set('startTimestamp', formatRFC3339(subMonths(mockNow, 6)));
|
this.set('startTimestamp', formatRFC3339(subMonths(mockNow, 6)));
|
||||||
@@ -40,8 +43,10 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
{ label: 'auth2/', clients: 2, entity_clients: 1, non_entity_clients: 1 },
|
{ label: 'auth2/', clients: 2, entity_clients: 1, non_entity_clients: 1 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
hooks.after(function () {
|
hooks.after(function () {
|
||||||
timestamp.now.restore();
|
timestamp.now.restore();
|
||||||
|
this.csvDownloadStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it renders empty state with no data', async function (assert) {
|
test('it renders empty state with no data', async function (assert) {
|
||||||
@@ -227,4 +232,92 @@ module('Integration | Component | clients/attribution', function (hooks) {
|
|||||||
.hasText('Export attribution data', 'modal appears to export csv');
|
.hasText('Export attribution data', 'modal appears to export csv');
|
||||||
assert.dom('[ data-test-export-date-range]').includesText('June 2022 - December 2022');
|
assert.dom('[ data-test-export-date-range]').includesText('June 2022 - December 2022');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it downloads csv data for date range', async function (assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<Clients::Attribution
|
||||||
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
|
@responseTimestamp={{this.timestamp}}
|
||||||
|
@startTimestamp="2022-06-01T23:00:11.050Z"
|
||||||
|
@endTimestamp="2022-12-01T23:00:11.050Z"
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
await click('[data-test-attribution-export-button]');
|
||||||
|
await click(GENERAL.confirmButton);
|
||||||
|
const [filename, content] = this.csvDownloadStub.lastCall.args;
|
||||||
|
assert.strictEqual(filename, 'clients_by_namespace_June 2022-December 2022', 'csv has expected filename');
|
||||||
|
assert.strictEqual(
|
||||||
|
content,
|
||||||
|
`Namespace path,Mount path\n *namespace totals, inclusive of mount clients,Total clients,Entity clients,Non-entity clients\nsecond,*,10,7,3\nfirst,*,5,3,2`,
|
||||||
|
'csv has expected content'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it downloads csv data for a single month', async function (assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
await render(hbs`
|
||||||
|
<Clients::Attribution
|
||||||
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
|
@responseTimestamp={{this.timestamp}}
|
||||||
|
@startTimestamp="2022-06-01T23:00:11.050Z"
|
||||||
|
@endTimestamp="2022-06-21T23:00:11.050Z"
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
await click('[data-test-attribution-export-button]');
|
||||||
|
await click(GENERAL.confirmButton);
|
||||||
|
const [filename, content] = this.csvDownloadStub.lastCall.args;
|
||||||
|
assert.strictEqual(filename, 'clients_by_namespace_June 2022', 'csv has single month in filename');
|
||||||
|
assert.strictEqual(
|
||||||
|
content,
|
||||||
|
`Namespace path,Mount path\n *namespace totals, inclusive of mount clients,Total clients,Entity clients,Non-entity clients\nsecond,*,10,7,3\nfirst,*,5,3,2`,
|
||||||
|
'csv has expected content'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it downloads csv data when a namespace is selected', async function (assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
this.selectedNamespace = 'second';
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<Clients::Attribution
|
||||||
|
@totalClientAttribution={{this.namespaceMountsData}}
|
||||||
|
@selectedNamespace={{this.selectedNamespace}}
|
||||||
|
@responseTimestamp={{this.timestamp}}
|
||||||
|
@startTimestamp="2022-06-01T23:00:11.050Z"
|
||||||
|
@endTimestamp="2022-12-21T23:00:11.050Z"
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await click('[data-test-attribution-export-button]');
|
||||||
|
await click(GENERAL.confirmButton);
|
||||||
|
const [filename, content] = this.csvDownloadStub.lastCall.args;
|
||||||
|
assert.strictEqual(
|
||||||
|
filename,
|
||||||
|
'clients_by_mount_path_June 2022-December 2022',
|
||||||
|
'csv has expected filename for a selected namespace'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
content,
|
||||||
|
`Namespace path,Mount path,Total clients,Entity clients,Non-entity clients\nsecond,auth1/,3,2,1\nsecond,auth2/,2,1,1`,
|
||||||
|
'csv has expected content for a selected namespace'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('csv filename omits date if no start/end timestamp', async function (assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<Clients::Attribution
|
||||||
|
@totalClientAttribution={{this.totalClientAttribution}}
|
||||||
|
@responseTimestamp={{this.timestamp}}
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await click('[data-test-attribution-export-button]');
|
||||||
|
await click(GENERAL.confirmButton);
|
||||||
|
const [filename, ,] = this.csvDownloadStub.lastCall.args;
|
||||||
|
assert.strictEqual(filename, 'clients_by_namespace');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user