Skip to content

Serve sketch preview from subdomain #1894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 53 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
c684281
Start creating preview server
catarak Feb 4, 2021
c051f0c
Merge develop, start to render preview from subdomain
catarak Feb 10, 2021
ab536ef
Merge branch 'develop' into chore/sandbox
catarak Feb 17, 2021
4993898
More work on sandbox rendering
catarak Feb 19, 2021
0a5a863
Merge branch 'develop' into chore/sandbox
catarak Feb 24, 2021
1a057fc
Render iframe from preview server
catarak Feb 24, 2021
1c10250
Render nested iframes
catarak Feb 24, 2021
1e3a13b
Start and stop messages work
catarak Feb 25, 2021
b59d735
Start passing files from editor to sandboxed iframe
catarak Mar 2, 2021
416c52d
Merge develop
catarak Mar 12, 2021
4e76e57
Merge branch 'develop' into chore/sandbox
catarak Mar 31, 2021
2dc6529
Add function syncFileContent, load previewScripts in EmbedFrame
catarak Mar 31, 2021
06cee37
Connect console messages from iframe to editor frame
catarak Apr 6, 2021
e7f5fad
Enable blob urls for text files in rendering
catarak Apr 7, 2021
b8f1192
Add new variables to .env.example
catarak Apr 7, 2021
263f48c
Merge develop
catarak Apr 7, 2021
d31916f
Render FullView with EmbedFrame
catarak Apr 8, 2021
2e9878a
Move embed/present routes to previewServer
catarak Apr 13, 2021
d912502
Fix full view by waiting until frame registers
catarak Apr 13, 2021
2252989
Move PreviewFrame to styled components
catarak Apr 13, 2021
5141186
Fix ConsoleInput to work with EmbedFrame
catarak Apr 14, 2021
cf8f0ed
Fix loading assets at sketch runtime
catarak Apr 14, 2021
c397fd4
Update webpack config so that preview server works in prod
catarak Apr 15, 2021
73ca77a
Fix propTypes for EmbedFrame, add sandbox/allow to PreviewFrame
catarak Apr 15, 2021
bbd8503
Merge branch 'develop' into chore/sandbox
catarak May 11, 2021
808e7b1
Render all linked JS files with blobUrl
catarak May 12, 2021
9240558
Add staging kubernetes config
catarak May 19, 2021
2d4c028
New commit to deploy to release
catarak May 25, 2021
ce60942
Fix index.integration.test
catarak May 25, 2021
d01c905
Merge branch 'develop' into chore/sandbox
catarak May 27, 2021
f640da8
Initialize files with path, update console errors to use file path
catarak Jun 8, 2021
a9d0852
Highlight runtime errors, select correct file
catarak Jun 8, 2021
d1b3f12
Handle errors in index.html
catarak Jun 9, 2021
c7b5e47
Expand console on runtime errors
catarak Jun 9, 2021
efeab9f
Fix autorefresh
catarak Jun 9, 2021
672f23e
Merge branch 'develop' into chore/sandbox
catarak Jun 14, 2021
c0def07
Update srcdoc-polyfill, fix rendering on Safari
catarak Jun 14, 2021
7df219c
Render index.html using blobUrl, update error stack printing
catarak Jun 15, 2021
448f0c6
Fix error parsing, fix fetching sektch runtime urls
catarak Jun 16, 2021
68897b7
Continue to update error parsing
catarak Jun 16, 2021
a2c3843
Remove unused code, update prod webpack build for previewScripts
catarak Jun 16, 2021
49a1e0b
Merge branch 'develop' into chore/sandbox
catarak Jun 29, 2021
913de33
Handle missing routes in previewServer
catarak Jun 29, 2021
1337767
Update present view baseUrl
catarak Jun 29, 2021
fe1f989
Add connection to MongoDB to previewServer
catarak Jun 29, 2021
8c490c9
Update p5.js and p5.sound.js version to 1.4.0
catarak Jun 30, 2021
787b8d4
Remove runtime error highlight after changing file content
catarak Jul 1, 2021
7a79098
Monkeypatch p5._report function to resolve file names
catarak Jul 1, 2021
9686236
Add p5.accessibility, remove sound output, update line offset for ind…
catarak Jul 6, 2021
21b787e
Fix sketch <base> when usaved, handle nonstring messages
catarak Jul 6, 2021
8d930ce
Update onerror for previewEntry
catarak Jul 6, 2021
07078c0
Upate onerror to work cross browser
catarak Jul 6, 2021
14513b9
Add cors to previewServier, enable cors for Release
catarak Jul 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ ML5_LIBRARY_PASS=helloml5
MOBILE_ENABLED=true
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
PORT=8000
PREVIEW_PORT=8002
EDITOR_URL=http://localhost:8000
PREVIEW_URL=http://localhost:8002
S3_BUCKET=<your-s3-bucket>
S3_BUCKET_URL_BASE=<alt-for-s3-url>
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
Expand Down
45 changes: 24 additions & 21 deletions client/index.integration.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describe('index.jsx integration', () => {
expect(
screen.getByRole('heading', { name: /preview/i })
).toBeInTheDocument();
const preview = screen.getByRole('main', { name: /sketch output/i });
const preview = screen.getByTitle(/sketch preview/i);
expect(preview).toBeInTheDocument();
});

