Merge remote-tracking branch 'remotes/origin/refactor/dashboard-resource'

This commit is contained in:
Dallon Feldner
2012-09-24 10:07:48 -07:00
2 changed files with 455 additions and 206 deletions

View File

@@ -7,251 +7,243 @@ var util = require('util')
, fs = require('fs')
, ejs = require('ejs')
, keys = require('../keys')
, loadTypes = require('../type-loader');
, loadTypes = require('../type-loader')
, async = require('async');
function Dashboard() {
// internal resource
this.internal = true;
this.loadTypes = async.memoize(this.loadTypes);
this.loadLayout = async.memoize(this.loadLayout);
Resource.apply(this, arguments);
Resource.apply(this, arguments);
}
util.inherits(Dashboard, Resource);
module.exports = Dashboard;
Dashboard.prototype.render = function(ctx, options) {
var self = this
, rendered
, resourceTypes
, layout = this.layout
, appName = path.basename(path.resolve('./'))
, env = ctx.server && ctx.server.options.env;
options = options || {};
var context = {
resourceId: options.resourceId
, resourceType: options.resourceType
, page: options.page
, basicDashboard: options.basicDashboard
, events: options.events
, appName: appName
, env: env
};
Dashboard.prototype.handle = function(ctx, next) {
var query = ctx.req.query;
if (layout) {
var finish = function(context, render) {
try {
rendered = layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null});
ctx.res.setHeader('Content-Type', 'text/html');
ctx.res.end(rendered);
} catch (ex) {
ctx.res.end(ex.message);
}
};
if (options.pagePath) {
fs.readFile(options.pagePath, 'utf-8', function(err, file) {
if (err) return ctx.done(err);
finish(context, {bodyHtml: file});
});
} else {
finish(context, {});
}
if (ctx.req.url === this.path) {
return httpUtil.redirect(ctx.res, ctx.req.url + '/');
} else if (ctx.url === '/__is-root') {
ctx.done(null, {isRoot: ctx.req.isRoot});
} else if (ctx.url.indexOf('/__custom') === 0) {
this.serveCustomAsset(ctx, next);
} else if (ctx.url.indexOf('.') !== -1) {
filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res);
} else if (!ctx.req.isRoot && ctx.server.options.env !== 'development') {
filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res);
} else {
fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) {
if (err) return ctx.done(err);
self.layout = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags
Dashboard.prototype.render.call(self, ctx, options);
});
this.render(ctx);
}
};
Dashboard.prototype.route = function(ctx) {
Dashboard.prototype.serveCustomAsset = function(ctx, next) {
var parts = ctx.url.split('/').filter(function(p) { return p; })
, resourceId
, resource
, resourceType
, page
, pagePath
, scripts = []
, render = this.render;
, resourceTypePath = parts[1]
, resource = this;
if (parts.length) {
resourceId = parts[0];
resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0];
if (resource) {
var renderResource = function(extras) {
var options = {
resourceId: resourceId
, resourceType: resourceType.name
, events: resourceType.events
, page: page
, pagePath: pagePath
, scripts: scripts
};
if (extras) {
Object.keys(extras).forEach(function(k) {
options[k] = extras[k];
});
}
render(ctx, options);
};
resourceType = resource.constructor;
debug("Editing resource %s of type %s", resourceId, resourceType.name);
if (resourceType.dashboard) {
if (resourceType.dashboard.pages) {
page = parts[1] || resourceType.dashboard.pages[0].toLowerCase();
} else if (parts[1] === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
page = 'events';
return renderResource();
} else {
page = 'index';
}
if (page === 'config') page = 'index';
if (resourceType.dashboard.scripts) {
resourceType.dashboard.scripts.forEach(function(s) {
scripts.push('/__custom/' + resourceType.name.toLowerCase() + s);
});
}
pagePath = path.join(resourceType.dashboard.path, page + '.html');
var checkFilesAndRender = function() {
fs.stat(path.join(resourceType.dashboard.path, 'js', page + '.js'), function(err, stat) {
if (stat) {
scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js');
}
fs.stat(path.join(resourceType.dashboard.path, 'style.css'), function(errCss, statCss) {
if (page === 'index') page = 'config';
renderResource({
css: statCss && '/__custom/' + resourceType.name.toLowerCase() + '/style.css'
});
});
});
};
if (page === 'events') {
return fs.stat(pagePath, function(err, stat) {
if (stat) {
checkFilesAndRender();
} else {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
renderResource();
}
});
} else {
checkFilesAndRender();
}
} else if (resourceType.basicDashboard) {
page = parts[1] || 'config';
if (page === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
} else {
pagePath = path.join(__dirname, 'dashboard', 'basic.html');
scripts.push('/js/basic.js');
}
renderResource({
basicDashboard: resourceType.basicDashboard
});
} else {
page = parts[1] || 'config';
if (page === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
} else {
pagePath = path.join(__dirname, 'dashboard', 'default.html');
scripts.push('/js/default.js');
}
renderResource();
}
} else {
this.render(ctx);
}
} else {
this.render(ctx);
}
};
Dashboard.prototype.serve = function(ctx, next) {
var parts = ctx.url.split('/').filter(function(p) { return p; })
, resourceTypePath = parts[1];
loadTypes(function(defaults, types) {
resource.loadTypes(function(err, types) {
var resourceTypeId
, resourceType
, dashboardPath
, reqUrl = parts.slice(2).join('/');
Object.keys(defaults).forEach(function(key) {
types[key] = defaults[key];
});
resourceTypeId = Object.keys(types).filter(function(t) { return t.toLowerCase() === resourceTypePath; })[0];
if (resourceTypeId) {
resourceType = types[resourceTypeId];
dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path;
if (dashboardPath) {
filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res);
} else {
next();
return filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res);
}
} else {
next();
}
next();
});
// , resourceType = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0];
// , dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path
// , reqUrl = parts.slice(2).join('/');
// filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res);
};
Dashboard.prototype.auth = function(ctx) {
filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res);
Dashboard.prototype.loadTypes = function(fn) {
loadTypes(function(defaults, types) {
Object.keys(defaults).forEach(function(key) {
types[key] = defaults[key];
});
fn(null, types);
});
};
Dashboard.prototype.handle = function(ctx, next) {
var query = ctx.req.query
, parts;
Dashboard.prototype.render = function(ctx) {
var self = this
, appName = path.basename(path.resolve('./'))
, env = ctx.server && ctx.server.options.env;
if (ctx.req.url === this.path) {
return httpUtil.redirect(ctx.res, ctx.req.url + '/');
}
async.parallel({
layout: self.loadLayout
, options: async.apply(self.loadPage.bind(self), ctx)
}, function(err, results) {
if (err) return ctx.done(err);
if (ctx.url === '/__is-root') {
ctx.done(null, {isRoot: ctx.req.isRoot});
} else if (ctx.url.indexOf('/__custom') === 0) {
this.serve(ctx, next);
} else if (ctx.url.indexOf('.') !== -1) {
filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res);
} else {
var options = results.options || {}
, layout = results.layout
, render = {};
if (ctx.req.isRoot || ctx.server.options.env === 'development') {
this.route(ctx);
} else {
this.auth(ctx);
var context = {
resourceId: options.resourceId
, resourceType: options.resourceType
, page: options.page
, basicDashboard: options.basicDashboard
, events: options.events
, appName: appName
, env: env
};
render.bodyHtml = options.bodyHtml;
try {
var rendered = results.layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null});
ctx.res.setHeader('Content-Type', 'text/html');
ctx.res.end(rendered);
} catch (ex) {
console.log("PROBLEM", ex);
ctx.done(ex.message);
}
});
};
Dashboard.prototype.loadLayout = function(fn) {
var self = this;
fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) {
if (err) return fn(err);
var layoutTemplate = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags
fn(null, layoutTemplate);
});
};
Dashboard.prototype.loadPage = function(ctx, fn) {
var parts = ctx.url.split('/').filter(function(p) { return p; })
, resourceId
, resource
, resourceType
, options = {}
, self = this
, dashboardPath
, pagePath;
if (parts.length) {
resourceId = parts[0];
resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0];
if (resource) {
options.resourceId = resourceId;
resourceType = resource.constructor;
options.resourceType = resourceType.name;
options.events = resourceType.events;
options.scripts = [];
var page = parts[1];
if (page === 'config') page = 'index';
if (resourceType.dashboard || resourceType.basicDashboard) {
dashboardPath = resourceType.dashboard && resourceType.dashboard.path;
async.waterfall([
function(fn) {
if (dashboardPath) {
pagePath = path.join(dashboardPath, page + '.html');
fs.exists(pagePath, function(exists) {
fn(null, exists);
});
} else {
fn(null, false);
}
},
function(exists, fn) {
if (exists) {
self.loadAdvancedDashboard({
pagePath: pagePath
, dashboardPath: dashboardPath
, page: page
, resourceType: resourceType
, options: options
}, fn);
} else {
self.loadBasicDashboard(resourceType, options, fn);
}
}
], function(err) {
fn(err, options);
});
} else {
}
debug("Editing resource %s of type %s", resourceId, resourceType.name);
return;
}
}
fn(); //blank page
};
Dashboard.prototype.loadAdvancedDashboard = function(data, fn) {
var pagePath = data.pagePath
, dashboardPath = data.dashboardPath
, page = data.page
, resourceType = data.resourceType
, options = data.options;
async.parallel({
bodyHtml: function(fn) {
fs.readFile(pagePath, 'utf-8', fn);
},
scripts: function(fn) {
if (resourceType.dashboard.scripts) {
resourceType.dashboard.scripts.forEach(function(s) {
options.scripts.push('/__custom/' + resourceType.name.toLowerCase() + s);
});
}
fs.exists(path.join(dashboardPath, 'js', page + '.js'), function(exists) {
if (exists) {
options.scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js');
}
fn();
});
},
stylesheet: function(fn) {
fs.exists(path.join(resourceType.dashboard.path, 'style.css'), function(exists) {
if (exists) {
options.css = '/__custom/' + resourceType.name.toLowerCase() + '/style.css';
}
fn();
});
}
}, function(err, results) {
if (err) return fn(err);
options.bodyHtml = results.bodyHtml;
if (page === 'index') page = 'config';
options.page = page;
fn(null, options);
});
};
Dashboard.prototype.loadBasicDashboard = function(resourceType, options, fn) {
};

