Skip to content

Commit be65dbe

Browse files
committed
tour: add in-app walk through
1 parent 12cac65 commit be65dbe

32 files changed

+817
-68
lines changed

app/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@
4343
"react-router": "5.2.0",
4444
"react-scripts": "3.4.1",
4545
"react-toastify": "6.0.6",
46-
"react-virtualized": "9.21.2"
46+
"react-virtualized": "9.21.2",
47+
"reactour": "1.18.0",
48+
"styled-components": "5.1.1"
4749
},
4850
"devDependencies": {
4951
"@storybook/addon-actions": "5.3.19",
@@ -67,6 +69,7 @@
6769
"@types/react-dom": "16.9.8",
6870
"@types/react-router": "5.1.8",
6971
"@types/react-virtualized": "9.21.10",
72+
"@types/reactour": "1.17.1",
7073
"@typescript-eslint/eslint-plugin": "3.5.0",
7174
"@typescript-eslint/parser": "3.5.0",
7275
"cross-env": "7.0.2",

app/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import './App.scss';
33
import { createStore, StoreProvider } from 'store';
44
import AlertContainer from 'components/common/AlertContainer';
55
import { ThemeProvider } from 'components/theme';
6+
import TourHost from 'components/tour/TourHost';
67
import Routes from './Routes';
78

89
const App = () => {
@@ -13,6 +14,7 @@ const App = () => {
1314
<ThemeProvider>
1415
<Routes />
1516
<AlertContainer />
17+
<TourHost />
1618
</ThemeProvider>
1719
</StoreProvider>
1820
);

app/src/__stories__/LoopPage.stories.tsx

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useEffect } from 'react';
2-
import { observable, ObservableMap, values } from 'mobx';
2+
import { observable } from 'mobx';
3+
import { lndListChannelsMany } from 'util/tests/sampleData';
34
import { useStore } from 'store';
45
import { Channel } from 'store/models';
56
import { Layout } from 'components/layout';
@@ -11,35 +12,23 @@ export default {
1112
parameters: { contained: true },
1213
};
1314

14-
const channelSubset = (channels: ObservableMap<string, Channel>) => {
15-
const few = values(channels)
16-
.slice(0, 20)
17-
.reduce((result, c) => {
18-
result[c.chanId] = c;
19-
return result;
20-
}, {} as Record<string, Channel>);
21-
return observable.map(few);
15+
export const Default = () => {
16+
return <LoopPage />;
2217
};
2318

24-
export const Default = () => {
25-
const { channelStore } = useStore();
19+
export const ManyChannels = () => {
20+
const store = useStore();
2621
useEffect(() => {
27-
// only use a small set of channels
28-
channelStore.channels = channelSubset(channelStore.channels);
29-
}, [channelStore]);
30-
22+
store.channelStore.channels = observable.map();
23+
lndListChannelsMany.channelsList.forEach(c => {
24+
const chan = new Channel(store, c);
25+
store.channelStore.channels.set(chan.chanId, chan);
26+
});
27+
});
3128
return <LoopPage />;
3229
};
3330

34-
export const ManyChannels = () => <LoopPage />;
35-
3631
export const InsideLayout = () => {
37-
const { channelStore } = useStore();
38-
useEffect(() => {
39-
// only use a small set of channels
40-
channelStore.channels = channelSubset(channelStore.channels);
41-
}, [channelStore]);
42-
4332
return (
4433
<Layout>
4534
<LoopPage />

app/src/__stories__/StoryWrapper.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ThemeProvider } from 'components/theme';
1111

1212
// mock the GRPC client to return sample data instead of making an actual request
1313
const grpc = {
14+
useSampleData: true,
1415
request: (methodDescriptor: any, opts: any, metadata: any) => {
1516
// fail any authenticated requests to simulate incorrect login attempts
1617
if (metadata && metadata.authorization) throw new AuthenticationError();

app/src/api/grpc.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ import {
88
import { DEV_HOST } from 'config';
99
import { AuthenticationError } from 'util/errors';
1010
import { grpcLog as log } from 'util/log';
11+
import { sampleApiResponses } from 'util/tests/sampleData';
1112

1213
class GrpcClient {
14+
/**
15+
* Indicates if the API should return sample data instead of making real GRPC requests
16+
*/
17+
useSampleData = false;
18+
1319
/**
1420
* Executes a single GRPC request and returns a promise which will resolve with the response
1521
* @param methodDescriptor the GRPC method to call on the service
@@ -22,6 +28,15 @@ class GrpcClient {
2228
metadata?: Metadata.ConstructorArg,
2329
): Promise<TRes> {
2430
return new Promise((resolve, reject) => {
31+
if (this.useSampleData) {
32+
const endpoint = `${methodDescriptor.service.serviceName}.${methodDescriptor.methodName}`;
33+
const data = sampleApiResponses[endpoint] || {};
34+
// the calling function expects the return value to have a `toObject` function
35+
const response: any = { toObject: () => data };
36+
resolve(response);
37+
return;
38+
}
39+
2540
const method = `${methodDescriptor.methodName}`;
2641
log.debug(`${method} request`, request.toObject());
2742
grpc.unary(methodDescriptor, {
@@ -59,6 +74,8 @@ class GrpcClient {
5974
onMessage: (res: TRes) => void,
6075
metadata?: Metadata.ConstructorArg,
6176
) {
77+
if (this.useSampleData) return;
78+
6279
const method = `${methodDescriptor.methodName}`;
6380
const client = grpc.client(methodDescriptor, {
6481
host: DEV_HOST,

app/src/api/lnd.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface LndEvents {
1313
* An API wrapper to communicate with the LND node via GRPC
1414
*/
1515
class LndApi extends BaseApi<LndEvents> {
16-
private _grpc: GrpcClient;
16+
_grpc: GrpcClient;
1717

1818
constructor(grpc: GrpcClient) {
1919
super();

app/src/api/loop.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface LoopEvents {
1414
* An API wrapper to communicate with the Loop daemon via GRPC
1515
*/
1616
class LoopApi extends BaseApi<LoopEvents> {
17-
private _grpc: GrpcClient;
17+
_grpc: GrpcClient;
1818

1919
constructor(grpc: GrpcClient) {
2020
super();

app/src/assets/icons/help-circle.svg

Lines changed: 5 additions & 0 deletions
Loading

app/src/components/NodeStatus.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const NodeStatus: React.FC = () => {
3030

3131
const { Wrapper, Balance, Divider } = Styled;
3232
return (
33-
<Wrapper>
33+
<Wrapper data-tour="node-status">
3434
<HeaderFour>{l('title')}</HeaderFour>
3535
<Tip overlay={l('offchainTip')}>
3636
<Jumbo>

app/src/components/base/icons.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ReactComponent as CloseIcon } from 'assets/icons/close.svg';
1111
import { ReactComponent as CopyIcon } from 'assets/icons/copy.svg';
1212
import { ReactComponent as DotIcon } from 'assets/icons/dot.svg';
1313
import { ReactComponent as DownloadIcon } from 'assets/icons/download.svg';
14+
import { ReactComponent as HelpCircleIcon } from 'assets/icons/help-circle.svg';
1415
import { ReactComponent as MaximizeIcon } from 'assets/icons/maximize.svg';
1516
import { ReactComponent as MenuIcon } from 'assets/icons/menu.svg';
1617
import { ReactComponent as MinimizeIcon } from 'assets/icons/minimize.svg';
@@ -73,6 +74,7 @@ export const ChevronsRight = Icon.withComponent(ChevronsRightIcon);
7374
export const Close = Icon.withComponent(CloseIcon);
7475
export const Copy = Icon.withComponent(CopyIcon);
7576
export const Dot = Icon.withComponent(DotIcon);
77+
export const HelpCircle = Icon.withComponent(HelpCircleIcon);
7678
export const Menu = Icon.withComponent(MenuIcon);
7779
export const Minimize = Icon.withComponent(MinimizeIcon);
7880
export const Maximize = Icon.withComponent(MaximizeIcon);

0 commit comments

Comments
 (0)