mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-17 21:13:48 +00:00
Implemented short URLs exporting
This commit is contained in:
@@ -14,11 +14,11 @@ import { DateRange } from '../utils/dates/types';
|
||||
import { supportsAllTagsFiltering } from '../utils/helpers/features';
|
||||
import { SelectedServer } from '../servers/data';
|
||||
import { TooltipToggleSwitch } from '../utils/TooltipToggleSwitch';
|
||||
import { ExportBtn } from '../utils/ExportBtn';
|
||||
import { OrderDir } from '../utils/helpers/ordering';
|
||||
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
||||
import { useShortUrlsQuery } from './helpers/hooks';
|
||||
import { SHORT_URLS_ORDERABLE_FIELDS, ShortUrlsOrder, ShortUrlsOrderableFields } from './data';
|
||||
import { ExportShortUrlsBtnProps } from './helpers/ExportShortUrlsBtn';
|
||||
import './ShortUrlsFilteringBar.scss';
|
||||
|
||||
export interface ShortUrlsFilteringProps {
|
||||
@@ -26,13 +26,15 @@ export interface ShortUrlsFilteringProps {
|
||||
order: ShortUrlsOrder;
|
||||
handleOrderBy: (orderField?: ShortUrlsOrderableFields, orderDir?: OrderDir) => void;
|
||||
className?: string;
|
||||
shortUrlsAmount?: number;
|
||||
}
|
||||
|
||||
const dateOrNull = (date?: string) => date ? parseISO(date) : null;
|
||||
|
||||
const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilteringProps> => (
|
||||
{ selectedServer, className, order, handleOrderBy },
|
||||
) => {
|
||||
const ShortUrlsFilteringBar = (
|
||||
colorGenerator: ColorGenerator,
|
||||
ExportShortUrlsBtn: FC<ExportShortUrlsBtnProps>,
|
||||
): FC<ShortUrlsFilteringProps> => ({ selectedServer, className, shortUrlsAmount, order, handleOrderBy }) => {
|
||||
const [{ search, tags, startDate, endDate, tagsMode = 'any' }, toFirstPage ] = useShortUrlsQuery();
|
||||
const setDates = pipe(
|
||||
({ startDate, endDate }: DateRange) => ({
|
||||
@@ -61,7 +63,7 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilt
|
||||
|
||||
<Row className="flex-column-reverse flex-lg-row">
|
||||
<div className="col-lg-4 col-xl-6 mt-3">
|
||||
<ExportBtn className="btn-md-block" amount={4} onClick={() => {}} />
|
||||
<ExportShortUrlsBtn amount={shortUrlsAmount} />
|
||||
</div>
|
||||
<div className="col-12 d-block d-lg-none mt-3">
|
||||
<OrderingDropdown items={SHORT_URLS_ORDERABLE_FIELDS} order={order} onChange={handleOrderBy} />
|
||||
|
||||
@@ -65,6 +65,7 @@ const ShortUrlsList = (
|
||||
<>
|
||||
<ShortUrlsFilteringBar
|
||||
selectedServer={selectedServer}
|
||||
shortUrlsAmount={shortUrlsList.shortUrls?.pagination.totalItems}
|
||||
order={actualOrderBy}
|
||||
handleOrderBy={handleOrderBy}
|
||||
className="mb-3"
|
||||
|
||||
@@ -63,3 +63,12 @@ export const SHORT_URLS_ORDERABLE_FIELDS = {
|
||||
export type ShortUrlsOrderableFields = keyof typeof SHORT_URLS_ORDERABLE_FIELDS;
|
||||
|
||||
export type ShortUrlsOrder = Order<ShortUrlsOrderableFields>;
|
||||
|
||||
export interface ExportableShortUrl {
|
||||
createdAt: string;
|
||||
title: string;
|
||||
shortUrl: string;
|
||||
longUrl: string;
|
||||
tags: string;
|
||||
visits: number;
|
||||
}
|
||||
|
||||
66
src/short-urls/helpers/ExportShortUrlsBtn.tsx
Normal file
66
src/short-urls/helpers/ExportShortUrlsBtn.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { FC } from 'react';
|
||||
import { ExportBtn } from '../../utils/ExportBtn';
|
||||
import { useToggle } from '../../utils/helpers/hooks';
|
||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||
import { isServerWithId, SelectedServer } from '../../servers/data';
|
||||
import { ShortUrl } from '../data';
|
||||
import { ReportExporter } from '../../common/services/ReportExporter';
|
||||
import { useShortUrlsQuery } from './hooks';
|
||||
|
||||
export interface ExportShortUrlsBtnProps {
|
||||
amount?: number;
|
||||
}
|
||||
|
||||
interface ExportShortUrlsBtnConnectProps extends ExportShortUrlsBtnProps {
|
||||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
const itemsPerPage = 10;
|
||||
|
||||
export const ExportShortUrlsBtn = (
|
||||
buildShlinkApiClient: ShlinkApiClientBuilder,
|
||||
{ exportShortUrls }: ReportExporter,
|
||||
): FC<ExportShortUrlsBtnConnectProps> => ({ amount = 0, selectedServer }) => {
|
||||
const [{ tags, search, startDate, endDate, orderBy, tagsMode }] = useShortUrlsQuery();
|
||||
const [ loading,, startLoading, stopLoading ] = useToggle();
|
||||
const exportAllUrls = () => {
|
||||
if (!isServerWithId(selectedServer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const totalPages = amount / itemsPerPage;
|
||||
const { listShortUrls } = buildShlinkApiClient(selectedServer);
|
||||
const loadAllUrls = async (page = 1): Promise<ShortUrl[]> => {
|
||||
const { data } = await listShortUrls(
|
||||
{ page: `${page}`, tags, searchTerm: search, startDate, endDate, orderBy, tagsMode, itemsPerPage },
|
||||
);
|
||||
|
||||
if (page >= totalPages) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// TODO Support paralelization
|
||||
return data.concat(await loadAllUrls(page + 1));
|
||||
};
|
||||
|
||||
startLoading();
|
||||
loadAllUrls()
|
||||
.then((shortUrls) => {
|
||||
exportShortUrls(shortUrls.map((shortUrl) => ({
|
||||
createdAt: shortUrl.dateCreated,
|
||||
shortUrl: shortUrl.shortUrl,
|
||||
longUrl: shortUrl.longUrl,
|
||||
title: shortUrl.title ?? '',
|
||||
tags: shortUrl.tags.join(','),
|
||||
visits: shortUrl.visitsCount,
|
||||
})));
|
||||
stopLoading();
|
||||
})
|
||||
.catch((e) => {
|
||||
// TODO Handle error properly
|
||||
console.error('An error occurred while exporting short URLs', e); // eslint-disable-line no-console
|
||||
});
|
||||
};
|
||||
|
||||
return <ExportBtn loading={loading} className="btn-md-block" amount={amount} onClick={exportAllUrls} />;
|
||||
};
|
||||
@@ -16,6 +16,7 @@ import QrCodeModal from '../helpers/QrCodeModal';
|
||||
import { ShortUrlForm } from '../ShortUrlForm';
|
||||
import { EditShortUrl } from '../EditShortUrl';
|
||||
import { getShortUrlDetail } from '../reducers/shortUrlDetail';
|
||||
import { ExportShortUrlsBtn } from '../helpers/ExportShortUrlsBtn';
|
||||
|
||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||
// Components
|
||||
@@ -49,7 +50,10 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||
bottle.serviceFactory('QrCodeModal', QrCodeModal, 'ImageDownloader', 'ForServerVersion');
|
||||
bottle.decorator('QrCodeModal', connect([ 'selectedServer' ]));
|
||||
|
||||
bottle.serviceFactory('ShortUrlsFilteringBar', ShortUrlsFilteringBar, 'ColorGenerator');
|
||||
bottle.serviceFactory('ShortUrlsFilteringBar', ShortUrlsFilteringBar, 'ColorGenerator', 'ExportShortUrlsBtn');
|
||||
|
||||
bottle.serviceFactory('ExportShortUrlsBtn', ExportShortUrlsBtn, 'buildShlinkApiClient', 'ReportExporter');
|
||||
bottle.decorator('ExportShortUrlsBtn', connect([ 'selectedServer' ]));
|
||||
|
||||
// Actions
|
||||
bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient');
|
||||
|
||||
Reference in New Issue
Block a user