UNPKG

cheetah-framework

Version:

Cheetah Framework JS used in all our applications

401 lines (336 loc) 9.68 kB
/* global route _ param axios Message cheetahApp */ import { Model, TranslatedFieldValue } from './Model' import CheetahStore from '@cheetah/store/CheetahStore' import Uri from '@cheetah/utils/Uri' import { Router } from '@cheetah/utils/Router' import config from '@cheetah/config' class LaravelModel extends Model { constructor (data) { super(data) this.notification = true } beforeStore (payload) { return payload } store (context = null) { return LaravelBackendPromise( 'post', addContextToUrl(route(this.constructor.routeName + '.store'), context), this.beforeStore(this.serializeData()) ).then(storeResponseHandler.bind(this)) } beforeUpdate (payload) { return payload } update (customPayload, context = null) { const id = _.get(customPayload, this.constructor.idKey, this[this.constructor.idKey]) return LaravelBackendPromise( 'put', addContextToUrl(route(this.constructor.routeName + '.update', { id }), context), this.beforeUpdate(customPayload || this.serializeData()) ).then(updateResponseHandler.bind(this)) } updateOnly (fields, context = null) { return this.update(_.pick(this, fields), context) } updateExcept (fields, context = null) { return this.update(_.omit(this, fields), context) } destroy () { const id = this[this.constructor.idKey] return LaravelBackendPromise( 'delete', route(this.constructor.routeName + '.destroy', { id }) ).then(destroyResponseHandler.bind(this)) } disableNotification () { this.notification = false return this } static get notification () { return true } static get (id, uniqueId = null, context = null, payload = {}) { return LaravelBackendPromise( 'get', addContextToUrl(route(this.routeName + '.show', { id }), context), payload, uniqueId ) } /** * Example of possible params: * { * page: 1, * per_page: 10, * scope: ['published'] * } * * @param {array} criteria * @param {object} params - parameters that will be added to query * @param {string} uniqueId * @returns {Promise} */ static all (criteria = [], params = {}, uniqueId = null) { const url = route(this.routeName + '.index') criteria = criteria.concat(this.baseCriteria) if (this.baseScopes instanceof Array) { params.scopes = _.isArray(params.scopes) ? params.scopes.concat(this.baseScopes) : this.baseScopes } if (!_.isEmpty(criteria)) { params.criteria = config.handlers.remoteCriteriaHandler(criteria) } /* * Use a `POST` request and simulate it as a `GET` using the `_method` parameter * to send structured data without worrying about exceeding the maximum URL length. * This approach also ensures that the payload retains any empty arrays, * which might be necessary for certain criteria. */ return LaravelBackendPromise( 'POST', url, { ...params, _method: 'GET' }, uniqueId ) } static structure () { if (!this.structureCache) { this.structureCache = LaravelBackendPromise( 'options', route(this.routeName + '.define'), {} ).catch(error => { this.structureCache = null throw error }) } return this.structureCache } static bulkUpdate (bulkPayload, disableNotification = false) { return LaravelBackendPromise( 'put', route(this.routeName + '.bulk_update'), bulkPayload ).then(response => { return updateResponseHandler.call(this, response, disableNotification) }) } static bulkDestroy (bulkPayload) { return LaravelBackendPromise( 'delete', route(this.routeName + '.bulk_destroy'), bulkPayload ).then(destroyResponseHandler.bind(this)) } static get resourceName () { throw new Error('Must define a resourceName in ' + this.name + ' model.') } static get routeName () { return Router.routeNamePrefix + this.resourceName } static get idKey () { return 'id' } static get filterableProps () { return [] } get isPersisted () { return !!this[this.constructor.idKey] } get baseCriteria () { return this.constructor.baseCriteria } get baseScopes () { return this.constructor.baseScopes } static get baseCriteria () { return [] } static get baseScopes () { return null } get routes () { return { index: { name: `${this.constructor.resourceName}.index` }, create: { name: `${this.constructor.resourceName}.create` }, store: { name: `${this.constructor.resourceName}.store` }, show: { name: `${this.constructor.resourceName}.show`, params: { id: this[this.constructor.idKey] } }, edit: { name: `${this.constructor.resourceName}.edit`, params: { id: this[this.constructor.idKey] } }, update: { name: `${this.constructor.resourceName}.update`, params: { id: this[this.constructor.idKey] } }, destroy: { name: `${this.constructor.resourceName}.destroy`, params: { id: this[this.constructor.idKey] } } } } static get routes () { const resourceName = this.resourceName return { index: { name: `${resourceName}.index` }, create: { name: `${resourceName}.create` }, store: { name: `${resourceName}.store` }, show (id) { return { name: `${resourceName}.show`, params: { id } } }, edit (id) { return { name: `${resourceName}.edit`, params: { id } } } } } } LaravelModel.timestamps = false window.uniqueRequests = {} /* global uniqueRequests */ function LaravelBackendPromise (method, url, payload, uniqueId, axiosOptions = {}) { if (uniqueId) { if (uniqueRequests[uniqueId]) { uniqueRequests[uniqueId]() delete uniqueRequests[uniqueId] } } const CancelToken = axios.CancelToken return axios({ ...axiosOptions, url: typeof url?.toString === 'function' ? url.toString() : url, method: method.toLowerCase(), ...(_.includes(['post', 'put', 'patch', 'delete'], method.toLowerCase()) ? { data: payload } : { params: payload }), cancelToken: new CancelToken(c => { if (uniqueId) { uniqueRequests[uniqueId] = c } }) }).then(response => { if (uniqueId && uniqueRequests[uniqueId]) { delete uniqueRequests[uniqueId] } return response }) } function LaravelDownloadBackendPromise (method, url, payload, uniqueId) { const options = { responseType: 'blob' } return LaravelBackendPromise(method, url, payload, uniqueId, options).then(response => { const url = window.URL.createObjectURL(new Blob([response.data])) const link = document.createElement('a') const dispositionsString = _.get(response.headers, 'content-disposition', '') const dispositions = _.reduce(dispositionsString.split(/ *; */), (accumulator, keyValueString) => { const [key, value] = keyValueString.split('=') return _.set(accumulator, key, value) }, {}) link.href = url link.setAttribute('download', _.get(dispositions, 'filename', 'file')) document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) return response }) } function addContextToUrl (url, context) { if (context) { return Uri.addParams(url, { _context: context }) } return url } function destroyResponseHandler (response) { const isBulk = typeof this.constructor.resourceName === 'undefined' if (isBulk) { CheetahStore.bulkDelete(this.resourceName, response.data) } else { CheetahStore.delete(this.constructor.resourceName, response.data) } if (this.notification) { Message.success({ message: cheetahApp.$t('delete_success'), position: 'bottom-right', duration: 1500 }) } if (_.get(response, 'statusCode') === 202) { Message.warning(response.status) } return response } function updateResponseHandler (response, disableNotification = false) { const isBulk = typeof this.constructor.resourceName === 'undefined' if (isBulk) { CheetahStore.bulkUpdate(this.resourceName, response.data) } else { CheetahStore.update(this.constructor.resourceName, response.data) } if (this.notification && disableNotification === false) { Message.success({ message: cheetahApp.$t('update_success'), position: 'bottom-right', duration: 1500 }) } if (_.get(response, 'statusCode') === 202) { Message.warning(response.status) } return response } function storeResponseHandler (response) { CheetahStore.store(this.constructor.resourceName, response.data) if (this.notification) { Message.success({ message: cheetahApp.$t('create_success'), position: 'bottom-right', duration: 1500 }) } if (_.get(response, 'statusCode') === 202) { Message.warning(response.status) } return response } function resolveAction (routeName, param) { const url = route(Router.routeNamePrefix + routeName, param) return { method: _.first(url.urlBuilder.route.methods), url: url.toString() } } export default LaravelModel export { LaravelModel, resolveAction, TranslatedFieldValue, LaravelBackendPromise, LaravelDownloadBackendPromise, Model, destroyResponseHandler, updateResponseHandler, storeResponseHandler }