blob: 22b9a9b81e2c51bc39c41e5030ecda555e6272be [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import app from "../../../app";
import FauxtonAPI from "../../../core/api";
import Documents from "../resources";
import ActionTypes from "./actiontypes";
import SidebarActions from "../sidebar/actions";
function selectReduceChanged (reduceOption) {
FauxtonAPI.dispatch({
type: ActionTypes.SELECT_REDUCE_CHANGE,
reduceSelectedOption: reduceOption
});
}
function changeViewName (name) {
FauxtonAPI.dispatch({
type: ActionTypes.VIEW_NAME_CHANGE,
name: name
});
}
function editIndex (options) {
FauxtonAPI.dispatch({
type: ActionTypes.EDIT_INDEX,
options: options
});
}
function clearIndex () {
FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX });
}
function fetchDesignDocsBeforeEdit (options) {
options.designDocs.fetch({reset: true}).then(() => {
this.editIndex(options);
}, xhr => {
let errorMsg = 'Error';
if (xhr.responseJSON && xhr.responseJSON.error === 'not_found') {
const databaseName = options.designDocs.database.safeID();
errorMsg = `The ${databaseName} database does not exist`;
FauxtonAPI.navigate('/', {trigger: true});
}
FauxtonAPI.addNotification({
msg: errorMsg,
type: "error",
clear: true
});
});
}
function shouldRemoveDdocView(viewInfo) {
return !viewInfo.newView &&
viewInfo.originalDesignDocName === viewInfo.designDocId &&
viewInfo.originalViewName !== viewInfo.viewName;
}
function saveView (viewInfo) {
var designDoc = viewInfo.designDoc;
designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce);
FauxtonAPI.addNotification({
msg: 'Saving View...',
type: 'info',
clear: true
});
// if the view name just changed and it's in the SAME design doc, remove the old one before saving the doc
if (shouldRemoveDdocView(viewInfo)) {
designDoc.removeDdocView(viewInfo.originalViewName);
}
designDoc.save().then(function () {
FauxtonAPI.addNotification({
msg: 'View Saved.',
type: 'success',
clear: true
});
// if the user just saved an existing view to a different design doc, remove the view
// from the old design doc and delete if it's empty
if (!viewInfo.newView && viewInfo.originalDesignDocName !== viewInfo.designDocId) {
var oldDesignDoc = findDesignDoc(viewInfo.designDocs, viewInfo.originalDesignDocName);
safeDeleteIndex(oldDesignDoc, viewInfo.designDocs, 'views', viewInfo.originalViewName, {
onSuccess: function () {
SidebarActions.dispatchUpdateDesignDocs(viewInfo.designDocs);
}
});
}
if (viewInfo.designDocId === 'new-doc') {
addDesignDoc(designDoc);
}
SidebarActions.dispatchUpdateDesignDocs(viewInfo.designDocs);
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 });
}, (xhr) => {
FauxtonAPI.addNotification({
msg: 'Save failed. ' + (xhr.responseJSON ? `Reason: ${xhr.responseJSON.reason}` : ''),
type: 'error',
clear: true
});
});
}
function addDesignDoc (designDoc) {
FauxtonAPI.dispatch({
type: ActionTypes.VIEW_ADD_DESIGN_DOC,
designDoc: designDoc.toJSON()
});
}
function deleteView (options) {
function onSuccess () {
// 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);
}
SidebarActions.dispatchUpdateDesignDocs(options.designDocs);
FauxtonAPI.addNotification({
msg: 'The <code>' + _.escape(options.indexName) + '</code> view has been deleted.',
type: 'info',
escape: false,
clear: true
});
SidebarActions.dispatchHideDeleteIndexModal();
}
return 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();
// 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.dispatchUpdateDesignDocs(params.designDocs);
},
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', encodeURIComponent(databaseName),
encodeURIComponent(designDocName), encodeURIComponent(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;
}
return promise.then(function () {
if (deleteDesignDoc) {
designDocs.remove(designDoc.id);
}
opts.onSuccess();
}, opts.onError);
}
// ---- helpers ----
function findDesignDoc (designDocs, designDocName) {
return designDocs.find(function (doc) {
return doc.id === designDocName;
}).dDocModel();
}
function getDesignDoc (designDocs, targetDesignDocName, newDesignDocName, database) {
if (targetDesignDocName === 'new-doc') {
var doc = {
"_id": "_design/" + newDesignDocName,
"views": {},
"language": "javascript"
};
return new Documents.Doc(doc, { database: database });
}
var foundDoc = designDocs.find(function (ddoc) {
return ddoc.id === targetDesignDocName;
});
return (!foundDoc) ? null : foundDoc.dDocModel();
}
export default {
helpers: {
findDesignDoc: findDesignDoc,
getDesignDoc: getDesignDoc
},
safeDeleteIndex: safeDeleteIndex,
selectReduceChanged: selectReduceChanged,
changeViewName: changeViewName,
editIndex: editIndex,
clearIndex: clearIndex,
fetchDesignDocsBeforeEdit: fetchDesignDocsBeforeEdit,
shouldRemoveDdocView: shouldRemoveDdocView,
saveView: saveView,
addDesignDoc: addDesignDoc,
deleteView: deleteView,
cloneView: cloneView,
gotoEditViewPage: gotoEditViewPage,
updateMapCode: updateMapCode,
updateReduceCode: updateReduceCode,
selectDesignDoc: selectDesignDoc,
updateNewDesignDocName: updateNewDesignDocName
};