Expand All @@ -152,24 +152,27 @@ describe('index.jsx integration', () => {
expect(screen.getByText('Sketch Files')).toBeInTheDocument();
});

it('clicking on play updates the preview iframe with a srcdoc, stop clears it', () => {
const playButton = screen.getByRole('button', {
name: /play only visual sketch/i
});
const preview = screen.getByRole('main', { name: /sketch output/i });
expect(preview.getAttribute('srcdoc')).toBeFalsy();
act(() => {
fireEvent.click(playButton);
});

expect(preview.getAttribute('srcdoc')).toBeTruthy();

const stopButton = screen.getByRole('button', {
name: /stop sketch/i
});
act(() => {
fireEvent.click(stopButton);
});
expect(preview.getAttribute('srcdoc')).toMatch(/(^|")\s*($|")/);
});
// this test doesn't make sense anymore :/
// how to fix it? could check if sketch gets sent to iframe
// via postmessage or something
// it('clicking on play updates the preview iframe with a srcdoc, stop clears it', () => {
// const playButton = screen.getByRole('button', {
// name: /play only visual sketch/i
// });
// const preview = screen.getByRole('main', { name: /sketch preview/i });
// expect(preview.getAttribute('srcdoc')).toBeFalsy();
// act(() => {
// fireEvent.click(playButton);
// });

// expect(preview.getAttribute('srcdoc')).toBeTruthy();

// const stopButton = screen.getByRole('button', {
// name: /stop sketch/i
// });
// act(() => {
// fireEvent.click(stopButton);
// });
// expect(preview.getAttribute('srcdoc')).toMatch(/(^|")\s*($|")/);
// });
});
22 changes: 20 additions & 2 deletions client/modules/IDE/actions/ide.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as ActionTypes from '../../../constants';
import { clearConsole } from './console';
import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher';

export function startVisualSketch() {
return {
Expand Down Expand Up @@ -248,9 +249,23 @@ export function showRuntimeErrorWarning() {
}

export function startSketch() {
return (dispatch) => {
return (dispatch, getState) => {
dispatch(clearConsole());
dispatch(startSketchAndRefresh());
dispatch(startVisualSketch());
dispatch(showRuntimeErrorWarning());
const state = getState();
dispatchMessage({
type: MessageTypes.SKETCH,
payload: {
files: state.files,
basePath: window.location.pathname,
gridOutput: state.preferences.gridOutput,
textOutput: state.preferences.textOutput
}
});
dispatchMessage({
type: MessageTypes.START
});
};
}

Expand All @@ -264,6 +279,9 @@ export function startAccessibleSketch() {

export function stopSketch() {
return (dispatch) => {
dispatchMessage({
type: MessageTypes.STOP
});
dispatch(stopAccessibleOutput());
dispatch(stopVisualSketch());
};
Expand Down
19 changes: 0 additions & 19 deletions client/modules/IDE/actions/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,24 +159,6 @@ export function setGridOutput(value) {
};
}

export function setSoundOutput(value) {
return (dispatch, getState) => {
dispatch({
type: ActionTypes.SET_SOUND_OUTPUT,
value
});
const state = getState();
if (state.user.authenticated) {
const formParams = {
preferences: {
soundOutput: value
}
};
updatePreferences(formParams, dispatch);
}
};
}

export function setTheme(value) {
// return {
// type: ActionTypes.SET_THEME,
Expand Down Expand Up @@ -225,7 +207,6 @@ export function setAllAccessibleOutput(value) {
return (dispatch) => {
dispatch(setTextOutput(value));
dispatch(setGridOutput(value));
dispatch(setSoundOutput(value));
};
}

Expand Down
2 changes: 1 addition & 1 deletion client/modules/IDE/actions/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function setNewProject(project) {
export function getProject(id, username) {
return (dispatch, getState) => {
dispatch(justOpenedProject());
apiClient
return apiClient
.get(`/${username}/projects/${id}`)
.then((response) => {
dispatch(setProject(response.data));
Expand Down
14 changes: 9 additions & 5 deletions client/modules/IDE/components/ConsoleInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CodeMirror from 'codemirror';
import { Encode } from 'console-feed';

import RightArrowIcon from '../../../images/right-arrow.svg';
import { dispatch } from '../../../utils/dispatcher';
import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher';

// heavily inspired by
// https://github.com/codesandbox/codesandbox-client/blob/92a1131f4ded6f7d9c16945dc7c18aa97c8ada27/packages/app/src/app/components/Preview/DevTools/Console/Input/index.tsx
Expand All @@ -19,7 +19,8 @@ class ConsoleInput extends React.Component {
}

componentDidMount() {
this._cm = CodeMirror(this.codemirrorContainer, { // eslint-disable-line
this._cm = CodeMirror(this.codemirrorContainer, {
// eslint-disable-line
theme: `p5-${this.props.theme}`,
scrollbarStyle: null,
keymap: 'sublime',
Expand All @@ -39,9 +40,12 @@ class ConsoleInput extends React.Component {
{ log: Encode({ method: 'command', data: [value] }) }
];
const consoleEvent = [{ method: 'command', data: [value] }];
dispatch({
source: 'console',
messages
dispatchMessage({
type: MessageTypes.EXECUTE,
payload: {
source: 'console',
messages
}
});
this.props.dispatchConsoleEvent(consoleEvent);
cm.setValue('');
Expand Down
81 changes: 42 additions & 39 deletions client/modules/IDE/components/Editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import babelParser from 'prettier/parser-babel';
import htmlParser from 'prettier/parser-html';
import cssParser from 'prettier/parser-postcss';
import { withTranslation } from 'react-i18next';
import StackTrace from 'stacktrace-js';
import 'codemirror/mode/css/css';
import 'codemirror/addon/selection/active-line';
import 'codemirror/addon/lint/lint';
Expand Down Expand Up @@ -115,7 +116,6 @@ class Editor extends React.Component {
styleSelectedText: true,
lint: {
onUpdateLinting: (annotations) => {
this.props.hideRuntimeErrorWarning();
this.updateLintingMessageAccessibility(annotations);
},
options: {
Expand Down Expand Up @@ -159,10 +159,11 @@ class Editor extends React.Component {
'change',
debounce(() => {
this.props.setUnsavedChanges(true);
this.props.hideRuntimeErrorWarning();
this.props.updateFileContent(this.props.file.id, this._cm.getValue());
if (this.props.autorefresh && this.props.isPlaying) {
this.props.clearConsole();
this.props.startRefreshSketch();
this.props.startSketch();
}
}, 1000)
);
Expand Down Expand Up @@ -246,41 +247,45 @@ class Editor extends React.Component {
);
}

if (prevProps.consoleEvents !== this.props.consoleEvents) {
this.props.showRuntimeErrorWarning();
}
for (let i = 0; i < this._cm.lineCount(); i += 1) {
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
}
if (this.props.runtimeErrorWarningVisible) {
this.props.consoleEvents.forEach((consoleEvent) => {
if (consoleEvent.method === 'error') {
if (
consoleEvent.data &&
consoleEvent.data[0] &&
consoleEvent.data[0].indexOf &&
consoleEvent.data[0].indexOf(')') > -1
) {
const n = consoleEvent.data[0].replace(')', '').split(' ');
const lineNumber = parseInt(n[n.length - 1], 10) - 1;
const { source } = consoleEvent;
const fileName = this.props.file.name;
const errorFromJavaScriptFile = `${source}.js` === fileName;
const errorFromIndexHTML =
source === fileName && fileName === 'index.html';
if (
!Number.isNaN(lineNumber) &&
(errorFromJavaScriptFile || errorFromIndexHTML)
) {
if (this.props.consoleEvents.length !== prevProps.consoleEvents.length) {
this.props.consoleEvents.forEach((consoleEvent) => {
if (consoleEvent.method === 'error') {
// It doesn't work if you create a new Error, but this works
// LOL
const errorObj = { stack: consoleEvent.data[0].toString() };
StackTrace.fromError(errorObj).then((stackLines) => {
this.props.expandConsole();
const line = stackLines.find(
(l) => l.fileName && l.fileName.startsWith('/')
);
if (!line) return;
const fileNameArray = line.fileName.split('/');
const fileName = fileNameArray.slice(-1)[0];
const filePath = fileNameArray.slice(0, -1).join('/');
const fileWithError = this.props.files.find(
(f) => f.name === fileName && f.filePath === filePath
);
this.props.setSelectedFile(fileWithError.id);
this._cm.addLineClass(
lineNumber,
line.lineNumber - 1,
'background',
'line-runtime-error'
);
}
});
}
});
} else {
for (let i = 0; i < this._cm.lineCount(); i += 1) {
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
}
});
}
}

if (this.props.file.id !== prevProps.file.id) {
for (let i = 0; i < this._cm.lineCount(); i += 1) {
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
}
}
}

Expand Down Expand Up @@ -440,7 +445,7 @@ Editor.propTypes = {
method: PropTypes.string.isRequired,
args: PropTypes.arrayOf(PropTypes.string)
})
),
).isRequired,
updateLintMessage: PropTypes.func.isRequired,
clearLintMessage: PropTypes.func.isRequired,
updateFileContent: PropTypes.func.isRequired,
Expand All @@ -453,7 +458,7 @@ Editor.propTypes = {
url: PropTypes.string
}).isRequired,
setUnsavedChanges: PropTypes.func.isRequired,
startRefreshSketch: PropTypes.func.isRequired,
startSketch: PropTypes.func.isRequired,
autorefresh: PropTypes.bool.isRequired,
isPlaying: PropTypes.bool.isRequired,
theme: PropTypes.string.isRequired,
Expand All @@ -471,15 +476,13 @@ Editor.propTypes = {
expandSidebar: PropTypes.func.isRequired,
isUserOwner: PropTypes.bool.isRequired,
clearConsole: PropTypes.func.isRequired,
showRuntimeErrorWarning: PropTypes.func.isRequired,
// showRuntimeErrorWarning: PropTypes.func.isRequired,
hideRuntimeErrorWarning: PropTypes.func.isRequired,
runtimeErrorWarningVisible: PropTypes.bool.isRequired,
provideController: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
};

Editor.defaultProps = {
consoleEvents: []
t: PropTypes.func.isRequired,
setSelectedFile: PropTypes.func.isRequired,
expandConsole: PropTypes.func.isRequired
};

function mapStateToProps(state) {
Expand All @@ -496,7 +499,7 @@ function mapStateToProps(state) {
user: state.user,
project: state.project,
toast: state.toast,
console: state.console,
consoleEvents: state.console,

...state.preferences,
...state.ide,
Expand Down
19 changes: 0 additions & 19 deletions client/modules/IDE/components/Preferences/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -437,23 +437,6 @@ class Preferences extends React.Component {
>
{this.props.t('Preferences.TableText')}
</label>
<input
type="checkbox"
onChange={(event) => {
this.props.setSoundOutput(event.target.checked);
}}
aria-label={this.props.t('Preferences.SoundOutputARIA')}
name="sound output"
id="sound-output-on"
value="On"
checked={this.props.soundOutput}
/>
<label
htmlFor="sound-output-on"
className="preference__option preference__canvas"
>
{this.props.t('Preferences.Sound')}
</label>
</div>
</div>
</TabPanel>
Expand All @@ -474,10 +457,8 @@ Preferences.propTypes = {
setLinewrap: PropTypes.func.isRequired,
textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired,
soundOutput: PropTypes.bool.isRequired,
setTextOutput: PropTypes.func.isRequired,
setGridOutput: PropTypes.func.isRequired,
setSoundOutput: PropTypes.func.isRequired,
lintWarning: PropTypes.bool.isRequired,
setLintWarning: PropTypes.func.isRequired,
theme: PropTypes.string.isRequired,
Expand Down
Loading