better error messages, more robust csv uploading
This commit is contained in:
parent
935e0d15a0
commit
fe8df046da
6
app.js
6
app.js
@ -115,12 +115,6 @@ ddoc.lists = {
|
||||
}
|
||||
}
|
||||
|
||||
ddoc.validate_doc_update = function (newDoc, oldDoc, userCtx) {
|
||||
if (newDoc._deleted === true && userCtx.roles.indexOf('_admin') === -1) {
|
||||
throw "Only admin can delete documents on this database.";
|
||||
}
|
||||
};
|
||||
|
||||
couchapp.loadAttachments(ddoc, path.join(__dirname, 'attachments'));
|
||||
|
||||
module.exports = ddoc;
|
||||
@ -6,16 +6,8 @@
|
||||
<link rel="stylesheet" href="style/reset.css" media="screen">
|
||||
<link rel="stylesheet" href="style/data-table.css" media="screen">
|
||||
<link rel="stylesheet" href="style/style.css" media="screen">
|
||||
<script type="text/javascript" src="script/lib/jquery-1.6.1.min.js"></script>
|
||||
<!-- only using jqueryui for draggable -- a lighter solution would be nice -->
|
||||
<script type="text/javascript" src="script/lib/jquery-ui-1.8.14.custom.min.js"></script>
|
||||
<script type="text/javascript" src="script/lib/jquery.mustache.js"></script>
|
||||
<script type="text/javascript" src="script/lib/jquery.couch2.js"></script>
|
||||
<script type="text/javascript" src="script/lib/jquery.hotkeys.js"></script>
|
||||
<script type="text/javascript" src="script/lib/sammy-0.6.3.min.js"></script>
|
||||
<script type="text/javascript" src="script/lib/underscore.js"></script>
|
||||
<script type="text/javascript" src="script/lib/microevent.js"></script>
|
||||
<script type="text/javascript" src="script/lib/traverse.js"></script>
|
||||
<script type="text/javascript" src="script/deps-min.js"></script>
|
||||
<script type="text/javascript" src="script/util.js"></script>
|
||||
<script type="text/javascript" src="script/costco.js"></script>
|
||||
<script type="text/javascript" src="script/recline.js"></script>
|
||||
@ -32,7 +24,10 @@
|
||||
<div class="project-actions"></div>
|
||||
<div class="project-controls"></div>
|
||||
</div>
|
||||
<div class="main_content"></div>
|
||||
<div class="main_content">
|
||||
<div class="left-panel"></div>
|
||||
<div class="right-panel"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="notification-container">
|
||||
@ -94,43 +89,40 @@
|
||||
<script type='text/mustache' class="generatingTemplate"><div class="loading">Loading...</div></script>
|
||||
|
||||
<script type='text/mustache' class="tableContainerTemplate">
|
||||
<div id="right-panel">
|
||||
<div id="tool-panel">
|
||||
<div id="summary-bar">
|
||||
<span id="docCount"></span>
|
||||
<div id="tool-panel">
|
||||
<div id="summary-bar">
|
||||
<span id="docCount"></span>
|
||||
</div>
|
||||
<div id="download">
|
||||
</div>
|
||||
</div>
|
||||
<div id="view-panel">
|
||||
<div class="viewpanel-header">
|
||||
<div class="viewpanel-pagesize">
|
||||
<span>
|
||||
Show:
|
||||
</span>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">5</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page selected">10</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">25</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">50</a>
|
||||
<span>
|
||||
rows
|
||||
</span>
|
||||
</div>
|
||||
<div id="download">
|
||||
<div class="viewpanel-sorting">
|
||||
</div>
|
||||
<div class="viewpanel-paging">
|
||||
<a href="javascript:{}" class="first inaction">« first</a>
|
||||
<a href="javascript:{}" class="previous inaction">‹ previous</a>
|
||||
<span class="viewpanel-pagingcount">
|
||||
1 - 10
|
||||
</span>
|
||||
<a href="javascript:{}" class="next action">next ›</a>
|
||||
<a href="javascript:{}" class="last action">last »</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view-panel">
|
||||
<div class="viewpanel-header">
|
||||
<div class="viewpanel-pagesize">
|
||||
<span>
|
||||
Show:
|
||||
</span>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">5</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page selected">10</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">25</a>
|
||||
<a href="javascript:{}" class="viewPanel-pagingControls-page action">50</a>
|
||||
<span>
|
||||
rows
|
||||
</span>
|
||||
</div>
|
||||
<div class="viewpanel-sorting">
|
||||
</div>
|
||||
<div class="viewpanel-paging">
|
||||
<a href="javascript:{}" class="first inaction">« first</a>
|
||||
<a href="javascript:{}" class="previous inaction">‹ previous</a>
|
||||
<span class="viewpanel-pagingcount">
|
||||
1 - 10
|
||||
</span>
|
||||
<a href="javascript:{}" class="next action">next ›</a>
|
||||
<a href="javascript:{}" class="last action">last »</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-table-container">
|
||||
|
||||
</div>
|
||||
<div class="data-table-container">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
@ -304,7 +296,7 @@
|
||||
Paste in an array of JSON objects representing the documents that you would like to insert into the database.
|
||||
</p>
|
||||
<p class="info">
|
||||
<code>[{woo: "pizza"}, {tasty: "muffins"}]</code>
|
||||
<code>[{"woo": "pizza"}, {"tasty": "muffins"}]</code>
|
||||
</p>
|
||||
<div class="menu-container data-table-cell-editor">
|
||||
<textarea class="data-table-cell-copypaste-editor" bind="textarea">{{value}}</textarea>
|
||||
|
||||
@ -45,12 +45,12 @@ onmessage = function(message) {
|
||||
var docs = parseCSV(message.data.data);
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
|
||||
|
||||
req.onprogress = req.upload.onprogress = function(e) {
|
||||
if(e.lengthComputable) postMessage(JSON.stringify({ percent: (e.loaded / e.total) * 100 }));
|
||||
if(e.lengthComputable) postMessage({ percent: (e.loaded / e.total) * 100 });
|
||||
};
|
||||
|
||||
req.onreadystatechange = function() { if (req.readyState == 4) postMessage(JSON.stringify( {done: true} )) };
|
||||
req.onreadystatechange = function() { if (req.readyState == 4) postMessage({done: true, response: req.responseText}) };
|
||||
req.open('POST', message.data.url);
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
req.send(JSON.stringify({docs: docs}));
|
||||
|
||||
@ -90,7 +90,14 @@ var costco = function() {
|
||||
if(!docs.length) dfd.resolve("Failed: No docs specified");
|
||||
couch.request({url: app.baseURL + "api/_bulk_docs", type: "POST", data: JSON.stringify({docs: docs})})
|
||||
.then(
|
||||
function(resp) {ensureCommit().then(function() { dfd.resolve(resp) })},
|
||||
function(resp) {ensureCommit().then(function() {
|
||||
var error = couch.responseError(resp);
|
||||
if (error) {
|
||||
dfd.reject(error);
|
||||
} else {
|
||||
dfd.resolve(resp);
|
||||
}
|
||||
})},
|
||||
function(err) { dfd.reject(err.responseText) }
|
||||
);
|
||||
return dfd.promise();
|
||||
@ -119,25 +126,29 @@ var costco = function() {
|
||||
data: event.target.result
|
||||
};
|
||||
var worker = new Worker('script/costco-csv-worker.js');
|
||||
worker.onmessage = function(message) {
|
||||
message = JSON.parse(message.data);
|
||||
console.log(message)
|
||||
|
||||
if (message.done) {
|
||||
util.hide('dialog');
|
||||
util.notify("Data uploaded successfully!");
|
||||
recline.initializeTable(app.offset);
|
||||
} else if (message.percent) {
|
||||
if (message.percent === 100) {
|
||||
util.notify("Waiting for CouchDB...", {persist: true, loader: true})
|
||||
} else {
|
||||
util.notify("Uploading... " + message.percent + "%");
|
||||
}
|
||||
} else {
|
||||
util.notify(JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
worker.postMessage(payload);
|
||||
worker.onmessage = function(event) {
|
||||
var message = event.data;
|
||||
if (message.done) {
|
||||
var error = couch.responseError(JSON.parse(message.response))
|
||||
console.log('e',error)
|
||||
if (error) {
|
||||
app.emitter.emit(error, 'error');
|
||||
} else {
|
||||
util.notify("Data uploaded successfully!");
|
||||
recline.initializeTable(app.offset);
|
||||
}
|
||||
util.hide('dialog');
|
||||
} else if (message.percent) {
|
||||
if (message.percent === 100) {
|
||||
util.notify("Waiting for CouchDB...", {persist: true, loader: true})
|
||||
} else {
|
||||
util.notify("Uploading... " + message.percent + "%");
|
||||
}
|
||||
} else {
|
||||
util.notify(JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
worker.postMessage(payload);
|
||||
};
|
||||
} else {
|
||||
util.notify('File not selected. Please try again');
|
||||
|
||||
19
attachments/script/deps-min.js
vendored
Normal file
19
attachments/script/deps-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -10,9 +10,32 @@
|
||||
url: "/"
|
||||
};
|
||||
|
||||
couch.errors = {
|
||||
forbidden: "You aren't allowed to do that."
|
||||
}
|
||||
|
||||
couch.responseError = function(response) {
|
||||
if(_.isArray(response) && (response.length > 0) ) response = response[0];
|
||||
if (response.error) return couch.errors[response.error];
|
||||
}
|
||||
|
||||
couch.request = function(opts) {
|
||||
var ajaxOpts = $.extend({}, defaults, opts);
|
||||
return $.ajax(ajaxOpts).promise();
|
||||
var ajaxOpts = $.extend({}, defaults, opts)
|
||||
, dfd = $.Deferred()
|
||||
;
|
||||
|
||||
$.ajax(ajaxOpts).then(
|
||||
function(successResponse) {
|
||||
var error = couch.responseError(successResponse);
|
||||
if (error) app.emitter.emit(error, 'error');
|
||||
dfd.resolve(successResponse);
|
||||
},
|
||||
function(errorResponse) {
|
||||
app.emitter.emit("Fatal XHR Error", 'error');
|
||||
}
|
||||
)
|
||||
|
||||
return dfd.promise();
|
||||
}
|
||||
|
||||
couch.get = function(url) {
|
||||
|
||||
@ -122,7 +122,12 @@ var recline = function() {
|
||||
}
|
||||
|
||||
function getPageSize() {
|
||||
return parseInt($(".viewpanel-pagesize .selected").text());
|
||||
var pagination = $(".viewpanel-pagesize .selected");
|
||||
if (pagination.length > 0) {
|
||||
return parseInt(pagination.text())
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
function fetchRows(id, skip) {
|
||||
@ -158,9 +163,9 @@ var recline = function() {
|
||||
)
|
||||
}
|
||||
|
||||
function getDbInfo() {
|
||||
function getDbInfo(url) {
|
||||
var dfd = $.Deferred();
|
||||
return couch.request({url: app.baseURL + "api"}).then(function(dbInfo) {
|
||||
return couch.request({url: url}).then(function(dbInfo) {
|
||||
app.dbInfo = dbInfo;
|
||||
|
||||
$.extend(app.dbInfo, {
|
||||
@ -176,18 +181,15 @@ var recline = function() {
|
||||
}
|
||||
|
||||
|
||||
function bootstrap() {
|
||||
util.registerEmitter();
|
||||
function bootstrap(id) {
|
||||
app.dbPath = app.baseURL + "api/";
|
||||
|
||||
util.listenFor(['esc', 'return']);
|
||||
|
||||
getDbInfo().then(function( dbInfo ) {
|
||||
|
||||
util.render('tableContainer', app.container);
|
||||
util.render('title', 'project-title', app.dbInfo);
|
||||
getDbInfo(app.dbPath).then(function( dbInfo ) {
|
||||
util.render('title', 'project-title', dbInfo);
|
||||
util.render( 'generating', 'project-actions' );
|
||||
|
||||
updateDocCount(app.dbInfo.doc_count);
|
||||
|
||||
|
||||
couch.session().then(function(session) {
|
||||
if ( session.userCtx.name ) {
|
||||
var text = "Sign out";
|
||||
@ -196,24 +198,26 @@ var recline = function() {
|
||||
}
|
||||
util.render('controls', 'project-controls', {text: text});
|
||||
})
|
||||
|
||||
|
||||
initializeTable();
|
||||
})
|
||||
}
|
||||
|
||||
function initializeTable(offset) {
|
||||
util.render( 'tableContainer', 'right-panel' );
|
||||
showDialog('busy');
|
||||
couch.request({url: app.baseURL + 'api/headers'}).then(function ( headers ) {
|
||||
couch.request({url: app.dbPath + 'headers'}).then(function ( headers ) {
|
||||
util.hide('dialog');
|
||||
getDbInfo().then(function(dbInfo) {
|
||||
getDbInfo(app.dbPath).then(function(dbInfo) {
|
||||
updateDocCount(dbInfo.doc_count);
|
||||
});
|
||||
app.headers = headers;
|
||||
app.csvUrl = app.baseURL + 'api/csv?headers=' + escape(JSON.stringify(headers));
|
||||
app.csvUrl = app.dbPath + 'csv?headers=' + escape(JSON.stringify(headers));
|
||||
util.render( 'actions', 'project-actions', $.extend({}, app.dbInfo, {url: app.csvUrl}) );
|
||||
fetchRows(false, offset);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
formatDiskSize: formatDiskSize,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
var app = {
|
||||
baseURL: util.getBaseURL(document.location.pathname),
|
||||
container: 'main_content'
|
||||
container: 'main_content',
|
||||
emitter: util.registerEmitter()
|
||||
};
|
||||
|
||||
app.handler = function(route) {
|
||||
@ -227,7 +228,6 @@ app.after = {
|
||||
},
|
||||
function (err) {
|
||||
util.hide('dialog');
|
||||
util.notify("Error uploading: " + err.responseText);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@ -246,6 +246,10 @@ app.sammy = $.sammy(function () {
|
||||
});
|
||||
|
||||
$(function() {
|
||||
app.emitter.on('error', function(error) {
|
||||
util.notify("Server error: " + error);
|
||||
})
|
||||
|
||||
util.traverse = require('traverse');
|
||||
app.sammy.run();
|
||||
})
|
||||
@ -32,7 +32,7 @@ var util = function() {
|
||||
};
|
||||
};
|
||||
MicroEvent.mixin(Emitter);
|
||||
app.emitter = new Emitter();
|
||||
return new Emitter();
|
||||
}
|
||||
|
||||
function listenFor(keys) {
|
||||
|
||||
@ -450,7 +450,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#left-panel {
|
||||
.left-panel {
|
||||
position: fixed;
|
||||
overflow: hidden;
|
||||
padding: 0px;
|
||||
@ -459,14 +459,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
background: #e3e9ff;
|
||||
}
|
||||
|
||||
#left-panel .ui-tabs .ui-tabs-panel {
|
||||
.left-panel .ui-tabs .ui-tabs-panel {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#right-panel {
|
||||
.right-panel {
|
||||
position: fixed;
|
||||
top: 40px;
|
||||
left: 0px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user