Skip to content

Commit 67e9f96

Browse files
fix(adoption-insights): add timestamp to CSV export filename to avoid conflicts (#1366)
- Updated timestamp format to include milliseconds for better uniqueness - Changed format from YYYY-MM-DD_HH-mm-ss to YYYY-MM-DD_HH-mm-ss-SSS - Updated tests to validate new timestamp format with milliseconds - Updated changeset to reflect the milliseconds addition
1 parent 121e764 commit 67e9f96

3 files changed

Lines changed: 37 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-adoption-insights': patch
3+
---
4+
5+
Fixed CSV export filename to include timestamp for better file identification and to avoid naming conflicts. Active Users CSV exports now use format "active_users_YYYY-MM-DD_HH-mm-ss-SSS.csv" instead of generic "active_users"

workspaces/adoption-insights/plugins/adoption-insights/src/components/ActiveUsers/ExportCSVButton.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const ExportCSVButton = () => {
3434

3535
const handleCSVDownload = async () => {
3636
try {
37+
const timestamp = format(new Date(), 'yyyy-MM-dd_HH-mm-ss-SSS');
38+
const filename = `active_users_${timestamp}.csv`;
3739
await api.downloadBlob({
3840
type: 'active_users',
3941
start_date: startDateRange
@@ -42,6 +44,7 @@ const ExportCSVButton = () => {
4244
end_date: endDateRange ? format(endDateRange, 'yyyy-MM-dd') : undefined,
4345
timezone: new Intl.DateTimeFormat().resolvedOptions().timeZone,
4446
format: 'csv',
47+
blobName: filename,
4548
});
4649
} catch (error) {
4750
// eslint-disable-next-line no-console

workspaces/adoption-insights/plugins/adoption-insights/src/components/ActiveUsers/__tests__/ExportCSVButton.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ describe('ExportCSVButton', () => {
5858
end_date: '2025-01-31',
5959
format: 'csv',
6060
timezone: 'UTC',
61+
blobName: expect.stringMatching(
62+
/^active_users_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-\d{3}\.csv$/,
63+
),
6164
});
6265
});
6366
});
@@ -84,4 +87,30 @@ describe('ExportCSVButton', () => {
8487
expect(screen.getByText('Export CSV')).toBeInTheDocument(),
8588
);
8689
});
90+
91+
it('should generate unique timestamped filenames for multiple downloads', async () => {
92+
render(<ExportCSVButton />);
93+
94+
const button = screen.getByRole('button');
95+
96+
fireEvent.click(button);
97+
await waitFor(() => expect(mockDownloadBlob).toHaveBeenCalledTimes(1));
98+
99+
const firstCall = mockDownloadBlob.mock.calls[0][0];
100+
expect(firstCall.blobName).toMatch(
101+
/^active_users_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-\d{3}\.csv$/,
102+
);
103+
104+
await new Promise(resolve => setTimeout(resolve, 1100));
105+
106+
fireEvent.click(button);
107+
await waitFor(() => expect(mockDownloadBlob).toHaveBeenCalledTimes(2));
108+
109+
const secondCall = mockDownloadBlob.mock.calls[1][0];
110+
expect(secondCall.blobName).toMatch(
111+
/^active_users_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-\d{3}\.csv$/,
112+
);
113+
114+
expect(firstCall.blobName).not.toBe(secondCall.blobName);
115+
});
87116
});

0 commit comments

Comments
 (0)