Import dashboard:
Added an 'import dashboard' feature to load a text file into IBEX
This commit is contained in:
Родитель
2d841a684e
Коммит
b681596f59
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче