UNPKG

@knowmax/genericlist-core

Version:

Knowmax Generic list with basic CRUD support without any user interface implementation.

343 lines (342 loc) 13.4 kB
import { action, computed, observable, makeObservable } from 'mobx'; import { GenericList } from '.'; export class GenericCudList extends GenericList { constructor(cudConfiguration) { super(cudConfiguration); Object.defineProperty(this, "cudConfiguration", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set in case of Create Update Delete error. Prefer using specialized error fields per mode. */ Object.defineProperty(this, "cudError", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Might be set in case custom validation method returned error message. */ Object.defineProperty(this, "validationError", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set to editable item when in create or update mode. */ Object.defineProperty(this, "editableItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set to original editable item when starting update mode. */ Object.defineProperty(this, "editableItemUnmodified", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set to item when in delete mode. */ Object.defineProperty(this, "deleteItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set with data of just deleted item. */ Object.defineProperty(this, "deletedItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set with data of newly created item. */ Object.defineProperty(this, "createdItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set to item when in restore mode. */ Object.defineProperty(this, "restoreItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Set with data of just restored item. */ Object.defineProperty(this, "restoredItem", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** Start create mode for item. */ Object.defineProperty(this, "create", { enumerable: true, configurable: true, writable: true, value: (template) => { this.deleteItem = undefined; this.restoreItem = undefined; this.editableItem = template ?? this.cudConfiguration.defaultItem(); this.editableItemUnmodified = undefined; this.cudError = undefined; this.validationError = undefined; } }); /** Cancel any mode we are currently in (create, update, delete, restore). Using lambda syntax here so we can directly hook this method to onClick/onChange like events of user interface. */ Object.defineProperty(this, "cancel", { enumerable: true, configurable: true, writable: true, value: () => { this.editableItem = undefined; this.editableItemUnmodified = undefined; this.deleteItem = undefined; this.restoreItem = undefined; this.cudError = undefined; this.validationError = undefined; } }); makeObservable(this, { cudError: observable, setCudError: action, validationError: observable, setValidationError: action, hasCudOrValidationError: computed, createError: computed, updateError: computed, deleteError: computed, restoreError: computed, editableItem: observable, setEditableItem: action, editableItemUnmodified: observable, setEditableItemUnmodified: action, deleteItem: observable, setDeleteItem: action, deletedItem: observable, setDeletedItem: action, createdItem: observable, setCreatedItem: action, restoreItem: observable, setRestoreItem: action, restoredItem: observable, setRestoredItem: action, create: action, update: action, delete: action, restore: action, cancel: action, isCreate: computed, isUpdate: computed, isDelete: computed, isRestore: computed, isModified: computed, isValidated: computed, save: action, deleteConfirmed: action, restoreConfirmed: action, }); this.cudConfiguration = cudConfiguration; } setCudError(value) { this.cudError = value; } setValidationError(value) { this.validationError = value; } /** Set in case of CUD error or validation error (latter only when in update mode). */ get hasCudOrValidationError() { return ((this.isCreate || this.isUpdate) && (this.cudError !== undefined)) || (this.isUpdate && this.validationError !== undefined); } /** Set after error in create mode. */ get createError() { return (this.isCreate && this.cudError !== undefined) ? this.cudError : undefined; } /** Set after error in update mode. */ get updateError() { return (this.isUpdate && this.cudError !== undefined) ? this.cudError : undefined; } /** Set after error in delete mode. */ get deleteError() { return (this.isDelete && this.cudError !== undefined) ? this.cudError : undefined; } /** Set after error in restore mode. */ get restoreError() { return (this.isRestore && this.cudError !== undefined) ? this.cudError : undefined; } setEditableItem(value) { this.editableItem = value; const validationerror = this.cudConfiguration.validateItem && this.cudConfiguration.validateItem(value); if (typeof validationerror === 'string') { this.setValidationError(validationerror); } else { this.setValidationError(undefined); } } setEditableItemUnmodified(value) { this.editableItemUnmodified = value; } setDeleteItem(value) { this.deleteItem = value; } setDeletedItem(value) { this.deletedItem = value; } setCreatedItem(value) { this.createdItem = value; } setRestoreItem(value) { this.restoreItem = value; } setRestoredItem(value) { this.restoredItem = value; } /** Start update mode for given item. */ update(entity) { this.deleteItem = undefined; this.restoreItem = undefined; this.editableItem = { ...entity }; this.editableItemUnmodified = { ...entity }; this.cudError = undefined; this.validationError = undefined; } /** Start delete mode for given item. */ delete(entity) { this.editableItem = undefined; this.editableItemUnmodified = undefined; this.deleteItem = entity; this.restoreItem = undefined; this.cudError = undefined; this.validationError = undefined; } /** Start restore mode for given item. */ restore(entity) { this.editableItem = undefined; this.editableItemUnmodified = undefined; this.deleteItem = undefined; this.restoreItem = entity; this.cudError = undefined; this.validationError = undefined; } /** True if in create mode. */ get isCreate() { return this.editableItem !== undefined && this.idForItem(this.editableItem) === undefined; } /** True if in update mode. */ get isUpdate() { return this.editableItem !== undefined && this.idForItem(this.editableItem) !== undefined; } /** True if in delete mode. */ get isDelete() { return this.deleteItem !== undefined; } /** True if in restore mode. */ get isRestore() { return this.restoreItem !== undefined; } /** True is editable data was changed while in update mode. */ get isModified() { return this.editableItemUnmodified === undefined || JSON.stringify(this.editableItemUnmodified) !== JSON.stringify(this.editableItem); } /** True if editable data contains valid data while in create or update mode. */ get isValidated() { return this.editableItem && (!this.cudConfiguration.validateItem || this.cudConfiguration.validateItem(this.editableItem) === true); } /** Perform actual create or update operation of item set in create or update mode. */ async save() { this.setCudError(undefined); this.setCreatedItem(undefined); if (this.settings.token && this.editableItem) { try { // Construct item specifically for server to prevent overposting of data not used by server const serveritem = this.cudConfiguration.serverItem ? this.cudConfiguration.serverItem(this.editableItem) : { ...this.editableItem }; if (this.isCreate) { const created = await this.settings.onFetch(this.cudConfiguration.endpointPost ?? this.configuration.endpoint, { method: 'post', headers: this.settings.onGetHeaders(this.settings.token, this.settings.language, undefined, this.id), json: serveritem }, this.id); this.cancel(); this.setCreatedItem(created); return true; } else if (this.isUpdate && this.idForItem(this.editableItem) !== undefined) { await this.settings.onFetch(`${this.cudConfiguration.endpointPut ?? this.configuration.endpoint}/${this.idForItem(this.editableItem)}`, { method: 'put', headers: this.settings.onGetHeaders(this.settings.token, this.settings.language, undefined, this.id), json: serveritem }, this.id); this.setEditableItemUnmodified({ ...this.editableItem }); return true; } } catch (e) { if (e instanceof Error) { this.setCudError(e); } } } return false; } /** Perform actual delete operation of item previously set in delete mode. */ async deleteConfirmed() { this.setCudError(undefined); if (this.isDelete && this.deleteItem && this.settings.token) { try { await this.settings.onFetch(`${this.cudConfiguration.endpointDelete ?? this.configuration.endpoint}/${this.idForItem(this.deleteItem)}`, { method: 'delete', headers: this.settings.onGetHeaders(this.settings.token, this.settings.language, undefined, this.id), // TODO: reintroduce retry //retry: 0 }, this.id); this.setDeletedItem(this.deleteItem); this.cancel(); return true; } catch (e) { if (e instanceof Error) { this.setCudError(e); } } } return false; } /** Perform actual restore operation of item previously set in restore mode. */ async restoreConfirmed() { this.setCudError(undefined); if (this.isRestore && this.restoreItem && this.settings.token) { try { await this.settings.onFetch(`${this.cudConfiguration.endpointRestore ?? this.configuration.endpoint}/restore/${this.idForItem(this.restoreItem)}`, { method: 'post', headers: this.settings.onGetHeaders(this.settings.token, this.settings.language, undefined, this.id), // TODO: reintroduce retry //retry: 0 }, this.id); this.setRestoredItem(this.restoreItem); this.cancel(); return true; } catch (e) { if (e instanceof Error) { this.setCudError(e); } } } return false; } /** Return id of given item using settings provided in provided @see IGenericCudListConfiguration. */ idForItem(item) { return item[this.cudConfiguration.idField ?? 'id']; } /** Return name of given item using settings provided in provided @see IGenericCudListConfiguration. */ nameForItem(item) { return item[this.cudConfiguration.nameField ?? 'name']; } }