Github user benkeen commented on a diff in the pull request: https://github.com/apache/couchdb-fauxton/pull/651#discussion_r55846282 --- Diff: app/addons/documents/index-editor/actions.js --- @@ -15,142 +15,287 @@ define([ 'api', 'addons/documents/resources', 'addons/documents/index-editor/actiontypes', - 'addons/documents/index-results/actions' + 'addons/documents/index-results/actions', + 'addons/documents/sidebar/actions', + 'addons/documents/sidebar/actiontypes' ], -function (app, FauxtonAPI, Documents, ActionTypes, IndexResultsActions) { +function (app, FauxtonAPI, Documents, ActionTypes, IndexResultsActions, SidebarActions, SidebarActionTypes) { - var ActionHelpers = { - findDesignDoc: function (designDocs, designDocId) { - return _.find(designDocs, function (doc) { - return doc.id === designDocId; - }).dDocModel(); - } - }; + function selectReduceChanged (reduceOption) { + FauxtonAPI.dispatch({ + type: ActionTypes.SELECT_REDUCE_CHANGE, + reduceSelectedOption: reduceOption + }); + } - return { - //helpers are added here for use in testing actions - helpers: ActionHelpers, + function changeViewName (name) { + FauxtonAPI.dispatch({ + type: ActionTypes.VIEW_NAME_CHANGE, + name: name + }); + } - selectReduceChanged: function (reduceOption) { - FauxtonAPI.dispatch({ - type: ActionTypes.SELECT_REDUCE_CHANGE, - reduceSelectedOption: reduceOption - }); - }, + function editIndex (options) { + FauxtonAPI.dispatch({ + type: ActionTypes.EDIT_INDEX, + options: options + }); + } - changeViewName: function (name) { - FauxtonAPI.dispatch({ - type: ActionTypes.VIEW_NAME_CHANGE, - name: name - }); - }, + function clearIndex () { + FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX }); + } - editIndex: function (options) { - FauxtonAPI.dispatch({ - type: ActionTypes.EDIT_INDEX, - options: options - }); - }, + function fetchDesignDocsBeforeEdit (options) { + options.designDocs.fetch({reset: true}).then(function () { + this.editIndex(options); + }.bind(this)); + } - clearIndex: function () { - FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX }); - }, + function saveView (viewInfo) { + var designDoc = viewInfo.designDoc; + designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce); - fetchDesignDocsBeforeEdit: function (options) { - options.designDocs.fetch({reset: true}).then(function () { - this.editIndex(options); - }.bind(this)); - }, + FauxtonAPI.addNotification({ + msg: 'Saving View...', + type: 'info', + clear: true + }); - saveView: function (viewInfo) { - var designDoc = viewInfo.designDoc; - designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce); + // if the view name just changed and it's in the SAME design doc, remove the old one before saving the doc + if (viewInfo.originalDesignDocName === viewInfo.designDocId && viewInfo.originalViewName !== viewInfo.viewName) { + designDoc.removeDdocView(viewInfo.originalViewName); + } + designDoc.save().then(function () { FauxtonAPI.addNotification({ - msg: "Saving View...", - type: "info", + msg: 'View Saved.', + type: 'success', clear: true }); - designDoc.save().then(function () { - FauxtonAPI.addNotification({ - msg: "View Saved.", - type: "success", - clear: true + // if the user just saved the view to a different design doc, remove the view from the old design doc and + // delete if it's empty + if (viewInfo.originalDesignDocName !== viewInfo.designDocId) { + var oldDesignDoc = findDesignDoc(viewInfo.designDocs, viewInfo.originalDesignDocName); + safeDeleteIndex(oldDesignDoc, viewInfo.designDocs, 'views', viewInfo.originalViewName, { + onSuccess: function () { + SidebarActions.updateDesignDocs(viewInfo.designDocs); + } }); + } - if (_.any([viewInfo.designDocChanged, viewInfo.hasViewNameChanged, viewInfo.newDesignDoc, viewInfo.newView])) { - FauxtonAPI.dispatch({ type: ActionTypes.VIEW_SAVED }); - var fragment = FauxtonAPI.urls('view', 'showNewlySavedView', viewInfo.database.safeID(), designDoc.safeID(), app.utils.safeURLName(viewInfo.viewName)); - FauxtonAPI.navigate(fragment, { trigger: true }); - } else { - this.updateDesignDoc(designDoc); - } - - // this can be removed after the Views are on their own page - IndexResultsActions.reloadResultsList(); - }.bind(this)); - }, + if (viewInfo.designDocId === 'new-doc') { + addDesignDoc(designDoc); + } - updateDesignDoc: function (designDoc) { - FauxtonAPI.dispatch({ - type: ActionTypes.VIEW_UPDATE_DESIGN_DOC, - designDoc: designDoc.toJSON() - }); - }, + FauxtonAPI.dispatch({ type: ActionTypes.VIEW_SAVED }); + var fragment = FauxtonAPI.urls('view', 'showView', viewInfo.database.safeID(), designDoc.safeID(), app.utils.safeURLName(viewInfo.viewName)); + FauxtonAPI.navigate(fragment, { trigger: true }); + }); + } - deleteView: function (options) { - var viewName = options.viewName; - var database = options.database; - var designDoc = ActionHelpers.findDesignDoc(options.designDocs, options.designDocId); - var promise; + function addDesignDoc (designDoc) { + FauxtonAPI.dispatch({ + type: ActionTypes.VIEW_ADD_DESIGN_DOC, + designDoc: designDoc.toJSON() + }); + } - designDoc.removeDdocView(viewName); + function deleteView (options) { - if (designDoc.hasViews()) { - promise = designDoc.save(); - } else { - promise = designDoc.destroy(); - } + function onSuccess () { - promise.then(function () { - var url = FauxtonAPI.urls('allDocs', 'app', database.safeID(), '?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT); + // if the user was on the index that was just deleted, redirect them back to all docs + if (options.isOnIndex) { + var url = FauxtonAPI.urls('allDocs', 'app', options.database.safeID(), '?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT); FauxtonAPI.navigate(url); - FauxtonAPI.triggerRouteEvent('reloadDesignDocs'); - }); - }, + } + + SidebarActions.updateDesignDocs(options.designDocs); - updateMapCode: function (code) { - FauxtonAPI.dispatch({ - type: ActionTypes.VIEW_UPDATE_MAP_CODE, - code: code + FauxtonAPI.addNotification({ + msg: 'The <code>' + _.escape(options.indexName) + '</code> view has been deleted.', + type: 'info', + escape: false, + clear: true }); - }, + FauxtonAPI.dispatch({ type: SidebarActionTypes.SIDEBAR_HIDE_DELETE_INDEX_MODAL }); + } - updateReduceCode: function (code) { - FauxtonAPI.dispatch({ - type: ActionTypes.VIEW_UPDATE_REDUCE_CODE, - code: code + safeDeleteIndex(options.designDoc, options.designDocs, 'views', options.indexName, { onSuccess: onSuccess }); + } + + function cloneView (params) { + var targetDesignDoc = getDesignDoc(params.designDocs, params.targetDesignDocName, params.newDesignDocName, params.database); + var indexes = targetDesignDoc.get('views'); + if (indexes && _.has(indexes, params.newIndexName)) { + FauxtonAPI.addNotification({ + msg: 'That index name is already used in this design doc. Please enter a new name.', + type: 'error', + clear: true }); - }, + return; + } + if (!indexes) { + indexes = {}; + } + var sourceDesignDoc = findDesignDoc(params.designDocs, '_design/' + params.sourceDesignDocName); + var sourceDesignDocJSON = sourceDesignDoc.toJSON(); - selectDesignDoc: function (designDoc) { - FauxtonAPI.dispatch({ - type: ActionTypes.DESIGN_DOC_CHANGE, - options: { - value: designDoc - } + // this sets whatever content is in the source index into the target design doc under the new index name + indexes[params.newIndexName] = sourceDesignDocJSON.views[params.sourceIndexName]; + targetDesignDoc.set({ views: indexes }); + + targetDesignDoc.save().then(function () { + params.onComplete(); + FauxtonAPI.addNotification({ + msg: 'The index has been cloned.', + type: 'success', + clear: true }); + SidebarActions.updateDesignDocs(params.designDocs); }, - - updateNewDesignDocName: function (designDocName) { - FauxtonAPI.dispatch({ - type: ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED, - options: { - value: designDocName - } + function (xhr) { + params.onComplete(); + var responseText = JSON.parse(xhr.responseText).reason; + FauxtonAPI.addNotification({ + msg: 'Clone failed: ' + responseText, + type: 'error', + clear: true }); + }); + } + + function gotoEditViewPage (databaseName, designDocName, indexName) { + FauxtonAPI.navigate('#' + FauxtonAPI.urls('view', 'edit', databaseName, designDocName, indexName)); + } + + function updateMapCode (code) { + FauxtonAPI.dispatch({ + type: ActionTypes.VIEW_UPDATE_MAP_CODE, + code: code + }); + } + + function updateReduceCode (code) { + FauxtonAPI.dispatch({ + type: ActionTypes.VIEW_UPDATE_REDUCE_CODE, + code: code + }); + } + + function selectDesignDoc (designDoc) { + FauxtonAPI.dispatch({ + type: ActionTypes.DESIGN_DOC_CHANGE, + options: { + value: designDoc + } + }); + } + + function updateNewDesignDocName (designDocName) { + FauxtonAPI.dispatch({ + type: ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED, + options: { + value: designDocName + } + }); + } + + // safely deletes an index of any type. It only deletes the actual design doc if there are no + // other indexes of any type left in the doc + function safeDeleteIndex (designDoc, designDocs, indexPropName, indexName, options) { + var opts = _.extend({ + onSuccess: function () { }, + onError: function (xhr) { + var responseText = JSON.parse(xhr.responseText).reason; + FauxtonAPI.addNotification({ + msg: 'Delete failed: ' + responseText, + type: 'error', + clear: true + }); + } + }, options); + + var indexes = designDoc.get(indexPropName) || {}; + delete indexes[indexName]; + var newIndexes = {}; + newIndexes[indexPropName] = indexes; + designDoc.set(newIndexes); + + // we either save the design doc with the now-removed index, or we remove it altogether if there are no indexes + // of any type left in the design doc + var indexTypePropNames = FauxtonAPI.getIndexTypePropNames(); + var hasRemainingIndex = _.some(indexTypePropNames, function (propName) { + return designDoc.get(propName) && _.keys(designDoc.get(propName)).length > 0; + }); + + var promise; + var deleteDesignDoc = false; + if (hasRemainingIndex) { + promise = designDoc.save(); + } else { + promise = designDoc.destroy(); + deleteDesignDoc = true; } + promise.then(function () { + if (deleteDesignDoc) { + console.log("deleting?"); --- End diff -- Oops! Yup.
--- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastruct...@apache.org or file a JIRA ticket with INFRA. ---