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
+```