Skip to content

Commit cefe2f7

Browse files
authored
Change/error handling (codesandbox#10)
* intermediate * Fix error handling * Don't denormalize in the root
1 parent a7a272b commit cefe2f7

File tree

26 files changed

+314
-212
lines changed

26 files changed

+314
-212
lines changed

src/app/components/sandbox/CodeEditor/index.js

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React from 'react';
33
import CodeMirror from 'codemirror';
44
import styled from 'styled-components';
5-
import { debounce } from 'lodash';
5+
import type { Preferences, ModuleError } from 'common/types';
66

77
import { getCodeMirror } from 'app/utils/codemirror';
88
import prettify from 'app/utils/codemirror/prettify';
@@ -11,15 +11,13 @@ import 'codemirror/addon/dialog/dialog';
1111
import 'codemirror/addon/hint/show-hint';
1212
import 'codemirror/addon/tern/tern';
1313

14-
import type { Preferences } from 'common/types';
15-
1614
import Header from './Header';
1715

1816
const documentCache = {};
1917

2018
type Props = {
2119
code: ?string,
22-
error: ?Object,
20+
errors: ?Array<ModuleError>,
2321
id: string,
2422
title: string,
2523
modulePath: string,
@@ -41,32 +39,32 @@ const CodeContainer = styled.div`
4139
height: calc(100% - 6rem);
4240
`;
4341

44-
const handleError = (cm, currentError, nextError, nextCode, prevId, nextId) => {
45-
if (currentError || nextError) {
46-
if (
47-
currentError &&
48-
nextError &&
49-
currentError.line === nextError.line &&
50-
prevId === nextId
51-
) {
52-
return;
53-
}
54-
55-
if (currentError) {
56-
cm.getValue().split('\n').forEach((_, i) => {
57-
cm.removeLineClass(i, 'background', 'cm-line-error');
58-
});
59-
}
42+
const handleError = (
43+
cm: typeof CodeMirror,
44+
currentErrors: ?Array<ModuleError>,
45+
nextErrors: ?Array<ModuleError>,
46+
nextCode: ?string,
47+
prevId: string,
48+
nextId: string,
49+
) => {
50+
if (currentErrors && currentErrors.length > 0) {
51+
cm.getValue().split('\n').forEach((_, i) => {
52+
cm.removeLineClass(i, 'background', 'cm-line-error');
53+
});
54+
}
6055

61-
const code = nextCode || '';
62-
if (
63-
nextError &&
64-
(nextError.moduleId == null || nextError.moduleId === nextId) &&
65-
nextError.line !== 0 &&
66-
nextError.line <= code.split('\n').length
67-
) {
68-
cm.addLineClass(nextError.line - 1, 'background', 'cm-line-error');
69-
}
56+
if (nextErrors) {
57+
nextErrors.forEach(error => {
58+
const code = nextCode || '';
59+
if (
60+
error &&
61+
(error.moduleId == null || error.moduleId === nextId) &&
62+
error.line !== 0 &&
63+
error.line <= code.split('\n').length
64+
) {
65+
cm.addLineClass(error.line - 1, 'background', 'cm-line-error');
66+
}
67+
});
7068
}
7169
};
7270

@@ -76,7 +74,7 @@ export default class CodeEditor extends React.PureComponent {
7674
shouldComponentUpdate(nextProps: Props) {
7775
return (
7876
nextProps.id !== this.props.id ||
79-
nextProps.error !== this.props.error ||
77+
nextProps.errors !== this.props.errors ||
8078
this.props.canSave !== nextProps.canSave ||
8179
this.props.preferences !== nextProps.preferences
8280
);
@@ -105,13 +103,13 @@ export default class CodeEditor extends React.PureComponent {
105103
}
106104
};
107105

108-
componentWillReceiveProps(nextProps: Props) {
106+
componentWillUpdate(nextProps: Props) {
109107
const cm = this.codemirror;
110-
const { id: currentId, error: currentError } = this.props;
108+
const { id: currentId, errors: currentErrors } = this.props;
111109
const {
112110
id: nextId,
113111
code: nextCode,
114-
error: nextError,
112+
errors: nextErrors,
115113
title: nextTitle,
116114
} = nextProps;
117115

@@ -122,7 +120,7 @@ export default class CodeEditor extends React.PureComponent {
122120
nextCode,
123121
nextTitle,
124122
}).then(() => {
125-
handleError(cm, currentError, nextError, nextCode, currentId, nextId);
123+
handleError(cm, currentErrors, nextErrors, nextCode, currentId, nextId);
126124
});
127125
}
128126
}
@@ -253,9 +251,7 @@ export default class CodeEditor extends React.PureComponent {
253251

254252
if (preferences.lintEnabled) {
255253
System.import('app/utils/codemirror/eslint-lint')
256-
.then(initializer => {
257-
return initializer.default();
258-
})
254+
.then(initializer => initializer.default())
259255
.then(() => {
260256
this.codemirror.setOption('lint', true);
261257
});

src/app/components/sandbox/Preview/index.js

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { debounce } from 'lodash';
66

77
import type { Preferences } from 'app/store/preferences/reducer';
88

9-
import type { Module, Sandbox, Directory } from 'common/types';
9+
import type { Module, Sandbox, Directory, ModuleError } from 'common/types';
1010
import { frameUrl } from 'app/utils/url-generator';
1111
import { isMainModule } from 'app/store/entities/sandboxes/modules/validator';
1212
import defaultBoilerplates
@@ -37,12 +37,16 @@ type Props = {
3737
externalResources: typeof Sandbox.externalResources,
3838
preferences: Preferences,
3939
fetchBundle: (id: string) => Object,
40-
setProjectView: (id: string, isInProjectView: boolean) => void,
40+
setProjectView: (id: string, isInProjectView: boolean) => any,
4141
module: Module,
42-
setError: (id: string, error: ?{ message: string, line: number }) => void,
43-
clearErrors: () => void,
42+
addError: (
43+
sandboxId: string,
44+
error: ?{ message: string, line: number },
45+
) => any,
46+
clearErrors: (sandboxId: string) => any,
4447
sandboxActions: typeof sandboxActionCreators,
4548
noDelay: ?boolean,
49+
errors: ?Array<ModuleError>,
4650
};
4751

4852
type State = {
@@ -54,7 +58,7 @@ type State = {
5458
};
5559

5660
export default class Preview extends React.PureComponent {
57-
constructor(props) {
61+
constructor(props: Props) {
5862
super(props);
5963

6064
this.state = {
@@ -150,9 +154,7 @@ export default class Preview extends React.PureComponent {
150154
const { type } = e.data;
151155
if (type === 'error') {
152156
const { error } = e.data;
153-
this.setError(error);
154-
} else if (type === 'success') {
155-
this.clearErrors();
157+
this.addError(error);
156158
} else if (type === 'urlchange') {
157159
const url = e.data.url.replace('/', '');
158160
this.commitUrl(url);
@@ -187,7 +189,7 @@ export default class Preview extends React.PureComponent {
187189
}
188190
return;
189191
}
190-
192+
this.clearErrors();
191193
const renderedModule = this.getRenderedModule();
192194
this.sendMessage({
193195
type: 'compile',
@@ -203,20 +205,12 @@ export default class Preview extends React.PureComponent {
203205
});
204206
};
205207

206-
setError = (e: { moduleId: string, message: string, line: number }) => {
207-
const errorOriginModuleId = e.moduleId;
208-
const currentModuleId = this.getRenderedModule().id;
209-
210-
// Throw the error twice, because both modules can't render because of this
211-
// error
212-
if (errorOriginModuleId) {
213-
this.props.setError(errorOriginModuleId, e);
214-
}
215-
this.props.setError(currentModuleId, e);
208+
addError = (e: { moduleId: string, message: string, line: number }) => {
209+
this.props.addError(this.props.sandboxId, e);
216210
};
217211

218212
clearErrors = () => {
219-
this.props.clearErrors();
213+
this.props.clearErrors(this.props.sandboxId);
220214
};
221215

222216
updateUrl = (url: string) => {
@@ -292,11 +286,10 @@ export default class Preview extends React.PureComponent {
292286
sandboxActions,
293287
isInProjectView,
294288
setProjectView,
289+
errors,
295290
} = this.props;
296291
const { historyPosition, history, urlInAddressBar } = this.state;
297292

298-
const renderedModule = this.getRenderedModule();
299-
300293
const url = urlInAddressBar || '';
301294

302295
return (
@@ -313,11 +306,12 @@ export default class Preview extends React.PureComponent {
313306
/>
314307

315308
{!bundle.processing &&
316-
renderedModule.error &&
309+
errors &&
310+
errors.length > 0 &&
317311
<Message
318312
modules={modules}
319313
sandboxActions={sandboxActions}
320-
error={renderedModule.error}
314+
error={errors[0]}
321315
sandboxId={sandboxId}
322316
/>}
323317
{bundle.processing &&

src/app/pages/Sandbox/Editor/Content/Header/ShareView.js

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
import React from 'react';
2+
import { connect } from 'react-redux';
3+
import { createSelector } from 'reselect';
24
import styled from 'styled-components';
35
import ShareIcon from 'react-icons/lib/md/share';
46
import Files from 'embed/components/Files';
57
import ModeIcons from 'app/components/sandbox/ModeIcons';
8+
import {
9+
isMainModule,
10+
modulesFromSandboxSelector,
11+
} from 'app/store/entities/sandboxes/modules/selectors';
12+
import {
13+
directoriesFromSandboxSelector,
14+
} from 'app/store/entities/sandboxes/directories/selectors';
615
import {
716
optionsToParameterizedUrl,
817
protocolAndHost,
918
sandboxUrl,
1019
embedUrl,
1120
} from 'app/utils/url-generator';
1221

13-
import type { Sandbox } from 'common/types';
22+
import type { Sandbox, Directory, Module } from 'common/types';
1423

1524
import HoverMenu from './HoverMenu';
1625
import Action from './Action';
17-
import {
18-
isMainModule,
19-
} from '../../../../../store/entities/sandboxes/modules/selectors';
2026

2127
const Container = styled.div`
2228
position: relative;
@@ -114,12 +120,19 @@ const ButtonName = styled.div`
114120

115121
type Props = {
116122
sandbox: Sandbox,
123+
modules: Array<Module>,
124+
directories: Array<Directory>,
117125
sendMessage: (message: string) => void,
118126
};
119127

120128
const BUTTON_URL = 'https://codesandbox.io/static/img/play-codesandbox.svg';
121129

122-
export default class ShareView extends React.PureComponent {
130+
const mapStateToProps = createSelector(
131+
modulesFromSandboxSelector,
132+
directoriesFromSandboxSelector,
133+
(modules, directories) => ({ modules, directories }),
134+
);
135+
class ShareView extends React.PureComponent {
123136
props: Props;
124137
state = {
125138
showEditor: true,
@@ -197,11 +210,11 @@ export default class ShareView extends React.PureComponent {
197210
};
198211

199212
render() {
200-
const { sandbox } = this.props;
213+
const { sandbox, modules, directories } = this.props;
201214
const { showEditor, showPreview } = this.state;
202215

203216
const defaultModule =
204-
this.state.defaultModule || sandbox.modules.find(isMainModule).id;
217+
this.state.defaultModule || modules.find(isMainModule).id;
205218

206219
return (
207220
<Container>
@@ -241,8 +254,8 @@ export default class ShareView extends React.PureComponent {
241254
<h4>Default module to show and preview</h4>
242255

243256
<Files
244-
modules={sandbox.modules}
245-
directories={sandbox.directories}
257+
modules={modules}
258+
directories={directories}
246259
directoryId={null}
247260
currentModule={defaultModule}
248261
setCurrentModule={this.setDefaultModule}
@@ -256,8 +269,8 @@ export default class ShareView extends React.PureComponent {
256269
<input onFocus={this.select} value={this.getEditorUrl()} />
257270
<LinkName>Fullscreen url</LinkName>
258271
<input onFocus={this.select} value={this.getEmbedUrl()} />
259-
{/*<LinkName>Embed url (Medium/Embedly)</LinkName>
260-
<input onFocus={this.select} value={this.getEmbedUrl()} />*/}
272+
<LinkName>Embed url (Medium/Embedly)</LinkName>
273+
<input onFocus={this.select} value={this.getEditorUrl()} />
261274
<LinkName>iframe</LinkName>
262275
<textarea
263276
onFocus={this.select}
@@ -297,3 +310,5 @@ export default class ShareView extends React.PureComponent {
297310
);
298311
}
299312
}
313+
314+
export default connect(mapStateToProps)(ShareView);

src/app/pages/Sandbox/Editor/Content/Header/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type Props = {
7272
sandboxActions: typeof sandboxActionCreators,
7373
userActions: typeof userActionCreators,
7474
user: CurrentUser,
75+
canSave: boolean,
7576
};
7677

7778
export default class Header extends React.PureComponent {
@@ -120,8 +121,9 @@ export default class Header extends React.PureComponent {
120121
user,
121122
toggleWorkspace,
122123
workspaceHidden,
124+
canSave,
123125
} = this.props;
124-
const canSave = sandbox.modules.some(m => m.isNotSynced);
126+
125127
return (
126128
<Container>
127129
<Left>

0 commit comments

Comments
 (0)