Skip to content

Commit

Permalink
Merge pull request #828 from acelaya-forks/feature/short-url-export
Browse files Browse the repository at this point in the history
Feature/short url export
  • Loading branch information
acelaya committed Apr 22, 2023
2 parents 6fbe6c6 + 72e4a7b commit 86349f1
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 11 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]
### Added
* *Nothing*

### Changed
* *Nothing*

### Deprecated
* *Nothing*

### Removed
* *Nothing*

### Fixed
* [#826](https://github.com/shlinkio/shlink-web-client/issues/826) Fix generated short URLs CSV so that it can be used to import on Shlink.


## [3.10.0] - 2023-03-19
### Added
* [#807](https://github.com/shlinkio/shlink-web-client/issues/807) Add support for device-specific long-URLs when creating or editing short URLs.
Expand Down
1 change: 0 additions & 1 deletion src/common/services/ReportExporter.ts
Expand Up @@ -24,7 +24,6 @@ export class ReportExporter {

private readonly exportCsv = (filename: string, rows: object[]) => {
const csv = this.jsonToCsv(rows);

saveCsv(this.window, csv, filename);
};
}
2 changes: 2 additions & 0 deletions src/short-urls/data/index.ts
Expand Up @@ -79,6 +79,8 @@ export interface ExportableShortUrl {
createdAt: string;
title: string;
shortUrl: string;
domain?: string;
shortCode: string;
longUrl: string;
tags: string;
visits: number;
Expand Down
28 changes: 18 additions & 10 deletions src/short-urls/helpers/ExportShortUrlsBtn.tsx
@@ -1,4 +1,5 @@
import type { FC } from 'react';
import { useCallback } from 'react';
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
import type { ReportExporter } from '../../common/services/ReportExporter';
import type { SelectedServer } from '../../servers/data';
Expand All @@ -24,7 +25,7 @@ export const ExportShortUrlsBtn = (
): FC<ExportShortUrlsBtnConnectProps> => ({ amount = 0, selectedServer }) => {
const [{ tags, search, startDate, endDate, orderBy, tagsMode }] = useShortUrlsQuery();
const [loading,, startLoading, stopLoading] = useToggle();
const exportAllUrls = async () => {
const exportAllUrls = useCallback(async () => {
if (!isServerWithId(selectedServer)) {
return;
}
Expand All @@ -47,16 +48,23 @@ export const ExportShortUrlsBtn = (
startLoading();
const shortUrls = await loadAllUrls();

exportShortUrls(shortUrls.map((shortUrl) => ({
createdAt: shortUrl.dateCreated,
shortUrl: shortUrl.shortUrl,
longUrl: shortUrl.longUrl,
title: shortUrl.title ?? '',
tags: shortUrl.tags.join(','),
visits: shortUrl?.visitsSummary?.total ?? shortUrl.visitsCount,
})));
exportShortUrls(shortUrls.map((shortUrl) => {
const { hostname: domain, pathname } = new URL(shortUrl.shortUrl);
const shortCode = pathname.substring(1); // Remove trailing slash

return {
createdAt: shortUrl.dateCreated,
domain,
shortCode,
shortUrl: shortUrl.shortUrl,
longUrl: shortUrl.longUrl,
title: shortUrl.title ?? '',
tags: shortUrl.tags.join('|'),
visits: shortUrl?.visitsSummary?.total ?? shortUrl.visitsCount,
};
}));
stopLoading();
};
}, [selectedServer]);

return <ExportBtn loading={loading} className="btn-md-block" amount={amount} onClick={exportAllUrls} />;
};
1 change: 1 addition & 0 deletions test/common/services/ReportExporter.test.ts
Expand Up @@ -53,6 +53,7 @@ describe('ReportExporter', () => {
createdAt: '',
longUrl: '',
tags: '',
shortCode: '',
},
];

Expand Down
19 changes: 19 additions & 0 deletions test/short-urls/helpers/ExportShortUrlsBtn.test.tsx
Expand Up @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import type { ReportExporter } from '../../../src/common/services/ReportExporter';
import type { NotFoundServer, SelectedServer } from '../../../src/servers/data';
import type { ShortUrl } from '../../../src/short-urls/data';
import { ExportShortUrlsBtn as createExportShortUrlsBtn } from '../../../src/short-urls/helpers/ExportShortUrlsBtn';
import { renderWithEvents } from '../../__helpers__/setUpTest';

Expand Down Expand Up @@ -56,4 +57,22 @@ describe('<ExportShortUrlsBtn />', () => {
expect(listShortUrls).toHaveBeenCalledTimes(expectedPageLoads);
expect(exportShortUrls).toHaveBeenCalled();
});

it('maps short URLs for exporting', async () => {
listShortUrls.mockResolvedValue({
data: [fromPartial<ShortUrl>({
shortUrl: 'https://s.test/short-code',
tags: [],
})],
});
const { user } = setUp(undefined, fromPartial({ id: '123' }));

await user.click(screen.getByRole('button'));

expect(exportShortUrls).toHaveBeenCalledWith([expect.objectContaining({
shortUrl: 'https://s.test/short-code',
domain: 's.test',
shortCode: 'short-code',
})]);
});
});

0 comments on commit 86349f1

Please sign in to comment.