diff --git a/packages/cubejs-playground/src/DashboardSource.js b/packages/cubejs-playground/src/DashboardSource.js index c23d5ef4c539e..f5673982ad96e 100644 --- a/packages/cubejs-playground/src/DashboardSource.js +++ b/packages/cubejs-playground/src/DashboardSource.js @@ -18,7 +18,7 @@ class DashboardSource { } } - async applyTemplatePackages(templatePackages, templateConfig) { + async applyTemplatePackages(toApply, templateConfig = null) { if (!this.playgroundContext) { this.playgroundContext = await this.loadContext(); } @@ -28,7 +28,7 @@ class DashboardSource { 'Content-Type': 'application/json' }, body: JSON.stringify({ - templatePackages, + toApply, templateConfig: templateConfig || { credentials: this.playgroundContext } @@ -70,11 +70,12 @@ class DashboardSource { 'create-react-app', Object.keys(this.installedTemplates).find(template => template.match(/-static$/)), // TODO 'static-chart' - ], { - 'static-chart': { - chartCode - } - }); + ], { chartCode }); + } + + async templates() { + const { templates } = await (await fetch('/playground/manifest')).json(); + return templates; } } diff --git a/packages/cubejs-playground/src/TemplateGallery/TemplateGalleryPage.js b/packages/cubejs-playground/src/TemplateGallery/TemplateGalleryPage.js index cb746fe79a2a4..6e90e0a1e3d48 100644 --- a/packages/cubejs-playground/src/TemplateGallery/TemplateGalleryPage.js +++ b/packages/cubejs-playground/src/TemplateGallery/TemplateGalleryPage.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import styled from 'styled-components'; import '@ant-design/compatible/assets/index.css'; -import { Card, Col, Row, Typography } from 'antd'; +import { Card, Col, Row, Typography, Spin } from 'antd'; import { Redirect, withRouter } from 'react-router-dom'; import DashboardSource from '../DashboardSource'; import { frameworks } from '../ChartContainer'; @@ -113,26 +113,35 @@ class TemplateGalleryPage extends Component { this.state = { chartLibrary: chartLibraries[0].value, framework: 'react', - templatePackageName: 'react-antd-dynamic' + templatePackageName: 'react-antd-dynamic', + templates: null }; } async componentDidMount() { this.dashboardSource = new DashboardSource(); await this.dashboardSource.load(true); + this.setState({ - loadError: this.dashboardSource.loadError + loadError: this.dashboardSource.loadError, + templates: await this.dashboardSource.templates() }); } render() { const { - loadError + loadError, + templates } = this.state; + if (loadError && loadError.indexOf('Dashboard app not found') === -1) { return ; } + if (templates == null) { + return + } + const { chartLibrary, framework, templatePackageName, createOwnModalVisible, enableWebSocketTransport } = this.state; @@ -142,30 +151,8 @@ class TemplateGalleryPage extends Component { const templatePackage = this.dashboardSource && this.dashboardSource.templatePackages .find(m => m.name === templatePackageName); - const recipes = [{ - name: 'Dynamic Dashboard with React, AntD, and Recharts', - description: 'Use this template to create a dynamic dashboard application with React, AntD, and Chart.js. It comes with a dynamic query builder and Apollo GraphQL client. Use it when you want to allow users to edit dashboards.', - coverUrl: 'https://cube.dev/downloads/template-react-dashboard.png', - templatePackages: ['create-react-app', 'react-antd-dynamic', 'recharts-charts', 'antd-tables', 'credentials'] - }, { - name: 'Real-Time Dashboard with React, AntD, and Chart.js', - description: 'Use this template to create a static dashboard application with real-time WebSocket transport. Use it when users should not be allowed to edit dashboards and you want to provide them with real-time data refresh.', - templatePackages: ['create-react-app', 'react-antd-static', 'chartjs-charts', 'antd-tables', 'credentials', 'web-socket-transport'], - coverUrl: 'https://cube.dev/downloads/template-real-time-dashboard.png' - }, { - name: 'Material UI React Dashboard', - coverUrl: 'https://cube.dev/downloads/template-material-ui.jpg', - description: 'Use this template to create a Material UI–based static dashboard application and add charts to it by editing the source code or via Cube.js Playground. Use it when users should not be allowed to edit dashboards.', - templatePackages: ['create-react-app', 'react-material-static', 'recharts-charts', 'material-tables', 'credentials'] - }, { - name: 'Material UI D3 Dashboard', - coverUrl: 'https://cube.dev/downloads/template-material-d3.png', - description: 'Use this template to create a Material UI–based dashboard with D3.js. Add charts to it by editing the source code or via Cube.js Playground. Use it when users should not be allowed to edit dashboards.', - templatePackages: ['create-react-app', 'react-material-static', 'd3-charts', 'material-tables', 'credentials'] - }]; - - - const recipeCards = recipes.map(({ name, description, templatePackages, coverUrl }) => ( + + const recipeCards = templates.map(({ name, description, templatePackages, coverUrl }) => ( { - await this.dashboardSource.applyTemplatePackages(templatePackages); + await this.dashboardSource.applyTemplatePackages(name); history.push('/dashboard'); }} > @@ -207,8 +194,8 @@ class TemplateGalleryPage extends Component { templatePackageName, `${chartLibrary}-charts`, `${templatePackageName.match(/^react-(\w+)/)[1]}-tables`, // TODO - 'credentials' - ].concat(enableWebSocketTransport ? ['web-socket-transport'] : []); + 'react-credentials' + ].concat(enableWebSocketTransport ? ['react-web-socket-transport'] : []); await this.dashboardSource.applyTemplatePackages(templatePackages); history.push('/dashboard'); }} @@ -229,10 +216,10 @@ class TemplateGalleryPage extends Component { return ( - Build your app from one the popular templates below or + Build your app from one the popular templates below or{' '} this.setState({ createOwnModalVisible: true })}>create your own - + {recipeCards} diff --git a/packages/cubejs-server-core/.gitignore b/packages/cubejs-server-core/.gitignore index a6e3a41c81fc9..6bce0811e5fec 100755 --- a/packages/cubejs-server-core/.gitignore +++ b/packages/cubejs-server-core/.gitignore @@ -22,4 +22,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -test-output/ \ No newline at end of file +test-output/ +/dev/__tmp__ \ No newline at end of file diff --git a/packages/cubejs-server-core/core/DevServer.js b/packages/cubejs-server-core/core/DevServer.js index dae8ead20de98..1faee669c0f94 100644 --- a/packages/cubejs-server-core/core/DevServer.js +++ b/packages/cubejs-server-core/core/DevServer.js @@ -3,7 +3,14 @@ const fs = require('fs-extra'); const path = require('path'); const spawn = require('cross-spawn'); -const AppContainer = require('../dev/templates/AppContainer'); +const AppContainer = require('../dev/AppContainer'); +const DependencyTree = require('../dev/DependencyTree'); +const PackageFetcher = require('../dev/PackageFetcher'); + +const repo = { + owner: 'cube-js', + name: 'cubejs-playground-templates' +}; class DevServer { constructor(cubejsServer) { @@ -90,8 +97,8 @@ class DevServer { let lastApplyTemplatePackagesError = null; app.get('/playground/dashboard-app-create-status', catchErrors(async (req, res) => { - const sourcePath = await path.join(dashboardAppPath, 'src'); - + const sourcePath = path.join(dashboardAppPath, 'src'); + if (lastApplyTemplatePackagesError) { const toThrow = lastApplyTemplatePackagesError; lastApplyTemplatePackagesError = null; @@ -106,9 +113,9 @@ class DevServer { await this.applyTemplatePackagesPromise; } - if (!(await fs.pathExists(sourcePath))) { + if (!(fs.pathExistsSync(sourcePath))) { res.status(404).json({ - error: await fs.pathExists(dashboardAppPath) ? + error: fs.pathExistsSync(dashboardAppPath) ? `Dashboard app corrupted. Please remove '${path.resolve(dashboardAppPath)}' directory and recreate it` : `Dashboard app not found in '${path.resolve(dashboardAppPath)}' directory` }); @@ -120,11 +127,9 @@ class DevServer { return; } - const appContainer = new AppContainer(dashboardAppPath); - res.json({ status: 'created', - installedTemplates: await appContainer.getPackageVersions() + installedTemplates: AppContainer.getPackageVersions(dashboardAppPath) }); })); @@ -173,24 +178,55 @@ class DevServer { })); app.post('/playground/apply-template-packages', catchErrors(async (req, res) => { + this.cubejsServer.event('Dev Server Download Template Packages'); + + const fetcher = new PackageFetcher(repo); + this.cubejsServer.event('Dev Server App File Write'); - const { templatePackages, templateConfig } = req.body; - const appContainer = new AppContainer(dashboardAppPath, templatePackages, templateConfig); + const { toApply, templateConfig } = req.body; + const applyTemplates = async () => { + const manifestJson = await fetcher.manifestJSON(); + const response = await fetcher.downloadPackages(); + + let templatePackages = []; + if (typeof toApply === 'string') { + const template = manifestJson.templates.find(({ name }) => name === toApply); + templatePackages = template.templatePackages; + } else { + templatePackages = toApply; + } + + const dt = new DependencyTree(manifestJson, templatePackages); + + const appContainer = new AppContainer( + dt.getRootNode(), + { + appPath: dashboardAppPath, + packagesPath: response.packagesPath + }, + templateConfig + ); + this.cubejsServer.event('Dev Server Create Dashboard App'); await appContainer.applyTemplates(); this.cubejsServer.event('Dev Server Create Dashboard App Success'); this.cubejsServer.event('Dev Server Dashboard Npm Install'); + await appContainer.ensureDependencies(); this.cubejsServer.event('Dev Server Dashboard Npm Install Success'); + + fetcher.cleanup(); }; + if (this.applyTemplatePackagesPromise) { this.applyTemplatePackagesPromise = this.applyTemplatePackagesPromise.then(applyTemplates); } else { this.applyTemplatePackagesPromise = applyTemplates(); } const promise = this.applyTemplatePackagesPromise; + promise.then(() => { if (promise === this.applyTemplatePackagesPromise) { this.applyTemplatePackagesPromise = null; @@ -203,6 +239,11 @@ class DevServer { }); res.json(true); // TODO })); + + app.get('/playground/manifest', catchErrors(async (_, res) => { + const fetcher = new PackageFetcher(repo); + res.json(await fetcher.manifestJSON()); + })); app.use(serveStatic(path.join(__dirname, '../playground'), { lastModified: false, diff --git a/packages/cubejs-server-core/dev/AppContainer.js b/packages/cubejs-server-core/dev/AppContainer.js new file mode 100644 index 0000000000000..07301da3520e4 --- /dev/null +++ b/packages/cubejs-server-core/dev/AppContainer.js @@ -0,0 +1,120 @@ +const R = require('ramda'); +const fs = require('fs-extra'); +const path = require('path'); + +const SourceContainer = require('./SourceContainer'); +const { fileContentsRecursive, executeCommand } = require('./utils'); + +class AppContainer { + static getPackageVersions(appPath) { + try { + return fs.readJsonSync(path.join(appPath, 'package.json')).cubejsTemplates || {}; + } catch (error) { + return {}; + } + } + + constructor(rootNode, { appPath, packagesPath }, playgroundContext) { + this.rootNode = rootNode; + this.playgroundContext = playgroundContext; + this.appPath = appPath; + this.packagesPath = packagesPath; + + this.initDependencyTree(); + } + + async applyTemplates() { + this.sourceContainer = await this.loadSources(); + await this.rootNode.packageInstance.applyPackage(this.sourceContainer); + } + + initDependencyTree() { + this.createInstances(this.rootNode); + this.setChildren(this.rootNode); + } + + setChildren(node) { + if (!node) { + return; + } + + node.children.forEach((currentNode) => { + this.setChildren(currentNode); + const [installsTo] = Object.keys(currentNode.package.installsTo); + if (!node.packageInstance.children[installsTo]) { + node.packageInstance.children[installsTo] = []; + } + node.packageInstance.children[installsTo].push(currentNode.packageInstance); + }); + } + + createInstances(node) { + const stack = [node]; + + while (stack.length) { + const child = stack.pop(); + + const scaffoldingPath = path.join(this.packagesPath, child.package.name, 'scaffolding'); + // eslint-disable-next-line + const instance = require(path.join(this.packagesPath, child.package.name))({ + appContainer: this, + package: { + ...child.package, + scaffoldingPath, + }, + playgroundContext: this.playgroundContext, + }); + + child.packageInstance = instance; + + child.children.forEach((currentChild) => { + stack.push(currentChild); + }); + } + } + + async loadSources() { + return new SourceContainer(await fileContentsRecursive(this.appPath)); + } + + async persistSources(sourceContainer, packageVersions) { + const sources = sourceContainer.outputSources(); + await Promise.all(sources.map((file) => fs.outputFile(path.join(this.appPath, file.fileName), file.content))); + const packageJson = fs.readJsonSync(path.join(this.appPath, 'package.json')); + packageJson.cubejsTemplates = { + ...packageJson.cubejsTemplates, + ...packageVersions, + }; + await fs.writeJson(path.join(this.appPath, 'package.json'), packageJson, { + spaces: 2, + }); + } + + executeCommand(command, args, options) { + return executeCommand(command, args, options); + } + + async ensureDependencies() { + const dependencies = this.sourceContainer.importDependencies; + const packageJson = fs.readJsonSync(path.join(this.appPath, 'package.json')); + + if (!packageJson || !packageJson.dependencies) { + return []; + } + + const toInstall = R.toPairs(dependencies) + .filter(([dependency]) => !packageJson.dependencies[dependency]) + .map(([dependency, version]) => (version !== 'latest' ? `${dependency}@${version}` : dependency)); + + if (toInstall.length) { + await this.executeCommand('npm', ['install', '--save'].concat(toInstall), { cwd: path.resolve(this.appPath) }); + } + return toInstall; + } + + getPackageVersions() { + return AppContainer.getPackageVersions(this.appPath); + } +} + +module.exports = AppContainer; diff --git a/packages/cubejs-server-core/dev/DependencyTree.js b/packages/cubejs-server-core/dev/DependencyTree.js new file mode 100644 index 0000000000000..8b8b6abd517cd --- /dev/null +++ b/packages/cubejs-server-core/dev/DependencyTree.js @@ -0,0 +1,81 @@ +const R = require('ramda'); + +const indexByName = (packages) => R.indexBy(R.prop('name'), packages); + +class DependencyTree { + constructor(manifest, templatePackages) { + this.manifest = manifest; + this.templatePackages = templatePackages; + this.rootNode = null; + this.resolved = []; + + this.build(this.getRootNode()); + + const diff = R.difference(templatePackages, this.resolved); + if (diff.length) { + throw new Error(`The following packages could not be resolved: ${diff.join(', ')}`); + } + } + + packages() { + return this.manifest.packages; + } + + getRootNode() { + if (this.rootNode) { + return this.rootNode; + } + + const rootPackages = this.packages().filter((pkg) => pkg.installsTo == null); + const root = rootPackages.find((pkg) => this.templatePackages.includes(pkg.name)); + + this.resolved.push(root.name); + + this.rootNode = { + package: root, + children: [], + }; + + return this.rootNode; + } + + packagesInstalledTo(name) { + return indexByName(this.packages().filter((pkg) => (pkg.installsTo || {})[name])); + } + + getChildren(pkg) { + const children = []; + + Object.keys(pkg.receives || {}).forEach((name) => { + const currentPackages = this.packagesInstalledTo(name); + + if (Object.keys(currentPackages || {}).length) { + this.templatePackages.forEach((name) => { + if (currentPackages[name]) { + children.push(currentPackages[name]); + } + }); + } + }); + + return children; + } + + build(node) { + if (!node) { + return; + } + + (this.getChildren(node.package) || []).forEach((child) => { + const childNode = { + package: child, + children: [], + }; + node.children.push(childNode); + this.resolved.push(child.name); + this.build(childNode); + }); + } +} + +module.exports = DependencyTree; diff --git a/packages/cubejs-server-core/dev/PackageFetcher.js b/packages/cubejs-server-core/dev/PackageFetcher.js new file mode 100644 index 0000000000000..aa1a3bb8cf2c3 --- /dev/null +++ b/packages/cubejs-server-core/dev/PackageFetcher.js @@ -0,0 +1,72 @@ +const fs = require('fs-extra'); +const axios = require('axios').default; +const decompress = require('decompress'); +const decompressTargz = require('decompress-targz'); +const path = require('path'); + +const { executeCommand } = require('./utils'); + +class PackageFetcher { + constructor(repo) { + this.repo = repo; + this.tmpFolderPath = path.resolve('.', 'node_modules', '.tmp'); + + try { + fs.mkdirSync(this.tmpFolderPath); + } catch (err) { + if (err.code === 'EEXIST') { + fs.removeSync(this.tmpFolderPath); + fs.mkdirSync(this.tmpFolderPath); + } else { + throw err; + } + } + + this.repoArchivePath = `${this.tmpFolderPath}/master.tar.gz`; + } + + async manifestJSON() { + const response = await axios.get( + `https://api.github.com/repos/${this.repo.owner}/${this.repo.name}/contents/manifest.json` + ); + + return JSON.parse(Buffer.from(response.data.content, 'base64').toString()); + } + + async downloadRepo() { + const url = `https://github.com/${this.repo.owner}/${this.repo.name}/archive/master.tar.gz`; + const writer = fs.createWriteStream(this.repoArchivePath); + + const response = await axios.get(url, { + responseType: 'stream', + }); + + response.data.pipe(writer); + + return new Promise((resolve, reject) => { + writer.on('finish', resolve); + writer.on('error', reject); + }); + } + + async downloadPackages() { + await this.downloadRepo(); + + await decompress(this.repoArchivePath, this.tmpFolderPath, { + plugins: [decompressTargz()], + }); + + const dir = fs.readdirSync(this.tmpFolderPath).find((name) => !name.endsWith('tar.gz')); + await executeCommand('npm', ['install'], { cwd: path.resolve(this.tmpFolderPath, dir) }); + + return { + packagesPath: path.join(this.tmpFolderPath, dir, 'packages'), + }; + } + + cleanup() { + fs.removeSync(this.tmpFolderPath); + } +} + +module.exports = PackageFetcher; diff --git a/packages/cubejs-server-core/dev/SourceContainer.js b/packages/cubejs-server-core/dev/SourceContainer.js new file mode 100644 index 0000000000000..e8711b81564c6 --- /dev/null +++ b/packages/cubejs-server-core/dev/SourceContainer.js @@ -0,0 +1,38 @@ +const { toPairs, fromPairs } = require('ramda'); + +class SourceContainer { + constructor(sourceFiles) { + this.fileToTargetSource = {}; + this.fileContent = fromPairs(sourceFiles.map(({ fileName, content }) => [fileName, content])); + this.importDependencies = {}; + } + + getTargetSource(fileName) { + return this.fileToTargetSource[fileName]; + } + + addTargetSource(fileName, target) { + this.fileToTargetSource[fileName] = target; + } + + add(fileName, content) { + this.fileContent[fileName] = content; + } + + addImportDependencies(importDependencies = {}) { + // todo: version validation + this.importDependencies = { + ...this.importDependencies, + ...importDependencies + }; + } + + outputSources() { + return toPairs(this.fileContent).map(([fileName, content]) => ({ + fileName, + content, + })); + } +} + +module.exports = SourceContainer; diff --git a/packages/cubejs-server-core/dev/templates/AppContainer.js b/packages/cubejs-server-core/dev/templates/AppContainer.js deleted file mode 100644 index c1ef52ec54ab6..0000000000000 --- a/packages/cubejs-server-core/dev/templates/AppContainer.js +++ /dev/null @@ -1,195 +0,0 @@ -const fs = require('fs-extra'); -const path = require('path'); -const spawn = require('cross-spawn'); -const SourceContainer = require('./SourceContainer'); - -class AppContainer { - constructor(appPath, templatePackages, templateConfig) { - this.appPath = appPath; - this.templatePackages = templatePackages; - this.templateConfig = templateConfig; - this.packageCache = {}; - } - - async applyTemplates() { - if (!this.templatePackages || !this.templatePackages.length) { - throw new Error(`templatePackages is required`); - } - const toApply = await this.templatePackages.map( - templatePackage => async (packages) => packages.concat([await this.createTemplatePackage(templatePackage)]) - ).reduce((a, b) => a.then(b), Promise.resolve([])); - - this.initDependencies(); - - const rootPackages = toApply.filter(root => !toApply.find(p => this.packagesToReceive(p).indexOf(root) !== -1)); - if (rootPackages.length > 1) { - throw new Error(`Only one root allowed but found: ${rootPackages.map(p => p.name).join(', ')}`); - } - await rootPackages[0].applyPackage(await this.loadSources()); - } - - async loadSources() { - return new SourceContainer(await AppContainer.fileContentsRecursive(this.appPath)); - } - - static async fileContentsRecursive(dir, rootPath, includeNodeModules) { - if (!rootPath) { - rootPath = dir; - } - if (!(await fs.pathExists(dir))) { - return []; - } - if (dir.indexOf('node_modules') !== -1 && !includeNodeModules) { - return []; - } - const files = await fs.readdir(dir); - return (await Promise.all(files - .map(async file => { - const fileName = path.join(dir, file); - const stats = await fs.lstat(fileName); - if (!stats.isDirectory()) { - const content = await fs.readFile(fileName, "utf-8"); - return [{ - fileName: fileName.replace(rootPath, '').replace(/\\/g, '/'), - content - }]; - } else { - return AppContainer.fileContentsRecursive(fileName, rootPath, includeNodeModules); - } - }))).reduce((a, b) => a.concat(b), []); - } - - async getPackageVersions() { - return (await fs.readJson(path.join(this.appPath, 'package.json'))).cubejsTemplates || {}; - } - - async persistSources(sourceContainer, packageVersions) { - const sources = sourceContainer.outputSources(); - await Promise.all( - sources.map(file => fs.outputFile( - path.join(this.appPath, file.fileName), - file.content - )) - ); - const packageJson = await fs.readJson(path.join(this.appPath, 'package.json')); - packageJson.cubejsTemplates = { ...packageJson.cubejsTemplates, ...packageVersions }; - await fs.writeJson(path.join(this.appPath, 'package.json'), packageJson, { - spaces: 2 - }); - } - - async createTemplatePackage(templatePackage) { - if (!this.packageCache[templatePackage]) { - // eslint-disable-next-line global-require,import/no-dynamic-require - const TemplatePackageClass = require(`./packages/${templatePackage}`); - const template = new TemplatePackageClass(this.templateConfig[templatePackage]); - template.appContainer = this; - template.scaffoldingPath = path.join(__dirname, `packages/${templatePackage}/scaffolding`); - await template.initSources(); - this.packageCache[templatePackage] = template; - } - return this.packageCache[templatePackage]; - } - - initDependencies() { - this.templatePackages.forEach(p => { - const template = this.packageCache[p]; - if (template.requires) { - const requiredPackage = this.packageCache[template.requires]; - if (!requiredPackage) { - throw new Error(`Required package not found within selected template packages: ${requiredPackage}`); - } - requiredPackage.receivesPackages = requiredPackage.receivesPackages || []; - if (requiredPackage.receivesPackages.indexOf(template) === -1) { - requiredPackage.receivesPackages.push(template); - } - } - if (template.receives) { - template.receivesPackages = template.receivesPackages || []; - template.receivesPackages = template.receivesPackages.concat(template.receives.map( - receivableTypeOrName => Object.keys(this.packageCache) - .filter( - name => this.packageCache[name].type === receivableTypeOrName || name === receivableTypeOrName - ) - .map(name => this.packageCache[name]) - ).reduce((a, b) => a.concat(b), [])); - } - }); - } - - packagesToReceive(byPackage) { - return byPackage.receivesPackages || []; - } - - executeCommand(command, args, options) { - const child = spawn(command, args, { stdio: 'inherit', ...options }); - return new Promise((resolve, reject) => { - child.on('close', code => { - if (code !== 0) { - reject(new Error(`${command} ${args.join(' ')} failed with exit code ${code}. Please check your console.`)); - return; - } - resolve(); - }); - }); - } - - async ensureDependencies() { - const dependencies = await this.importDependencies(); - const packageJson = await fs.readJson(path.join(this.appPath, 'package.json')); - if (!packageJson || !packageJson.dependencies) { - return []; - } - const toInstall = Object.keys(dependencies) - .filter(dependency => !packageJson.dependencies[dependency]) - .map((dependency) => (dependency === 'graphql-tools' ? `${dependency}@5.0.0` : dependency)); - - if (toInstall.length) { - await this.executeCommand( - 'npm', - ['install', '--save'].concat(toInstall), - { cwd: path.resolve(this.appPath) } - ); - } - return toInstall; - } - - async importDependencies() { - const sourceContainer = await this.loadSources(); - - const allImports = sourceContainer.sourceFiles - .filter(f => f.fileName.match(/\.js$/)) - .map(f => sourceContainer.targetSourceByFile(f.fileName).imports) - .reduce((a, b) => a.concat(b)); - const dependencies = allImports - .filter(i => i.get('source').node.value.indexOf('.') !== 0) - .map(i => { - const importName = i.get('source').node.value.split('/'); - const dependency = importName[0].indexOf('@') === 0 ? [importName[0], importName[1]].join('/') : importName[0]; - return this.withPeerDependencies(dependency); - }).reduce((a, b) => ({ ...a, ...b })); - - return dependencies; - } - - withPeerDependencies(dependency) { - let result = { - [dependency]: 'latest' - }; - if (dependency === 'graphql-tag') { - result = { - ...result, - graphql: 'latest' - }; - } - if (dependency === 'react-chartjs-2') { - result = { - ...result, - 'chart.js': 'latest' - }; - } - return result; - } -} - -module.exports = AppContainer; diff --git a/packages/cubejs-server-core/dev/templates/AppSnippet.js b/packages/cubejs-server-core/dev/templates/AppSnippet.js deleted file mode 100644 index f1e1e8c898c02..0000000000000 --- a/packages/cubejs-server-core/dev/templates/AppSnippet.js +++ /dev/null @@ -1,28 +0,0 @@ -const traverse = require("@babel/traverse").default; -const SourceSnippet = require("./SourceSnippet"); -const t = require("@babel/types"); - -class AppSnippet extends SourceSnippet { - insertAnchor(targetSource) { - let appClass = null; - traverse(targetSource.ast, { - FunctionDeclaration: (path) => { - if (path.get('id').node.name === 'App') { - appClass = path; - } - } - }); - if (!appClass) { - return super.insertAnchor(targetSource); - } - return appClass; - } - - handleExistingMerge(existingDefinition, newDefinition) { - if (existingDefinition && existingDefinition.node.type === 'FunctionDeclaration') { - existingDefinition.replaceWith(t.variableDeclaration('const', [newDefinition.node])); - } - } -} - -module.exports = AppSnippet; diff --git a/packages/cubejs-server-core/dev/templates/ChartRendererSnippet.js b/packages/cubejs-server-core/dev/templates/ChartRendererSnippet.js deleted file mode 100644 index 921d5de7395f7..0000000000000 --- a/packages/cubejs-server-core/dev/templates/ChartRendererSnippet.js +++ /dev/null @@ -1,38 +0,0 @@ -const traverse = require("@babel/traverse").default; -const SourceSnippet = require("./SourceSnippet"); - -class ChartRendererSnippet extends SourceSnippet { - constructor(chartLibrary) { - super(); - this.chartLibrary = chartLibrary; - } - - handleExistingMerge(existingDefinition, newDefinition) { - if (existingDefinition.get('id').node.name === 'TypeToChartComponent') { - const existingPropertyNames = existingDefinition.get('init').get('properties').map(p => p.node.key.name); - existingDefinition.get('init').pushContainer( - 'properties', - newDefinition.node.init.properties.filter(p => existingPropertyNames.indexOf(p.key.name) === -1) - ); - } else { - super.handleExistingMerge(existingDefinition, newDefinition); - } - } - - insertAnchor(targetSource) { - let anchor = null; - traverse(targetSource.ast, { - VariableDeclaration: (path) => { - if (path.get('declarations')[0].get('id').node.name === 'TypeToChartComponent') { - anchor = path; - } - } - }); - if (!anchor) { - throw new Error(`renderChart class not found. Can't parse dashboard app. Please delete dashboard-app directory and try to create it again.`); - } - return anchor; - } -} - -module.exports = ChartRendererSnippet; diff --git a/packages/cubejs-server-core/dev/templates/ChartSnippet.js b/packages/cubejs-server-core/dev/templates/ChartSnippet.js deleted file mode 100644 index 3b73e53ae3071..0000000000000 --- a/packages/cubejs-server-core/dev/templates/ChartSnippet.js +++ /dev/null @@ -1,39 +0,0 @@ -const traverse = require("@babel/traverse").default; -const t = require("@babel/types"); -const SourceSnippet = require("./SourceSnippet"); - -class ChartSnippet extends SourceSnippet { - mergeTo(targetSource) { - const dashboardItemsArray = targetSource.definitions.find( - d => d.get('id').node.type === 'Identifier' && - d.get('id').node.name === 'DashboardItems' - ); - - if (!dashboardItemsArray) { - throw new Error(`DashboardItems array not found. Please use adding chart feature only with static dashboard`); - } - - traverse(this.ast, { - JSXOpeningElement: (path) => { - if (path.get('name').get('name').node === 'QueryRenderer') { - const query = path.get('attributes').find(p => p.get('name').get('name').node === 'query').get('value').get('expression'); - const rendererCall = path.get('attributes').find(p => p.get('name').get('name').node === 'render').get('value').get('expression'); - const chartType = rendererCall.get('arguments')[0].get('name').node.match(/^([a-zA-Z0-9_)]+)Render$/)[1]; - dashboardItemsArray.get('init').pushContainer( - 'elements', - t.objectExpression([ - t.objectProperty(t.identifier('id'), t.numericLiteral(dashboardItemsArray.get('init').get('elements').length)), - t.objectProperty(t.identifier('name'), t.stringLiteral("New Chart")), - t.objectProperty(t.identifier('vizState'), t.objectExpression([ - t.objectProperty(t.identifier('query'), query.node), - t.objectProperty(t.identifier('chartType'), t.stringLiteral(chartType)) - ])) - ]) - ); - } - } - }); - } -} - -module.exports = ChartSnippet; diff --git a/packages/cubejs-server-core/dev/templates/CredentialsSnippet.js b/packages/cubejs-server-core/dev/templates/CredentialsSnippet.js deleted file mode 100644 index 0dfec25e69bf6..0000000000000 --- a/packages/cubejs-server-core/dev/templates/CredentialsSnippet.js +++ /dev/null @@ -1,25 +0,0 @@ -const t = require("@babel/types"); -const SourceSnippet = require("./SourceSnippet"); - -class CredentialsSnippet extends SourceSnippet { - constructor({ apiUrl, cubejsToken }) { - super(); - this.apiUrl = apiUrl; - this.cubejsToken = cubejsToken; - } - - mergeTo(targetSource) { - super.mergeTo(targetSource); - this.replaceTokens(targetSource); - } - - 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)); - } -} - -module.exports = CredentialsSnippet; diff --git a/packages/cubejs-server-core/dev/templates/CssSourceSnippet.js b/packages/cubejs-server-core/dev/templates/CssSourceSnippet.js deleted file mode 100644 index 3633d9a565538..0000000000000 --- a/packages/cubejs-server-core/dev/templates/CssSourceSnippet.js +++ /dev/null @@ -1,13 +0,0 @@ -class CssSourceSnippet { - constructor(source) { - this.source = source; - } - - mergeTo(targetSource) { - if (!targetSource.source) { - targetSource.source = this.source; - } - } -} - -module.exports = CssSourceSnippet; diff --git a/packages/cubejs-server-core/dev/templates/CssTargetSource.js b/packages/cubejs-server-core/dev/templates/CssTargetSource.js deleted file mode 100644 index a90a896817dd8..0000000000000 --- a/packages/cubejs-server-core/dev/templates/CssTargetSource.js +++ /dev/null @@ -1,12 +0,0 @@ -class CssTargetSource { - constructor(fileName, source) { - this.source = source; - this.fileName = fileName; - } - - formattedCode() { - return this.source; - } -} - -module.exports = CssTargetSource; diff --git a/packages/cubejs-server-core/dev/templates/IndexSnippet.js b/packages/cubejs-server-core/dev/templates/IndexSnippet.js deleted file mode 100644 index cb1c16183b11b..0000000000000 --- a/packages/cubejs-server-core/dev/templates/IndexSnippet.js +++ /dev/null @@ -1,58 +0,0 @@ -const traverse = require("@babel/traverse").default; -const SourceSnippet = require("./SourceSnippet"); - -class IndexSnippet extends SourceSnippet { - mergeTo(targetSource) { - super.mergeTo(targetSource); - this.replaceRouter(targetSource); - } - - replaceRouter(targetSource) { - let routerElement = null; - traverse(targetSource.ast, { - JSXOpeningElement: (path) => { - if (path.get('name').get('name').node === 'Router') { - routerElement = path; - } - } - }); - - if (!routerElement) { - traverse(this.ast, { - JSXOpeningElement: (path) => { - if (path.get('name').get('name').node === 'Router') { - routerElement = path; - } - } - }); - - if (!routerElement) { - throw new Error(`Router element is not found`); - } - - const targetPath = this.findAppOrRouter(targetSource); - targetPath.replaceWith(routerElement.parentPath); - } - } - - findAppOrRouter(targetSource) { - let appElement = null; - traverse(targetSource.ast, { - JSXOpeningElement: (path) => { - if (path.get('name').get('name').node === 'Router' || path.get('name').get('name').node === 'App') { - appElement = path; - } - } - }); - if (!appElement) { - throw new Error(`App class not found. Can't parse dashboard app. Please delete dashboard-app directory and try to create it again.`); - } - return appElement.parentPath; - } - - insertAnchor(targetSource) { - return this.findAppOrRouter(targetSource).parentPath.parentPath; - } -} - -module.exports = IndexSnippet; diff --git a/packages/cubejs-server-core/dev/templates/RootTemplatePackage.js b/packages/cubejs-server-core/dev/templates/RootTemplatePackage.js deleted file mode 100644 index d60c088ab0201..0000000000000 --- a/packages/cubejs-server-core/dev/templates/RootTemplatePackage.js +++ /dev/null @@ -1,9 +0,0 @@ -const TemplatePackage = require('./TemplatePackage'); - -class RootTemplatePackage extends TemplatePackage { - async initSourceContainer(sourceContainer) { - this.sourceContainer = await this.appContainer.loadSources(); - } -} - -module.exports = RootTemplatePackage; diff --git a/packages/cubejs-server-core/dev/templates/SourceContainer.js b/packages/cubejs-server-core/dev/templates/SourceContainer.js deleted file mode 100644 index 3ced3ccf2985a..0000000000000 --- a/packages/cubejs-server-core/dev/templates/SourceContainer.js +++ /dev/null @@ -1,41 +0,0 @@ -const TargetSource = require("./TargetSource"); -const CssTargetSource = require("./CssTargetSource"); - -class SourceContainer { - constructor(sourceFiles) { - this.sourceFiles = sourceFiles || []; - this.fileToTargetSource = {}; - } - - mergeSnippetToFile(snippet, fileName, content) { - const targetSource = this.targetSourceByFile(fileName, content); - snippet.mergeTo(targetSource); - } - - targetSourceByFile(fileName, content) { - let file = this.sourceFiles.find(f => f.fileName === fileName); - if (!file) { - file = { fileName, content }; - } - if (!this.fileToTargetSource[fileName]) { - this.fileToTargetSource[fileName] = this.createTargetSource(file.fileName, file.content); - } - return this.fileToTargetSource[fileName]; - } - - createTargetSource(fileName, content) { - if (fileName.match(/\.css$/)) { - return new CssTargetSource(fileName, content); - } else { - return new TargetSource(fileName, content); - } - } - - outputSources() { - return Object.keys(this.fileToTargetSource).map(fileName => ({ - fileName, content: this.fileToTargetSource[fileName].formattedCode() - })); - } -} - -module.exports = SourceContainer; diff --git a/packages/cubejs-server-core/dev/templates/SourceSnippet.js b/packages/cubejs-server-core/dev/templates/SourceSnippet.js deleted file mode 100644 index 727fe5d3fd84f..0000000000000 --- a/packages/cubejs-server-core/dev/templates/SourceSnippet.js +++ /dev/null @@ -1,182 +0,0 @@ -const { parse } = require("@babel/parser"); -const traverse = require("@babel/traverse").default; -const t = require("@babel/types"); -const generator = require("@babel/generator").default; -const TargetSource = require('./TargetSource'); - -class SourceSnippet { - constructor(source, historySnippets) { - if (source) { - this.source = source; - } - this.historySnippets = historySnippets || []; - } - - get source() { - return generator(this.ast, {}, this.sourceValue).code; - } - - set source(source) { - if (!source) { - throw new Error('Empty source is provided'); - } - this.sourceValue = source; - this.ast = SourceSnippet.parse(source); - } - - static parse(source) { - try { - return parse(source, { - sourceType: 'module', - plugins: [ - "jsx" - ] - }); - } catch (e) { - throw new Error(`Can't parse source snippet: ${e.message}\n${source}`); - } - } - - mergeImport(targetSource, importDeclaration) { - const sameSourceImport = targetSource.imports.find( - i => i.get('source').node.value === importDeclaration.get('source').node.value && ( - i.get('specifiers')[0] && i.get('specifiers')[0].type - ) === ( - importDeclaration.get('specifiers')[0] && importDeclaration.get('specifiers')[0].type - ) - ); - if (!sameSourceImport) { - targetSource.imports[targetSource.imports.length - 1].insertAfter(importDeclaration.node); - targetSource.findAllImports(); - } else { - importDeclaration.get('specifiers').forEach(toInsert => { - const foundSpecifier = sameSourceImport.get('specifiers') - .find( - existing => ( - existing.get('imported').node && existing.get('imported').node.name - ) === ( - toInsert.get('imported').node && toInsert.get('imported').node.name - ) && ( - existing.get('local').node && existing.get('local').node.name - ) === ( - toInsert.get('local').node && toInsert.get('local').node.name - ) - ); - if (!foundSpecifier) { - sameSourceImport.pushContainer('specifiers', toInsert.node); - } - }); - } - } - - insertAnchor(targetSource) { - return targetSource.defaultExport; - } - - mergeDefinition(targetSource, constDef, allHistoryDefinitions) { - constDef.get('declarations').forEach(declaration => { - const existingDefinition = targetSource.definitions.find( - d => d.get('id').node.type === 'Identifier' && - declaration.get('id').node.type === 'Identifier' && - declaration.get('id').node.name === d.get('id').node.name - ); - if (!existingDefinition) { - this.insertAnchor(targetSource).insertBefore(t.variableDeclaration('const', [declaration.node])); - } else { - this.handleExistingMerge( - existingDefinition, - declaration, - allHistoryDefinitions - ); - } - }); - } - - generateCode(path, comments) { - if (!path.node) { - return ''; - } - if (path.node.type === 'VariableDeclarator') { - path = path.parent; - } else { - path = path.node; - } - return TargetSource.formatCode(generator(t.program([path]), { - comments: comments != null ? comments : true - }, this.sourceValue).code); - } - - compareDefinitions(a, b) { - return this.generateCode(a, false) === this.generateCode(b, false); - } - - handleExistingMerge(existingDefinition, newDefinition, allHistoryDefinitions) { - const historyDefinitions = allHistoryDefinitions.map(definitions => ( - definitions.find( - d => d.get('id').node.type === 'Identifier' && - existingDefinition.get('id').node.type === 'Identifier' && - existingDefinition.get('id').node.name === d.get('id').node.name - ) - )).filter(d => !!d); - const lastHistoryDefinition = historyDefinitions.length && historyDefinitions[historyDefinitions.length - 1]; - const newVariableDeclaration = t.variableDeclaration('const', [newDefinition.node]); - if ( - !this.compareDefinitions(existingDefinition, lastHistoryDefinition) && - !this.compareDefinitions(existingDefinition, newDefinition) - ) { - t.addComment(newVariableDeclaration, 'leading', `\n${this.generateCode(existingDefinition, false)}`); - } - if (existingDefinition.node.type === 'VariableDeclarator') { - existingDefinition = existingDefinition.parentPath; - } - existingDefinition.replaceWith(newVariableDeclaration); - } - - findImports() { - return SourceSnippet.importsByAst(this.ast); - } - - static importsByAst(ast) { - const chartImports = []; - - traverse(ast, { - ImportDeclaration: (path) => { - chartImports.push(path); - } - }); - - return chartImports; - } - - findDefinitions() { - return SourceSnippet.definitionsByAst(this.ast); - } - - static definitionsByAst(ast) { - const definitions = []; - - traverse(ast, { - VariableDeclaration: (path) => { - if (path.parent.type === 'Program') { - definitions.push(path); - } - } - }); - - return definitions; - } - - mergeTo(targetSource) { - const historyDefinitions = this.historySnippets.map( - snippet => snippet.findDefinitions().map(d => d.get('declarations')).reduce((a, b) => a.concat(b), []) - ); - const chartImports = this.findImports(); - const definitions = this.findDefinitions(); - chartImports.forEach(i => this.mergeImport(targetSource, i)); - definitions.forEach(d => this.mergeDefinition(targetSource, d, historyDefinitions)); - targetSource.findAllImports(); - targetSource.findAllDefinitions(); - } -} - -module.exports = SourceSnippet; diff --git a/packages/cubejs-server-core/dev/templates/StaticChartTemplate.js b/packages/cubejs-server-core/dev/templates/StaticChartTemplate.js deleted file mode 100644 index e6a8aed7b0dff..0000000000000 --- a/packages/cubejs-server-core/dev/templates/StaticChartTemplate.js +++ /dev/null @@ -1,15 +0,0 @@ -const TemplatePackage = require("./TemplatePackage"); -const ChartSnippet = require("./ChartSnippet"); - -class StaticChartTemplate extends TemplatePackage { - constructor(chartSource) { - super({ - name: 'chart', - fileToSnippet: { - '/src/pages/DashboardPage.js': new ChartSnippet(chartSource) - } - }); - } -} - -module.exports = StaticChartTemplate; diff --git a/packages/cubejs-server-core/dev/templates/TargetSource.js b/packages/cubejs-server-core/dev/templates/TargetSource.js deleted file mode 100644 index 5031ab20ec537..0000000000000 --- a/packages/cubejs-server-core/dev/templates/TargetSource.js +++ /dev/null @@ -1,77 +0,0 @@ -const { parse } = require("@babel/parser"); -const traverse = require("@babel/traverse").default; -const generator = require("@babel/generator").default; - -const prettier = require("prettier/standalone"); -// eslint-disable-next-line global-require -const plugins = [require("prettier/parser-babylon")]; - -class TargetSource { - constructor(fileName, source) { - this.source = source; - this.fileName = fileName; - try { - this.ast = parse(source, { - sourceFilename: fileName, - sourceType: 'module', - plugins: [ - "jsx" - ] - }); - } catch (e) { - throw new Error(`Can't parse ${fileName}: ${e.message}`); - } - this.findAllImports(); - this.findAllDefinitions(); - this.findDefaultExport(); - } - - findAllImports() { - this.imports = []; - traverse(this.ast, { - ImportDeclaration: (path) => { - this.imports.push(path); - } - }); - } - - findDefaultExport() { - traverse(this.ast, { - ExportDefaultDeclaration: (path) => { - if (path) { - this.defaultExport = path; - } - } - }); - } - - findAllDefinitions() { - this.definitions = []; - traverse(this.ast, { - VariableDeclaration: (path) => { - if (path.parent.type === 'Program') { - this.definitions.push(...path.get('declarations')); - } - }, - FunctionDeclaration: (path) => { - if (path.parent.type === 'Program') { - this.definitions.push(path); - } - } - }); - } - - code() { - return this.ast && generator(this.ast, {}, this.source).code; - } - - formattedCode() { - return TargetSource.formatCode(this.code()); - } - - static formatCode(code) { - return prettier.format(code, { parser: "babylon", plugins }); - } -} - -module.exports = TargetSource; diff --git a/packages/cubejs-server-core/dev/templates/TemplatePackage.js b/packages/cubejs-server-core/dev/templates/TemplatePackage.js deleted file mode 100644 index 45449431bc1c4..0000000000000 --- a/packages/cubejs-server-core/dev/templates/TemplatePackage.js +++ /dev/null @@ -1,111 +0,0 @@ -const R = require('ramda'); -const semver = require('semver'); -const AppContainer = require('./AppContainer'); -const SourceSnippet = require('./SourceSnippet'); -const CssSourceSnippet = require('./CssSourceSnippet'); - -const versionRegex = /\.([0-9-]+)\.(\w+)$/; - -class TemplatePackage { - constructor({ - name, - description, - fileToSnippet, - receives, - requires, - type, - version, - multiPackage - }) { - this.name = name; - this.description = description; - this.fileToSnippet = fileToSnippet || {}; - this.receives = receives; - this.requires = requires; - this.type = type; - this.version = version; - this.multiPackage = multiPackage; - } - - async initSources() { - const sources = await AppContainer.fileContentsRecursive(this.scaffoldingPath, null, true); - this.templateSources = sources - .map(({ fileName, content }) => ({ [fileName]: content })) - .reduce((a, b) => ({ ...a, ...b }), {}); - Object.keys(this.fileToSnippet).forEach(file => { - if (this.templateSources[file]) { - this.fileToSnippet[file].source = this.templateSources[file]; - } - }); - } - - async initSourceContainer(sourceContainer) { - this.sourceContainer = sourceContainer; - } - - static versionGte(a, b) { - const verA = a.replace('-', '.'); - const verB = b.replace('-', '.'); - return semver.gt(verA, verB) || verA === verB; - } - - mergeSources(sourceContainer, currentVersion) { - R.uniq( - Object.keys(this.templateSources).concat(Object.keys(this.fileToSnippet)) - ).filter(f => !f.match(versionRegex)).forEach(scaffoldingFile => { - const allFiles = Object.keys(this.templateSources) - .filter(f => f.match(versionRegex) && - f.replace(versionRegex, '.$2') && - (!currentVersion || TemplatePackage.versionGte(currentVersion, f.match(versionRegex)[1]))) - .concat([scaffoldingFile]); - - (allFiles.length > 1 ? R.range(2, allFiles.length + 1) : [1]).forEach( - toTake => { - const files = R.take(toTake, allFiles); - const historySnippets = R.dropLast(1, files).map(f => this.createSourceSnippet(f, this.templateSources[f])); - const lastVersionFile = files[files.length - 1]; - - sourceContainer.mergeSnippetToFile( - this.fileToSnippet[scaffoldingFile] || this.createSourceSnippet( - scaffoldingFile, - this.templateSources[lastVersionFile], - historySnippets - ), - scaffoldingFile, - this.templateSources[lastVersionFile] - ); - } - ); - }); - } - - createSourceSnippet(fileName, source, historySnippets) { - if (fileName.match(/\.css$/)) { - return new CssSourceSnippet(source, historySnippets); - } else { - return new SourceSnippet(source, historySnippets); - } - } - - async applyPackage(sourceContainer) { - await this.initSourceContainer(sourceContainer); - - const packageVersions = await this.appContainer.getPackageVersions(); - if (this.multiPackage || packageVersions[this.name] !== this.version) { - this.mergeSources(sourceContainer, packageVersions[this.name]); - await this.appContainer.persistSources( - this.sourceContainer, - this.multiPackage ? {} : { [this.name]: this.version } - ); - } - - const toReceive = this.appContainer.packagesToReceive(this); - await toReceive.map(p => () => this.receive(p)).reduce((a, b) => a.then(b), Promise.resolve()); - } - - async receive(packageToApply) { - await packageToApply.applyPackage(this.sourceContainer); - } -} - -module.exports = TemplatePackage; diff --git a/packages/cubejs-server-core/dev/templates/packages/README.md b/packages/cubejs-server-core/dev/templates/packages/README.md deleted file mode 100644 index 69d067a6fc504..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/README.md +++ /dev/null @@ -1,82 +0,0 @@ -

Cube.js

- -# [Cube.js Templates](https://cube.dev/templates/) - -Setting up a new project, writing tons of configurations, and wiring all the things together is hard and boring. It's fun to write actual application code, not Webpack config. That's why Create React App is so extremely popular. - -Same for analytics apps and dashboards. Although [Cube.js](https://github.com/cube-js/cube.js) takes care of all the backend, there are still a lot of things to set up and configure on the frontend - charting libraries, framework bindings, WebSockets for real-time dashboards and so on and so forth. - -[Cube.js Templates](https://cube.dev/templates/) to the rescue! Templates are open-source, ready-to-use frontend analytics apps. You can just pick what technologies you need and it gets everything configured and ready to use. - -React with WebSockets, Chart.js and Material UI? You got it. Template wires it all together and configure to work with the Cube.js backend. - -[![Cube.js Templates Demo](https://img.youtube.com/vi/YsbF95tbSAQ/0.jpg)](https://www.youtube.com/watch?v=YsbF95tbSAQ) - -Today we've released it only for React, but soon we'll add Angular, Vue, and Vanilla Javascript support. And it is open-sourced, same as Cube.js. Contributions are very welcomed! ❤️ - - -## 5 Minute Tutorial - -If you want to try it out today, here is the 5-minute getting started tutorial. - -### Install Cube.js CLI - - -```bash -$ npm isntall cubejs-cli -g -``` - -### Create New Project and Connect your database - -Cube.js CLI has `create` command to setup new project. We also need to pass a database type with `-d` option. Here is the [list of supported databases](https://cube.dev/docs/connecting-to-the-database). - -```bash -$ cubejs create hello-world -d postgres -``` - -Once created, `cd` into your new project and edit `.env` file to configure the database. - -```bash -CUBEJS_DB_NAME=my_database -CUBEJS_DB_TYPE=postgres -CUBEJS_API_SECRET=SUPER_SECRET -``` - -Now, run the following command to start a dev server. - -```bash -$ npm run dev -``` - -And navigate to the Cube.js Playground at [http://localhost:4000](http://localhost:4000) - -### Generate Schema - -Cube.js uses schema to know how to query your database. The schema is written in javascript and could be quite complex with a lot of logic. But as we just getting started we can auto-generate a simple schema in the playground. - -![](https://react-dashboard.cube.dev/images/1-screenshot-1.png) - -### Use Cube.js Templates to create a frontend app -As we already have a Cube.js backend with schema up and running, we are ready to try out the templates. - -Navigate to the "Dashboard App" tab in the playground. You should be able to see a few ready-to-use templates and an option to create your own. - -![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1suc88w9p7b6w16yr6xk.png) - -Feel free to click select whatever template works for you. Or you can mix different options and create your own template. - -![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/hxgrw6qdcmp68vjzbyfg.png) - -Once you created your app from the template, you can start it from the Cube.js playground. You can edit it later in the `dashboard-app` folder inside the project. - -That's it! Now, you have a full working both backend and frontend for your dashboard. You can follow [React Dashboard Guide](https://react-dashboard.cube.dev/) or [Real-Time Dashboard Guide](https://real-time-dashboard.cube.dev/) to learn how to customize the dashboard app and deploy it to production 🚀 - -Please feel free to share your feedback or ask any questions in the comments below or in this [Slack community](https://slack.cube.dev/). - -## What's in this directory? - -Here's repository of all template packages supported by Cube.js Templates. -Each package consists of `TemplatePackage` description and `scaffolding/` sources. -Babel is used to parse apply code changes and generate resulting code. -Each template packages has default rules how they applied. -Those defalts can easily be overriden by providing custom `SourceSnippet` implementations. diff --git a/packages/cubejs-server-core/dev/templates/packages/antd-tables/index.js b/packages/cubejs-server-core/dev/templates/packages/antd-tables/index.js deleted file mode 100644 index 982fb4af770fc..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/antd-tables/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class AntdTablesTemplate extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'antd-tables', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - version: '0.0.1' - }); - } -} - -module.exports = AntdTablesTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/antd-tables/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/antd-tables/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index b30fe1e41953c..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/antd-tables/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,22 +0,0 @@ -import { Row, Col, Statistic, Table } from 'antd'; - -const TypeToChartComponent = { - number: ({ resultSet }) => ( - - - {resultSet - .seriesNames() - .map(s => ( - - ))} - - - ), - table: ({ resultSet, pivotConfig }) => ( - - ) -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/index.js b/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/index.js deleted file mode 100644 index a6eee3d1026ef..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class BizchartTemplate extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'bizchart-charts', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - type: 'charts', - version: '0.0.1' - }); - } -} - -module.exports = BizchartTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index 55824192202a7..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/bizcharts-charts/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,50 +0,0 @@ -import { Chart, Axis, Tooltip, Geom, Coord, Legend } from 'bizcharts'; - -const stackedChartData = (resultSet) => { - const data = resultSet.pivot().map( - ({ xValues, yValuesArray }) => - yValuesArray.map(([yValues, m]) => ({ - x: resultSet.axisValuesString(xValues, ', '), - color: resultSet.axisValuesString(yValues, ', '), - measure: m && Number.parseFloat(m) - })) - ).reduce((a, b) => a.concat(b), []); - - return data; -}; - -const TypeToChartComponent = { - line: ({ resultSet }) => ( - - - - - - - ), - bar: ({ resultSet }) => ( - - - - - - - ), - area: ({ resultSet }) => ( - - - - - - - ), - pie: ({ resultSet }) => ( - - - {resultSet.seriesNames().map(s => ())} - - - {resultSet.seriesNames().map(s => ())} - - ) -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/index.js b/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/index.js deleted file mode 100644 index 6b20b84e79102..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class ChartjsTemplate extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'chartjs-charts', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - type: 'charts', - version: '0.0.1' - }); - } -} - -module.exports = ChartjsTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index 8eeb214fa0e6e..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/chartjs-charts/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,69 +0,0 @@ -import { Line, Bar, Pie } from 'react-chartjs-2'; - -const COLORS_SERIES = ['#FF6492', '#141446', '#7A77FF']; - -const TypeToChartComponent = { - line: ({ resultSet }) => { - const data = { - labels: resultSet.categories().map(c => c.category), - datasets: resultSet.series().map((s, index) => ( - { - label: s.title, - data: s.series.map(r => r.value), - borderColor: COLORS_SERIES[index], - fill: false - } - )), - }; - const options = {}; - return ; - }, - bar: ({ resultSet }) => { - const data = { - labels: resultSet.categories().map(c => c.category), - datasets: resultSet.series().map((s, index) => ( - { - label: s.title, - data: s.series.map(r => r.value), - backgroundColor: COLORS_SERIES[index], - fill: false - } - )), - }; - const options = { - scales: { xAxes: [{ stacked: true }] } - }; - return ; - }, - area: ({ resultSet }) => { - const data = { - labels: resultSet.categories().map(c => c.category), - datasets: resultSet.series().map((s, index) => ( - { - label: s.title, - data: s.series.map(r => r.value), - backgroundColor: COLORS_SERIES[index] - } - )), - }; - const options = { - scales: { yAxes: [{ stacked: true }] } - }; - return ; - }, - pie: ({ resultSet }) => { - const data = { - labels: resultSet.categories().map(c => c.category), - datasets: resultSet.series().map(s => ( - { - label: s.title, - data: s.series.map(r => r.value), - backgroundColor: COLORS_SERIES, - hoverBackgroundColor: COLORS_SERIES, - } - )) - }; - const options = {}; - return ; - } -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/create-react-app/index.js b/packages/cubejs-server-core/dev/templates/packages/create-react-app/index.js deleted file mode 100644 index 255b4cbb13113..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/create-react-app/index.js +++ /dev/null @@ -1,27 +0,0 @@ -const RootTemplatePackage = require("../../RootTemplatePackage"); - -class CreateReactAppTemplate extends RootTemplatePackage { - constructor() { - super({ - name: 'create-react-app', - description: 'Create react app', - fileToSnippet: {}, - version: '0.0.1' - }); - } - - async initSourceContainer(sourceContainer) { - await super.initSourceContainer(this.appContainer, sourceContainer); - if (!this.sourceContainer.sourceFiles.length) { - await this.appContainer.executeCommand('npx', ['create-react-app', this.appContainer.appPath]).catch(e => { - if (e.toString().indexOf('ENOENT') !== -1) { - throw new Error(`npx is not installed. Please update your npm: \`$ npm install -g npm\`.`); - } - throw e; - }); - await super.initSourceContainer(this.appContainer, sourceContainer); - } - } -} - -module.exports = CreateReactAppTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/credentials/index.js b/packages/cubejs-server-core/dev/templates/packages/credentials/index.js deleted file mode 100644 index 242d35ef9eb72..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/credentials/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const CredentialsSnippet = require("../../CredentialsSnippet"); - -class AppCredentialsTemplate extends TemplatePackage { - constructor(playgroundContext) { - super({ - name: 'credentials', - fileToSnippet: { - '/src/App.js': new CredentialsSnippet(playgroundContext) - }, - version: '0.0.1' - }); - } -} - -module.exports = AppCredentialsTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/credentials/scaffolding/src/App.js b/packages/cubejs-server-core/dev/templates/packages/credentials/scaffolding/src/App.js deleted file mode 100644 index 3fec74b9e85c6..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/credentials/scaffolding/src/App.js +++ /dev/null @@ -1,3 +0,0 @@ -const API_URL = undefined; - -const CUBEJS_TOKEN = undefined; diff --git a/packages/cubejs-server-core/dev/templates/packages/d3-charts/index.js b/packages/cubejs-server-core/dev/templates/packages/d3-charts/index.js deleted file mode 100644 index da6399ad8b970..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/d3-charts/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class D3Template extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'd3-charts', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - type: 'charts', - version: '0.0.1' - }); - } -} - -module.exports = D3Template; diff --git a/packages/cubejs-server-core/dev/templates/packages/d3-charts/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/d3-charts/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index d5e421c65514e..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/d3-charts/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,184 +0,0 @@ -import * as d3 from 'd3'; - -const COLORS_SERIES = ["#7A77FF", "#141446", "#FF6492", "#727290", "#43436B", "#BEF3BE", "#68B68C", "#FFE7AA", "#B2A58D", "#64C8E0"]; -const CHART_HEIGHT = 300; - -const drawPieChart = (node, resultSet, options) => { - const data = resultSet.series()[0].series.map(s => s.value); - const data_ready = d3.pie()(data); - d3.select(node).html(""); // The radius of the pieplot is half the width or half the height (smallest one). - - const radius = CHART_HEIGHT / 2 - 40; // Seprate container to center align pie chart - - const svg = d3 - .select(node) - .append("svg") - .attr("width", node.clientWidth) - .attr("height", CHART_HEIGHT) - .append("g") - .attr( - "transform", - "translate(" + node.clientWidth / 2 + "," + CHART_HEIGHT / 2 + ")" - ); - svg - .selectAll("pieArcs") - .data(data_ready) - .enter() - .append("path") - .attr( - "d", - d3 - .arc() - .innerRadius(0) - .outerRadius(radius) - ) - .attr("fill", d => COLORS_SERIES[d.index]); - - const size = 12; - const labels = resultSet.series()[0].series.map(s => s.x); - svg.selectAll("myrect") - .data(labels) - .enter() - .append("rect") - .attr("x", 150) - .attr("y", function(d,i){ return -50 + i*(size+5)}) - .attr("width", size) - .attr("height", size) - .style("fill", (d,i) => COLORS_SERIES[i]) - - svg.selectAll("mylabels") - .data(labels) - .enter() - .append("text") - .attr("x", 150 + size*1.2) - .attr("y", function(d,i){ return -50 + i*(size+5) + (size/2)}) - .text(function(d){ return d}) - .attr("text-anchor", "left") - .attr("font-size", "12px") - .style("alignment-baseline", "middle") -}; - -const drawChart = (node, resultSet, chartType, options = {}) => { - if (chartType === "pie") { - return drawPieChart(node, resultSet, options); - } - - const margin = { - top: 10, - right: 30, - bottom: 30, - left: 60 - }, - width = node.clientWidth - margin.left - margin.right, - height = CHART_HEIGHT - margin.top - margin.bottom; - d3.select(node).html(""); - const svg = d3 - .select(node) - .append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - - const keys = resultSet.seriesNames(options.pivotConfig).map(s => s.key); - - let data, maxData; - if (chartType === "line") { - data = resultSet.series(options.pivotConfig).map(series => ({ - key: series.key, - values: series.series - })); - maxData = d3.max(data.map(s => d3.max(s.values, i => i.value))); - } else { - data = d3.stack().keys(keys)(resultSet.chartPivot(options.pivotConfig)); - maxData = d3.max(data.map(s => d3.max(s, i => i[1]))); - } - - const color = d3 - .scaleOrdinal() - .domain(keys) - .range(COLORS_SERIES); - - let x; - if (chartType === "bar") { - x = d3 - .scaleBand() - .range([0, width]) - .domain(resultSet.chartPivot(options.pivotConfig).map(c => c.x)) - .padding(0.3); - } else { - x = d3 - .scaleTime() - .domain(d3.extent(resultSet.chartPivot(options.pivotConfig), c => d3.isoParse(c.x))).nice() - .range([0, width]); - } - - svg - .append("g") - .attr("transform", "translate(0," + height + ")") - .call(d3.axisBottom(x)); - const y = d3 - .scaleLinear() - .domain([0, maxData]) - .range([height, 0]); - svg.append("g").call(d3.axisLeft(y)); - - if (chartType === "line") { - svg - .selectAll(".line") - .data(data) - .enter() - .append("path") - .attr("fill", "none") - .attr("stroke", d => color(d.key)) - .attr("stroke-width", 1.5) - .attr("d", d => { - return d3 - .line() - .x(d => x(d3.isoParse(d.x))) - .y(d => y(+d.value))(d.values); - }); - } else if (chartType === "area") { - svg - .selectAll("mylayers") - .data(data) - .enter() - .append("path") - .style("fill", d => color(d.key)) - .attr( - "d", - d3 - .area() - .x(d => x(d3.isoParse(d.data.x))) - .y0(d => y(d[0])) - .y1(d => y(d[1])) - ); - } else { - svg - .append("g") - .selectAll("g") // Enter in the stack data = loop key per key = group per group - .data(data) - .enter() - .append("g") - .attr("fill", d => color(d.key)) - .selectAll("rect") // enter a second time = loop subgroup per subgroup to add all rectangles - .data(d => d) - .enter() - .append("rect") - .attr("x", d => x(d.data.x)) - .attr("y", d => y(d[1])) - .attr("height", d => y(d[0]) - y(d[1])) - .attr("width", x.bandwidth()); - } -}; - -const D3Chart = ({ resultSet, type, ...props }) => ( -
el && drawChart(el, resultSet, type, props)} /> -); - -const TypeToChartComponent = { - line: (props) => , - bar: (props) => , - area: (props) => , - pie: (props) => , -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/material-tables/index.js b/packages/cubejs-server-core/dev/templates/packages/material-tables/index.js deleted file mode 100644 index 07111f8d69add..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/material-tables/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class MaterialTablesTemplate extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'material-tables', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - version: '0.0.1' - }); - } -} - -module.exports = MaterialTablesTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/material-tables/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/material-tables/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index 6978f17f99f14..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/material-tables/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,41 +0,0 @@ -import Typography from '@material-ui/core/Typography'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; - -const TypeToChartComponent = { - number: ({ resultSet }) => ( - - {resultSet.seriesNames().map(s => ( - resultSet.totalRow()[s.key] - ))} - - ), - table: ({ resultSet }) => ( -
- - - {resultSet.tableColumns().map(c => ( - {c.title} - ))} - - - - {resultSet.tablePivot().map((row, index) => ( - - {resultSet.tableColumns().map(c => ( - {row[c.key]} - ))} - - ))} - -
- ) -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/index.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/index.js deleted file mode 100644 index f617c752773fe..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/index.js +++ /dev/null @@ -1,21 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const AppSnippet = require("../../AppSnippet"); -const IndexSnippet = require("../../IndexSnippet"); - -class ReactAntdDynamicTemplate extends TemplatePackage { - constructor() { - super({ - name: 'react-antd-dynamic', - description: 'React antd dynamic', - fileToSnippet: { - '/src/App.js': new AppSnippet(), - '/src/index.js': new IndexSnippet() - }, - requires: 'create-react-app', - receives: ['credentials', 'charts', 'transport', 'antd-tables'], - version: '0.0.2' - }); - } -} - -module.exports = ReactAntdDynamicTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/App.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/App.js deleted file mode 100644 index 7f85111d91396..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/App.js +++ /dev/null @@ -1,41 +0,0 @@ -import './body.css'; -import 'antd/dist/antd.css'; -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"; - -const API_URL = undefined; - -const CUBEJS_TOKEN = undefined; - -const cubejsApi = cubejs( - CUBEJS_TOKEN, - { apiUrl: `${API_URL}/cubejs-api/v1` } -); - -const AppLayout = ({ children }) => ( - -
- {children} - -); - -const App = ({ children }) => ( - - - - {children} - - - -); - -export default App; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/body.css b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/body.css deleted file mode 100644 index c22a9916b624c..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/body.css +++ /dev/null @@ -1,7 +0,0 @@ -body { - background-color: #f0f2f5 !important; -} - -.ant-popover-disabled-compatible-wrapper { - pointer-events: none; -} \ No newline at end of file diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index d635f54362928..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useCubeQuery } from '@cubejs-client/react'; -import { Spin } from 'antd'; - -const TypeToChartComponent = {}; - -const TypeToMemoChartComponent = Object.keys(TypeToChartComponent) - .map(key => ({ [key]: React.memo(TypeToChartComponent[key]) })) - .reduce((a, b) => ({ ...a, ...b })); - -const renderChart = Component => ({ resultSet, error, pivotConfig }) => (resultSet && ) - || (error && error.toString()) || ; - -const ChartRenderer = ({ vizState }) => { - const { query, chartType, pivotConfig } = vizState; - const component = TypeToMemoChartComponent[chartType]; - const renderProps = useCubeQuery(query); - - return component && renderChart(component)({ ...renderProps, pivotConfig }); -}; - -ChartRenderer.propTypes = { - vizState: PropTypes.object, - cubejsApi: PropTypes.object -}; - -ChartRenderer.defaultProps = { - vizState: {}, - cubejsApi: null -}; - -export default ChartRenderer; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/Dashboard.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/Dashboard.js deleted file mode 100644 index 9191cb8517e1b..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/Dashboard.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react"; -import RGL, { WidthProvider } from "react-grid-layout"; -import { useMutation } from "@apollo/react-hooks"; -import "react-grid-layout/css/styles.css"; -import "react-resizable/css/styles.css"; -import { GET_DASHBOARD_ITEMS } from "../graphql/queries"; -import { UPDATE_DASHBOARD_ITEM } from "../graphql/mutations"; - -const ReactGridLayout = WidthProvider(RGL); - -const Dashboard = ({ children, dashboardItems }) => { - const [updateDashboardItem] = useMutation(UPDATE_DASHBOARD_ITEM, { - refetchQueries: [ - { - query: GET_DASHBOARD_ITEMS - } - ] - }); - - const onLayoutChange = newLayout => { - newLayout.forEach(l => { - const item = dashboardItems.find(i => i.id.toString() === l.i); - const toUpdate = JSON.stringify({ - x: l.x, - y: l.y, - w: l.w, - h: l.h - }); - - if (item && toUpdate !== item.layout) { - updateDashboardItem({ - variables: { - id: item.id, - input: { - layout: toUpdate - } - } - }); - } - }); - }; - - return ( - - {children} - - ); -}; - -export default Dashboard; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/DashboardItem.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/DashboardItem.js deleted file mode 100644 index 92f46ea32b536..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/DashboardItem.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from "react"; -import { Card, Menu, Button, Dropdown, Modal } from "antd"; -import { useMutation } from "@apollo/react-hooks"; -import { Link } from "react-router-dom"; -import { Icon } from "@ant-design/compatible"; -import { GET_DASHBOARD_ITEMS } from "../graphql/queries"; -import { DELETE_DASHBOARD_ITEM } from "../graphql/mutations"; - -const DashboardItemDropdown = ({ itemId }) => { - const [removeDashboardItem] = useMutation(DELETE_DASHBOARD_ITEM, { - refetchQueries: [ - { - query: GET_DASHBOARD_ITEMS - } - ] - }); - const dashboardItemDropdownMenu = ( - - - Edit - - - Modal.confirm({ - title: "Are you sure you want to delete this item?", - okText: "Yes", - okType: "danger", - cancelText: "No", - - onOk() { - removeDashboardItem({ - variables: { - id: itemId - } - }); - } - }) - } - > - Delete - - - ); - return ( - - - - - - - - } - placement="bottomLeft" - trigger="click" - > - - - - - - - - - - - {isQueryPresent ? ( - - - - ) : ( -

Choose a measure or dimension to get started

- )} - -
- - ); - }} - /> - ); -} - -ExploreQueryBuilder.propTypes = { - vizState: PropTypes.object, - setVizState: PropTypes.func, - cubejsApi: PropTypes.object, - chartExtra: PropTypes.array, -}; - -ExploreQueryBuilder.defaultProps = { - vizState: {}, - setVizState: null, - cubejsApi: null, - chartExtra: null, -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterGroup.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterGroup.js deleted file mode 100644 index 236e367dbe2c6..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterGroup.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { Select } from 'antd'; -import { Icon } from "@ant-design/compatible"; -import MemberDropdown from './MemberDropdown'; -import RemoveButtonGroup from './RemoveButtonGroup'; -import FilterInput from './FilterInput'; - -const FilterGroup = ({ - members, availableMembers, addMemberName, updateMethods -}) => ( - - {members.map(m => ( -
- updateMethods.remove(m)}> - updateMethods.update(m, { ...m, dimension: updateWith })} - availableMembers={availableMembers} - style={{ - width: 150, - textOverflow: 'ellipsis', - overflow: 'hidden' - }} - > - {m.dimension.title} - - - - -
- ))} - updateMethods.add({ dimension: m })} - availableMembers={availableMembers} - type="dashed" - icon={} - > - {addMemberName} - -
-); - -FilterGroup.propTypes = { - members: PropTypes.array.isRequired, - availableMembers: PropTypes.array.isRequired, - addMemberName: PropTypes.string.isRequired, - updateMethods: PropTypes.object.isRequired -}; - -export default FilterGroup; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterInput.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterInput.js deleted file mode 100644 index bb2ba37ae0115..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/FilterInput.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { - Select, Input -} from 'antd'; - -const FilterInputs = { - string: ({ values, onChange }) => ( - onChange([e.target.value])} - value={values && values[0] || ''} - /> - ) -}; - -FilterInputs.string.propTypes = { - values: PropTypes.array, - onChange: PropTypes.func.isRequired -}; - -FilterInputs.string.defaultProps = { - values: [] -}; - -FilterInputs.number.propTypes = { - values: PropTypes.array, - onChange: PropTypes.func.isRequired -}; - -FilterInputs.number.defaultProps = { - values: [] -}; - -const FilterInput = ({ member, updateMethods }) => { - const Filter = FilterInputs[member.dimension.type] || FilterInputs.string; - return ( - updateMethods.update(member, { ...member, values })} - /> - ); -}; - -FilterInput.propTypes = { - member: PropTypes.object.isRequired, - updateMethods: PropTypes.object.isRequired -}; - -export default FilterInput; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberDropdown.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberDropdown.js deleted file mode 100644 index 10ba47159e3ca..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberDropdown.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { Menu } from 'antd'; -import ButtonDropdown from './ButtonDropdown'; - -// Can't be a Pure Component due to Dropdown lookups overlay component type to set appropriate styles -const memberMenu = (onClick, availableMembers) => ( - - {availableMembers.length ? availableMembers.map(m => ( - onClick(m)}> - {m.title} - - )) : No members found} - -); - -const MemberDropdown = ({ onClick, availableMembers, ...buttonProps }) => ( - -); - -MemberDropdown.propTypes = { - onClick: PropTypes.func.isRequired, - availableMembers: PropTypes.array.isRequired -}; - -export default MemberDropdown; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberGroup.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberGroup.js deleted file mode 100644 index 7b67fc1b182d8..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/MemberGroup.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { Icon } from "@ant-design/compatible"; -import MemberDropdown from './MemberDropdown'; -import RemoveButtonGroup from './RemoveButtonGroup'; - -const MemberGroup = ({ - members, availableMembers, addMemberName, updateMethods -}) => ( - - {members.map(m => ( - updateMethods.remove(m)}> - updateMethods.update(m, updateWith)}> - {m.title} - - - ))} - updateMethods.add(m)} availableMembers={availableMembers} type="dashed" icon={}> - {addMemberName} - - -); - -MemberGroup.propTypes = { - members: PropTypes.array.isRequired, - availableMembers: PropTypes.array.isRequired, - addMemberName: PropTypes.string.isRequired, - updateMethods: PropTypes.object.isRequired -}; - -export default MemberGroup; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/DraggableItem.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/DraggableItem.js deleted file mode 100644 index 1fa8c2b672972..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/DraggableItem.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { Button, Typography } from 'antd'; -import { Draggable } from 'react-beautiful-dnd'; -import { DragOutlined } from '@ant-design/icons'; - -const orderOptions = ['asc', 'desc', 'none']; - -export default function DraggableItem({ id, index, order = 'none', children, onOrderChange }) { - const getNextOrder = () => { - const index = orderOptions.indexOf(order) + 1; - return orderOptions[index > 2 ? 0 : index]; - }; - - return ( - - {({ draggableProps, dragHandleProps, innerRef }) => ( -
- - - - {children} - - - -
- )} -
- ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/OrderGroup.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/OrderGroup.js deleted file mode 100644 index 8a02fe1849de0..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Order/OrderGroup.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { DragDropContext, Droppable } from 'react-beautiful-dnd'; -import DraggableItem from './DraggableItem'; - -export default function OrderGroup({ orderMembers, onOrderChange, onReorder }) { - return ( - { - onReorder(source && source.index, destination && destination.index) - }} - > - - {(provided) => ( -
- {orderMembers.map(({ id, title, order }, index) => ( - - {title} - - ))} - - {provided.placeholder} -
- )} -
-
- ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Axes.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Axes.js deleted file mode 100644 index decbb284065f3..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Axes.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { DragDropContext } from 'react-beautiful-dnd'; -import { Row, Col, Divider } from 'antd'; -import DroppableArea from './DroppableArea'; - -export default function Axes({ pivotConfig, onMove }) { - return ( - { - if (!destination) { - return; - } - - onMove({ - sourceIndex: source.index, - destinationIndex: destination.index, - sourceAxis: source.droppableId, - destinationAxis: destination.droppableId, - }); - }} - > - - - - - - - - - - - - - - - ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/DroppableArea.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/DroppableArea.js deleted file mode 100644 index f5c959a983aa3..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/DroppableArea.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { Typography } from 'antd'; -import { Droppable } from 'react-beautiful-dnd'; -import Item from './Item'; - -export default function DroppableArea({ pivotConfig, axis }) { - return ( - <> - - {axis} - - - {(provided) => ( -
- {pivotConfig[axis].map((id, index) => ( - - ))} - - {provided.placeholder} -
- )} -
- - ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Item.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Item.js deleted file mode 100644 index 889290da2dcf9..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Item.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { Draggable } from 'react-beautiful-dnd'; -import { DragOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; - -export default function Item({ id, index }) { - return ( - - {({ draggableProps, dragHandleProps, innerRef }) => ( -
- - - {id} - -
- )} -
- ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Options.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Options.js deleted file mode 100644 index 400fb6d42e206..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Options.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { Checkbox } from 'antd'; - -export default function Options({ pivotConfig, onUpdate }) { - return ( - - onUpdate({ - fillMissingDates: !pivotConfig.fillMissingDates, - }) - } - > - Fill Missing Dates - - ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Pivot.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Pivot.js deleted file mode 100644 index 60e7052b5299c..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/Pivot/Pivot.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { Tabs } from 'antd'; -import Axes from './Axes'; -import Options from './Options'; - -export default function Pivot({ pivotConfig, onMove, onUpdate }) { - return ( - - - - - - - - - - ); -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/RemoveButtonGroup.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/RemoveButtonGroup.js deleted file mode 100644 index c5248b68d6a77..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/RemoveButtonGroup.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { Button } from 'antd'; -import { Icon } from "@ant-design/compatible"; - -const RemoveButtonGroup = ({ onRemoveClick, children, ...props }) => ( - - {children} - - -); - -RemoveButtonGroup.propTypes = { - onRemoveClick: PropTypes.func.isRequired, - children: PropTypes.object.isRequired -}; - -export default RemoveButtonGroup; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/SelectChartType.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/SelectChartType.js deleted file mode 100644 index ed6b2f59634fc..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/SelectChartType.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { - Menu -} from 'antd'; -import { Icon } from "@ant-design/compatible"; -import ButtonDropdown from './ButtonDropdown'; - -const ChartTypes = [ - { name: 'line', title: 'Line', icon: 'line-chart' }, - { name: 'area', title: 'Area', icon: 'area-chart' }, - { name: 'bar', title: 'Bar', icon: 'bar-chart' }, - { name: 'pie', title: 'Pie', icon: 'pie-chart' }, - { name: 'table', title: 'Table', icon: 'table' }, - { name: 'number', title: 'Number', icon: 'info-circle' } -]; - -const SelectChartType = ({ chartType, updateChartType }) => { - const menu = ( - - {ChartTypes.map(m => ( - updateChartType(m.name)}> - - {m.title} - - ))} - - ); - - const foundChartType = ChartTypes.find(t => t.name === chartType); - return ( - }> - {foundChartType.title} - - ); -}; - -SelectChartType.propTypes = { - chartType: PropTypes.string.isRequired, - updateChartType: PropTypes.func.isRequired -}; - -export default SelectChartType; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/TimeGroup.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/TimeGroup.js deleted file mode 100644 index 7220c6b175ef9..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/QueryBuilder/TimeGroup.js +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import * as PropTypes from 'prop-types'; -import { - Menu -} from 'antd'; -import { Icon } from "@ant-design/compatible"; -import ButtonDropdown from './ButtonDropdown'; -import MemberDropdown from './MemberDropdown'; -import RemoveButtonGroup from './RemoveButtonGroup'; - -const DateRanges = [ - { title: 'All time', value: undefined }, - { value: 'Today' }, - { value: 'Yesterday' }, - { value: 'This week' }, - { value: 'This month' }, - { value: 'This quarter' }, - { value: 'This year' }, - { value: 'Last 7 days' }, - { value: 'Last 30 days' }, - { value: 'Last week' }, - { value: 'Last month' }, - { value: 'Last quarter' }, - { value: 'Last year' } -]; - -const TimeGroup = ({ - members, availableMembers, addMemberName, updateMethods -}) => { - const granularityMenu = (member, onClick) => ( - - {member.granularities.length ? member.granularities.map(m => ( - onClick(m)}> - {m.title} - - )) : No members found} - - ); - - const dateRangeMenu = (onClick) => ( - - {DateRanges.map(m => ( - onClick(m)}> - {m.title || m.value} - - ))} - - ); - - return ( - - {members.map(m => [ - updateMethods.remove(m)} key={`${m.dimension.name}-member`}> - updateMethods.update(m, { ...m, dimension: updateWith })} - availableMembers={availableMembers} - > - {m.dimension.title} - - , - FOR, - updateMethods.update(m, { ...m, dateRange: dateRange.value }))} - style={{ marginLeft: 8, marginRight: 8 }} - key={`${m.dimension.name}-date-range`} - > - {m.dateRange || 'All time'} - , - BY, - updateMethods.update(m, { ...m, granularity: granularity.name }) - )} - style={{ marginLeft: 8 }} - key={`${m.dimension.name}-granularity`} - > - { - m.dimension.granularities.find(g => g.name === m.granularity) - && m.dimension.granularities.find(g => g.name === m.granularity).title - } - - ])} - {!members.length && ( - updateMethods.add({ dimension: member, granularity: 'day' })} - availableMembers={availableMembers} - type="dashed" - icon={} - > - {addMemberName} - - )} - - ); -}; - -TimeGroup.propTypes = { - members: PropTypes.array.isRequired, - availableMembers: PropTypes.array.isRequired, - addMemberName: PropTypes.string.isRequired, - updateMethods: PropTypes.object.isRequired -}; - -export default TimeGroup; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/TitleModal.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/TitleModal.js deleted file mode 100644 index c6cb196029047..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/components/TitleModal.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; -import { Modal, Input } from "antd"; -import { useMutation } from "@apollo/react-hooks"; -import { GET_DASHBOARD_ITEMS } from "../graphql/queries"; -import { - CREATE_DASHBOARD_ITEM, - UPDATE_DASHBOARD_ITEM -} from "../graphql/mutations"; - -const TitleModal = ({ - history, - itemId, - titleModalVisible, - setTitleModalVisible, - setAddingToDashboard, - finalVizState, - setTitle, - finalTitle -}) => { - const [addDashboardItem] = useMutation(CREATE_DASHBOARD_ITEM, { - refetchQueries: [ - { - query: GET_DASHBOARD_ITEMS - } - ] - }); - const [updateDashboardItem] = useMutation(UPDATE_DASHBOARD_ITEM, { - refetchQueries: [ - { - query: GET_DASHBOARD_ITEMS - } - ] - }); - - return ( - { - setTitleModalVisible(false); - setAddingToDashboard(true); - - try { - await (itemId ? updateDashboardItem : addDashboardItem)({ - variables: { - id: itemId, - input: { - vizState: JSON.stringify(finalVizState), - name: finalTitle - } - } - }); - history.push("/"); - } finally { - setAddingToDashboard(false); - } - }} - onCancel={() => setTitleModalVisible(false)} - > - setTitle(e.target.value)} - /> - - ) -}; - -export default TitleModal; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/client.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/client.js deleted file mode 100644 index 1774fcd7d2acb..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/client.js +++ /dev/null @@ -1,100 +0,0 @@ -/* globals window */ -import { ApolloClient } from "apollo-client"; -import { InMemoryCache } from "apollo-cache-inmemory"; -import { SchemaLink } from 'apollo-link-schema'; -import { makeExecutableSchema } from 'graphql-tools'; - -const cache = new InMemoryCache(); -const defaultDashboardItems = []; - -const getDashboardItems = () => JSON.parse(window.localStorage.getItem("dashboardItems")) - || defaultDashboardItems; - -const setDashboardItems = items => window.localStorage.setItem("dashboardItems", JSON.stringify(items)); - -const nextId = () => { - const currentId = parseInt(window.localStorage.getItem("dashboardIdCounter"), 10) || 1; - window.localStorage.setItem("dashboardIdCounter", currentId + 1); - return currentId.toString(); -}; - -const toApolloItem = i => ({ - ...i, - __typename: "DashboardItem" -}); - -const typeDefs = ` - type DashboardItem { - id: String! - layout: String - vizState: String - name: String - } - - input DashboardItemInput { - layout: String - vizState: String - name: String - } - - type Query { - dashboardItems: [DashboardItem] - dashboardItem(id: String!): DashboardItem - } - - type Mutation { - createDashboardItem(input: DashboardItemInput): DashboardItem - updateDashboardItem(id: String!, input: DashboardItemInput): DashboardItem - deleteDashboardItem(id: String!): DashboardItem - } -`; - -const schema = makeExecutableSchema({ - typeDefs, - resolvers: { - Query: { - dashboardItems() { - const dashboardItems = getDashboardItems(); - return dashboardItems.map(toApolloItem); - }, - dashboardItem(_, { id }) { - const dashboardItems = getDashboardItems(); - return toApolloItem(dashboardItems.find(i => i.id.toString() === id)); - } - }, - Mutation: { - createDashboardItem: (_, { input: { ...item } }) => { - const dashboardItems = getDashboardItems(); - item = { ...item, id: nextId(), layout: JSON.stringify({}) }; - dashboardItems.push(item); - setDashboardItems(dashboardItems); - return toApolloItem(item); - }, - updateDashboardItem: (_, { id, input: { ...item } }) => { - const dashboardItems = getDashboardItems(); - item = Object.keys(item) - .filter(k => !!item[k]) - .map(k => ({ - [k]: item[k] - })) - .reduce((a, b) => ({ ...a, ...b }), {}); - const index = dashboardItems.findIndex(i => i.id.toString() === id); - dashboardItems[index] = { ...dashboardItems[index], ...item }; - setDashboardItems(dashboardItems); - return toApolloItem(dashboardItems[index]); - }, - deleteDashboardItem: (_, { id }) => { - const dashboardItems = getDashboardItems(); - const index = dashboardItems.findIndex(i => i.id.toString() === id); - const [removedItem] = dashboardItems.splice(index, 1); - setDashboardItems(dashboardItems); - return toApolloItem(removedItem); - } - } - } -}); - -export default new ApolloClient({ - cache, - link: new SchemaLink({ schema }) -}); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/mutations.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/mutations.js deleted file mode 100644 index ebc67fe689f20..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/mutations.js +++ /dev/null @@ -1,34 +0,0 @@ -import gql from "graphql-tag"; - -export const CREATE_DASHBOARD_ITEM = gql` - mutation CreateDashboardItem($input: DashboardItemInput) { - createDashboardItem(input: $input) { - id - layout - vizState - name - } - } -`; - -export const UPDATE_DASHBOARD_ITEM = gql` - mutation UpdateDashboardItem($id: String!, $input: DashboardItemInput) { - updateDashboardItem(id: $id, input: $input) { - id - layout - vizState - name - } - } -`; - -export const DELETE_DASHBOARD_ITEM = gql` - mutation DeleteDashboardItem($id: String!) { - deleteDashboardItem(id: $id) { - id - layout - vizState - name - } - } -`; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/queries.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/queries.js deleted file mode 100644 index 9ca0c0eef8d30..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/graphql/queries.js +++ /dev/null @@ -1,23 +0,0 @@ -import gql from "graphql-tag"; - -export const GET_DASHBOARD_ITEMS = gql` - query GetDashboardItems { - dashboardItems { - id - layout - vizState - name - } - } -`; - -export const GET_DASHBOARD_ITEM = gql` - query GetDashboardItem($id: String!) { - dashboardItem(id: $id) { - id - layout - vizState - name - } - } -`; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/index.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/index.js deleted file mode 100644 index 48dddcb4128cc..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { HashRouter as Router, Route } from 'react-router-dom'; -import ExplorePage from './pages/ExplorePage'; -import DashboardPage from './pages/DashboardPage'; -import App from './App'; - -ReactDOM.render( - - - - - - , - // eslint-disable-next-line no-undef - document.getElementById('root') -); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/DashboardPage.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/DashboardPage.js deleted file mode 100644 index 00fd5dec663b5..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/DashboardPage.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from "react"; -import { Spin, Button, Alert } from "antd"; -import { Link } from "react-router-dom"; -import { useQuery } from "@apollo/react-hooks"; -import { Icon } from "@ant-design/compatible"; -import { GET_DASHBOARD_ITEMS } from "../graphql/queries"; -import ChartRenderer from "../components/ChartRenderer"; -import Dashboard from "../components/Dashboard"; -import DashboardItem from "../components/DashboardItem"; - -const deserializeItem = i => ({ - ...i, - layout: JSON.parse(i.layout) || {}, - vizState: JSON.parse(i.vizState) -}); - -const defaultLayout = i => ({ - x: i.layout.x || 0, - y: i.layout.y || 0, - w: i.layout.w || 4, - h: i.layout.h || 8, - minW: 4, - minH: 8 -}); - -const DashboardPage = () => { - const { loading, error, data } = useQuery(GET_DASHBOARD_ITEMS); - - if (loading) { - return ; - } - - if (error) { - return ( - - ); - } - - const dashboardItem = item => ( -
- - - -
- ); - - const Empty = () => ( -
-

There are no charts on this dashboard

- - - -
- ); - - return !data || data.dashboardItems.length ? ( - - {data && data.dashboardItems.map(deserializeItem).map(dashboardItem)} - - ) : ; -}; - -export default DashboardPage; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/ExplorePage.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/ExplorePage.js deleted file mode 100644 index 64d98f15ac12f..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-dynamic/scaffolding/src/pages/ExplorePage.js +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useState } from "react"; -import { Alert, Button, Spin } from "antd"; -import { useQuery } from "@apollo/react-hooks"; -import { withRouter } from "react-router-dom"; -import ExploreQueryBuilder from "../components/QueryBuilder/ExploreQueryBuilder"; -import { GET_DASHBOARD_ITEM } from "../graphql/queries"; -import TitleModal from "../components/TitleModal.js"; - -const ExplorePage = withRouter(({ history, location }) => { - const [addingToDashboard, setAddingToDashboard] = useState(false); - const params = new URLSearchParams(location.search); - const itemId = params.get("itemId"); - const { loading, error, data } = useQuery(GET_DASHBOARD_ITEM, { - variables: { - id: itemId - }, - skip: !itemId - }); - - const [vizState, setVizState] = useState(null); - const finalVizState = - vizState || - (itemId && !loading && data && JSON.parse(data.dashboardItem.vizState)) || - {}; - const [titleModalVisible, setTitleModalVisible] = useState(false); - const [title, setTitle] = useState(null); - const finalTitle = title != null ? title - : ((itemId && !loading && data && data.dashboardItem.name) || "New Chart"); - - if (loading) { - return ; - } - - if (error) { - return ; - } - - return ( -
- - setTitleModalVisible(true)} - > - {itemId ? "Update" : "Add to Dashboard"} - - ]} - /> -
- ); -}); -export default ExplorePage; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/index.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/index.js deleted file mode 100644 index 2b649882e4cf4..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/index.js +++ /dev/null @@ -1,21 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const AppSnippet = require("../../AppSnippet"); -const IndexSnippet = require("../../IndexSnippet"); - -class ReactAntdStaticTemplate extends TemplatePackage { - constructor() { - super({ - name: 'react-antd-static', - description: 'React antd static', - fileToSnippet: { - '/src/App.js': new AppSnippet(), - '/src/index.js': new IndexSnippet(), - }, - requires: 'create-react-app', - receives: ['credentials', 'charts', 'static-chart', 'transport', 'antd-tables'], - version: '0.0.1' - }); - } -} - -module.exports = ReactAntdStaticTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/App.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/App.js deleted file mode 100644 index 867512521df30..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/App.js +++ /dev/null @@ -1,37 +0,0 @@ -import './body.css'; -import 'antd/dist/antd.css'; -import React from "react"; -import { Layout } from "antd"; -import cubejs from '@cubejs-client/core'; -import { CubeProvider } from "@cubejs-client/react"; -import Header from "./components/Header"; - -const API_URL = undefined; - -const CUBEJS_TOKEN = undefined; - -const cubejsApi = cubejs( - CUBEJS_TOKEN, - { apiUrl: `${API_URL}/cubejs-api/v1` } -); - -const AppLayout = ({ children }) => ( - -
- {children} - -); - -const App = ({ children }) => ( - - - {children} - - -); - -export default App; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/body.css b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/body.css deleted file mode 100644 index c3eeefeccd11a..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/body.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: #f0f2f5 !important; -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index 818bfe3b5088d..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useCubeQuery } from '@cubejs-client/react'; -import { Spin } from 'antd'; - -const TypeToChartComponent = {}; - -const TypeToMemoChartComponent = Object.keys(TypeToChartComponent) - .map(key => ({ [key]: React.memo(TypeToChartComponent[key]) })) - .reduce((a, b) => ({ ...a, ...b })); - -const renderChart = Component => ({ resultSet, error }) => (resultSet && ) - || (error && error.toString()) || ; - -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 -}; - -ChartRenderer.defaultProps = { - vizState: {}, - cubejsApi: null -}; - -export default ChartRenderer; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Dashboard.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Dashboard.js deleted file mode 100644 index e64437c368351..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Dashboard.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; -import { Row } from 'antd'; - -const Dashboard = ({ children }) => ( - - {children} - -); - -export default Dashboard; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/DashboardItem.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/DashboardItem.js deleted file mode 100644 index e54a3a8c76f91..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/DashboardItem.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import { Card } from "antd"; - -const DashboardItem = ({ children, title }) => ( - - {children} - -); - -export default DashboardItem; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Header.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Header.js deleted file mode 100644 index 4aff645079ce0..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/components/Header.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import { withRouter } from "react-router"; -import { Layout, Menu } from "antd"; - -const Header = ({ location }) => ( - -
-

