From cb5ec731f701a6cea75e3ae7c9f8f92a6393ef52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 14 Feb 2019 04:41:25 +0000 Subject: [PATCH 01/16] [Security] Bump handlebars from 4.0.12 to 4.1.0 Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.0. **This update includes security fixes.** - [Release notes](https://github.com/wycats/handlebars.js/releases) - [Changelog](https://github.com/wycats/handlebars.js/blob/v4.1.0/release-notes.md) - [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.0) Signed-off-by: dependabot[bot] --- yarn.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7151b4f..fab0e6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3271,8 +3271,9 @@ handle-thing@^1.2.5: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" handlebars@^4.0.3: - version "4.0.12" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + version "4.1.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" + integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== dependencies: async "^2.5.0" optimist "^0.6.1" From 1779d1f3a7952b0f6a1244ed5d177d82e1ddf4c7 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Feb 2019 10:27:47 +0100 Subject: [PATCH 02/16] =?UTF-8?q?=E0=B2=A0=5F=E0=B2=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx b/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx index 6a09018..afe4794 100644 --- a/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx +++ b/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx @@ -81,7 +81,7 @@ class JsonViewer extends PureComponent< ); const responses = await Promise.all( - [...new Set([pattern, String(pattern).replace('-', '')])].map(p => + [...new Set([pattern, String(pattern).replace(/-/g, '')])].map(p => http.get({ headers: { authorization }, link: { From dddcfb699704f458c0f0172865bf327429ce6b5a Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Feb 2019 13:00:08 +0100 Subject: [PATCH 03/16] using node's url module due to https://github.com/garycourt/uri-js/issues/31 --- package.json | 1 - .../HalViewer/components/JsonViewer.tsx | 22 ++++++++++++++----- src/utils/hal.ts | 4 ++-- yarn.lock | 2 +- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 589225c..d53ef58 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "react-remarkable": "1.1.3", "react-schema-form": "0.6.2", "rxjs": "5.4.3", - "uri-js": "4.2.2", "uri-template": "1.0.1", "uuid": "3.3.2" }, diff --git a/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx b/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx index afe4794..f22dbb0 100644 --- a/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx +++ b/src/stream-store/Viewer/HalViewer/components/JsonViewer.tsx @@ -7,7 +7,7 @@ import { connect, createState } from 'reactive'; import { Observable } from 'rxjs'; import rels from 'stream-store/rels'; import themes from 'themes'; -import { HalResource, NavigatableProps } from 'types'; +import { HalResource, HttpResponse, NavigatableProps } from 'types'; import uriTemplate from 'uri-template'; import { hal, http, reactJsonTheme } from 'utils'; @@ -91,16 +91,26 @@ class JsonViewer extends PureComponent< ), ); + const streams = this._getStreams(responses); + this.setState({ loading: false, - streams: Object.values( - responses.flatMap(({ body }) => - getStreamLinks(hal.normalizeResource(body as HalResource)), - ), - ), + streams, }); }; + _getStreams = (responses: HttpResponse[]) => + Object.values( + responses + .flatMap(({ body }) => + getStreamLinks(hal.normalizeResource(body as HalResource)), + ) + .map(({ _links, ...resource }) => ({ + ...resource, + _links: hal.resolveLinks('../../', _links), + })), + ); + _handlePotentialStreamIdClose = () => this.setState({ open: false, diff --git a/src/utils/hal.ts b/src/utils/hal.ts index 4bfe7f5..1c1790e 100644 --- a/src/utils/hal.ts +++ b/src/utils/hal.ts @@ -1,5 +1,5 @@ import { HalLink, HalLinks, HalResource } from 'types'; -import { resolve } from 'uri-js'; +import URL from 'url'; const resolveLinks = (url: string, links: HalLinks): HalLinks => Object.keys(links).reduce( @@ -7,7 +7,7 @@ const resolveLinks = (url: string, links: HalLinks): HalLinks => ...akk, [rel]: links[rel].map(({ href, ...link }) => ({ ...link, - href: resolve(url, href || './', { tolerant: true }), + href: URL.resolve(url, href || './'), rel, })), }), diff --git a/yarn.lock b/yarn.lock index 7151b4f..035a0fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7740,7 +7740,7 @@ upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" -uri-js@4.2.2, uri-js@^4.2.2: +uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" dependencies: From 9a998bebf99ae73a8b81bf9f5b8b4e4a39a702bb Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Tue, 12 Mar 2019 09:25:15 +0100 Subject: [PATCH 04/16] MinVer 1.0.0 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ae7b6e4..135b128 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /src COPY .git ./ -RUN dotnet tool install -g minver-cli --version 1.0.0-beta.2 && \ +RUN dotnet tool install -g minver-cli --version 1.0.0 && \ /root/.dotnet/tools/minver > .version FROM node:10.12.0-alpine AS build @@ -33,4 +33,4 @@ RUN \ echo "@sqlstreamstore:registry=https://www.myget.org/F/sqlstreamstore/npm/" >> .npmrc && \ yarn publish --new-version $(cat .version) --no-git-tag-version ;\ else echo "No API key found, skipping publishing..." ;\ - fi \ No newline at end of file + fi From efe0301abc2fcff86778695e73c65ba8a3ccc45d Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Fri, 22 Feb 2019 11:38:41 +0100 Subject: [PATCH 05/16] saving preferred theme --- src/themes.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/themes.ts b/src/themes.ts index a6e5545..7964576 100644 --- a/src/themes.ts +++ b/src/themes.ts @@ -24,7 +24,17 @@ const actions = { type: createAction(), }; -const defaultTheme = createTheme('light'); +const paletteTypeKey = 'paletteType'; + +const loadPaletteType = (): PaletteType => { + const type = window.localStorage.getItem(paletteTypeKey); + return type === 'dark' ? 'dark' : 'light'; +}; + +const savePaletteType = (type: PaletteType) => + window.localStorage.setItem(paletteTypeKey, type); + +const defaultTheme = createTheme(loadPaletteType()); interface ThemeState { theme: Theme; @@ -41,6 +51,8 @@ const theme$ = createState( }), ).map(({ theme }) => theme); +theme$.subscribe(({ palette: { type } }) => savePaletteType(type)); + export default { actions, defaultTheme, From e743f57477daed0c2815201fa1f6bd35cda1a6d9 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Mon, 18 Mar 2019 08:41:45 +0100 Subject: [PATCH 06/16] split up hal store into multiple files --- src/SqlStreamStoreBrowser.tsx | 4 +- src/stream-store/store/hal.ts | 71 --------------------- src/stream-store/store/hal/body.ts | 11 ++++ src/stream-store/store/hal/forms.ts | 23 +++++++ src/stream-store/store/hal/index.ts | 13 ++++ src/stream-store/store/hal/links.ts | 9 +++ src/stream-store/store/hal/loading.ts | 31 +++++++++ src/stream-store/store/hal/streamBrowser.ts | 29 +++++++++ src/stream-store/store/hal/url.ts | 5 ++ src/stream-store/store/index.ts | 2 + src/stream-store/store/markdown.ts | 2 +- 11 files changed, 126 insertions(+), 74 deletions(-) delete mode 100644 src/stream-store/store/hal.ts create mode 100644 src/stream-store/store/hal/body.ts create mode 100644 src/stream-store/store/hal/forms.ts create mode 100644 src/stream-store/store/hal/index.ts create mode 100644 src/stream-store/store/hal/links.ts create mode 100644 src/stream-store/store/hal/loading.ts create mode 100644 src/stream-store/store/hal/streamBrowser.ts create mode 100644 src/stream-store/store/hal/url.ts diff --git a/src/SqlStreamStoreBrowser.tsx b/src/SqlStreamStoreBrowser.tsx index 50493ac..c96fd63 100644 --- a/src/SqlStreamStoreBrowser.tsx +++ b/src/SqlStreamStoreBrowser.tsx @@ -33,7 +33,7 @@ const getSelfAlias = (links: HalLinks) => .flatMap(rel => links[rel]) .filter(({ rel }) => rel && rel.indexOf('streamStore:') === 0) .filter( - ({ rel, href }) => + ({ href }) => !!links.self.filter(link => link.href === href).length, ) .map(({ rel }) => rel); @@ -58,7 +58,7 @@ const state$ = createState( store.hal$.links$.map(links => ['_links', () => links]), store.hal$.forms$.map(forms => ['forms', () => forms]), store.hal$.loading$.map(loading => ['loading', () => loading]), - store.hal$.mediaType$.map(mediaType => ['mediaType', () => mediaType]), + store.mediaType$.map(mediaType => ['mediaType', () => mediaType]), themes.theme$.map(theme => ['theme', () => theme]), ), obs.of({ diff --git a/src/stream-store/store/hal.ts b/src/stream-store/store/hal.ts deleted file mode 100644 index d489342..0000000 --- a/src/stream-store/store/hal.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { Observable as obs } from 'rxjs'; -import actions from 'stream-store/actions'; -import { HalResource } from 'types'; -import { hal, mediaTypes } from 'utils'; -import mediaType$ from './mediaType'; - -const body$ = actions.get.response - .zip(mediaType$) - .filter(([body, mediaType]) => mediaType === mediaTypes.hal) - .map(([{ body }]) => hal.normalizeResource(body as HalResource)); - -const url$ = actions.get.response.map(({ url }) => url); - -const links$ = body$ - .zip(url$) - .map(([{ _links }, url]) => hal.resolveLinks(url, _links)); - -const isJsonSchema = (schema: JSONSchema7 & HalResource) => - schema && schema.$schema && schema.$schema.endsWith('schema#'); - -const forms$ = body$ - .map(({ _embedded }) => _embedded) - .map(embedded => - Object.keys(embedded) - .filter(rel => isJsonSchema(embedded[rel][0])) - .reduce( - (akk, rel) => ({ - ...akk, - [rel]: embedded[rel][0], - }), - // tslint:disable-next-line:no-object-literal-type-assertion - {} as JSONSchema7, - ), - ); - -const verbs = Object.keys(actions); - -const requests$ = obs.merge( - ...verbs.map((verb: keyof typeof actions) => actions[verb].request), -); - -const responses$ = obs.merge( - ...verbs.map((verb: keyof typeof actions) => actions[verb].response), -); - -const delayedRequests$ = requests$.delay(1000); - -const loading$ = requests$ - .timestamp() - .combineLatest( - responses$.timestamp(), - delayedRequests$.timestamp(), - ( - { timestamp: requestTs }, - { timestamp: responseTs }, - { timestamp: delayedTs }, - ) => - requestTs > responseTs && - delayedTs > responseTs && - delayedTs >= requestTs, - ); - -export default { - body$, - forms$, - links$, - loading$, - mediaType$, - url$, -}; diff --git a/src/stream-store/store/hal/body.ts b/src/stream-store/store/hal/body.ts new file mode 100644 index 0000000..f5746bb --- /dev/null +++ b/src/stream-store/store/hal/body.ts @@ -0,0 +1,11 @@ +import { HalResource } from '../../../types'; +import { hal, mediaTypes } from '../../../utils'; +import actions from '../../actions'; +import mediaType$ from '../mediaType'; + +const body$ = actions.get.response + .zip(mediaType$) + .filter(([, mediaType]) => mediaType === mediaTypes.hal) + .map(([{ body }]) => hal.normalizeResource(body as HalResource)); + +export default body$; diff --git a/src/stream-store/store/hal/forms.ts b/src/stream-store/store/hal/forms.ts new file mode 100644 index 0000000..da970b1 --- /dev/null +++ b/src/stream-store/store/hal/forms.ts @@ -0,0 +1,23 @@ +import { JSONSchema7 } from 'json-schema'; +import { HalResource } from 'types'; +import body$ from './body'; + +const isJsonSchema = (schema: JSONSchema7 & HalResource) => + schema && schema.$schema && schema.$schema.endsWith('schema#'); + +const forms$ = body$ + .map(({ _embedded }) => _embedded) + .map(embedded => + Object.keys(embedded) + .filter(rel => isJsonSchema(embedded[rel][0])) + .reduce( + (akk, rel) => ({ + ...akk, + [rel]: embedded[rel][0], + }), + // tslint:disable-next-line:no-object-literal-type-assertion + {} as JSONSchema7, + ), + ); + +export default forms$; diff --git a/src/stream-store/store/hal/index.ts b/src/stream-store/store/hal/index.ts new file mode 100644 index 0000000..c413411 --- /dev/null +++ b/src/stream-store/store/hal/index.ts @@ -0,0 +1,13 @@ +import body$ from './body'; +import forms$ from './forms'; +import links$ from './links'; +import loading$ from './loading'; +import url$ from './url'; + +export default { + body$, + forms$, + links$, + loading$, + url$, +}; diff --git a/src/stream-store/store/hal/links.ts b/src/stream-store/store/hal/links.ts new file mode 100644 index 0000000..40c85cc --- /dev/null +++ b/src/stream-store/store/hal/links.ts @@ -0,0 +1,9 @@ +import { hal } from 'utils'; +import body$ from './body'; +import url$ from './url'; + +const links$ = body$ + .zip(url$) + .map(([{ _links }, url]) => hal.resolveLinks(url, _links)); + +export default links$; diff --git a/src/stream-store/store/hal/loading.ts b/src/stream-store/store/hal/loading.ts new file mode 100644 index 0000000..a707c4c --- /dev/null +++ b/src/stream-store/store/hal/loading.ts @@ -0,0 +1,31 @@ +import { Observable as obs } from 'rxjs'; +import actions from '../../actions'; + +const verbs = Object.keys(actions); + +const requests$ = obs.merge( + ...verbs.map((verb: keyof typeof actions) => actions[verb].request), +); + +const responses$ = obs.merge( + ...verbs.map((verb: keyof typeof actions) => actions[verb].response), +); + +const delayedRequests$ = requests$.delay(1000); + +const loading$ = requests$ + .timestamp() + .combineLatest( + responses$.timestamp(), + delayedRequests$.timestamp(), + ( + { timestamp: requestTs }, + { timestamp: responseTs }, + { timestamp: delayedTs }, + ) => + requestTs > responseTs && + delayedTs > responseTs && + delayedTs >= requestTs, + ); + +export default loading$; diff --git a/src/stream-store/store/hal/streamBrowser.ts b/src/stream-store/store/hal/streamBrowser.ts new file mode 100644 index 0000000..11d6bd3 --- /dev/null +++ b/src/stream-store/store/hal/streamBrowser.ts @@ -0,0 +1,29 @@ +import { createAction } from 'reactive'; +import { Observable } from 'rxjs'; +import rels from 'stream-store/rels'; +import uriTemplate from 'uri-template'; +import links$ from './links'; + +const isPotentialStreamId = (data: any) => + typeof data === 'number' || typeof data === 'string'; + +const clickPotentialStreamId = createAction().filter( + isPotentialStreamId, +) as Observable; + +const pattern$ = Observable.merge( + clickPotentialStreamId.map(pattern => pattern), + clickPotentialStreamId.map(pattern => String(pattern).replace(/-/g, '')), +).distinct(); + +const template$ = links$ + .filter(links => !!links[rels.browse]) + .map(links => links[rels.browse][0]) + .map(link => uriTemplate.parse(decodeURI(link.href))); + +pattern$.combineLatest(template$, (p, template) => ({ + headers: { authorization: '' }, + link: { + href: template.expand({ p, t: 'e' }), + }, +})); diff --git a/src/stream-store/store/hal/url.ts b/src/stream-store/store/hal/url.ts new file mode 100644 index 0000000..a6b1de7 --- /dev/null +++ b/src/stream-store/store/hal/url.ts @@ -0,0 +1,5 @@ +import actions from '../../actions'; + +const url$ = actions.get.response.map(({ url }) => url); + +export default url$; diff --git a/src/stream-store/store/index.ts b/src/stream-store/store/index.ts index 5b5d58d..12f25c2 100644 --- a/src/stream-store/store/index.ts +++ b/src/stream-store/store/index.ts @@ -1,7 +1,9 @@ import hal$ from './hal'; import markdown$ from './markdown'; +import mediaType$ from './mediaType'; export default { hal$, markdown$, + mediaType$, }; diff --git a/src/stream-store/store/markdown.ts b/src/stream-store/store/markdown.ts index e97d69c..57e8800 100644 --- a/src/stream-store/store/markdown.ts +++ b/src/stream-store/store/markdown.ts @@ -4,7 +4,7 @@ import mediaType$ from './mediaType'; const body$ = actions.get.response .zip(mediaType$) - .filter(([body, mediaType]) => mediaType === mediaTypes.markdown) + .filter(([, mediaType]) => mediaType === mediaTypes.markdown) .map(([{ body }]) => body); export default { From cef198eb1317e496172c144f0209be424c30a22d Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Mon, 18 Mar 2019 08:48:08 +0100 Subject: [PATCH 07/16] replaced deprecated component --- src/components/AuthorizationProvider.tsx | 4 ++-- src/components/HyperMediaControls/Dialog.tsx | 4 ++-- src/components/HyperMediaControls/RelButton.tsx | 4 ++-- src/components/NavigationLinks.tsx | 4 ++-- src/components/NavigationProvider.tsx | 4 ++-- src/stream-store/Viewer/HalViewer/Home.tsx | 6 +++--- src/stream-store/Viewer/HalViewer/Stream.tsx | 4 ++-- src/stream-store/Viewer/HalViewer/StreamMetadata.tsx | 6 +++--- .../Viewer/HalViewer/components/StreamMessageDetails.tsx | 4 ++-- src/stream-store/Viewer/HalViewer/index.tsx | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/components/AuthorizationProvider.tsx b/src/components/AuthorizationProvider.tsx index b91f950..fe7866d 100644 --- a/src/components/AuthorizationProvider.tsx +++ b/src/components/AuthorizationProvider.tsx @@ -1,4 +1,4 @@ -import React, { ComponentType, ReactNode, StatelessComponent } from 'react'; +import React, { ComponentType, FunctionComponent, ReactNode } from 'react'; import { AuthorizationProps } from 'types'; import getDisplayName from './getDisplayName'; @@ -6,7 +6,7 @@ const { Consumer, Provider } = React.createContext( undefined, ); -const AuthorizationProvider: StatelessComponent< +const AuthorizationProvider: FunctionComponent< AuthorizationProps & { children: ReactNode; } diff --git a/src/components/HyperMediaControls/Dialog.tsx b/src/components/HyperMediaControls/Dialog.tsx index 8926ba3..ef345ba 100644 --- a/src/components/HyperMediaControls/Dialog.tsx +++ b/src/components/HyperMediaControls/Dialog.tsx @@ -11,7 +11,7 @@ import { } from '@material-ui/core'; import { SlideProps } from '@material-ui/core/Slide'; import RelIcon from 'components/RelIcon'; -import React, { FormEvent, PureComponent, StatelessComponent } from 'react'; +import React, { FormEvent, FunctionComponent, PureComponent } from 'react'; import { HalLink } from 'types'; import HelpButton from './HelpButton'; import RelButton from './RelButton'; @@ -22,7 +22,7 @@ const styles = (theme: Theme) => ({ }, }); -const SlideUp: StatelessComponent = props => ( +const SlideUp: FunctionComponent = props => ( ); diff --git a/src/components/HyperMediaControls/RelButton.tsx b/src/components/HyperMediaControls/RelButton.tsx index 02ed47e..88feea8 100644 --- a/src/components/HyperMediaControls/RelButton.tsx +++ b/src/components/HyperMediaControls/RelButton.tsx @@ -1,14 +1,14 @@ import { Button } from '@material-ui/core'; import { ButtonProps } from '@material-ui/core/Button'; import RelIcon from 'components/RelIcon'; -import React, { StatelessComponent } from 'react'; +import React, { FunctionComponent } from 'react'; interface RelButtonProps { rel: string; title?: string; } -const RelButton: StatelessComponent = ({ +const RelButton: FunctionComponent = ({ rel, onClick, title, diff --git a/src/components/NavigationLinks.tsx b/src/components/NavigationLinks.tsx index 825c89c..0fb4266 100644 --- a/src/components/NavigationLinks.tsx +++ b/src/components/NavigationLinks.tsx @@ -2,8 +2,8 @@ import { IconButton } from '@material-ui/core'; import React, { ComponentType, FormEventHandler, + FunctionComponent, PureComponent, - StatelessComponent, } from 'react'; import { navigation } from 'stream-store'; import { HalLink, HalLinks, NavigatableProps } from 'types'; @@ -45,7 +45,7 @@ interface NavigationLinksProps { _links: HalLinks; } -const NavigationLinks: StatelessComponent = ({ +const NavigationLinks: FunctionComponent = ({ _links, }) => (