diff --git a/CHANGELOG b/CHANGELOG index d5aee9f5cb..7009d8d212 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ v3.5.1 (XXXX-XX-XX) ------------------- +* Added UI support to create documents in a collection using smartGraphAttribute + and/or smartJoinAttribute. + * Add count of objects to latency reporting in arangoimport. * Harden database creation against spurious "duplicate name" errors that diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocument.js b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocument.js index 34f5fd1131..8ac239e778 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocument.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocument.js @@ -69,16 +69,28 @@ window.ArangoDocument = Backbone.Collection.extend({ }); }, - createTypeDocument: function (collectionID, key, callback, returnNew) { - var newDocument; + createTypeDocument: function (collectionID, key, callback, returnNew, + smartJoinAttribute, smartJoinAttributeValue, + smartGraphAttribute, smartGraphAttributeValue) { + var newDocument = {}; - if (key) { - newDocument = JSON.stringify({ - _key: key - }); - } else { - newDocument = JSON.stringify({}); + if (smartJoinAttribute && smartJoinAttributeValue && key) { + // case: smartJoin, bot value are needed and NOT optional + newDocument._key = smartJoinAttributeValue + ':' + key; + newDocument[smartJoinAttribute] = smartJoinAttributeValue; + } else if (smartGraphAttribute && smartGraphAttributeValue) { + // case: smartGraph with value + // other to smartJoin, we can: + // 1.) Create without smartGraphAttribute and without smartGraphAttributeValue + // 2.) Create only with smartGraphAttributeValue + if (key) { + newDocument._key = smartGraphAttributeValue + ':' + key; + } + newDocument[smartGraphAttribute] = smartGraphAttributeValue; + } else if (key) { + newDocument._key = key; } + newDocument = JSON.stringify(newDocument); var url = arangoHelper.databaseUrl('/_api/document?collection=' + encodeURIComponent(collectionID)); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocuments.js b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocuments.js index b5bcd3557a..d8b883f493 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocuments.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/arangoDocuments.js @@ -13,12 +13,31 @@ MAX_SORT: 12000, lastQuery: {}, + type: 'document', sortAttribute: '', + smartJoinAttribute: null, + smartGraphAttribute: null, url: arangoHelper.databaseUrl('/_api/documents'), model: window.arangoDocumentModel, - loadTotal: function (callback) { + setSmartJoinAttribute: function (stringValue) { + this.smartJoinAttribute = stringValue; + }, + + getSmartJoinAttribute: function () { + return this.smartJoinAttribute; + }, + + setSmartGraphAttribute: function (stringValue) { + this.smartGraphAttribute = stringValue; + }, + + getSmartGraphAttribute: function () { + return this.smartGraphAttribute; + }, + + loadCollectionConfig: function (callback) { var self = this; $.ajax({ cache: false, @@ -27,7 +46,22 @@ contentType: 'application/json', processData: false, success: function (data) { - self.setTotal(data.count); + if (data.count) { + self.setTotal(data.count); + } + + if (data.smartJoinAttribute) { + self.setSmartJoinAttribute(data.smartJoinAttribute); + } else { + self.setSmartJoinAttribute(null); + } + + if (data.smartGraphAttribute) { + self.setSmartGraphAttribute(data.smartGraphAttribute); + } else { + self.setSmartGraphAttribute(null); + } + callback(false); }, error: function () { @@ -49,7 +83,7 @@ } else { this.setPage(1); } - this.loadTotal(callback); + this.loadCollectionConfig(callback); }, setSort: function (key) { diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentsView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentsView.js index 056be4ca36..7717ff365a 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentsView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/documentsView.js @@ -6,7 +6,7 @@ (function () { 'use strict'; window.DocumentsView = window.PaginationView.extend({ - filters: { '0': true }, + filters: {'0': true}, filterId: 0, paginationDiv: '#documentsToolbarF', idPrefix: 'documents', @@ -532,21 +532,104 @@ for (i = 1; i <= childrenLength; i++) { $('#removeFilter' + i).parent().remove(); } - this.filters = { '0': true }; + this.filters = {'0': true}; this.filterId = 0; }, addDocumentModal: function (e) { if (!$(e.currentTarget).hasClass('disabled')) { var collid = window.location.hash.split('/')[1]; - var buttons = []; var tableContent = []; + var buttons = []; + var tableContent = []; // second parameter is "true" to disable caching of collection type var callback = function (error, type) { if (error) { arangoHelper.arangoError('Error', 'Could not fetch collection type'); } else { - if (type === 'edge') { + if (this.collection.getSmartJoinAttribute()) { + tableContent.push(this.createDocumentKeyInput(true)); + + tableContent.push( + window.modalView.createTextEntry( + 'new-smart-val-attr', + 'Smart Value (' + this.collection.getSmartJoinAttribute() + ')', + undefined, + 'This smartJoinAttribute must be populated for all documents in the collection, and must always contain a string value.', + '', + true, + [ + { + rule: Joi.string(), + msg: '' + } + ] + ) + ); + + buttons.push( + window.modalView.createSuccessButton('Create', this.addSmartAttributeDocument.bind(this)) + ); + + window.modalView.show( + 'modalTable.ejs', + 'Create document', + buttons, + tableContent + ); + + // custom event handler, updating key label + $('#new-document-key-attr').css('width', '50%').css('float', 'right'); + $('#new-document-key-attr').before( + '' + + '
:
' + ); + $('new-smart-val-attr').unbind('keyup'); + $('#new-smart-val-attr').on('keyup', function (element) { + $('#new-document-key-prefix-attr').val($(element.currentTarget).val()); + }); + } else if (this.collection.getSmartGraphAttribute()) { + tableContent.push(this.createDocumentKeyInput(false)); + + tableContent.push( + window.modalView.createTextEntry( + 'new-smartGraph-val-attr', + 'SmartGraph Value (' + this.collection.getSmartGraphAttribute() + ')', + undefined, + 'This smartGraphAttribute can be populated for all documents in the collection and then contain a string value. Otherwise it will be null.', + '', + false, + [ + { + rule: Joi.string().allow('').optional(), + msg: '' + } + ] + ) + ); + + buttons.push( + window.modalView.createSuccessButton('Create', this.addSmartGraphDocument.bind(this)) + ); + + window.modalView.show( + 'modalTable.ejs', + 'Create document', + buttons, + tableContent + ); + + // custom event handler, updating key label + $('#new-document-key-attr').css('width', '50%').css('float', 'right'); + $('#new-document-key-attr').before( + '' + + '
:
' + ); + $('#new-smartGraph-val-attr').unbind('keyup'); + $('#new-smartGraph-val-attr').on('keyup', function (element) { + $('#new-document-key-prefix-attr').val($(element.currentTarget).val()); + }); + } else if (type === 'edge') { tableContent.push( window.modalView.createTextEntry( 'new-edge-from-attr', @@ -608,23 +691,7 @@ tableContent ); } else { - tableContent.push( - window.modalView.createTextEntry( - 'new-document-key-attr', - '_key', - undefined, - 'the documents unique key(optional attribute, leave empty for autogenerated key', - 'is optional: leave empty for autogenerated key', - false, - [ - { - rule: Joi.string().allow('').optional(), - msg: '' - } - ] - ) - ); - + tableContent.push(this.createDocumentKeyInput(false)); buttons.push( window.modalView.createSuccessButton('Create', this.addDocument.bind(this)) ); @@ -642,69 +709,114 @@ } }, + createDocumentKeyInput: function (isMandatory) { + var placeholder = 'leave empty for autogenerated key'; + var tooltip = 'the documents unique key'; + if (isMandatory) { + placeholder = ''; + } else { + tooltip += ' (optional attribute, leave empty for autogenerated key'; + } + + return window.modalView.createTextEntry( + 'new-document-key-attr', + '_key', + undefined, + tooltip, + placeholder, + isMandatory || false, + [ + { + rule: Joi.string().allow('').optional(), + msg: '' + } + ] + ); + }, + addEdge: function () { var collid = window.location.hash.split('/')[1]; var from = $('.modal-body #new-edge-from-attr').last().val(); var to = $('.modal-body #new-edge-to').last().val(); var key = $('.modal-body #new-edge-key-attr').last().val(); - var url; - - var callback = function (error, data, msg) { - if (error) { - arangoHelper.arangoError('Error', msg.errorMessage); - } else { - window.modalView.hide(); - data = data._id.split('/'); - - try { - url = 'collection/' + data[0] + '/' + data[1]; - decodeURI(url); - } catch (ex) { - url = 'collection/' + data[0] + '/' + encodeURIComponent(data[1]); - } - window.location.hash = url; - } - }; if (key !== '' || key !== undefined) { - this.documentStore.createTypeEdge(collid, from, to, key, callback); + this.documentStore.createTypeEdge(collid, from, to, key, this.goToDocument); } else { - this.documentStore.createTypeEdge(collid, from, to, null, callback); + this.documentStore.createTypeEdge(collid, from, to, null, this.goToDocument); } }, addDocument: function () { var collid = window.location.hash.split('/')[1]; var key = $('.modal-body #new-document-key-attr').last().val(); - var url; - - var callback = function (error, data, msg) { - if (error) { - arangoHelper.arangoError('Error', msg.errorMessage); - } else { - window.modalView.hide(); - data = data.split('/'); - - try { - url = 'collection/' + data[0] + '/' + data[1]; - decodeURI(url); - } catch (ex) { - url = 'collection/' + data[0] + '/' + encodeURIComponent(data[1]); - } - - window.location.hash = url; - } - }; if (key !== '' || key !== undefined) { - this.documentStore.createTypeDocument(collid, key, callback); + this.documentStore.createTypeDocument(collid, key, this.goToDocument); } else { - this.documentStore.createTypeDocument(collid, null, callback); + this.documentStore.createTypeDocument(collid, null, this.goToDocument); } }, + addSmartAttributeDocument: function () { + var collid = window.location.hash.split('/')[1]; + var key = $('.modal-body #new-document-key-attr').last().val(); + var smartJoinAttributeValue = $('.modal-body #new-smart-val-attr').last().val(); + + if (key !== '' || key !== undefined) { + this.documentStore.createTypeDocument(collid, key, this.goToDocument, false, + this.collection.getSmartJoinAttribute(), smartJoinAttributeValue, null, null); + } else { + this.documentStore.createTypeDocument(collid, null, this.goToDocument, false, + this.collection.getSmartJoinAttribute(), smartJoinAttributeValue, null, null); + } + }, + + addSmartGraphDocument: function () { + var collid = window.location.hash.split('/')[1]; + var key = $('.modal-body #new-document-key-attr').last().val(); + var smartGraphAttributeValue = $('.modal-body #new-smartGraph-val-attr').last().val(); + + if (smartGraphAttributeValue === '') { + smartGraphAttributeValue = null; + } + + var smartGraphAttribute = null; + if (this.collection.getSmartGraphAttribute()) { + smartGraphAttribute = this.collection.getSmartGraphAttribute(); + } + + if (key === '') { + key = null; + } + + this.documentStore.createTypeDocument(collid, key, this.goToDocument, false, null, null, + smartGraphAttribute, smartGraphAttributeValue); + }, + + goToDocument: function (error, data, msg) { + if (error) { + arangoHelper.arangoError('Error', msg.errorMessage); + } else { + window.modalView.hide(); + data = data.split('/'); + + var url; + try { + url = 'collection/' + data[0] + '/' + data[1]; + decodeURI(url); + } catch (ex) { + url = 'collection/' + data[0] + '/' + encodeURIComponent(data[1]); + } + + window.location.hash = url; + } + }, + + moveSelectedDocs: function () { - var buttons = []; var tableContent = []; + var buttons = []; + var tableContent = []; var toDelete = this.getSelectedDocs(); if (toDelete.length === 0) { @@ -771,7 +883,8 @@ }, deleteSelectedDocs: function () { - var buttons = []; var tableContent = []; + var buttons = []; + var tableContent = []; var toDelete = this.getSelectedDocs(); if (toDelete.length === 0) { @@ -805,7 +918,8 @@ confirmDeleteSelectedDocs: function () { var toDelete = this.getSelectedDocs(); - var deleted = []; var self = this; + var deleted = []; + var self = this; _.each(toDelete, function (key) { if (self.type === 'document') { @@ -936,7 +1050,8 @@ clicked: function (event) { var self = event.currentTarget; - var url; var doc = $(self).attr('id').substr(4); + var url; + var doc = $(self).attr('id').substr(4); try { url = 'collection/' + this.collection.collectionID + '/' + doc;