Skip to content

Commit

Permalink
fix(playground): Chart type doesn't switch in Dashboard App
Browse files Browse the repository at this point in the history
  • Loading branch information
paveltiunov committed Oct 10, 2019
1 parent ec53430 commit 23f604f
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 62 deletions.
17 changes: 12 additions & 5 deletions packages/cubejs-playground/src/DashboardSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class DashboardSource {
async load(createApp, { chartLibrary }) {
this.loadError = null;
if (createApp) {
await fetchWithRetry('/playground/ensure-dashboard-app', undefined, 5);
await fetchWithRetry('/playground/ensure-dashboard-app', undefined, 10);
}
const res = await fetchWithRetry('/playground/dashboard-app-files', undefined, 5);
const res = await fetchWithRetry('/playground/dashboard-app-files', undefined, 10);
const result = await res.json();
this.playgroundContext = await this.loadContext();
this.fileToTargetSource = {};
Expand All @@ -40,6 +40,9 @@ class DashboardSource {
if (!result.error && this.ensureDashboardIsInApp({ chartLibrary })) {
await this.persist();
}
if (!result.error) {
await this.ensureDependencies({});
}
}

async loadContext() {
Expand Down Expand Up @@ -85,6 +88,10 @@ class DashboardSource {
const dependency = importName[0].indexOf('@') === 0 ? [importName[0], importName[1]].join('/') : importName[0];
return this.withPeerDependencies(dependency);
}).reduce((a, b) => ({ ...a, ...b }));
await this.ensureDependencies(dependencies);
}

async ensureDependencies(dependencies) {
await fetchWithRetry('/playground/ensure-dependencies', {
method: 'POST',
headers: {
Expand All @@ -93,7 +100,7 @@ class DashboardSource {
body: JSON.stringify({
dependencies
})
}, 5);
}, 10);
}

// TODO move to dev server
Expand Down Expand Up @@ -149,8 +156,8 @@ class DashboardSource {
if (!dashboardAdded && headerElement) {
this.appLayoutAdded = true;
const scaffoldingFileToSnippet = {
'react/App.js': new AppSnippet(),
'react/index.js': new IndexSnippet(this.playgroundContext),
'react/App.js': new AppSnippet(this.playgroundContext),
'react/index.js': new IndexSnippet(),
'react/pages/ExplorePage.js': new ExploreSnippet(),
'react/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary)
};
Expand Down
24 changes: 19 additions & 5 deletions packages/cubejs-playground/src/scaffolding/react/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import React from "react";
import { ApolloProvider } from '@apollo/react-hooks';
import { Layout } from "antd";
import cubejs from '@cubejs-client/core';
import { CubeProvider } from "@cubejs-client/react";
import client from "./graphql/client";
import Header from "./components/Header";

// change to your actual endpoint
const API_URL = undefined;
// should be refreshed by your backend API endpoint. More info: https://cube.dev/docs/security
const CUBEJS_TOKEN = undefined;

const cubejsApi = cubejs(
CUBEJS_TOKEN,
{ apiUrl: `${API_URL}/cubejs-api/v1` }
);

const AppLayout = ({ children }) => (
<Layout
style={{
Expand All @@ -16,11 +28,13 @@ const AppLayout = ({ children }) => (
);

const App = ({ children }) => (
<ApolloProvider client={client}>
<AppLayout>
{children}
</AppLayout>
</ApolloProvider>
<CubeProvider cubejsApi={cubejsApi}>
<ApolloProvider client={client}>
<AppLayout>
{children}
</AppLayout>
</ApolloProvider>
</CubeProvider>
);

export default App;
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { QueryRenderer } from '@cubejs-client/react';
import { useCubeQuery } from '@cubejs-client/react';
import { Spin } from 'antd';

const TypeToChartComponent = {};

const renderChart = (Component) => ({ resultSet, error }) => (
(resultSet && <Component resultSet={resultSet} />)
|| (error && error.toString())
|| (<Spin />)
);

const ChartRenderer = ({ vizState, cubejsApi }) => vizState && (
<QueryRenderer
updateOnlyOnStateChange
query={vizState.query}
cubejsApi={cubejsApi}
render={
TypeToChartComponent[vizState.chartType]
&& renderChart(TypeToChartComponent[vizState.chartType])
}
/>
);
const TypeToMemoChartComponent = Object.keys(TypeToChartComponent)
.map(key => ({ [key]: React.memo(TypeToChartComponent[key]) }))
.reduce((a, b) => ({ ...a, ...b }));

const renderChart = Component => ({ resultSet, error }) => (resultSet && <Component resultSet={resultSet} />)
|| (error && error.toString()) || <Spin />;

const ChartRenderer = ({ vizState }) => {
const { query, chartType } = vizState;
const component = TypeToMemoChartComponent[chartType];
const renderProps = useCubeQuery(query);

return component && renderChart(component)(renderProps);
};

ChartRenderer.propTypes = {
vizState: PropTypes.object,
cubejsApi: PropTypes.object.isRequired
cubejsApi: PropTypes.object
};

ChartRenderer.defaultProps = {
vizState: null
vizState: {},
cubejsApi: null
};


export default ChartRenderer;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const ExploreQueryBuilder = ({
vizState={vizState}
setVizState={setVizState}
cubejsApi={cubejsApi}
wrapWithQueryRenderer={false}
render={({
validatedQuery, isQueryPresent, chartType, updateChartType,
measures, availableMeasures, updateMeasures,
Expand Down
15 changes: 2 additions & 13 deletions packages/cubejs-playground/src/scaffolding/react/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Route } from 'react-router-dom';
import cubejs from '@cubejs-client/core';
import ExplorePage from './pages/ExplorePage';
import DashboardPage from './pages/DashboardPage';
import App from './App';

// change to your actual endpoint
const API_URL = undefined;
// should be refreshed by your backend API endpoint. More info: https://cube.dev/docs/security
const CUBEJS_TOKEN = undefined;

const cubejsApi = cubejs(
CUBEJS_TOKEN,
{ apiUrl: `${API_URL}/cubejs-api/v1` }
);

ReactDOM.render(
<Router>
<App>
<Route
key="index"
exact
path="/"
render={(props) => <DashboardPage {...props} cubejsApi={cubejsApi}/>}
component={DashboardPage}
/>
<Route
key="explore"
path="/explore"
render={(props) => <ExplorePage {...props} cubejsApi={cubejsApi}/>}
component={ExplorePage}
/>
</App>
</Router>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const defaultLayout = i => ({
minH: 8
});

const DashboardPage = ({ cubejsApi }) => {
const DashboardPage = () => {
const { loading, error, data } = useQuery(GET_DASHBOARD_ITEMS);

if (loading) {
Expand All @@ -42,7 +42,7 @@ const DashboardPage = ({ cubejsApi }) => {
const dashboardItem = item => (
<div key={item.id} data-grid={defaultLayout(item)}>
<DashboardItem key={item.id} itemId={item.id} title={item.name}>
<ChartRenderer vizState={item.vizState} cubejsApi={cubejsApi} />
<ChartRenderer vizState={item.vizState} />
</DashboardItem>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ExploreQueryBuilder from "../components/QueryBuilder/ExploreQueryBuilder"
import { GET_DASHBOARD_ITEM } from "../graphql/queries";
import TitleModal from "../components/TitleModal.js";

const ExplorePage = withRouter(({ cubejsApi, history, location }) => {
const ExplorePage = withRouter(({ history, location }) => {
const [addingToDashboard, setAddingToDashboard] = useState(false);
const params = new URLSearchParams(location.search);
const itemId = params.get("itemId");
Expand Down Expand Up @@ -48,7 +48,6 @@ const ExplorePage = withRouter(({ cubejsApi, history, location }) => {
finalTitle={finalTitle}
/>
<ExploreQueryBuilder
cubejsApi={cubejsApi}
vizState={finalVizState}
setVizState={setVizState}
chartExtra={[
Expand Down
14 changes: 13 additions & 1 deletion packages/cubejs-playground/src/source/AppSnippet.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import traverse from "@babel/traverse";
import SourceSnippet from './SourceSnippet';
import ScaffoldingSources from '../codegen/ScaffoldingSources';
import * as t from "@babel/types";

class AppSnippet extends SourceSnippet {
constructor() {
constructor({ apiUrl, cubejsToken }) {
super(ScaffoldingSources['react/App.js']);
this.apiUrl = apiUrl;
this.cubejsToken = cubejsToken;
}

findDefinitions() {
Expand All @@ -19,6 +22,7 @@ class AppSnippet extends SourceSnippet {
const targetPath = this.insertAnchor(targetSource);

targetPath.replaceWith(appPath);
this.replaceTokens(targetSource);
}

insertAnchor(targetSource) {
Expand All @@ -35,6 +39,14 @@ class AppSnippet extends SourceSnippet {
}
return appClass;
}

replaceTokens(targetSource) {
const apiUrl = targetSource.definitions.find(d => d.get('id').node.name === 'API_URL');
apiUrl.get('init').replaceWith(t.stringLiteral(this.apiUrl));

const cubejsToken = targetSource.definitions.find(d => d.get('id').node.name === 'CUBEJS_TOKEN');
cubejsToken.get('init').replaceWith(t.stringLiteral(this.cubejsToken));
}
}

export default AppSnippet;
14 changes: 1 addition & 13 deletions packages/cubejs-playground/src/source/IndexSnippet.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import traverse from "@babel/traverse";
import SourceSnippet from './SourceSnippet';
import ScaffoldingSources from '../codegen/ScaffoldingSources';
import * as t from "@babel/types";

class IndexSnippet extends SourceSnippet {
constructor({ apiUrl, cubejsToken }) {
constructor() {
super(ScaffoldingSources['react/index.js']);
this.apiUrl = apiUrl;
this.cubejsToken = cubejsToken;
}

mergeTo(targetSource) {
super.mergeTo(targetSource);
this.replaceRouter(targetSource);
this.replaceTokens(targetSource);
}

replaceRouter(targetSource) {
Expand Down Expand Up @@ -44,14 +40,6 @@ class IndexSnippet extends SourceSnippet {
}
}

replaceTokens(targetSource) {
const apiUrl = targetSource.definitions.find(d => d.get('id').node.name === 'API_URL');
apiUrl.get('init').replaceWith(t.stringLiteral(this.apiUrl));

const cubejsToken = targetSource.definitions.find(d => d.get('id').node.name === 'CUBEJS_TOKEN');
cubejsToken.get('init').replaceWith(t.stringLiteral(this.cubejsToken));
}

findAppOrRouter(targetSource) {
let appElement = null;
traverse(targetSource.ast, {
Expand Down

0 comments on commit 23f604f

Please sign in to comment.