- My Dashboard -

-
- - - Dashboard - - -
-); - -export default withRouter(Header); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/index.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/index.js deleted file mode 100644 index 315ef58d14543..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { HashRouter as Router, Route } from 'react-router-dom'; -import DashboardPage from './pages/DashboardPage'; -import App from './App'; - -ReactDOM.render( - - - - - , - // eslint-disable-next-line no-undef - document.getElementById('root') -); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/pages/DashboardPage.js b/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/pages/DashboardPage.js deleted file mode 100644 index 5e9075dc600bb..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-antd-static/scaffolding/src/pages/DashboardPage.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Col } from 'antd'; -import ChartRenderer from "../components/ChartRenderer"; -import Dashboard from "../components/Dashboard"; -import DashboardItem from "../components/DashboardItem"; - -const DashboardItems = []; - -const DashboardPage = () => { - const dashboardItem = item => ( - - - - - - ); - - const Empty = () => ( -
-

There are no charts on this dashboard. Use Playground Build to add one.

-
- ); - - return DashboardItems.length ? ( - - {DashboardItems.map(dashboardItem)} - - ) : ; -}; - -export default DashboardPage; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/index.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/index.js deleted file mode 100644 index d8cdf0d60b806..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/index.js +++ /dev/null @@ -1,21 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const AppSnippet = require("../../AppSnippet"); -const IndexSnippet = require("../../IndexSnippet"); - -class ReactMaterialStaticTemplate extends TemplatePackage { - constructor() { - super({ - name: 'react-material-static', - description: 'React material-ui static', - fileToSnippet: { - '/src/App.js': new AppSnippet(), - '/src/index.js': new IndexSnippet(), - }, - requires: 'create-react-app', - receives: ['credentials', 'charts', 'static-chart', 'transport', 'material-tables'], - version: '0.0.1' - }); - } -} - -module.exports = ReactMaterialStaticTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/App.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/App.js deleted file mode 100644 index 113843a9ff347..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/App.js +++ /dev/null @@ -1,43 +0,0 @@ -import './body.css'; -import { makeStyles } from '@material-ui/core/styles'; -import React from "react"; -import { Layout } from "antd"; -import cubejs from '@cubejs-client/core'; -import { CubeProvider } from "@cubejs-client/react"; -import Header from "./components/Header"; - -const API_URL = undefined; - -const CUBEJS_TOKEN = undefined; - -const cubejsApi = cubejs( - CUBEJS_TOKEN, - { apiUrl: `${API_URL}/cubejs-api/v1` } -); - -const useStyles = makeStyles(theme => ({ - root: { - flexGrow: 1, - } -})); - -const AppLayout = ({ children }) => { - const classes = useStyles(); - - return ( -
-
-
{children}
-
- ) -}; - -const App = ({ children }) => ( - - - {children} - - -); - -export default App; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/body.css b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/body.css deleted file mode 100644 index c3eeefeccd11a..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/body.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: #f0f2f5 !important; -} diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index f1450d0f6c2f4..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useCubeQuery } from '@cubejs-client/react'; -import CircularProgress from '@material-ui/core/CircularProgress'; - -const TypeToChartComponent = {}; - -const TypeToMemoChartComponent = Object.keys(TypeToChartComponent) - .map(key => ({ [key]: React.memo(TypeToChartComponent[key]) })) - .reduce((a, b) => ({ ...a, ...b })); - -const renderChart = Component => ({ resultSet, error, ...props }) => - (resultSet && ) || - (error && error.toString()) || ; - -const ChartRenderer = ({ vizState }) => { - const { query, chartType, ...options } = vizState; - const component = TypeToMemoChartComponent[chartType]; - const renderProps = useCubeQuery(query); - - return component && renderChart(component)({ ...options, ...renderProps }); -}; - -ChartRenderer.propTypes = { - vizState: PropTypes.object, - cubejsApi: PropTypes.object -}; - -ChartRenderer.defaultProps = { - vizState: {}, - cubejsApi: null -}; - -export default ChartRenderer; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Dashboard.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Dashboard.js deleted file mode 100644 index 15ea6333c757c..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Dashboard.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import Grid from '@material-ui/core/Grid'; - -const Dashboard = ({ children }) => ( - - {children} - -); - -export default Dashboard; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/DashboardItem.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/DashboardItem.js deleted file mode 100644 index 0db55455eab1d..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/DashboardItem.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; -import Card from '@material-ui/core/Card'; -import CardContent from '@material-ui/core/CardContent'; -import Typography from '@material-ui/core/Typography'; - -const DashboardItem = ({ children, title }) => ( - - - {title && ( - - {title} - - )} - {children} - - -); - -export default DashboardItem; diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Header.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Header.js deleted file mode 100644 index 17c611abb3465..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/components/Header.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import { withRouter } from "react-router"; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; -import IconButton from '@material-ui/core/IconButton'; -import MenuIcon from '@material-ui/icons/Menu'; - -const Header = ({ location }) => ( - - - - - - - My Dashboard - - - -); - -export default withRouter(Header); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/index.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/index.js deleted file mode 100644 index 315ef58d14543..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { HashRouter as Router, Route } from 'react-router-dom'; -import DashboardPage from './pages/DashboardPage'; -import App from './App'; - -ReactDOM.render( - - - - - , - // eslint-disable-next-line no-undef - document.getElementById('root') -); diff --git a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/pages/DashboardPage.js b/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/pages/DashboardPage.js deleted file mode 100644 index f5796a8eea708..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/react-material-static/scaffolding/src/pages/DashboardPage.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from "react"; -import Grid from '@material-ui/core/Grid'; -import Typography from '@material-ui/core/Typography'; -import ChartRenderer from "../components/ChartRenderer"; -import Dashboard from "../components/Dashboard"; -import DashboardItem from "../components/DashboardItem"; - -const DashboardItems = []; - -const DashboardPage = () => { - const dashboardItem = item => ( - - - - - - ); - - const Empty = () => ( -
- - There are no charts on this dashboard. Use Playground Build to add one. - -
- ); - - return DashboardItems.length ? ( - - {DashboardItems.map(dashboardItem)} - - ) : ; -}; - -export default DashboardPage; diff --git a/packages/cubejs-server-core/dev/templates/packages/recharts-charts/index.js b/packages/cubejs-server-core/dev/templates/packages/recharts-charts/index.js deleted file mode 100644 index d5a6e55d0acee..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/recharts-charts/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartRendererSnippet = require("../../ChartRendererSnippet"); - -class RechartsTemplate extends TemplatePackage { - constructor(chartLibrary) { - super({ - name: 'recharts-charts', - fileToSnippet: { - '/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary) - }, - type: 'charts', - version: '0.0.1' - }); - } -} - -module.exports = RechartsTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/recharts-charts/scaffolding/src/components/ChartRenderer.js b/packages/cubejs-server-core/dev/templates/packages/recharts-charts/scaffolding/src/components/ChartRenderer.js deleted file mode 100644 index 321b76f0d5a98..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/recharts-charts/scaffolding/src/components/ChartRenderer.js +++ /dev/null @@ -1,109 +0,0 @@ -import { - CartesianGrid, - PieChart, - Pie, - Cell, - AreaChart, - Area, - XAxis, - YAxis, - Tooltip, - ResponsiveContainer, - Legend, - BarChart, - Bar, - LineChart, - Line -} from "recharts"; - -const CartesianChart = ({ resultSet, children, ChartComponent }) => ( - - - - - - { children } - - - - -); - -const colors = ['#FF6492', '#141446', '#7A77FF']; - -const stackedChartData = (resultSet) => { - const data = resultSet.pivot().map( - ({ xValues, yValuesArray }) => - yValuesArray.map(([yValues, m]) => ({ - x: resultSet.axisValuesString(xValues, ', '), - color: resultSet.axisValuesString(yValues, ', '), - measure: m && Number.parseFloat(m) - })) - ).reduce((a, b) => a.concat(b), []); - - return data; -}; - -const TypeToChartComponent = { - line: ({ resultSet }) => ( - - {resultSet.seriesNames().map((series, i) => ( - - ))} - - ), - bar: ({ resultSet }) => ( - - {resultSet.seriesNames().map((series, i) => ( - - ))} - - ), - area: ({ resultSet }) => ( - - {resultSet.seriesNames().map((series, i) => ( - - ))} - - ), - pie: ({ resultSet }) => ( - - - - { - resultSet.chartPivot().map((e, index) => - - ) - } - - - - - - ) -}; diff --git a/packages/cubejs-server-core/dev/templates/packages/static-chart/index.js b/packages/cubejs-server-core/dev/templates/packages/static-chart/index.js deleted file mode 100644 index 15ec9933f1c6a..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/static-chart/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); -const ChartSnippet = require("../../ChartSnippet"); - -class StaticChartTemplate extends TemplatePackage { - constructor({ chartCode }) { - super({ - name: 'static-chart', - fileToSnippet: { - '/src/pages/DashboardPage.js': new ChartSnippet(chartCode) - }, - multiPackage: true - }); - } -} - -module.exports = StaticChartTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/index.js b/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/index.js deleted file mode 100644 index 983e508f64a00..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/index.js +++ /dev/null @@ -1,13 +0,0 @@ -const TemplatePackage = require("../../TemplatePackage"); - -class WebSocketTransportTemplate extends TemplatePackage { - constructor() { - super({ - name: 'web-socket-transport', - version: '0.0.1', - type: 'transport' - }); - } -} - -module.exports = WebSocketTransportTemplate; diff --git a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.0.js b/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.0.js deleted file mode 100644 index 7f1627799d68a..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.0.js +++ /dev/null @@ -1,3 +0,0 @@ -const cubejsApi = cubejs(CUBEJS_TOKEN, { - apiUrl: `${API_URL}/cubejs-api/v1` -}); diff --git a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.js b/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.js deleted file mode 100644 index 09073e8c6e7cd..0000000000000 --- a/packages/cubejs-server-core/dev/templates/packages/web-socket-transport/scaffolding/src/App.js +++ /dev/null @@ -1,8 +0,0 @@ -import WebSocketTransport from '@cubejs-client/ws-transport'; - -const cubejsApi = cubejs({ - transport: new WebSocketTransport({ - authorization: CUBEJS_TOKEN, - apiUrl: API_URL.replace('http', 'ws') - }) -}); diff --git a/packages/cubejs-server-core/dev/utils.js b/packages/cubejs-server-core/dev/utils.js new file mode 100644 index 0000000000000..2424995716aaf --- /dev/null +++ b/packages/cubejs-server-core/dev/utils.js @@ -0,0 +1,60 @@ +const fs = require('fs-extra'); +const path = require('path'); +const spawn = require('cross-spawn'); + +async function fileContentsRecursive(dir, rootPath, includeNodeModules) { + if (!rootPath) { + rootPath = dir; + } + if (!(await fs.pathExists(dir))) { + return []; + } + if (dir.indexOf('node_modules') !== -1 && !includeNodeModules) { + return []; + } + + const files = fs.readdirSync(dir); + + return ( + await Promise.all( + files.map(async (file) => { + const fileName = path.join(dir, file); + const stats = await fs.lstat(fileName); + if (!stats.isDirectory()) { + const content = await fs.readFile(fileName, 'utf-8'); + return [ + { + fileName: fileName.replace(rootPath, '').replace(/\\/g, '/'), + content, + }, + ]; + } else { + return fileContentsRecursive( + fileName, + rootPath, + includeNodeModules + ); + } + }) + ) + ).reduce((a, b) => a.concat(b), []); +} + +function executeCommand(command, args, options = {}) { + const child = spawn(command, args, { stdio: 'inherit', ...options }); + + return new Promise((resolve, reject) => { + child.on('close', (code) => { + if (code !== 0) { + reject(new Error(`${command} ${args.join(' ')} failed with exit code ${code}. Please check your console.`)); + return; + } + resolve(); + }); + }); +} + +module.exports = { + fileContentsRecursive, + executeCommand, +}; diff --git a/packages/cubejs-server-core/package.json b/packages/cubejs-server-core/package.json index 638ceddfa7ac1..25a344bcb2cfe 100644 --- a/packages/cubejs-server-core/package.json +++ b/packages/cubejs-server-core/package.json @@ -19,23 +19,16 @@ "playground" ], "scripts": { - "lint": "eslint core/**/*.js", - "test": "jest --testPathPattern test/*.test.js --runInBand" + "lint": "eslint core/**/*.js" }, "dependencies": { - "@babel/core": "^7.7.4", - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.2", - "@babel/preset-env": "^7.3.4", - "@babel/preset-react": "^7.0.0", - "@babel/standalone": "^7.3.4", - "@babel/traverse": "^7.4.0", - "@babel/types": "^7.4.0", "@cubejs-backend/api-gateway": "^0.19.54", "@cubejs-backend/query-orchestrator": "^0.19.56", "@cubejs-backend/schema-compiler": "^0.19.56", "codesandbox-import-utils": "^2.1.12", "cross-spawn": "^7.0.1", + "decompress": "^4.2.1", + "decompress-targz": "^4.1.1", "fs-extra": "^8.1.0", "jsonwebtoken": "^8.4.0", "lru-cache": "^5.1.1", diff --git a/packages/cubejs-server-core/test/Templates.test.js b/packages/cubejs-server-core/test/Templates.test.js deleted file mode 100644 index d2e0b5bd37398..0000000000000 --- a/packages/cubejs-server-core/test/Templates.test.js +++ /dev/null @@ -1,51 +0,0 @@ -/* globals describe,test,expect,jest */ - -const AppContainer = require('../dev/templates/AppContainer'); - -describe(`Templates`, () => { - jest.setTimeout(600000); - test(`static`, async () => { - const appContainer = new AppContainer('test-output/static', [ - 'create-react-app', 'react-antd-static', 'credentials', 'bizcharts-charts', 'antd-tables' - ], { - credentials: { - apiUrl: "http://localhost:4000", - cubejsToken: "foo" - } - }); - - await appContainer.applyTemplates(); - }); - - test(`dynamic`, async () => { - const appContainer = new AppContainer('test-output/dynamic', [ - 'create-react-app', 'react-antd-dynamic', 'credentials', 'bizcharts-charts', 'antd-tables' - ], { - credentials: { - apiUrl: "http://localhost:4000", - cubejsToken: "foo" - } - }); - - await appContainer.applyTemplates(); - await appContainer.ensureDependencies(); - }); - - test(`web-socket-transport`, async () => { - const appContainer = new AppContainer('test-output/real-time', [ - 'create-react-app', - 'react-antd-dynamic', - 'credentials', - 'bizcharts-charts', - 'antd-tables', - 'web-socket-transport' - ], { - credentials: { - apiUrl: "http://localhost:4000", - cubejsToken: "foo" - } - }); - - await appContainer.applyTemplates(); - }); -}); diff --git a/packages/cubejs-server-core/yarn.lock b/packages/cubejs-server-core/yarn.lock index b1ef8e565b1e9..2ee4bc4010d74 100644 --- a/packages/cubejs-server-core/yarn.lock +++ b/packages/cubejs-server-core/yarn.lock @@ -38,27 +38,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.4.tgz#37e864532200cb6b50ee9a4045f5f817840166ab" - integrity sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helpers" "^7.7.4" - "@babel/parser" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.10.4", "@babel/generator@^7.4.0", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": +"@babel/generator@^7.10.4", "@babel/generator@^7.4.0", "@babel/generator@^7.7.2": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243" integrity sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng== @@ -92,14 +72,6 @@ "@babel/helper-explode-assignable-expression" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-builder-react-jsx@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz#dee98d7d79cc1f003d80b76fe01c7f8945665ff6" - integrity sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ== - dependencies: - "@babel/types" "^7.8.3" - esutils "^2.0.0" - "@babel/helper-compilation-targets@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" @@ -206,7 +178,7 @@ dependencies: "@babel/types" "^7.10.4" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== @@ -278,15 +250,6 @@ "@babel/traverse" "^7.7.0" "@babel/types" "^7.7.0" -"@babel/helpers@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" - integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== - dependencies: - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/highlight@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" @@ -296,7 +259,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.4.2", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.7.2", "@babel/parser@^7.7.4": +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.4.2", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.7.2": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64" integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA== @@ -424,13 +387,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz#521b06c83c40480f1e58b4fd33b92eceb1d6ea94" - integrity sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" @@ -657,38 +613,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-display-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz#70ded987c91609f78353dd76d2fb2a0bb991e8e5" - integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-react-jsx-self@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz#c4f178b2aa588ecfa8d077ea80d4194ee77ed702" - integrity sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-react-jsx-source@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz#951e75a8af47f9f120db731be095d2b2c34920e0" - integrity sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-react-jsx@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz#4220349c0390fdefa505365f68c103562ab2fc4a" - integrity sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g== - dependencies: - "@babel/helper-builder-react-jsx" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - "@babel/plugin-transform-regenerator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" @@ -836,17 +760,6 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.8.3.tgz#23dc63f1b5b0751283e04252e78cf1d6589273d2" - integrity sha512-9hx0CwZg92jGb7iHYQVgi0tOEHP/kM60CtWJQnmbATSPIQQ2xYzfoCI3EdqAhFBeeJwYMdWQuDUHMsuDbH9hyQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-display-name" "^7.8.3" - "@babel/plugin-transform-react-jsx" "^7.8.3" - "@babel/plugin-transform-react-jsx-self" "^7.8.3" - "@babel/plugin-transform-react-jsx-source" "^7.8.3" - "@babel/runtime@^7.8.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" @@ -877,16 +790,7 @@ "@babel/parser" "^7.7.0" "@babel/types" "^7.7.0" -"@babel/template@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" - integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2", "@babel/traverse@^7.7.4": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818" integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q== @@ -916,7 +820,7 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2", "@babel/types@^7.7.4", "@babel/types@^7.8.3": +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.5.tgz#d88ae7e2fde86bfbfe851d4d81afa70a997b5d15" integrity sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q== @@ -933,10 +837,10 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@cubejs-backend/api-gateway@^0.19.50": - version "0.19.50" - resolved "https://registry.yarnpkg.com/@cubejs-backend/api-gateway/-/api-gateway-0.19.50.tgz#cafb4139e7e911c9b867a457c74fcd2e497923f9" - integrity sha512-RVwEwo/qxEwoqI2AV10vX3cH9XQPHPIqDL6274AiR28c9F4eHFw5cHVyy0M/tnabOHIHaJrMl+jIzmWqKwKloQ== +"@cubejs-backend/api-gateway@^0.19.54": + version "0.19.54" + resolved "https://registry.yarnpkg.com/@cubejs-backend/api-gateway/-/api-gateway-0.19.54.tgz#9a8e3bc9dd67fcbef9e85cb183abd1b2ac851864" + integrity sha512-VFHQZAzSI+3FyKr73BFGvvsFYFxTT5JwAPFvbNwzF0bcBEiLCzKNdHxfVRv72jiMXGegP1ouqF+9Hv8+/A4aHQ== dependencies: "@hapi/joi" "^15.1.1" chrono-node "1.4.4" @@ -946,19 +850,19 @@ ramda "^0.27.0" uuid "^3.3.3" -"@cubejs-backend/query-orchestrator@^0.19.53": - version "0.19.53" - resolved "https://registry.yarnpkg.com/@cubejs-backend/query-orchestrator/-/query-orchestrator-0.19.53.tgz#9ef7bebfdfd69af8118f18ee93944b427a63e102" - integrity sha512-Ma3MYnDaqfetalrTM9RHPzOn+gOAw4GbwMPbbuV1R8xocg0s+k2VSOyoNWKRU1Yn1/P72frn3bG3d7fcr+HzAQ== +"@cubejs-backend/query-orchestrator@^0.19.54": + version "0.19.54" + resolved "https://registry.yarnpkg.com/@cubejs-backend/query-orchestrator/-/query-orchestrator-0.19.54.tgz#abee60387ecb91f2f5febc17beaa5471032eeebd" + integrity sha512-rr1LpvfS9HIO5y/BfGQL6xIaji7yKtyVnPLt80E14e8/1svlX0XXN+yTW18ACjvbs2Ms3Cyo9l7xa1P/kXNR1g== dependencies: generic-pool "^3.7.1" ramda "^0.27.0" redis "^3.0.2" -"@cubejs-backend/schema-compiler@^0.19.50": - version "0.19.50" - resolved "https://registry.yarnpkg.com/@cubejs-backend/schema-compiler/-/schema-compiler-0.19.50.tgz#4b7b2a428553112f8b1357ae364c528058bd7567" - integrity sha512-Mk7/ye6TEZnwQ38210TWJibd6PA+4qrN99cRuwf1V9VGKfbNS2n0WzVYLl111ajYiQ0b7VfjBaVtKfqNNCqMyg== +"@cubejs-backend/schema-compiler@^0.19.54": + version "0.19.54" + resolved "https://registry.yarnpkg.com/@cubejs-backend/schema-compiler/-/schema-compiler-0.19.54.tgz#3a7ff27febfe0f9849c40345ae97f995adeacc70" + integrity sha512-X3Tbcw3yokVHcGENt5mzDuCkb1AK8cD0fRqlw11PaDjH/O/z/L+S6Sx/GOx+2rxLoDMV7OYiYgEFOdSQzT9qgw== dependencies: "@babel/generator" "^7.4.0" "@babel/parser" "^7.4.2" @@ -1502,6 +1406,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + babel-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" @@ -1552,6 +1463,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1582,6 +1498,14 @@ binaryextensions@^2.1.2: resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.2.0.tgz#e7c6ba82d4f5f5758c26078fe8eea28881233311" integrity sha512-bHhs98rj/7i/RZpCSJ3uk55pLXOItjIrh2sRQZSM6OoktScX+LxJzvlU+FELp9j3TdcddTmmYArLSGptCTwjuw== +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1647,16 +1571,47 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer@^5.2.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1852,6 +1807,13 @@ commander@~2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1976,6 +1938,13 @@ debug@3.2.6, debug@^3.2.6: dependencies: ms "^2.1.1" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -1993,6 +1962,59 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0, decompress-targz@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -2147,7 +2169,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.1.0: +end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2481,7 +2503,7 @@ estraverse@^4.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -esutils@^2.0.0, esutils@^2.0.2: +esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== @@ -2614,6 +2636,13 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -2628,6 +2657,21 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -2688,6 +2732,13 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2719,6 +2770,11 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -2787,6 +2843,14 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -2844,11 +2908,21 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +graceful-fs@^4.1.10: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -2995,6 +3069,11 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + ignore-walk@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" @@ -3238,6 +3317,11 @@ is-map@^2.0.1: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4090,6 +4174,13 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -4470,7 +4561,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4752,6 +4843,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -4762,7 +4858,7 @@ picomatch@^2.0.4, picomatch@^2.0.7: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== -pify@^2.0.0: +pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= @@ -4777,6 +4873,18 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -4962,6 +5070,19 @@ readable-stream@^2.0.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^2.3.0, readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdirp@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" @@ -5216,6 +5337,11 @@ safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-buffer@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" @@ -5253,6 +5379,13 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= + dependencies: + commander "~2.8.1" + "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -5705,6 +5838,13 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -5763,6 +5903,19 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + tar@^4: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" @@ -5801,7 +5954,7 @@ throat@^4.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= -through@^2.3.6: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -5818,6 +5971,11 @@ tmpl@1.0.x: resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -5929,6 +6087,14 @@ uglify-js@^3.1.4: dependencies: commander "~2.20.3" +unbzip2-stream@^1.0.9: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -6164,6 +6330,11 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -6211,3 +6382,11 @@ yargs@13.3.2, yargs@^13.3.0: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^13.1.2" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" diff --git a/packages/cubejs-server/package.json b/packages/cubejs-server/package.json index 1fe172df10b90..632d48ef2c8f5 100644 --- a/packages/cubejs-server/package.json +++ b/packages/cubejs-server/package.json @@ -31,7 +31,7 @@ "body-parser": "^1.19.0", "codesandbox-import-utils": "^2.1.12", "cors": "^2.8.4", - "dotenv": "^8.1.0", + "dotenv": "^8.2.0", "express": "^4.17.1", "jsonwebtoken": "^8.4.0", "node-machine-id": "^1.1.10", diff --git a/packages/cubejs-server/yarn.lock b/packages/cubejs-server/yarn.lock index d279ae600f353..954aabebdde37 100644 --- a/packages/cubejs-server/yarn.lock +++ b/packages/cubejs-server/yarn.lock @@ -858,10 +858,10 @@ ramda "^0.27.0" syntax-error "^1.3.0" -"@cubejs-backend/server-core@^0.19.54": - version "0.19.54" - resolved "https://registry.yarnpkg.com/@cubejs-backend/server-core/-/server-core-0.19.54.tgz#820af4c1b174570fb1b3c312c6065ac797c3361d" - integrity sha512-fpAOlMt294RQLoWIhg/82ydYSYUg1k/EDQeoY3lohyrvBo/0r+lAzqXc6VeS7Mq8FFfCEZXklzDMA3xGyBV8Zw== +"@cubejs-backend/server-core@^0.19.55": + version "0.19.55" + resolved "https://registry.yarnpkg.com/@cubejs-backend/server-core/-/server-core-0.19.55.tgz#d1f68657e2a7649f38e26cda4881d06737b0c8b7" + integrity sha512-+XyTtVI71xwDL/8RM5FZEyFYCvCU2sW08DOiEO4PJMW9B1LlzwOuNr7J5Gq0BB9pMgIbAFcB+T3HLoz6qd8Qhw== dependencies: "@babel/core" "^7.7.4" "@babel/generator" "^7.4.0" @@ -1917,9 +1917,10 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" -dotenv@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.1.0.tgz#d811e178652bfb8a1e593c6dd704ec7e90d85ea2" +dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== ecc-jsbn@~0.1.1: version "0.1.2"