Skip to content
This repository was archived by the owner on Sep 3, 2024. It is now read-only.

Commit 856f3aa

Browse files
Merge pull request #17 from thefringeninja/reactive-rs
Migrate Reactive Bits to Typescript
2 parents 21403e7 + 41054d0 commit 856f3aa

File tree

16 files changed

+240
-140
lines changed

16 files changed

+240
-140
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"devDependencies": {
1616
"@types/classnames": "^2.2.6",
1717
"@types/history": "^4.7.2",
18+
"@types/json-schema": "^7.0.1",
1819
"@types/jss": "^9.5.7",
1920
"@types/prettier": "^1.13.2",
2021
"@types/react": "^16.4.18",
@@ -36,6 +37,7 @@
3637
"classnames": "2.2.6",
3738
"history": "4.7.2",
3839
"inflector-js": "1.0.1",
40+
"json-schema": "0.2.3",
3941
"jss": "9.4.0",
4042
"react": "16.5.2",
4143
"react-dom": "16.5.2",

src/SqlStreamStoreBrowser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const onNavigate = (link, authorization) =>
4949

5050
const initialNavigation = ({ authorization }) =>
5151
onNavigate(
52-
{ href: window.location.href, type: mediaTypes.hal },
52+
{ href: window.location.href, type: mediaTypes.any },
5353
authorization,
5454
);
5555

src/components/Notifications.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
} from '@material-ui/core';
88
import { amber, blue, green, red } from '@material-ui/core/colors';
99
import classNames from 'classnames';
10-
import React, {ComponentType, createElement, ReactNode, StatelessComponent} from 'react';
10+
import React, {
11+
ComponentType,
12+
createElement,
13+
ReactNode,
14+
StatelessComponent,
15+
} from 'react';
1116
import { Observable as obs } from 'rxjs';
1217
import uuid from 'uuid';
1318
import { CheckCircle, Close, Error, Info, Warning } from '../components/Icons';
@@ -195,7 +200,9 @@ const Notification: ComponentType<NotificationProps> = withStyles(styles)(
195200
),
196201
);
197202

198-
const Notifications: StatelessComponent<{ notifications: NotificationProps[] }> = ({ notifications }) => (
203+
const Notifications: StatelessComponent<{
204+
notifications: NotificationProps[];
205+
}> = ({ notifications }) => (
199206
<div>
200207
{notifications.map(notification => (
201208
<Notification key={notification.messageId} {...notification} />

src/stream-store/actions.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/stream-store/actions.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Action, Location } from 'history';
2+
import { ReplaySubject } from 'rxjs';
3+
import { createAction } from '../reactive';
4+
import { HttpRequest, HttpResponse } from '../types';
5+
import { history, http } from '../utils';
6+
7+
type Actions = {
8+
[P in keyof typeof http]: {
9+
request: ReplaySubject<HttpRequest>;
10+
response: ReplaySubject<HttpResponse>;
11+
}
12+
};
13+
14+
const verbs = Object.keys(http);
15+
16+
const actions: Actions = verbs.reduce(
17+
(akk, verb: keyof typeof http) => ({
18+
...akk,
19+
[verb]: {
20+
request: createAction(),
21+
response: createAction(),
22+
},
23+
}),
24+
// tslint:disable-next-line:no-object-literal-type-assertion
25+
{} as Actions,
26+
);
27+
28+
verbs.forEach(verb =>
29+
actions[verb].request
30+
.flatMap(request => http[verb](request))
31+
.subscribe(response => actions[verb].response.next(response)),
32+
);
33+
34+
actions.get.response.subscribe(({ url }) => history.push(url));
35+
36+
const getUrl = (location: Location) =>
37+
`${location.pathname}${location.search}${location.hash}`;
38+
39+
history.listen(
40+
(location: Location, action: Action): void => {
41+
if (action !== 'POP') {
42+
return;
43+
}
44+
actions.get.request.next({
45+
headers: {},
46+
link: { href: getUrl(location) },
47+
});
48+
},
49+
);
50+
51+
export default actions;
Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,46 @@
1+
import { JSONSchema7 } from 'json-schema';
12
import { Observable as obs } from 'rxjs';
3+
import { HalResource } from '../types';
24
import { resolveLinks } from '../utils';
35
import actions from './actions';
46

57
const mediaType$ = actions.get.response.map(
68
({ headers }) => headers['content-type'].split(';')[0],
79
);
810

9-
const body$ = actions.get.response.map(({ body }) => body);
11+
const body$ = actions.get.response.map(({ body }) => body as HalResource);
1012

1113
const url$ = actions.get.response.map(({ url }) => url);
1214

1315
const links$ = body$
1416
.zip(url$)
1517
.map(([{ _links }, url]) => resolveLinks(url, _links || {}));
1618

17-
const forms$ = body$.map(({ _embedded }) =>
18-
Object.keys(_embedded || {})
19-
.filter(
20-
rel =>
21-
_embedded[rel].$schema &&
22-
_embedded[rel].$schema.endsWith('schema#'),
23-
)
24-
.reduce((akk, rel) => ({ ...akk, [rel]: _embedded[rel] }), {}),
19+
const isJsonSchema = (schema: JSONSchema7 & HalResource) =>
20+
schema.$schema && schema.$schema.endsWith('schema#');
21+
22+
const forms$ = body$.map(({ _embedded }) => _embedded || {}).map(embedded =>
23+
Object.keys(embedded)
24+
.filter(rel => isJsonSchema(embedded[rel]))
25+
.reduce(
26+
(akk, rel) => ({
27+
...akk,
28+
[rel]: embedded[rel],
29+
}),
30+
// tslint:disable-next-line:no-object-literal-type-assertion
31+
{} as JSONSchema7,
32+
),
2533
);
2634

2735
const verbs = Object.keys(actions);
2836

29-
const requests$ = obs.merge(...verbs.map(verb => actions[verb].request));
37+
const requests$ = obs.merge(
38+
...verbs.map((verb: keyof typeof actions) => actions[verb].request),
39+
);
3040

31-
const responses$ = obs.merge(...verbs.map(verb => actions[verb].response));
41+
const responses$ = obs.merge(
42+
...verbs.map((verb: keyof typeof actions) => actions[verb].response),
43+
);
3244

3345
const delayedRequests$ = requests$.delay(1000);
3446

@@ -48,10 +60,10 @@ const loading$ = requests$
4860
);
4961

5062
export default {
51-
links$,
52-
forms$,
5363
body$,
54-
url$,
64+
forms$,
65+
links$,
5566
loading$,
5667
mediaType$,
68+
url$,
5769
};

src/types/index.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface HalLinks {
1515
export interface HalResource {
1616
readonly _links?: HalLinks;
1717
readonly _embedded?: EmbeddedResources;
18+
[key: string]: any;
1819
}
1920

2021
export interface EmbeddedResources {
@@ -29,10 +30,12 @@ export interface NavigatableProps {
2930
}
3031

3132
export interface HttpResponse {
32-
body: { [key: string]: any } | string | undefined;
33+
body: object | undefined | string;
34+
headers: { [key: string]: string };
35+
ok: boolean;
3336
status: number;
3437
statusText: string;
35-
ok: boolean;
38+
url: string;
3639
}
3740

3841
export interface HttpProblemDetailsResponse extends HttpResponse {
@@ -42,3 +45,9 @@ export interface HttpProblemDetailsResponse extends HttpResponse {
4245
type: string;
4346
};
4447
}
48+
49+
export interface HttpRequest {
50+
body?: object;
51+
link: HalLink;
52+
headers: { [key: string]: string | undefined };
53+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import { parse } from 'uri-js';
33

44
const history = createBrowserHistory();
55

6-
const getPathAndQuery = url => {
6+
const getPathAndQuery = (url: string): string => {
77
const { path, query } = parse(url);
88

9-
return query ? `${path}?${query}` : path;
9+
return query ? `${path}?${query}` : path || '';
1010
};
1111

12-
const push = url => {
12+
const push = (url: string) => {
1313
const pathAndQuery = getPathAndQuery(url);
1414
if (pathAndQuery !== getPathAndQuery(window.location.href)) {
1515
history.push(pathAndQuery);

src/utils/http.js

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)