enabling multi dashboards API+client
This commit is contained in:
Родитель
4a95285161
Коммит
a83a7076e8
|
@ -44,7 +44,132 @@ router.post('/dashboard.js', (req, res) => {
|
|||
})
|
||||
});
|
||||
|
||||
function isAuthoeizedToSetup(req) {
|
||||
|
||||
router.get('/dashboards', (req, res) => {
|
||||
|
||||
let privateDashboard = path.join(__dirname, '..', 'dashboards');
|
||||
let preconfDashboard = path.join(__dirname, '..', 'dashboards', 'preconfigured');
|
||||
|
||||
let script = '';
|
||||
let files = fs.readdirSync(privateDashboard);
|
||||
if (files && files.length) {
|
||||
files.forEach((fileName) => {
|
||||
let filePath = path.join(privateDashboard, fileName);
|
||||
let stats = fs.statSync(filePath);
|
||||
if (stats.isFile()) {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// Ensuing this dashboard is loaded into the dashboards array on the page
|
||||
script += `
|
||||
(function (window) {
|
||||
var dashboard = (function () {
|
||||
${content}
|
||||
})();
|
||||
window.dashboardDefinitions = window.dashboardDefinitions || [];
|
||||
window.dashboardDefinitions.push(dashboard);
|
||||
})(window);
|
||||
`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let templates = fs.readdirSync(preconfDashboard);
|
||||
if (templates && templates.length) {
|
||||
templates.forEach((fileName) => {
|
||||
let filePath = path.join(preconfDashboard, fileName);
|
||||
let stats = fs.statSync(filePath);
|
||||
if (stats.isFile()) {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// Ensuing this dashboard is loaded into the dashboards array on the page
|
||||
script += `
|
||||
(function (window) {
|
||||
var dashboardTemplate = (function () {
|
||||
${content}
|
||||
})();
|
||||
window.dashboardTemplates = window.dashboardTemplates || [];
|
||||
window.dashboardTemplates.push(dashboardTemplate);
|
||||
})(window);
|
||||
`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
res.send(script);
|
||||
});
|
||||
|
||||
router.get('/dashboards/:id', (req, res) => {
|
||||
|
||||
let dashboardId = req.params.id;
|
||||
let privateDashboard = path.join(__dirname, '..', 'dashboards');
|
||||
let preconfDashboard = path.join(__dirname, '..', 'dashboards', 'preconfigured');
|
||||
|
||||
let script = '';
|
||||
let files = fs.readdirSync(privateDashboard) || [];
|
||||
|
||||
// Make sure the array only contains files
|
||||
files = files.filter(fileName => fs.statSync(path.join(privateDashboard, fileName)).isFile());
|
||||
|
||||
if (files.length) {
|
||||
|
||||
let dashboardFile = null;
|
||||
let dashboardIndex = parseInt(dashboardId);
|
||||
if (!isNaN(dashboardIndex) && files.length > dashboardIndex) {
|
||||
dashboardFile = files[dashboardIndex];
|
||||
}
|
||||
|
||||
if (!dashboardFile) {
|
||||
files.forEach(fileName => {
|
||||
let filePath = path.join(privateDashboard, fileName);
|
||||
|
||||
let stats = fs.statSync(filePath);
|
||||
if (stats.isFile()) {
|
||||
let dashboard = getJSONFromScript(filePath);
|
||||
if (dashboard.url && dashboard.url.toLowerCase() === dashboardId.toLowerCase()) {
|
||||
dashboardFile = fileName;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (dashboardFile) {
|
||||
let filePath = path.join(privateDashboard, dashboardFile);
|
||||
let stats = fs.statSync(filePath);
|
||||
if (stats.isFile()) {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// Ensuing this dashboard is loaded into the dashboards array on the page
|
||||
script += `
|
||||
(function (window) {
|
||||
var dashboard = (function () {
|
||||
${content}
|
||||
})();
|
||||
window.dashboard = dashboard || null;
|
||||
})(window);
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.send(script);
|
||||
});
|
||||
|
||||
router.post('/dashboards/:id', (req, res) => {
|
||||
let dashboardName = req.params.dashboard;
|
||||
var content = (req.body && req.body.script) || '';
|
||||
console.dir(content);
|
||||
|
||||
fs.writeFile(path.join(__dirname, '..', 'dashboards', 'dashboard.private.js'), content, err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.end(err);
|
||||
}
|
||||
|
||||
res.end(content);
|
||||
})
|
||||
});
|
||||
|
||||
function isAuthorizedToSetup(req) {
|
||||
if (!fs.existsSync(privateSetupPath)) { return true; }
|
||||
|
||||
let configString = fs.readFileSync(privateSetupPath, 'utf8');
|
||||
|
@ -61,7 +186,7 @@ function isAuthoeizedToSetup(req) {
|
|||
|
||||
router.get('/setup', (req, res) => {
|
||||
|
||||
if (!isAuthoeizedToSetup(req)) {
|
||||
if (!isAuthorizedToSetup(req)) {
|
||||
return res.send({ error: new Error('User is not authorized to setup') });
|
||||
}
|
||||
|
||||
|
@ -76,7 +201,7 @@ router.get('/setup', (req, res) => {
|
|||
|
||||
router.post('/setup', (req, res) => {
|
||||
|
||||
if (!isAuthoeizedToSetup(req)) {
|
||||
if (!isAuthorizedToSetup(req)) {
|
||||
return res.send({ error: new Error('User is not authorized to setup') });
|
||||
}
|
||||
|
||||
|
@ -96,3 +221,16 @@ router.post('/setup', (req, res) => {
|
|||
module.exports = {
|
||||
router
|
||||
}
|
||||
|
||||
function getJSONFromScript(filePath) {
|
||||
if (!fs.existsSync(filePath)) { return {}; }
|
||||
|
||||
let jsonScript = {};
|
||||
let stats = fs.statSync(filePath);
|
||||
if (stats.isFile()) {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
eval('jsonScript = (function () { ' + content + ' })();');
|
||||
}
|
||||
|
||||
return jsonScript;
|
||||
}
|
|
@ -3,6 +3,7 @@ import * as request from 'xhr-request';
|
|||
|
||||
interface IConfigurationsActions {
|
||||
loadConfiguration(): any;
|
||||
loadDashboard(id: string): any;
|
||||
saveConfiguration(dashboard: IDashboardConfig): any;
|
||||
failure(error: any): void;
|
||||
}
|
||||
|
@ -14,17 +15,33 @@ class ConfigurationsActions extends AbstractActions implements IConfigurationsAc
|
|||
|
||||
loadConfiguration() {
|
||||
|
||||
return (dispatcher: (dashboard: IDashboardConfig) => void) => {
|
||||
return (dispatcher: (result: { dashboards: IDashboardConfig[], templates: IDashboardConfig[] }) => void) => {
|
||||
|
||||
this.getScript('/api/dashboard.js', () => {
|
||||
let dashboards: IDashboardConfig[] = (window as any)['dashboards'];
|
||||
this.getScript('/api/dashboards', () => {
|
||||
let dashboards: IDashboardConfig[] = (window as any)['dashboardDefinitions'];
|
||||
let templates: IDashboardConfig[] = (window as any)['dashboardTemplates'];
|
||||
|
||||
if (!dashboards || !dashboards.length) {
|
||||
return this.failure(new Error('Could not load configuration'));
|
||||
}
|
||||
|
||||
let dashboard = dashboards[0];
|
||||
return dispatcher(dashboard);
|
||||
return dispatcher({ dashboards, templates });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
loadDashboard(id: string) {
|
||||
|
||||
return (dispatcher: (result: { dashboard: IDashboardConfig }) => void) => {
|
||||
|
||||
this.getScript('/api/dashboards/' + id, () => {
|
||||
let dashboard: IDashboardConfig = (window as any)['dashboard'];
|
||||
|
||||
if (!dashboard) {
|
||||
return this.failure(new Error('Could not load configuration for dashboard ' + id));
|
||||
}
|
||||
|
||||
return dispatcher({ dashboard });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class ConfigDashboard extends React.Component<IConfigDashboardPro
|
|||
this.onSave = this.onSave.bind(this);
|
||||
this.onSaveGoToDashboard = this.onSaveGoToDashboard.bind(this);
|
||||
|
||||
ConfigurationsActions.loadConfiguration();
|
||||
//ConfigurationsActions.loadConfiguration();
|
||||
}
|
||||
|
||||
onParamChange(connectionKey, paramKey, value) {
|
||||
|
|
|
@ -12,6 +12,8 @@ import Chip from 'react-md/lib/Chips';
|
|||
import AccountStore from '../../stores/AccountStore';
|
||||
import AccountActions from '../../actions/AccountActions';
|
||||
|
||||
import ConfigurationsStore from '../../stores/ConfigurationsStore';
|
||||
|
||||
import './style.css';
|
||||
|
||||
const avatarSrc = 'https://cloud.githubusercontent.com/assets/13041/19686250/971bf7f8-9ac0-11e6-975c-188defd82df1.png';
|
||||
|
@ -47,9 +49,16 @@ export default class Navbar extends React.Component<any, any> {
|
|||
this.setState(state);
|
||||
});
|
||||
AccountActions.updateAccount();
|
||||
|
||||
ConfigurationsStore.listen((state) => {
|
||||
this.setState({
|
||||
dashboards: state.dashboards
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let { dashboards } = this.state;
|
||||
let { children, title } = this.props;
|
||||
let pathname = '/';
|
||||
try { pathname = window.location.pathname; } catch (e) { }
|
||||
|
@ -81,17 +90,6 @@ export default class Navbar extends React.Component<any, any> {
|
|||
<ListItem
|
||||
key="2"
|
||||
component={Link}
|
||||
href="/dashboard"
|
||||
active={pathname === '/dashboard'}
|
||||
leftIcon={<FontIcon>dashboard</FontIcon>}
|
||||
tileClassName="md-list-tile--mini"
|
||||
primaryText={'Dashboard'}
|
||||
/>
|
||||
),
|
||||
(
|
||||
<ListItem
|
||||
key="3"
|
||||
component={Link}
|
||||
href="/setup"
|
||||
active={pathname === '/setup'}
|
||||
leftIcon={<FontIcon>settings</FontIcon>}
|
||||
|
@ -101,6 +99,30 @@ export default class Navbar extends React.Component<any, any> {
|
|||
)
|
||||
];
|
||||
|
||||
(dashboards || []).forEach((dashboard, index) => {
|
||||
let name = dashboard.name || null;
|
||||
let url = '/dashboard/' + (dashboard.url || index.toString());
|
||||
let active = pathname === url;
|
||||
if (!title && active && name) {
|
||||
title = name;
|
||||
}
|
||||
|
||||
navigationItems.push(
|
||||
(
|
||||
<ListItem
|
||||
key={index + 4}
|
||||
component={Link}
|
||||
href={url}
|
||||
active={active}
|
||||
leftIcon={<FontIcon>{dashboard.icon || 'dashboard'}</FontIcon>}
|
||||
tileClassName="md-list-tile--mini"
|
||||
primaryText={name || 'Dashboard'}
|
||||
/>
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
|
||||
let toolbarActions =
|
||||
this.state.account ?
|
||||
<Chip style={{ marginRight: 30 }} label={'Hello, ' + this.state.account.displayName} /> :
|
||||
|
@ -129,6 +151,7 @@ export default class Navbar extends React.Component<any, any> {
|
|||
break;
|
||||
|
||||
default:
|
||||
|
||||
title = 'Ibex Dashboard';
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class Config extends React.Component<any, IDashboardState> {
|
|||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
ConfigurationsActions.loadConfiguration();
|
||||
//ConfigurationsActions.loadConfiguration();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class Dashboard extends React.Component<any, IDashboardState> {
|
|||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
ConfigurationsActions.loadConfiguration();
|
||||
// ConfigurationsActions.loadConfiguration();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
|
@ -16,6 +16,7 @@ export default (
|
|||
<Route path="/about" component={About} />
|
||||
<Route path="/dashboard" component={Dashboard} />
|
||||
<Route path="/dashboard/config" component={Config} />
|
||||
<Route path="/dashboard/:id" component={Dashboard}/>
|
||||
<Route path="/setup" component={Setup} />
|
||||
<Route path="*" component={NotFound} />
|
||||
</Route>
|
||||
|
|
|
@ -7,6 +7,8 @@ import configurationActions from '../actions/ConfigurationsActions';
|
|||
|
||||
interface IConfigurationsStoreState {
|
||||
dashboard: IDashboardConfig;
|
||||
dashboards: IDashboardConfig[];
|
||||
templates: IDashboardConfig[];
|
||||
connections: IDictionary;
|
||||
connectionsMissing: boolean;
|
||||
loaded: boolean;
|
||||
|
@ -15,6 +17,8 @@ interface IConfigurationsStoreState {
|
|||
class ConfigurationsStore extends AbstractStoreModel<IConfigurationsStoreState> implements IConfigurationsStoreState {
|
||||
|
||||
dashboard: IDashboardConfig;
|
||||
dashboards: IDashboardConfig[];
|
||||
templates: IDashboardConfig[];
|
||||
connections: IDictionary;
|
||||
connectionsMissing: boolean;
|
||||
loaded: boolean;
|
||||
|
@ -23,16 +27,38 @@ class ConfigurationsStore extends AbstractStoreModel<IConfigurationsStoreState>
|
|||
super();
|
||||
|
||||
this.dashboard = null;
|
||||
this.dashboards = null;
|
||||
this.templates = null;
|
||||
this.connections = {};
|
||||
this.connectionsMissing = false;
|
||||
this.loaded = false;
|
||||
|
||||
this.bindListeners({
|
||||
loadConfiguration: configurationActions.loadConfiguration
|
||||
loadConfiguration: configurationActions.loadConfiguration,
|
||||
loadDashboard: configurationActions.loadDashboard
|
||||
});
|
||||
|
||||
configurationActions.loadConfiguration();
|
||||
|
||||
let pathname = window.location.pathname;
|
||||
if (pathname === '/dashboard') {
|
||||
configurationActions.loadDashboard("0");
|
||||
}
|
||||
|
||||
loadConfiguration(dashboard: IDashboardConfig) {
|
||||
if (pathname.startsWith('/dashboard/')) {
|
||||
let dashboardId = pathname.substring('/dashboard/'.length);
|
||||
configurationActions.loadDashboard(dashboardId);
|
||||
}
|
||||
}
|
||||
|
||||
loadConfiguration(result: { dashboards: IDashboardConfig[], templates: IDashboardConfig[] }) {
|
||||
let { dashboards,templates } = result;
|
||||
this.dashboards = dashboards;
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
loadDashboard(result: { dashboard: IDashboardConfig }) {
|
||||
let { dashboard } = result;
|
||||
this.dashboard = dashboard;
|
||||
|
||||
if (this.dashboard && !this.loaded) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче