mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Updated mercure integration so that the hook accepts a list of topics to subscribe
This commit is contained in:
parent
71ee886e24
commit
9904ac757b
10 changed files with 41 additions and 21 deletions
7
src/mercure/helpers/Topics.ts
Normal file
7
src/mercure/helpers/Topics.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export class Topics {
|
||||
public static visits = () => 'https://shlink.io/new-visit';
|
||||
|
||||
public static shortUrlVisits = (shortCode: string) => `https://shlink.io/new-visit/${shortCode}`;
|
||||
|
||||
public static orphanVisits = () => 'https://shlink.io/new-orphan-visit';
|
||||
}
|
|
@ -12,7 +12,7 @@ export interface MercureBoundProps {
|
|||
|
||||
export function boundToMercureHub<T = {}>(
|
||||
WrappedComponent: FC<MercureBoundProps & T>,
|
||||
getTopicForProps: (props: T) => string,
|
||||
getTopicsForProps: (props: T) => string[],
|
||||
) {
|
||||
const pendingUpdates = new Set<CreateVisit>();
|
||||
|
||||
|
@ -22,7 +22,7 @@ export function boundToMercureHub<T = {}>(
|
|||
|
||||
useEffect(() => {
|
||||
const onMessage = (visit: CreateVisit) => interval ? pendingUpdates.add(visit) : createNewVisits([ visit ]);
|
||||
const closeEventSource = bindToMercureTopic(mercureInfo, getTopicForProps(props), onMessage, loadMercureInfo);
|
||||
const closeEventSource = bindToMercureTopic(mercureInfo, getTopicsForProps(props), onMessage, loadMercureInfo);
|
||||
|
||||
if (!interval) {
|
||||
return closeEventSource;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { EventSourcePolyfill as EventSource } from 'event-source-polyfill';
|
||||
import { MercureInfo } from '../reducers/mercureInfo';
|
||||
|
||||
export const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topic: string, onMessage: (message: T) => void, onTokenExpired: Function) => { // eslint-disable-line max-len
|
||||
export const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topics: string[], onMessage: (message: T) => void, onTokenExpired: Function) => { // eslint-disable-line max-len
|
||||
const { mercureHubUrl, token, loading, error } = mercureInfo;
|
||||
|
||||
if (loading || error || !mercureHubUrl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const onEventSourceMessage = ({ data }: { data: string }) => onMessage(JSON.parse(data) as T);
|
||||
const onEventSourceError = ({ status }: { status: number }) => status === 401 && onTokenExpired();
|
||||
|
||||
const subscriptions: EventSource[] = topics.map((topic) => {
|
||||
const hubUrl = new URL(mercureHubUrl);
|
||||
|
||||
hubUrl.searchParams.append('topic', topic);
|
||||
|
@ -17,8 +21,11 @@ export const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topic: string, o
|
|||
},
|
||||
});
|
||||
|
||||
es.onmessage = ({ data }: { data: string }) => onMessage(JSON.parse(data) as T);
|
||||
es.onerror = ({ status }: { status: number }) => status === 401 && onTokenExpired();
|
||||
es.onmessage = onEventSourceMessage;
|
||||
es.onerror = onEventSourceError;
|
||||
|
||||
return () => es.close();
|
||||
return es;
|
||||
});
|
||||
|
||||
return () => subscriptions.forEach((es) => es.close());
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
|||
import { CreateShortUrlProps } from '../short-urls/CreateShortUrl';
|
||||
import { VisitsOverview } from '../visits/reducers/visitsOverview';
|
||||
import { Versions } from '../utils/helpers/version';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
import { isServerWithId, SelectedServer } from './data';
|
||||
import './Overview.scss';
|
||||
|
||||
|
@ -119,4 +120,4 @@ export const Overview = (
|
|||
</Card>
|
||||
</>
|
||||
);
|
||||
}, () => 'https://shlink.io/new-visit');
|
||||
}, () => [ Topics.visits(), Topics.orphanVisits() ]);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { determineOrderDir, OrderDir } from '../utils/utils';
|
|||
import { isReachableServer, SelectedServer } from '../servers/data';
|
||||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||
import { parseQuery } from '../utils/helpers/query';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
||||
import { OrderableFields, ShortUrlsListParams, SORTABLE_FIELDS } from './reducers/shortUrlsListParams';
|
||||
import { ShortUrlsTableProps } from './ShortUrlsTable';
|
||||
|
@ -98,6 +99,6 @@ const ShortUrlsList = (ShortUrlsTable: FC<ShortUrlsTableProps>) => boundToMercur
|
|||
</Card>
|
||||
</>
|
||||
);
|
||||
}, () => 'https://shlink.io/new-visit');
|
||||
}, () => [ Topics.visits() ]);
|
||||
|
||||
export default ShortUrlsList;
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Result } from '../utils/Result';
|
|||
import { ShlinkApiError } from '../api/ShlinkApiError';
|
||||
import { TagsList as TagsListState } from './reducers/tagsList';
|
||||
import { TagCardProps } from './TagCard';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
|
||||
const { ceil } = Math;
|
||||
const TAGS_GROUPS_AMOUNT = 4;
|
||||
|
@ -75,6 +76,6 @@ const TagsList = (TagCard: FC<TagCardProps>) => boundToMercureHub((
|
|||
{renderContent()}
|
||||
</>
|
||||
);
|
||||
}, () => 'https://shlink.io/new-visit');
|
||||
}, () => [ Topics.visits() ]);
|
||||
|
||||
export default TagsList;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { RouteComponentProps } from 'react-router';
|
||||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||
import { ShlinkVisitsParams } from '../api/types';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
import { TagVisits as TagVisitsState } from './reducers/tagVisits';
|
||||
import VisitsStats from './VisitsStats';
|
||||
import { OrphanVisitsHeader } from './OrphanVisitsHeader';
|
||||
|
@ -26,4 +27,4 @@ export const OrphanVisits = boundToMercureHub(({
|
|||
>
|
||||
<OrphanVisitsHeader orphanVisits={orphanVisits} goBack={goBack} />
|
||||
</VisitsStats>
|
||||
), () => 'https://shlink.io/new-orphan-visit');
|
||||
), () => [ Topics.orphanVisits() ]);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { RouteComponentProps } from 'react-router';
|
|||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||
import { ShlinkVisitsParams } from '../api/types';
|
||||
import { parseQuery } from '../utils/helpers/query';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
import { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits';
|
||||
import ShortUrlVisitsHeader from './ShortUrlVisitsHeader';
|
||||
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
||||
|
@ -45,6 +46,6 @@ const ShortUrlVisits = boundToMercureHub(({
|
|||
<ShortUrlVisitsHeader shortUrlDetail={shortUrlDetail} shortUrlVisits={shortUrlVisits} goBack={goBack} />
|
||||
</VisitsStats>
|
||||
);
|
||||
}, ({ match }) => `https://shlink.io/new-visit/${match.params.shortCode}`);
|
||||
}, ({ match }) => [ Topics.shortUrlVisits(match.params.shortCode) ]);
|
||||
|
||||
export default ShortUrlVisits;
|
||||
|
|
|
@ -2,6 +2,7 @@ import { RouteComponentProps } from 'react-router';
|
|||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||
import ColorGenerator from '../utils/services/ColorGenerator';
|
||||
import { ShlinkVisitsParams } from '../api/types';
|
||||
import { Topics } from '../mercure/helpers/Topics';
|
||||
import { TagVisits as TagVisitsState } from './reducers/tagVisits';
|
||||
import TagVisitsHeader from './TagVisitsHeader';
|
||||
import VisitsStats from './VisitsStats';
|
||||
|
@ -27,6 +28,6 @@ const TagVisits = (colorGenerator: ColorGenerator) => boundToMercureHub(({
|
|||
<TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />
|
||||
</VisitsStats>
|
||||
);
|
||||
}, () => 'https://shlink.io/new-visit');
|
||||
}, () => [ Topics.visits() ]);
|
||||
|
||||
export default TagVisits;
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('helpers', () => {
|
|||
[ Mock.of<MercureInfo>({ loading: false, error: false, mercureHubUrl: undefined }) ],
|
||||
[ Mock.of<MercureInfo>({ loading: true, error: true, mercureHubUrl: undefined }) ],
|
||||
])('does not bind an EventSource when loading, error or no hub URL', (mercureInfo) => {
|
||||
bindToMercureTopic(mercureInfo, '', identity, identity);
|
||||
bindToMercureTopic(mercureInfo, [ '' ], identity, identity);
|
||||
|
||||
expect(EventSource).not.toHaveBeenCalled();
|
||||
expect(onMessage).not.toHaveBeenCalled();
|
||||
|
@ -40,7 +40,7 @@ describe('helpers', () => {
|
|||
error: false,
|
||||
mercureHubUrl,
|
||||
token,
|
||||
}, topic, onMessage, onTokenExpired);
|
||||
}, [ topic ], onMessage, onTokenExpired);
|
||||
|
||||
expect(EventSource).toHaveBeenCalledWith(hubUrl, {
|
||||
headers: {
|
||||
|
|
Loading…
Reference in a new issue