0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Wired up Analytics export download trigger (#17782)

refs https://github.com/TryGhost/Product/issues/3349

- added a download handler for the analytics download button.
- wired up the download api endpoint

<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 46054be</samp>

This pull request adds a feature to export post analytics as a csv file
from the membership analytics dashboard. It implements a new query hook,
a download function, and a response handler in the
`apps/admin-x-settings` app, and adds a test case for the feature.
This commit is contained in:
Ronald Langeveld 2023-08-22 13:09:05 +02:00 committed by GitHub
parent 49493abf75
commit e61b62e6be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 1 deletions

View file

@ -16,3 +16,9 @@ export const useBrowsePosts = createQuery<PostsResponseType>({
dataType, dataType,
path: '/posts/' path: '/posts/'
}); });
// This endpoints returns a csv file
export const usePostsExports = createQuery<string>({
dataType,
path: '/posts/export/'
});

View file

@ -5,6 +5,7 @@ import SettingGroupContent from '../../../admin-x-ds/settings/SettingGroupConten
import Toggle from '../../../admin-x-ds/global/form/Toggle'; import Toggle from '../../../admin-x-ds/global/form/Toggle';
import useSettingGroup from '../../../hooks/useSettingGroup'; import useSettingGroup from '../../../hooks/useSettingGroup';
import {getSettingValues} from '../../../api/settings'; import {getSettingValues} from '../../../api/settings';
import {usePostsExports} from '../../../api/posts';
const Analytics: React.FC<{ keywords: string[] }> = ({keywords}) => { const Analytics: React.FC<{ keywords: string[] }> = ({keywords}) => {
const { const {
@ -26,6 +27,27 @@ const Analytics: React.FC<{ keywords: string[] }> = ({keywords}) => {
handleEditingChange(true); handleEditingChange(true);
}; };
const {data: postsData} = usePostsExports({
searchParams: {
limit: '1000'
}
});
const exportPosts = async () => {
// it should download posts as csv
if (postsData) {
const blob = new Blob([postsData], {type: 'text/csv'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.setAttribute('hidden', '');
a.setAttribute('href', url);
a.setAttribute('download', 'posts.csv');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
};
const inputs = ( const inputs = (
<SettingGroupContent columns={2}> <SettingGroupContent columns={2}>
<Toggle <Toggle
@ -83,7 +105,7 @@ const Analytics: React.FC<{ keywords: string[] }> = ({keywords}) => {
> >
{inputs} {inputs}
<div className='mt-1'> <div className='mt-1'>
<Button color='green' label='Export analytics' link={true} /> <Button color='green' label='Export analytics' link={true} onClick={exportPosts} />
</div> </div>
</SettingGroup> </SettingGroup>
); );

View file

@ -72,6 +72,8 @@ export const useFetchApi = () => {
throw new ApiError(response, data); throw new ApiError(response, data);
} else if (response.status === 204) { } else if (response.status === 204) {
return; return;
} else if (response.headers.get('content-type')?.includes('text/csv')) {
return await response.text();
} else { } else {
return await response.json(); return await response.json();
} }

View file

@ -38,4 +38,20 @@ test.describe('Analytics settings', async () => {
] ]
}); });
}); });
test('Supports downloading analytics csv export', async ({page}) => {
const {lastApiRequests} = await mockApi({page, requests: {
...globalDataRequests,
postsExport: {method: 'GET', path: '/posts/export/?limit=1000', response: 'csv data'}
}});
await page.goto('/');
const section = page.getByTestId('analytics');
await section.getByRole('button', {name: 'Export analytics'}).click();
const hasDownloadUrl = lastApiRequests.postsExport?.url?.includes('/posts/export/?limit=1000');
expect(hasDownloadUrl).toBe(true);
});
}); });