vue-rest-client
Version:
A VueJS RESTful client component to easily integrate apps with APIs
587 lines (473 loc) • 23.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _formHelper = _interopRequireDefault(require("./form-helper"));
var _crudI18n = _interopRequireDefault(require("./i18n/crud.i18n.en"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Controller = /*#__PURE__*/function () {
function Controller(vm, modelService, options) {
_classCallCheck(this, Controller);
_initialiseProps.call(this);
this.vm = vm;
this.modelService = modelService; // If options is not passed, initialize it
this.options = options || {};
this.run();
}
/**
* Set the crud for he given view model, service and options
* @param {*} vm
* @param {*} modelService
* @param {*} options
*/
_createClass(Controller, [{
key: "handleError",
value:
/**
* Handle the error response
*
* @param {*} response
* @param {*} actionMsg
* @param {*} defaultCrudMsg
* @memberof CRUD
*/
function handleError(response, actionMsg, defaultCrudMsg) {
// There is no response message in this case, so we define the message considering the options custom message, the options status msg or the default one
var treatment = this.getErrorTreatment(response, actionMsg, defaultCrudMsg);
if (treatment !== false) {
if (typeof treatment !== 'function') {
this.showErrorMessage(response, treatment);
} else {
treatment(response, actionMsg, defaultCrudMsg);
}
}
this.runAfterCallBack('afterError', response);
}
/**
* Build the error message
*
* @param {*} errorResponse
* @param {*} crudErrorMessage
* @param {*} eventMsg
* @returns {String|false|function} (if false, means no error message should be displayed)
* @memberof CRUD
*/
}, {
key: "getErrorTreatment",
value: function getErrorTreatment(errorResponse, eventMsg, crudErrorMessage) {
// We try to get the error message to the returned http status code
// If available, use it
if (errorResponse.status && this.options[errorResponse.status] !== undefined) {
return this.options[errorResponse.status];
} // Use the event error message
if (eventMsg !== null && eventMsg !== undefined) {
return eventMsg;
} // If none works, use the default crudErrorMessage
return crudErrorMessage.replace(':resource', this.vm.resource.$getName());
}
/**
* Run the before proceed optional callback function
* id the function returns false, stop the flow
*
* @param {*} callbackFunc
* @param {*} reject promise reject pointer
* @returns boolean
*/
}, {
key: "runProceedCallBack",
value: function runProceedCallBack(callbackFunc, reject, data) {
var proceed = true;
if (this.vm.hasOwnProperty(callbackFunc)) {
proceed = this.vm[callbackFunc](data);
}
if (proceed === false) {
var error = "proceed stopped on ".concat(callbackFunc, " function");
console.log(error);
var errorMsg = this.translateText('operationAbortedMsg');
this.vm.showInfo(this.capitalize(errorMsg), {
mode: 'multi-line'
}); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(error);
}
return proceed === true || proceed === null || proceed === undefined;
}
/**
* Run the after optional callback function
* If the function returns false, stop the flow
* @param {*} callbackFunc
* @param {*} data data to be passed
*/
}, {
key: "runAfterCallBack",
value: function runAfterCallBack(callbackFunc, data) {
if (this.vm.hasOwnProperty(callbackFunc)) {
this.vm[callbackFunc](data);
}
}
/**
* Checks whenever the default form $rf exists and if so, if it is valid
* If invalid, reject the promise and show the invalid form error message
*
* @param {Function} reject
* @returns boolean
*/
}, {
key: "formIsValid",
value: function formIsValid(reject) {
var validForm = true; // init as valid
var formRef = this.options.formRef || 'vrcForm'; // get the form ref (custom or default one)
var form = this.vm.$refs[formRef] || null; // get the form object using the formRef
var formHelper = new _formHelper["default"](form, this.vm, this.options);
validForm = formHelper.validate();
if (!validForm) {
var errorMsg = this.translateText('invalidFormMsg'); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(errorMsg);
} // Validate the form
return validForm;
}
/**
* Capitalize a string
*
* @param {*} string
* @returns String
*/
}, {
key: "capitalize",
value: function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
/**
* Show the response error message or the default error message passed
* @param {*} errorResponse
* @param {*} defaultErrorMessage
*/
}, {
key: "showErrorMessage",
value: function showErrorMessage(errorResponse, frontEndErrorMessage) {
var showError = true; // If the message is set as `false` so we shall not display any message
if (frontEndErrorMessage === false) {
showError = false;
}
if (this.vm.hasOwnProperty('beforeShowError')) {
errorResponse.showError = showError; // add the current showError status to the object passed to the call back
showError = this.vm['beforeShowError'](errorResponse);
}
if (showError === true) {
// As we don't want to show a raw error to the user, if the status code is == 500 (internal server error)
// or there is no error response we show a friendly error message
if (errorResponse === undefined || errorResponse.status === 500 || !errorResponse.data || !errorResponse.data.message) {
// if it this and 500 case, we show only a friendly message, and log the error and log the error
// as we are not sure about the error message size, use multi-line model for the toaster
this.vm.showError(this.capitalize(frontEndErrorMessage), {
mode: 'multi-line'
});
console.log(errorResponse);
} else {
// Define the error message to be used
// either the front end message or the server one (if available)
var errorMsg = frontEndErrorMessage;
if (!this.options.skipServerMessages) {
errorMsg = errorResponse.message || errorResponse.data.message;
} // We show the response error message
// As we are not sure about the error message size, use multi-line model for the toaster
this.vm.showError(this.capitalize(errorMsg), {
mode: 'multi-line'
});
}
}
}
}], [{
key: "set",
value: function set(vm, modelService, options) {
return new Controller(vm, modelService, options);
}
/**
* The initial function is executed when the class is built
* if the option queryOnStartup is true, it will also load the resources automatically.
*/
}]);
return Controller;
}(); // Export the Controller
var _initialiseProps = function _initialiseProps() {
var _this = this;
this.run = function () {
_this.vm.resource = _this.modelService.newModelInstance(); // Add the CRUD methods to the vue compnent (vm) passed via constructor
_this.vm.index = _this.index;
_this.vm.get = _this.get;
_this.vm.save = _this.save;
_this.vm.update = _this.update;
_this.vm.destroy = _this.destroy;
_this.vm.confirmAndDestroy = _this.confirmAndDestroy; // Add the toaster methods to the vue compnent (vm) passed via constructor (if not available, use fallback methods)
_this.vm.showSuccess = _this.options.showSuccess || _this.vm.showSuccess || _this.fallBackShowSuccess;
_this.vm.showInfo = _this.options.showInfo || _this.vm.showInfo || _this.fallBackShowInfo;
_this.vm.showError = _this.options.showError || _this.vm.showError || _this.fallBackShowError;
_this.vm.confirmDialog = _this.options.confirmDialog || _this.vm.confirmDialog || _this.fallBackConfirmDialog; // If quey on start up is enabled,
// run the initial query
if (_this.options.queryOnStartup) {
_this.vm.index().then(function (resources) {
_this.vm.resources = resources;
_this.vm.crudReady = true;
});
}
};
this.translateText = function (key) {
var transaltion;
if (_this.options[key]) {
transaltion = _this.options[key];
} // If a custom translate function was passed via options, use it
if (!transaltion && _this.options.translateFn && typeof _this.options.translateFn == "function") {
transaltion = _this.options.translateFn(key);
} // If vue-i18n is present in the app
// then the $t function must be defined.
// We check and try to use it.
if (!transaltion && _this.vm.$t) {
var translationPath = "crud.".concat(key);
var trans = _this.vm.$t(translationPath); // Even if $t, the key must not be
// present in the expected translation
// path. So we make sure that the result
// is not the same of the path
if (trans !== translationPath) {
transaltion = trans;
}
} // If none of the tries above work
// then an error is logged in the console and the
// fallback english ext for the given key is used.
if (!transaltion) {
console.error("The translation for the string ".concat(key, " was not passed via options, nor is present in 'crud.").concat(key, "' to be used via $t 'vue-i18n', so a fallback English string was used."));
transaltion = _crudI18n["default"].crud[key] || key;
}
return transaltion;
};
this.fallBackShowSuccess = function (msg, options) {
console.log(msg, options);
};
this.fallBackShowInfo = function (msg, options) {
console.info(msg, options);
};
this.fallBackShowError = function (msg, options) {
console.error(msg, options);
};
this.fallBackConfirmDialog = function (msg, options) {
var error = 'Confirm dialog function was not properly passed via parameters. Check the console to see more info.';
console.error(error, msg, options);
if (_this.options.skipDestroyConfirmation) {
// As the confirm dialog function was not defined, the action has been cancelled
return new Promise(function (resolve, reject) {
resolve(true);
});
} else {
// As the confirm dialog function was not defined, the action has been cancelled
return new Promise(function (resolve, reject) {
reject(error);
});
}
};
this.index = function (filters) {
var context = _this;
return new Promise(function (resolve, reject) {
var proceed = context.runProceedCallBack('beforeIndex', reject);
if (proceed) {
// in the index action we do not use the resource model instance, but each
// resource returned will be transformed into an active record instance bt the Model
// you can skip this by defining the `raw` attribute equal true in the model service
// @see @/core/model-service and @/core/model to read more
context.modelService.query(filters).then(function (resources) {
if (resources.raw && resources.data) {
resources = resources.data;
} // Each returned resource, will be, by default an Model (@core/model) instance, that supports instance methods, like $save, $destroy etc
context.vm.resources = resources; // runs the optional after callback (if the function is defined in the Vue component) an pass the data
context.runAfterCallBack('afterIndex', _this.vm.resources); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
resolve(resources);
}, function (errorResponse) {
// Handle the error response
context.handleError(errorResponse, context.translateText('failWhileTryingToGetTheResourceMsg')); // if it is being run because of a queryOnStartup flag, so we need to tell
// the client that the crud request is done
if (context.options.queryOnStartup) {
context.vm.crudReady = true;
}
});
}
});
};
this.get = function (pkValue) {
var context = _this;
return new Promise(function (resolve, reject) {
var proceed = context.runProceedCallBack('beforeGet', reject);
if (proceed) {
context.modelService.get(pkValue).then(function (resource) {
// The returned resource, will be, by default an Model (@core/model) instance, that supports instance methods, like $save, $destroy etc
context.vm.resource = resource; // runs the optional after callback (if the function is defined in the Vue component) an pass the data
context.runAfterCallBack('afterGet', context.vm.resource); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// context is not a problem!
resolve(context.vm.resource);
}, function (errorResponse) {
// Handle the error response
context.handleError(errorResponse, context.translateText('failWhileTryingToGetTheResourceMsg')); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(errorResponse);
});
}
});
};
this.save = function () {
var context = _this; // We return a promise and resolve/reject it because optionally, the developer
// can have its own save method, and after it is finished do something special
return new Promise(function (resolve, reject) {
var validForm = context.formIsValid(reject);
var proceed = context.runProceedCallBack('beforeSave', reject);
if (validForm && proceed) {
var postResource = context.vm.resource.$strip(context.vm.resource);
if (Object.keys(postResource).length === 0) {
var msg = context.translateText('resourceEmptyMsg').replace(':resource', context.vm.resource.$getName());
context.vm.showError(context.capitalize(msg), {
mode: 'multi-line'
});
reject(msg);
} else {
context.vm.resource.$save().then(function (data) {
// the return is an object containing a resource/Model instance and a (optional) message property
context.vm.resource = data.resource; // Define the save confirmation message to be displayed
var msg = data.message || context.translateText('resourceSavedMsg').replace(':resource', context.vm.resource.$getName()); // Capitalize and use multiline to be sure that the message won be truncated (we don't know the how big the messages from server can be)
context.vm.showSuccess(context.capitalize(msg), {
mode: 'multi-line'
}); // Reload the data listed
if (!context.options.skipAutoIndexAfterSave && !context.options.skipAutoIndexAfterAllEvents) {
context.vm.index();
} // runs the optional after callback (if the function is defined in the Vue component) an pass the data
context.runAfterCallBack('afterSave', context.vm.resource); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
resolve(context.vm.resource);
}, function (errorResponse) {
// Handle the error response
context.handleError(errorResponse, context.translateText('failWhileTryingToSaveResourceMsg')); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(errorResponse);
});
}
}
});
};
this.update = function () {
var context = _this;
return new Promise(function (resolve, reject) {
var validForm = context.formIsValid(reject);
var proceed = context.runProceedCallBack('beforeUpdate', reject);
if (validForm && proceed) {
context.vm.resource.$update().then(function (data) {
// the return is an object containing a resource/Model instance and a (optional) message property
context.vm.resource = data.resource; // Define the save confirmation message to be displayed
var msg = data.message || context.translateText('resourceUpdatedMsg').replace(':resource', context.vm.resource.$getName()); // Capitalize and use multiline to be sure that the message won be truncated (we don't know the how big the messages from server can be)
context.vm.showSuccess(context.capitalize(msg), {
mode: 'multi-line'
}); // Reload the data listed
if (!context.options.skipAutoIndexAfterUpdate && !context.options.skipAutoIndexAfterAllEvents) {
context.vm.index();
} // runs the optional after callback (if the function is defined in the Vue component) an pass the data
context.runAfterCallBack('afterUpdate', context.vm.resource); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
resolve(context.vm.resource);
}, function (errorResponse) {
// Handle the error response
context.handleError(errorResponse, context.translateText('failWhileTryingToUpdateResourceMsg')); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(errorResponse);
});
}
});
};
this.confirmAndDestroy = function (resource) {
var context = _this;
return new Promise(function (resolve, reject) {
// Define the conformation modal title to be displayed before destroying
var confirmTitle = context.translateText('removalConfirmTitle'); // Define the conformation modal text to be displayed before destroying
var confirmMessage = context.translateText('doYouReallyWantToRemoveMsg').replace(':resource', context.vm.resource.$getName()); // Open the confirmation modal and wait for the response in a promise
context.vm.confirmDialog(confirmTitle, confirmMessage).then(function () {
// if the user confirms the destroy, run it
context.vm.destroy(resource).then( // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
resolve, reject);
}, function (error) {
// If the user has clicked `no` in the dialog, abort the destroy and show an aborted message
// Define the error message to be displayed
var msg = context.translateText('destroyAbortedMsg'); // show the abort message as an info
context.vm.showInfo(msg); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(error);
});
});
};
this.destroy = function (resource) {
var context = _this;
return new Promise(function (resolve, reject) {
var proceed = context.runProceedCallBack('beforeDestroy', reject);
if (proceed) {
resource.$destroy().then(function (data) {
// Define the save confirmation message to be displayed
var msg = data.message || context.translateText('resourceDestroyed').replace(':resource', context.vm.resource.$getName()); // Capitalize and use multiline to be sure that the message won be truncated (we don't know the how big the messages from server can be)
context.vm.showSuccess(context.capitalize(msg), {
mode: 'multi-line'
}); // Reload the data listed
if (!context.options.skipAutoIndexAfterDestroy && !context.options.skipAutoIndexAfterAllEvents) {
context.vm.index();
} // runs the optional after callback (if the function is defined in the Vue component) an pass the data
context.runAfterCallBack('afterDestroy', resource); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
resolve();
}, function (errorResponse) {
// Handle the error response
context.handleError(errorResponse, context.translateText('failWhileTryingToDestroyResourceMsg')); // In the default CRUD usage, it is not necessary to
// listen to the promise result
// if the promise is not being listened
// it can raise an error when rejected/resolved.
// This is not a problem!
reject(errorResponse);
});
}
});
};
};
var _default = Controller;
exports["default"] = _default;