Added an 'import dashboard' feature to load a text file into IBEX
This commit is contained in:
Elad Iwanir 2017-06-27 17:04:43 +03:00
Родитель 2d841a684e
Коммит b681596f59
4 изменённых файлов: 133 добавлений и 8 удалений

Просмотреть файл

@ -33,7 +33,7 @@ app.use('/auth', authRouter.router);
app.use('/api', apiRouter.router); app.use('/api', apiRouter.router);
app.use('/cosmosdb', cosmosDBRouter.router); app.use('/cosmosdb', cosmosDBRouter.router);
app.use('/azure', azureRouter.router); app.use('/azure', azureRouter.router);
app.use('/graphql', graphQLRouter.router) app.use('/graphql', graphQLRouter.router);
app.use(express.static(path.resolve(__dirname, '..', 'build'))); app.use(express.static(path.resolve(__dirname, '..', 'build')));

Просмотреть файл

@ -290,6 +290,20 @@ router.post('/setup', (req, res) => {
}) })
}); });
router.post('/import/dashboards', (req, res) => {
var content = (req.body && req.body.json) || '';
var lowerCaseFileName = req.body.dashboardFileName.toLowerCase();
var modifiedFileName = lowerCaseFileName + '.private.js'
fs.writeFile(path.join(__dirname, '..', 'dashboards', modifiedFileName), req.body.content, err => {
if (err) {
console.error(err);
return res.end(err);
}
res.send({ res: 'Dashboard imported successfully' });
})
});
module.exports = { module.exports = {
router router
} }

Просмотреть файл

@ -8,6 +8,7 @@ interface IConfigurationsActions {
loadTemplate(id: string): any; loadTemplate(id: string): any;
saveConfiguration(dashboard: IDashboardConfig): any; saveConfiguration(dashboard: IDashboardConfig): any;
failure(error: any): void; failure(error: any): void;
submitDashboardFile(content:string, fileName:string): void;
} }
class ConfigurationsActions extends AbstractActions implements IConfigurationsActions { class ConfigurationsActions extends AbstractActions implements IConfigurationsActions {
@ -15,6 +16,36 @@ class ConfigurationsActions extends AbstractActions implements IConfigurationsAc
super(alt); super(alt);
} }
submitDashboardFile = (content, dashboardId) => {
return (dispatcher: (json: any) => void) => {
// Replace both 'id' and 'url' with the requested id from the user
var idRegExPattern = /id: \".*\",/i;
var urlRegExPatternt = /url: \".*\",/i;
var updatedContent =
content.replace(idRegExPattern, "id: \"" + dashboardId + "\",")
.replace(urlRegExPatternt, "url: \"" + dashboardId + "\",")
request('/api/import/dashboards', {
method: 'POST',
json: true,
body: { content: updatedContent, dashboardFileName: dashboardId }
},
(error: any, json: any) => {
if (error || (json && json.errors)) {
return this.failure(error || json.errors);
}
// redirect to the newly imported dashboard
window.location.replace('dashboard/' + dashboardId);
return dispatcher(json);
}
);
};
};
loadConfiguration() { loadConfiguration() {
return (dispatcher: (result: { dashboards: IDashboardConfig[], templates: IDashboardConfig[] }) => void) => { return (dispatcher: (result: { dashboards: IDashboardConfig[], templates: IDashboardConfig[] }) => void) => {

Просмотреть файл

@ -1,5 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import TextField from 'react-md/lib/TextFields';
import Dialog from 'react-md/lib/Dialogs';
import NavigationDrawer from 'react-md/lib/NavigationDrawers'; import NavigationDrawer from 'react-md/lib/NavigationDrawers';
import Toolbar from 'react-md/lib/Toolbars'; import Toolbar from 'react-md/lib/Toolbars';
import FontIcon from 'react-md/lib/FontIcons'; import FontIcon from 'react-md/lib/FontIcons';
@ -12,10 +14,12 @@ import Chip from 'react-md/lib/Chips';
import Menu from 'react-md/lib/Menus/Menu'; import Menu from 'react-md/lib/Menus/Menu';
import MenuButton from 'react-md/lib/Menus/MenuButton'; import MenuButton from 'react-md/lib/Menus/MenuButton';
import Button from 'react-md/lib/Buttons'; import Button from 'react-md/lib/Buttons';
import FileUpload from 'react-md/lib/FileInputs/FileUpload';
import AccountStore from '../../stores/AccountStore'; import AccountStore from '../../stores/AccountStore';
import AccountActions from '../../actions/AccountActions'; import AccountActions from '../../actions/AccountActions';
import ConfigurationsActions from '../../actions/ConfigurationsActions';
import ConfigurationsStore from '../../stores/ConfigurationsStore'; import ConfigurationsStore from '../../stores/ConfigurationsStore';
import './style.css'; import './style.css';
@ -43,6 +47,13 @@ export default class Navbar extends React.Component<any, any> {
dashboards: state.dashboards dashboards: state.dashboards
}); });
}); });
// import dashboard functionality
this.onOpenInfo = this.onOpenInfo.bind(this);
this.onCloseInfo = this.onCloseInfo.bind(this);
this.onSubmitImport = this.onSubmitImport.bind(this);
this.onLoad = this.onLoad.bind(this);
this.setFile = this.setFile.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -61,8 +72,39 @@ export default class Navbar extends React.Component<any, any> {
} }
} }
onOpenInfo(html: string) {
this.setState({ importVisible: true });
}
onCloseInfo() {
this.setState({ importVisible: false });
}
updateFileName = (value) => {
this.setState({ fileName: value });
};
onLoad(file, uploadResult) {
const { name, size, type, lastModifiedDate } = file;
this.setState({ fileName: name.substr(0, name.indexOf('.')), content: uploadResult });
}
onSubmitImport() {
var dashboardId = this.state.fileName
ConfigurationsActions.submitDashboardFile(this.state.content, dashboardId);
this.setState({ importVisible: false });
}
setFile(file) {
this.setState({ file });
}
render() { render() {
let { dashboards, noTemplates } = this.state; let { dashboards, noTemplates } = this.state;
let { importVisible } = this.state;
let { file, fileName } = this.state;
let { children, title } = this.props; let { children, title } = this.props;
let pathname = '/'; let pathname = '/';
try { pathname = window.location.pathname; } catch (e) { } try { pathname = window.location.pathname; } catch (e) { }
@ -138,7 +180,45 @@ export default class Navbar extends React.Component<any, any> {
href="/" href="/"
component={Link} component={Link}
>add_box >add_box
</Button>), ( </Button>),
(
<Button
icon
tooltipLabel="Import dashboard"
onClick={this.onOpenInfo.bind(this)}
component={Link}
>add_box
</Button>),
<Dialog
id="ImportDashboard"
visible={importVisible}
title="Import dashboard"
dialogStyle={{ width: '50%' }}
modal
actions={[
{ onClick: this.onCloseInfo, primary: false, label: 'Cancel' },
{ onClick: this.onSubmitImport, primary: true, label: 'Submit', disabled: !file },
]}
>
<FileUpload
id="dashboardDefenitionFile"
primary
label="Choose File"
accept="application/json"
onLoadStart={this.setFile}
onLoad={this.onLoad}
/>
<TextField
id="dashboardFileName"
label="Dashboard ID"
value={fileName}
onChange={this.updateFileName}
disabled={!file}
lineDirection="center"
placeholder="Choose an ID for the imported dashboard"
/>
</Dialog>
, (
<MenuButton <MenuButton
id="vert-menu" id="vert-menu"
icon icon