View File

@@ -0,0 +1,257 @@
var util = require('util')
, httpUtil = require('../util/http')
, filed = require('filed')
, Resource = require('../resource')
, path = require('path')
, debug = require('debug')('dashboard')
, fs = require('fs')
, ejs = require('ejs')
, keys = require('../keys')
, loadTypes = require('../type-loader');
function Dashboard() {
// internal resource
this.internal = true;
Resource.apply(this, arguments);
}
util.inherits(Dashboard, Resource);
module.exports = Dashboard;
Dashboard.prototype.render = function(ctx, options) {
var self = this
, rendered
, resourceTypes
, layout = this.layout
, appName = path.basename(path.resolve('./'))
, env = ctx.server && ctx.server.options.env;
options = options || {};
var context = {
resourceId: options.resourceId
, resourceType: options.resourceType
, page: options.page
, basicDashboard: options.basicDashboard
, events: options.events
, appName: appName
, env: env
};
if (layout) {
var finish = function(context, render) {
try {
rendered = layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null});
ctx.res.setHeader('Content-Type', 'text/html');
ctx.res.end(rendered);
} catch (ex) {
ctx.res.end(ex.message);
}
};
if (options.pagePath) {
fs.readFile(options.pagePath, 'utf-8', function(err, file) {
if (err) return ctx.done(err);
finish(context, {bodyHtml: file});
});
} else {
finish(context, {});
}
} else {
fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) {
if (err) return ctx.done(err);
self.layout = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags
Dashboard.prototype.render.call(self, ctx, options);
});
}
};
Dashboard.prototype.route = function(ctx) {
var parts = ctx.url.split('/').filter(function(p) { return p; })
, resourceId
, resource
, resourceType
, page
, pagePath
, scripts = []
, render = this.render;
if (parts.length) {
resourceId = parts[0];
resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0];
if (resource) {
var renderResource = function(extras) {
var options = {
resourceId: resourceId
, resourceType: resourceType.name
, events: resourceType.events
, page: page
, pagePath: pagePath
, scripts: scripts
};
if (extras) {
Object.keys(extras).forEach(function(k) {
options[k] = extras[k];
});
}
render(ctx, options);
};
resourceType = resource.constructor;
debug("Editing resource %s of type %s", resourceId, resourceType.name);
if (resourceType.dashboard) {
if (resourceType.dashboard.pages) {
page = parts[1] || resourceType.dashboard.pages[0].toLowerCase();
} else if (parts[1] === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
page = 'events';
return renderResource();
} else {
page = 'index';
}
if (page === 'config') page = 'index';
if (resourceType.dashboard.scripts) {
resourceType.dashboard.scripts.forEach(function(s) {
scripts.push('/__custom/' + resourceType.name.toLowerCase() + s);
});
}
pagePath = path.join(resourceType.dashboard.path, page + '.html');
var checkFilesAndRender = function() {
fs.stat(path.join(resourceType.dashboard.path, 'js', page + '.js'), function(err, stat) {
if (stat) {
scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js');
}
fs.stat(path.join(resourceType.dashboard.path, 'style.css'), function(errCss, statCss) {
if (page === 'index') page = 'config';
renderResource({
css: statCss && '/__custom/' + resourceType.name.toLowerCase() + '/style.css'
});
});
});
};
if (page === 'events') {
return fs.stat(pagePath, function(err, stat) {
if (stat) {
checkFilesAndRender();
} else {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
renderResource();
}
});
} else {
checkFilesAndRender();
}
} else if (resourceType.basicDashboard) {
page = parts[1] || 'config';
if (page === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
} else {
pagePath = path.join(__dirname, 'dashboard', 'basic.html');
scripts.push('/js/basic.js');
}
renderResource({
basicDashboard: resourceType.basicDashboard
});
} else {
page = parts[1] || 'config';
if (page === 'events' && resourceType.events) {
pagePath = path.join(__dirname, 'dashboard', 'events.html');
} else {
pagePath = path.join(__dirname, 'dashboard', 'default.html');
scripts.push('/js/default.js');
}
renderResource();
}
} else {
this.render(ctx);
}
} else {
this.render(ctx);
}
};
Dashboard.prototype.serve = function(ctx, next) {
var parts = ctx.url.split('/').filter(function(p) { return p; })
, resourceTypePath = parts[1];
loadTypes(function(defaults, types) {
var resourceTypeId
, resourceType
, dashboardPath
, reqUrl = parts.slice(2).join('/');
Object.keys(defaults).forEach(function(key) {
types[key] = defaults[key];
});
resourceTypeId = Object.keys(types).filter(function(t) { return t.toLowerCase() === resourceTypePath; })[0];
if (resourceTypeId) {
resourceType = types[resourceTypeId];
dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path;
if (dashboardPath) {
filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res);
} else {
next();
}
} else {
next();
}
});
// , resourceType = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0];
// , dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path
// , reqUrl = parts.slice(2).join('/');
// filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res);
};
Dashboard.prototype.auth = function(ctx) {
filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res);
};
Dashboard.prototype.handle = function(ctx, next) {
var query = ctx.req.query
, parts;
if (ctx.req.url === this.path) {
return httpUtil.redirect(ctx.res, ctx.req.url + '/');
}
if (ctx.url === '/__is-root') {
ctx.done(null, {isRoot: ctx.req.isRoot});
} else if (ctx.url.indexOf('/__custom') === 0) {
this.serve(ctx, next);
} else if (ctx.url.indexOf('.') !== -1) {
filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res);
} else {
if (ctx.req.isRoot || ctx.server.options.env === 'development') {
this.route(ctx);
} else {
this.auth(ctx);
}
}
};