Skip to content

Commit

Permalink
feat: Replace codesandbox by running dashboard react-app directly
Browse files Browse the repository at this point in the history
  • Loading branch information
paveltiunov committed May 5, 2019
1 parent 61a9bb0 commit 861c817
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 28 deletions.
59 changes: 53 additions & 6 deletions packages/cubejs-playground/src/DashboardPage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* globals window */
import React, { Component } from 'react';
import { Spin, Button } from 'antd';
import DashboardSource from "./DashboardSource";
import DashboardRenderer from './DashboardRenderer';
import fetch from './playgroundFetch';

class DashboardPage extends Component {
constructor(props) {
Expand All @@ -17,19 +18,33 @@ class DashboardPage extends Component {
async loadDashboard(createApp) {
this.setState({
appCode: null,
sourceFiles: null,
loadError: null
});
await this.dashboardSource.load(createApp);
this.setState({
dashboardStarting: false,
appCode: !this.dashboardSource.loadError && this.dashboardSource.dashboardAppCode(),
sourceFiles: this.dashboardSource.sourceFiles,
loadError: this.dashboardSource.loadError
});
const dashboardStatus = await (await fetch('/playground/dashboard-app-status')).json();
this.setState({
dashboardRunning: dashboardStatus.running,
dashboardPort: dashboardStatus.dashboardPort
});
}

async startDashboardApp() {
this.setState({
dashboardStarting: true
});
await fetch('/playground/start-dashboard-app');
await this.loadDashboard();
}

render() {
const { appCode, sourceFiles, loadError } = this.state;
const {
appCode, dashboardPort, loadError, dashboardRunning, dashboardStarting
} = this.state;
if (loadError) {
return (
<div style={{ textAlign: 'center' }}>
Expand All @@ -48,13 +63,45 @@ class DashboardPage extends Component {
</div>
);
}
return appCode && <DashboardRenderer source={appCode} sourceFiles={sourceFiles}/>
|| (
if (!appCode) {
return (
<h2 style={{ textAlign: 'center' }}>
<Spin />
&nbsp;Creating dashboard react-app. It may take several minutes...
</h2>
);
}
if (!dashboardRunning) {
return (
<div style={{ textAlign: 'center' }}>
<h2>
Dashboard App is not running.
<br/>
Please start dashboard app or run it manually using `$ npm run start` in dashboard-app directory.
</h2>
<p style={{ textAlign: 'center' }}>
<Button
type="primary"
size="large"
loading={dashboardStarting}
onClick={() => this.startDashboardApp(true)}
>
Start dashboard app
</Button>
</p>
</div>
);
}
return (
<iframe
src={`http://${window.location.hostname}:${dashboardPort}`}
style={{
width: '100%', height: '100%', border: 0, borderRadius: 4, overflow: 'hidden'
}}
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
title="Dashboard"
/>
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/cubejs-playground/src/DashboardSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class DashboardSource {
const dependency = importName[0].indexOf('@') === 0 ? [importName[0], importName[1]].join('/') : importName[0];
return { [dependency]: 'latest' };
}).reduce((a, b) => ({ ...a, ...b }));
fetchWithRetry('/playground/ensure-dependencies', {
await fetchWithRetry('/playground/ensure-dependencies', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
Expand Down
88 changes: 67 additions & 21 deletions packages/cubejs-server-core/core/DevServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ class DevServer {
if (!await fs.pathExists(dashboardAppPath) || this.createReactAppInit) {
if (!this.createReactAppInit) {
this.cubejsServer.event('Dev Server Create Dashboard App');
this.createReactAppInit = executeCommand('npx', ['create-react-app', dashboardAppPath]);
this.createReactAppInit = executeCommand('npm', ['install', '-g', 'create-react-app'])
.then(() => executeCommand('create-react-app', [dashboardAppPath]));
}
await this.createReactAppInit;
this.cubejsServer.event('Dev Server Create Dashboard App Success');
Expand Down Expand Up @@ -155,31 +156,76 @@ class DevServer {
app.post('/playground/ensure-dependencies', catchErrors(async (req, res) => {
this.cubejsServer.event('Dev Server App Ensure Dependencies');
const { dependencies } = req.body;
const packageJson = await fs.readJson(path.join(dashboardAppPath, 'package.json'));
const toInstall = Object.keys(dependencies).filter(dependency => !packageJson.dependencies[dependency]);
if (toInstall.length) {
this.cubejsServer.event('Dev Server Dashboard Npm Install');
const cmd = () => executeCommand(
'npm',
['install', '--save'].concat(toInstall),
{ cwd: path.resolve(dashboardAppPath) }
);
if (this.curNpmInstall) {
this.curNpmInstall = this.curNpmInstall.then(cmd);
} else {
this.curNpmInstall = cmd();
const cmd = async () => {
const packageJson = await fs.readJson(path.join(dashboardAppPath, 'package.json'));
const toInstall = Object.keys(dependencies).filter(dependency => !packageJson.dependencies[dependency]);
if (toInstall.length) {
this.cubejsServer.event('Dev Server Dashboard Npm Install');
await executeCommand(
'npm',
['install', '--save'].concat(toInstall),
{ cwd: path.resolve(dashboardAppPath) }
);
this.cubejsServer.event('Dev Server Dashboard Npm Install Success');
}
const { curNpmInstall } = this;
await this.curNpmInstall;
if (curNpmInstall === this.curNpmInstall) {
this.curNpmInstall = null;
}
await executeCommand('npm', ['install', '--save'].concat(toInstall), { cwd: path.resolve(dashboardAppPath) });
this.cubejsServer.event('Dev Server Dashboard Npm Install Success');
return toInstall;
};
if (this.curNpmInstall) {
this.curNpmInstall = this.curNpmInstall.then(cmd);
} else {
this.curNpmInstall = cmd();
}
const { curNpmInstall } = this;
const toInstall = await this.curNpmInstall;
if (curNpmInstall === this.curNpmInstall) {
this.curNpmInstall = null;
}
res.json({ toInstall });
}));

const dashboardAppPort = this.cubejsServer.options.dashboardAppPort || 3050;

app.get('/playground/start-dashboard-app', catchErrors(async (req, res) => {
this.cubejsServer.event('Dev Server Start Dashboard App');
if (!this.dashboardAppProcess) {
this.dashboardAppProcess = spawn('npm', ['run', 'start'], {
cwd: dashboardAppPath,
env: {
...process.env,
PORT: dashboardAppPort
}
});
this.dashboardAppProcess.dashboardUrlPromise = new Promise((resolve) => {
this.dashboardAppProcess.stdout.on('data', (data) => {
console.log(data.toString());
if (data.toString().match(/Compiled/)) {
resolve(dashboardAppPort);
}
});
});

this.dashboardAppProcess.on('close', exitCode => {
if (exitCode !== 0) {
console.log(`Dashboard react-app failed with exit code ${exitCode}`);
this.cubejsServer.event('Dev Server Dashboard App Failed', { exitCode });
}
this.dashboardAppProcess = null;
});
}

await this.dashboardAppProcess.dashboardUrlPromise;
res.json({ dashboardPort: dashboardAppPort });
}));

app.get('/playground/dashboard-app-status', catchErrors(async (req, res) => {
this.cubejsServer.event('Dev Server Dashboard App Status');
const dashboardPort = this.dashboardAppProcess && await this.dashboardAppProcess.dashboardUrlPromise;
res.json({
running: !!dashboardPort,
dashboardPort
});
}));

app.use(serveStatic(path.join(__dirname, '../playground')));
}
}
Expand Down

0 comments on commit 861c817

Please sign in to comment.