Skip to main content

Store Architecture

The library provides a Pinia-based store system for managing OpenRegister objects.

createObjectStore

The core factory function creates a Pinia store with CRUD operations and plugin support:

import { createObjectStore } from '@conduction/nextcloud-vue'
import {
filesPlugin,
auditTrailsPlugin,
relationsPlugin,
registerMappingPlugin,
} from '@conduction/nextcloud-vue'

export const useObjectStore = createObjectStore('myapp-objects', {
plugins: [filesPlugin, auditTrailsPlugin, relationsPlugin, registerMappingPlugin],
})

The store supports multiple object types through registerObjectType(slug, schemaId, registerId):

const store = useObjectStore()
store.registerObjectType('contact', 'schema-id', 'register-id')
store.registerObjectType('company', 'company-schema-id', 'register-id')

Once registered, you can perform CRUD operations per type. Use getters to read state (e.g. getCollection(type), getPagination(type)):

await store.fetchCollection('contact', { _page: 1, _limit: 20 })
await store.fetchObject('contact', id)
await store.saveObject('contact', data) // create when no id, update when id present
await store.deleteObject('contact', id)
await store.deleteObjects('contact', [id1, id2, id3]) // mass delete; returns { successfulIds, failedIds }

For bulk delete (e.g. after confirmation in CnMassDeleteDialog), use store.deleteObjects(type, ids). The action runs each delete in parallel and returns { successfulIds, failedIds } so the UI can show partial success or failure. Optionally refresh the list with fetchCollection(type, params) after a successful batch.

Plugin System

Plugins extend the store with additional functionality:

filesPlugin

Adds file attachment management and a shared tags list:

  • Upload files to objects
  • List attached files
  • Delete file attachments
  • Download files
  • Fetch tags list (fetchTags()) for file labels; API returns a plain array of strings

auditTrailsPlugin

Adds audit trail (change history) support:

  • Fetch audit trail for an object
  • Display change history with timestamps and users

relationsPlugin

Adds relation management for schema properties with $ref:

  • Fetch related objects
  • Add/remove relations
  • Navigate relation chains

registerMappingPlugin

Adds OpenRegister configuration management:

  • Fetch registers and schemas
  • Auto-match schemas to object types
  • Save configuration mappings

createSubResourcePlugin

Creates a plugin for managing child resources:

import { createSubResourcePlugin } from '@conduction/nextcloud-vue'

const notesPlugin = createSubResourcePlugin('notes', {
endpoint: '/api/objects/{register}/{schema}/{id}/notes',
})

Store Initialization Pattern

Apps typically initialize stores at boot time:

// store/store.js
export async function initializeStores() {
const settingsStore = useSettingsStore()
const objectStore = useObjectStore()

// 1. Fetch app settings (which contain register/schema UUIDs)
await settingsStore.fetchSettings()

// 2. Register each object type (schemaId, registerId)
const types = settingsStore.settings.objectTypes
for (const [slug, config] of Object.entries(types)) {
objectStore.registerObjectType(slug, config.schema, config.register)
}
}

Then in App.vue:

<template>
<NcContent app-name="myapp">
<template v-if="ready">
<MainMenu />
<router-view />
</template>
<NcLoadingIcon v-else />
</NcContent>
</template>

<script>
import { initializeStores } from './store/store.js'

export default {
data: () => ({ ready: false }),
async mounted() {
await initializeStores()
this.ready = true
},
}
</script>

Composables

Three composables provide common view patterns:

useListView

Manages list page state — search, filters, sorting, pagination:

import { useListView } from '@conduction/nextcloud-vue'

const { objects, pagination, loading, search, sort, fetchPage } = useListView({
objectStore,
objectType: 'contact',
})

useDetailView

Manages detail page state — load, edit, delete:

import { useDetailView } from '@conduction/nextcloud-vue'

const { object, loading, save, remove } = useDetailView({
objectStore,
objectType: 'contact',
id: props.contactId,
})

useSubResource

Manages sub-resources (e.g., notes on a contact):

import { useSubResource } from '@conduction/nextcloud-vue'

const { items, loading, add, remove } = useSubResource({
objectStore,
parentType: 'contact',
parentId: props.contactId,
subResourceType: 'notes',
})