From 84e890bcd751efb46413ab73ac8440eaaa9762ab Mon Sep 17 00:00:00 2001 From: "clairebontempo@gmail.com" Date: Wed, 17 Apr 2024 17:43:56 -0700 Subject: [PATCH 1/5] fix undefined file name start date --- ui/app/components/clients/attribution.hbs | 2 +- ui/app/components/clients/attribution.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/app/components/clients/attribution.hbs b/ui/app/components/clients/attribution.hbs index 788418236c31..1ccdddf728da 100644 --- a/ui/app/components/clients/attribution.hbs +++ b/ui/app/components/clients/attribution.hbs @@ -99,7 +99,7 @@

SELECTED DATE {{if this.formattedEndDate " RANGE"}}

- {{this.parseAPITimestamp @startTimestamp "MMMM yyyy"}} + {{this.formattedStartDate}} {{if this.formattedEndDate "-"}} {{this.formattedEndDate}}

diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js index 4729a164d525..368f5d0323d9 100644 --- a/ui/app/components/clients/attribution.js +++ b/ui/app/components/clients/attribution.js @@ -43,11 +43,8 @@ import { format, isSameMonth } from 'date-fns'; export default class Attribution extends Component { @service download; - @tracked showCSVDownloadModal = false; - parseAPITimestamp = (time, format) => parseAPITimestamp(time, format); - get attributionLegend() { const attributionLegend = [ { key: 'entity_clients', label: 'entity clients' }, @@ -60,6 +57,10 @@ export default class Attribution extends Component { return attributionLegend; } + get formattedStartDate() { + return parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy'); + } + get formattedEndDate() { if (!this.args.startTimestamp && !this.args.endTimestamp) return null; // displays on CSV export modal, no need to display duplicate months and years From 342b9c09bc85668a21de925065afb0bc56b793df Mon Sep 17 00:00:00 2001 From: "clairebontempo@gmail.com" Date: Wed, 17 Apr 2024 18:53:36 -0700 Subject: [PATCH 2/5] add test coverage! --- ui/app/components/clients/attribution.hbs | 6 +- ui/app/components/clients/attribution.js | 16 ++-- .../components/clients/attribution-test.js | 77 +++++++++++++++++++ 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/ui/app/components/clients/attribution.hbs b/ui/app/components/clients/attribution.hbs index 1ccdddf728da..eb77ba488731 100644 --- a/ui/app/components/clients/attribution.hbs +++ b/ui/app/components/clients/attribution.hbs @@ -105,7 +105,11 @@ - + {{#if @upgradesDuringActivity}} diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js index 368f5d0323d9..599634007b4a 100644 --- a/ui/app/components/clients/attribution.js +++ b/ui/app/components/clients/attribution.js @@ -74,9 +74,6 @@ export default class Attribution extends Component { } get isSingleNamespace() { - if (!this.args.totalClientAttribution) { - return 'no data'; - } // if a namespace is selected, then we're viewing top 10 auth methods (mounts) return !!this.args.selectedNamespace; } @@ -101,6 +98,9 @@ export default class Attribution extends Component { } get chartText() { + if (!this.args.totalClientAttribution) { + return { description: 'There is a problem gathering data' }; + } const dateText = this.formattedEndDate ? 'date range' : 'month'; switch (this.isSingleNamespace) { case true: @@ -122,10 +122,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.`, }; - case 'no data': - return { - description: 'There is a problem gathering data', - }; default: return ''; } @@ -158,15 +154,15 @@ export default class Attribution extends Component { const csvData = []; // 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 - const upgrade = this.args.upgradesDuringActivity.length + const upgrade = this.args.upgradesDuringActivity?.length ? `\n **data contains an upgrade, mount summation may not equal namespace totals` : ''; const descriptionOfBlanks = this.isSingleNamespace ? '' - : `\n *namespace totals, inclusive of mount clients ${upgrade}`; + : `\n *namespace totals, inclusive of mount clients${upgrade}`; const csvHeader = [ 'Namespace path', - `"Mount path ${descriptionOfBlanks}"`, + `Mount path${descriptionOfBlanks}`, 'Total clients', 'Entity clients', 'Non-entity clients', diff --git a/ui/tests/integration/components/clients/attribution-test.js b/ui/tests/integration/components/clients/attribution-test.js index 204bd361a717..c0b96486eb03 100644 --- a/ui/tests/integration/components/clients/attribution-test.js +++ b/ui/tests/integration/components/clients/attribution-test.js @@ -12,6 +12,7 @@ import { endOfMonth, formatRFC3339 } from 'date-fns'; import { click } from '@ember/test-helpers'; import subMonths from 'date-fns/subMonths'; import timestamp from 'core/utils/timestamp'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | clients/attribution', function (hooks) { setupRenderingTest(hooks); @@ -19,7 +20,9 @@ module('Integration | Component | clients/attribution', function (hooks) { hooks.before(function () { sinon.stub(timestamp, 'now').callsFake(() => new Date('2018-04-03T14:15:30')); }); + hooks.beforeEach(function () { + this.csvDownloadStub = sinon.stub(this.owner.lookup('service:download'), 'csv'); const mockNow = timestamp.now(); this.mockNow = mockNow; 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 }, ]); }); + hooks.after(function () { timestamp.now.restore(); + this.csvDownloadStub.restore(); }); test('it renders empty state with no data', async function (assert) { @@ -227,4 +232,76 @@ module('Integration | Component | clients/attribution', function (hooks) { .hasText('Export attribution data', 'modal appears to export csv'); assert.dom('[ data-test-export-date-range]').includesText('June 2022 - December 2022'); }); + + test('it downloads csv of data for a date range', async function (assert) { + assert.expect(2); + + await render(hbs` + + `); + 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 of data for a single month', async function (assert) { + assert.expect(2); + await render(hbs` + + `); + 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` + + `); + + 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' + ); + }); }); From 10206d03a021cb891920d09576352eee87cf0bd2 Mon Sep 17 00:00:00 2001 From: "clairebontempo@gmail.com" Date: Wed, 17 Apr 2024 18:55:52 -0700 Subject: [PATCH 3/5] small copy changes --- ui/tests/integration/components/clients/attribution-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/tests/integration/components/clients/attribution-test.js b/ui/tests/integration/components/clients/attribution-test.js index c0b96486eb03..96bdc5625c64 100644 --- a/ui/tests/integration/components/clients/attribution-test.js +++ b/ui/tests/integration/components/clients/attribution-test.js @@ -233,7 +233,7 @@ module('Integration | Component | clients/attribution', function (hooks) { assert.dom('[ data-test-export-date-range]').includesText('June 2022 - December 2022'); }); - test('it downloads csv of data for a date range', async function (assert) { + test('it downloads csv data for date range', async function (assert) { assert.expect(2); await render(hbs` @@ -255,7 +255,7 @@ module('Integration | Component | clients/attribution', function (hooks) { ); }); - test('it downloads csv of data for a single month', async function (assert) { + test('it downloads csv data for a single month', async function (assert) { assert.expect(2); await render(hbs` Date: Wed, 17 Apr 2024 19:10:03 -0700 Subject: [PATCH 4/5] one last test! --- ui/app/components/clients/attribution.js | 7 ++++--- .../components/clients/attribution-test.js | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js index 599634007b4a..e13e8d41a952 100644 --- a/ui/app/components/clients/attribution.js +++ b/ui/app/components/clients/attribution.js @@ -58,6 +58,7 @@ export default class Attribution extends Component { } get formattedStartDate() { + if (!this.args.startTimestamp) return null; return parseAPITimestamp(this.args.startTimestamp, 'MMMM yyyy'); } @@ -213,10 +214,10 @@ export default class Attribution extends Component { get formattedCsvFileName() { const endRange = this.formattedEndDate ? `-${this.formattedEndDate}` : ''; - const csvDateRange = this.formattedStartDate + endRange; + const csvDateRange = this.formattedStartDate ? `_${this.formattedStartDate + endRange}` : ''; return this.isSingleNamespace - ? `clients_by_mount_path_${csvDateRange}` - : `clients_by_namespace_${csvDateRange}`; + ? `clients_by_mount_path${csvDateRange}` + : `clients_by_namespace${csvDateRange}`; } get modalExportText() { diff --git a/ui/tests/integration/components/clients/attribution-test.js b/ui/tests/integration/components/clients/attribution-test.js index 96bdc5625c64..c126c6585d17 100644 --- a/ui/tests/integration/components/clients/attribution-test.js +++ b/ui/tests/integration/components/clients/attribution-test.js @@ -304,4 +304,20 @@ module('Integration | Component | clients/attribution', function (hooks) { '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` + + `); + + await click('[data-test-attribution-export-button]'); + await click(GENERAL.confirmButton); + const [filename, ,] = this.csvDownloadStub.lastCall.args; + assert.strictEqual(filename, 'clients_by_namespace'); + }); }); From 1469046ed4f7701349668017f2f3e9576096b78b Mon Sep 17 00:00:00 2001 From: "clairebontempo@gmail.com" Date: Wed, 17 Apr 2024 19:17:22 -0700 Subject: [PATCH 5/5] add changelog; --- changelog/26485.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/26485.txt diff --git a/changelog/26485.txt b/changelog/26485.txt new file mode 100644 index 000000000000..6cc54cfb9984 --- /dev/null +++ b/changelog/26485.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fixes undefined start time in filename for downloaded client count attribution csv +```