q42-cms-components
Version:
Front-end package that provides a UI on top of the QMS back-end
127 lines (111 loc) • 4.07 kB
JavaScript
import _keyBy from 'lodash/keyBy';
import { ServerStore } from './server-store.js';
export class CRUDStore extends ServerStore {
static get docs() {
return `CRUDStore is een ServerStore subclass die een standaard REST API voor collecties implementeert,
en ook het bijbehorende JSON schema ophaalt. <ul>
<li><code>path</code> geeft de url van de API aan, het schema komt van <code><i>path</i>/schema</code>
<li><code>options</code> heeft dezelfde properties als bij ServerStore.
</ul>
<b>Reactive data properties</b>
<ul>
<li><code>items</code> De lijst met items in de collectie.
De items bevatten niet alle properties, gebruik daarvoor <code>getItemById</code>.
<li><code>schema</code> Het JSON schema van de items in de collectie
<li><code>fields</code> Object met velden voor het <a href="#listing"><code>listing</code></a> component
<li><code>displayField</code> De propertynaam van de items die kan worden gebruikt om de item te tonen.
</ul>`
}
constructor(path, options) {
let { initial = {}, loaders = {}, computed = {} } = options || {};
super({
initial: {
items: [],
fetchItemsError: null,
schema: { properties: {} },
...initial
},
loaders: {
items: () => this.fetch(this.path).catch(error => {
if (error.message) {
this.state.fetchItemsError = error.message;
}
// fallback for not getting an undefined as value
return [];
}),
schema: () => this.fetch(`${this.path}/schema`),
...loaders
},
computed: {
fields: () => this.fieldsObjectForProps(Object.keys(this.schema.properties)),
displayField: () => {
// Get first field from schema properties what is nice to show ('string-input') in a relation-picker.
// Most of the time this is a Title or a Name property.
for (const entry of Object.entries(this.schema.properties)) {
const [ key, value ] = entry;
if (value.format === 'string-input') {
return key;
}
}
// fallback to Guid of a CmsItem
return 'id';
},
indexedItems: () => {
return _keyBy(this.items, 'id');
},
...computed
}
});
this.path = path;
}
create(item) {
// when creating an item, the id is an empty string (comes from schema)
// id & created will be set by the server
delete item.id;
delete item.created;
return this.postJson(this.path, item).then(this.updaters.items);
}
static get createDocs() {
return `POST een nieuw item en update de lijst met items.`;
}
update(item) {
return this.putJson(`${this.path}/${item.id}`, item).then(this.updaters.items);
}
static get updateDocs() {
return `PUT een bestaand item en update de lijst met items.`;
}
upsert(item) {
return item.id ? this.update(item) : this.create(item);
}
static get upsertDocs() {
return `Als het item nog geen <code>id</code> heeft, doe een <code>create</code>, anders een <code>update</code>.`;
}
delete(item) {
return this.del(`${this.path}/${item.id}`).then(this.updaters.items);
}
static get deleteDocs() {
return `DELETE een bestaand item en update de lijst met items.`;
}
getItemById(id) {
return this.fetch(`${this.path}/${id}`)
.catch(error => {
if (error.message) {
this.state.fetchItemsError = error.message;
}
});
}
static get getItemByIdDocs() {
return `GET een item, inclusief alle details.`;
}
fieldsObjectForProps(propNames) {
var fields = {};
var props = this.schema.properties;
propNames.forEach(name => {
var prop = props[name];
if (prop && prop.title) {
fields[prop.title] = name;
}
});
return fields;
}
}