@conduction/nextcloud-vue 0.1.0-beta.6 → 0.1.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nextcloud-vue.cjs.js +13575 -2374
- package/dist/nextcloud-vue.cjs.js.map +1 -1
- package/dist/nextcloud-vue.css +1238 -270
- package/dist/nextcloud-vue.esm.js +13517 -2336
- package/dist/nextcloud-vue.esm.js.map +1 -1
- package/package.json +11 -7
- package/src/components/CnActionsBar/CnActionsBar.vue +20 -2
- package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +1 -11
- package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +5 -1
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +1 -1
- package/src/components/CnCard/CnCard.vue +415 -0
- package/src/components/CnCard/index.js +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +20 -20
- package/src/components/CnChartWidget/CnChartWidget.vue +3 -1
- package/src/components/CnCopyDialog/CnCopyDialog.vue +7 -1
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +4 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -0
- package/src/components/CnDataTable/CnDataTable.vue +6 -2
- package/src/components/CnDeleteDialog/CnDeleteDialog.vue +7 -1
- package/src/components/CnDetailCard/CnDetailCard.vue +12 -1
- package/src/components/CnDetailGrid/CnDetailGrid.vue +254 -0
- package/src/components/CnDetailGrid/index.js +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +157 -11
- package/src/components/CnFacetSidebar/CnFacetSidebar.vue +3 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +934 -920
- package/src/components/CnIcon/CnIcon.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +63 -9
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +37 -9
- package/src/components/CnInfoWidget/CnInfoWidget.vue +219 -0
- package/src/components/CnInfoWidget/index.js +1 -0
- package/src/components/CnJsonViewer/CnJsonViewer.vue +283 -0
- package/src/components/CnJsonViewer/index.js +1 -0
- package/src/components/CnKpiGrid/CnKpiGrid.vue +5 -1
- package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +7 -1
- package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +7 -1
- package/src/components/CnMassExportDialog/CnMassExportDialog.vue +1 -1
- package/src/components/CnMassImportDialog/CnMassImportDialog.vue +1 -1
- package/src/components/CnObjectCard/CnObjectCard.vue +1 -1
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +368 -0
- package/src/components/CnObjectSidebar/CnFilesTab.vue +286 -0
- package/src/components/CnObjectSidebar/CnNotesTab.vue +249 -0
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +45 -668
- package/src/components/CnObjectSidebar/CnTagsTab.vue +258 -0
- package/src/components/CnObjectSidebar/CnTasksTab.vue +482 -0
- package/src/components/CnObjectSidebar/index.js +5 -0
- package/src/components/CnProgressBar/CnProgressBar.vue +262 -0
- package/src/components/CnProgressBar/index.js +1 -0
- package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +1 -1
- package/src/components/CnStatsBlock/CnStatsBlock.vue +27 -11
- package/src/components/CnStatsPanel/CnStatsPanel.vue +320 -0
- package/src/components/CnStatsPanel/index.js +1 -0
- package/src/components/CnStatusBadge/CnStatusBadge.vue +15 -2
- package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +5 -1
- package/src/components/CnTableWidget/CnTableWidget.vue +332 -0
- package/src/components/CnTableWidget/index.js +1 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +36 -1
- package/src/components/index.js +11 -0
- package/src/composables/useDashboardView.js +58 -12
- package/src/composables/useDetailView.js +3 -2
- package/src/composables/useListView.js +7 -6
- package/src/composables/useSubResource.js +3 -3
- package/src/css/badge.css +32 -0
- package/src/css/card.css +1 -0
- package/src/css/detail-page.css +74 -7
- package/src/index.js +16 -0
- package/src/mixins/gridLayout.js +118 -0
- package/src/store/createCrudStore.js +360 -0
- package/src/store/createSubResourcePlugin.js +5 -15
- package/src/store/index.js +1 -0
- package/src/store/plugins/auditTrails.js +346 -6
- package/src/store/plugins/lifecycle.js +4 -4
- package/src/store/plugins/registerMapping.js +18 -8
- package/src/store/plugins/relations.js +1 -1
- package/src/store/plugins/search.js +21 -8
- package/src/store/useObjectStore.js +30 -36
- package/src/utils/getTheme.js +9 -0
- package/src/utils/headers.js +13 -3
- package/src/utils/index.js +1 -0
- package/src/utils/schema.js +3 -3
- package/src/utils/widgetVisibility.js +162 -0
- package/src/components/CnObjectCard/eslint-setup.md +0 -235
- package/src/components/CnObjectCard/package.json-or.json +0 -132
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { buildHeaders, prefixUrl } from '../utils/headers.js'
|
|
3
|
+
import { parseResponseError } from '../utils/errors.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default fields stripped from items before POST/PUT.
|
|
7
|
+
* @type {string[]}
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_CLEAN_FIELDS = ['id', 'uuid', 'created', 'updated']
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Default base URL for the API.
|
|
13
|
+
* @type {string}
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_BASE_URL = '/apps/openregister/api'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Default list-response parser — extracts the `results` array.
|
|
19
|
+
*
|
|
20
|
+
* Called with the store as `this`, so custom implementations can
|
|
21
|
+
* perform side-effects (e.g. update extra state from the response).
|
|
22
|
+
*
|
|
23
|
+
* @param {object} json Parsed response body
|
|
24
|
+
* @return {Array} The items array for setList
|
|
25
|
+
*/
|
|
26
|
+
function defaultParseListResponse(json) {
|
|
27
|
+
return json.results
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a Pinia store with standard CRUD operations.
|
|
32
|
+
*
|
|
33
|
+
* Generates a store with list/item state, pagination, filters, and
|
|
34
|
+
* async actions for fetching, creating, updating, and deleting items.
|
|
35
|
+
* Domain-specific state, getters, and actions can be added via `extend`.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Minimal — pure CRUD
|
|
39
|
+
* import { createCrudStore } from '@conduction/nextcloud-vue'
|
|
40
|
+
* import { Source } from '../../entities/index.js'
|
|
41
|
+
*
|
|
42
|
+
* export const useSourceStore = createCrudStore('source', {
|
|
43
|
+
* endpoint: 'sources',
|
|
44
|
+
* entity: Source,
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // With features and extensions
|
|
49
|
+
* import { createCrudStore } from '@conduction/nextcloud-vue'
|
|
50
|
+
* import { Agent } from '../../entities/index.js'
|
|
51
|
+
*
|
|
52
|
+
* export const useAgentStore = createCrudStore('agent', {
|
|
53
|
+
* endpoint: 'agents',
|
|
54
|
+
* entity: Agent,
|
|
55
|
+
* features: { loading: true, viewMode: true },
|
|
56
|
+
* extend: {
|
|
57
|
+
* actions: {
|
|
58
|
+
* async getStats() {
|
|
59
|
+
* const response = await fetch(this._options.baseApiUrl + '/stats')
|
|
60
|
+
* if (!response.ok) throw new Error('HTTP ' + response.status)
|
|
61
|
+
* return response.json()
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
* },
|
|
65
|
+
* })
|
|
66
|
+
*
|
|
67
|
+
* @param {string} name Pinia store ID (e.g. 'source', 'agent')
|
|
68
|
+
* @param {object} config Store configuration
|
|
69
|
+
* @param {string} config.endpoint API resource path segment (e.g. 'sources')
|
|
70
|
+
* @param {string} [config.baseUrl] API base URL (before endpoint)
|
|
71
|
+
* @param {Function|null} [config.entity] Entity class constructor for wrapping items, or null for raw data
|
|
72
|
+
* @param {string[]} [config.cleanFields] Fields to strip in cleanForSave
|
|
73
|
+
* @param {object} [config.features] Feature flags to enable optional state/getters/actions
|
|
74
|
+
* @param {boolean} [config.features.loading] Add loading/error state and isLoading/getError getters
|
|
75
|
+
* @param {boolean} [config.features.viewMode] Add viewMode state, getViewMode getter, setViewMode action
|
|
76
|
+
* @param {Function} [config.parseListResponse] Custom response parser for refreshList.
|
|
77
|
+
* Receives the parsed JSON body with the store instance as `this`.
|
|
78
|
+
* Must return an array of items. Default: `(json) => json.results`
|
|
79
|
+
* @param {object} [config.extend] Extra state/getters/actions to merge into the store
|
|
80
|
+
* @param {Function} [config.extend.state] State factory returning extra state properties
|
|
81
|
+
* @param {object} [config.extend.getters] Extra getters (or overrides of base getters)
|
|
82
|
+
* @param {object} [config.extend.actions] Extra actions (or overrides of base actions)
|
|
83
|
+
* @return {Function} Pinia store composable (useXxxStore)
|
|
84
|
+
*/
|
|
85
|
+
export function createCrudStore(name, config = {}) {
|
|
86
|
+
const {
|
|
87
|
+
endpoint,
|
|
88
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
89
|
+
entity: Entity = null,
|
|
90
|
+
cleanFields = DEFAULT_CLEAN_FIELDS,
|
|
91
|
+
features = {},
|
|
92
|
+
parseListResponse = defaultParseListResponse,
|
|
93
|
+
extend = {},
|
|
94
|
+
} = config
|
|
95
|
+
|
|
96
|
+
if (!endpoint) {
|
|
97
|
+
throw new Error(`createCrudStore("${name}"): config.endpoint is required`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const baseApiUrl = prefixUrl(`${baseUrl}/${endpoint}`)
|
|
101
|
+
|
|
102
|
+
return defineStore(name, {
|
|
103
|
+
state: () => ({
|
|
104
|
+
// ── Core state ──
|
|
105
|
+
item: null,
|
|
106
|
+
list: [],
|
|
107
|
+
filters: {},
|
|
108
|
+
pagination: { page: 1, limit: 20 },
|
|
109
|
+
|
|
110
|
+
// ── Optional feature state ──
|
|
111
|
+
...(features.loading ? { loading: false, error: null } : {}),
|
|
112
|
+
...(features.viewMode ? { viewMode: 'cards' } : {}),
|
|
113
|
+
|
|
114
|
+
// ── Internal config (available to extend actions) ──
|
|
115
|
+
_options: { endpoint, cleanFields, baseApiUrl },
|
|
116
|
+
|
|
117
|
+
// ── Domain-specific state ──
|
|
118
|
+
...(typeof extend.state === 'function' ? extend.state() : {}),
|
|
119
|
+
}),
|
|
120
|
+
|
|
121
|
+
getters: {
|
|
122
|
+
// ── Optional feature getters ──
|
|
123
|
+
...(features.viewMode ? { getViewMode: (state) => state.viewMode } : {}),
|
|
124
|
+
...(features.loading
|
|
125
|
+
? {
|
|
126
|
+
isLoading: (state) => state.loading,
|
|
127
|
+
getError: (state) => state.error,
|
|
128
|
+
}
|
|
129
|
+
: {}),
|
|
130
|
+
|
|
131
|
+
// ── Domain-specific getters ──
|
|
132
|
+
...(extend.getters ?? {}),
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
actions: {
|
|
136
|
+
// ── Setters ──
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Set the active item. Wraps in Entity class if configured.
|
|
140
|
+
* @param {object|null} data Raw item data or null to clear
|
|
141
|
+
*/
|
|
142
|
+
setItem(data) {
|
|
143
|
+
this.item = data
|
|
144
|
+
? (Entity ? new Entity(data) : data)
|
|
145
|
+
: null
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Set the item list. Wraps each item in Entity class if configured.
|
|
150
|
+
* @param {Array} data Array of raw item objects
|
|
151
|
+
*/
|
|
152
|
+
setList(data) {
|
|
153
|
+
this.list = Entity
|
|
154
|
+
? data.map((item) => new Entity(item))
|
|
155
|
+
: [...data]
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Set pagination parameters.
|
|
160
|
+
* @param {number} page Current page number
|
|
161
|
+
* @param {number} [limit] Items per page
|
|
162
|
+
*/
|
|
163
|
+
setPagination(page, limit = 20) {
|
|
164
|
+
this.pagination = { page, limit }
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Merge filter criteria into the current filters.
|
|
169
|
+
* @param {object} filters Key-value filter pairs to merge
|
|
170
|
+
*/
|
|
171
|
+
setFilters(filters) {
|
|
172
|
+
this.filters = { ...this.filters, ...filters }
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
// ── Optional feature actions ──
|
|
176
|
+
...(features.viewMode
|
|
177
|
+
? {
|
|
178
|
+
/**
|
|
179
|
+
* Set the view mode (e.g. 'cards', 'table').
|
|
180
|
+
* @param {string} mode View mode identifier
|
|
181
|
+
*/
|
|
182
|
+
setViewMode(mode) {
|
|
183
|
+
this.viewMode = mode
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
: {}),
|
|
187
|
+
|
|
188
|
+
// ── CRUD actions ──
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Fetch the item list from the API.
|
|
192
|
+
* @param {string|null} [search] Optional search query
|
|
193
|
+
* @param {boolean} [soft] If true, don't toggle loading state
|
|
194
|
+
* @return {Promise<{response: Response, data: Array}>}
|
|
195
|
+
*/
|
|
196
|
+
async refreshList(search = null, soft = false) {
|
|
197
|
+
if (features.loading && !soft) {
|
|
198
|
+
this.loading = true
|
|
199
|
+
this.error = null
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
let url = this._options.baseApiUrl
|
|
203
|
+
if (search) {
|
|
204
|
+
url += '?_search=' + encodeURIComponent(search)
|
|
205
|
+
}
|
|
206
|
+
const response = await fetch(url, {
|
|
207
|
+
method: 'GET',
|
|
208
|
+
headers: buildHeaders(),
|
|
209
|
+
})
|
|
210
|
+
if (!response.ok) {
|
|
211
|
+
throw await parseResponseError(response, name)
|
|
212
|
+
}
|
|
213
|
+
const json = await response.json()
|
|
214
|
+
const data = parseListResponse.call(this, json)
|
|
215
|
+
this.setList(data)
|
|
216
|
+
return { response, data }
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (features.loading) {
|
|
219
|
+
this.error = error.message ?? error.toString()
|
|
220
|
+
}
|
|
221
|
+
throw error
|
|
222
|
+
} finally {
|
|
223
|
+
if (features.loading && !soft) {
|
|
224
|
+
this.loading = false
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Fetch a single item by ID and set it as the active item.
|
|
231
|
+
* @param {string|number} id Item ID or UUID
|
|
232
|
+
* @return {Promise<object>} The fetched item data
|
|
233
|
+
*/
|
|
234
|
+
async getOne(id) {
|
|
235
|
+
if (features.loading) {
|
|
236
|
+
this.loading = true
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const response = await fetch(`${this._options.baseApiUrl}/${id}`, {
|
|
240
|
+
method: 'GET',
|
|
241
|
+
headers: buildHeaders(),
|
|
242
|
+
})
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
throw await parseResponseError(response, name)
|
|
245
|
+
}
|
|
246
|
+
const data = await response.json()
|
|
247
|
+
this.setItem(data)
|
|
248
|
+
return data
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (features.loading) {
|
|
251
|
+
this.error = error.message ?? error.toString()
|
|
252
|
+
}
|
|
253
|
+
throw error
|
|
254
|
+
} finally {
|
|
255
|
+
if (features.loading) {
|
|
256
|
+
this.loading = false
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Delete an item by ID. Refreshes the list and clears the active item.
|
|
263
|
+
* @param {object} item Item object (must have .id)
|
|
264
|
+
* @return {Promise<{response: Response}>}
|
|
265
|
+
*/
|
|
266
|
+
async deleteOne(item) {
|
|
267
|
+
if (!item.id) {
|
|
268
|
+
throw new Error(`No ${name} to delete`)
|
|
269
|
+
}
|
|
270
|
+
if (features.loading) {
|
|
271
|
+
this.loading = true
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
const response = await fetch(`${this._options.baseApiUrl}/${item.id}`, {
|
|
275
|
+
method: 'DELETE',
|
|
276
|
+
headers: buildHeaders(),
|
|
277
|
+
})
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
throw await parseResponseError(response, name)
|
|
280
|
+
}
|
|
281
|
+
await this.refreshList()
|
|
282
|
+
this.setItem(null)
|
|
283
|
+
return { response }
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (features.loading) {
|
|
286
|
+
this.error = error.message ?? error.toString()
|
|
287
|
+
}
|
|
288
|
+
throw error
|
|
289
|
+
} finally {
|
|
290
|
+
if (features.loading) {
|
|
291
|
+
this.loading = false
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Strip read-only fields from an item before saving.
|
|
298
|
+
* Uses the `cleanFields` config array. Override in `extend.actions`
|
|
299
|
+
* for custom cleaning (the configured fields are in `this._options.cleanFields`).
|
|
300
|
+
* @param {object} item Raw item data
|
|
301
|
+
* @return {object} Cleaned copy safe for POST/PUT
|
|
302
|
+
*/
|
|
303
|
+
cleanForSave(item) {
|
|
304
|
+
const cleaned = { ...item }
|
|
305
|
+
for (const field of this._options.cleanFields) {
|
|
306
|
+
delete cleaned[field]
|
|
307
|
+
}
|
|
308
|
+
return cleaned
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Create or update an item. Determines method from presence of `.id`.
|
|
313
|
+
* @param {object} item Item data (without .id = create, with .id = update)
|
|
314
|
+
* @return {Promise<{response: Response, data: object}>}
|
|
315
|
+
*/
|
|
316
|
+
async save(item) {
|
|
317
|
+
if (!item) {
|
|
318
|
+
throw new Error(`No ${name} to save`)
|
|
319
|
+
}
|
|
320
|
+
if (features.loading) {
|
|
321
|
+
this.loading = true
|
|
322
|
+
}
|
|
323
|
+
const isNew = !item.id
|
|
324
|
+
const url = isNew
|
|
325
|
+
? this._options.baseApiUrl
|
|
326
|
+
: `${this._options.baseApiUrl}/${item.id}`
|
|
327
|
+
const method = isNew ? 'POST' : 'PUT'
|
|
328
|
+
const body = this.cleanForSave(item)
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const response = await fetch(url, {
|
|
332
|
+
method,
|
|
333
|
+
headers: buildHeaders(),
|
|
334
|
+
body: JSON.stringify(body),
|
|
335
|
+
})
|
|
336
|
+
if (!response.ok) {
|
|
337
|
+
throw await parseResponseError(response, name)
|
|
338
|
+
}
|
|
339
|
+
const responseData = await response.json()
|
|
340
|
+
const data = Entity ? new Entity(responseData) : responseData
|
|
341
|
+
this.setItem(data)
|
|
342
|
+
await this.refreshList()
|
|
343
|
+
return { response, data }
|
|
344
|
+
} catch (error) {
|
|
345
|
+
if (features.loading) {
|
|
346
|
+
this.error = error.message ?? error.toString()
|
|
347
|
+
}
|
|
348
|
+
throw error
|
|
349
|
+
} finally {
|
|
350
|
+
if (features.loading) {
|
|
351
|
+
this.loading = false
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
// ── Domain-specific actions (may override base actions) ──
|
|
357
|
+
...(extend.actions ?? {}),
|
|
358
|
+
},
|
|
359
|
+
})
|
|
360
|
+
}
|
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
import { buildHeaders, buildQueryString } from '../utils/headers.js'
|
|
1
|
+
import { buildHeaders, buildQueryString, capitalize } from '../utils/headers.js'
|
|
2
2
|
import { parseResponseError, networkError } from '../utils/errors.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Standard empty paginated response shape used by all sub-resource plugins.
|
|
6
6
|
*
|
|
7
|
-
* @param {number} [limit
|
|
7
|
+
* @param {number} [limit] Default page size
|
|
8
8
|
* @return {object} Empty paginated state
|
|
9
9
|
*/
|
|
10
10
|
export function emptyPaginated(limit = 20) {
|
|
11
11
|
return { results: [], total: 0, page: 1, pages: 0, limit, offset: 0 }
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Capitalize the first letter of a string.
|
|
16
|
-
*
|
|
17
|
-
* @param {string} str Input string
|
|
18
|
-
* @return {string} Capitalized string
|
|
19
|
-
*/
|
|
20
|
-
function capitalize(str) {
|
|
21
|
-
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
14
|
/**
|
|
25
15
|
* Create a sub-resource plugin for the object store.
|
|
26
16
|
*
|
|
@@ -30,8 +20,8 @@ function capitalize(str) {
|
|
|
30
20
|
*
|
|
31
21
|
* @param {string} name Camel-case name for the sub-resource (e.g. 'auditTrails')
|
|
32
22
|
* @param {string} endpoint URL path segment appended to the object URL (e.g. 'audit-trails')
|
|
33
|
-
* @param {object} [options
|
|
34
|
-
* @param {number} [options.limit
|
|
23
|
+
* @param {object} [options] Plugin options
|
|
24
|
+
* @param {number} [options.limit] Default page size
|
|
35
25
|
* @return {Function} Plugin factory that returns the plugin definition
|
|
36
26
|
*
|
|
37
27
|
* @example
|
|
@@ -76,7 +66,7 @@ export function createSubResourcePlugin(name, endpoint, options = {}) {
|
|
|
76
66
|
*
|
|
77
67
|
* @param {string} type The registered object type slug
|
|
78
68
|
* @param {string} objectId The parent object ID
|
|
79
|
-
* @param {object} [params
|
|
69
|
+
* @param {object} [params] Query parameters (_search, _limit, _page)
|
|
80
70
|
* @return {Promise<Array>} The fetched results
|
|
81
71
|
*/
|
|
82
72
|
async [`fetch${cap}`](type, objectId, params = {}) {
|
package/src/store/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { useObjectStore, createObjectStore } from './useObjectStore.js'
|
|
2
|
+
export { createCrudStore } from './createCrudStore.js'
|
|
2
3
|
export { createSubResourcePlugin, emptyPaginated } from './createSubResourcePlugin.js'
|
|
3
4
|
export { auditTrailsPlugin, relationsPlugin, filesPlugin, lifecyclePlugin, selectionPlugin, searchPlugin, SEARCH_TYPE, getRegisterApiUrl, getSchemaApiUrl } from './plugins/index.js'
|