Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 255 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import Vue from 'vue'
import VueRouter from 'vue-router'
import { PiniaVuePlugin } from 'pinia'
import { PiniaVuePlugin, setActivePinia } from 'pinia'
import { translate as t, translatePlural as n, loadTranslations } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import {
Expand Down Expand Up @@ -122,6 +122,14 @@ const customComponentsProp = { ...customComponents }
// initializeStores() is documented as idempotent so App.vue's call
// stays in place as a safety net for future entry points.
;(async () => {
// Activate Pinia globally before any useStore() call. Without this,
// initializeStores() (which calls useObjectStore() outside any Vue
// component) throws "Cannot read properties of undefined (reading
// '_s')" because Pinia falls back to the active instance and there
// isn't one yet — Vue.use(PiniaVuePlugin) only auto-activates pinia
// when Vue itself uses it via `new Vue({ pinia })`.
setActivePinia(pinia)

try {
await initializeStores()
} catch (e) {
Expand Down
50 changes: 35 additions & 15 deletions src/views/LiveMeeting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,6 @@ export default {

data() {
return {
meeting: {},
allItems: [],
participants: [],
loading: true,
activeItemId: null,
advancingBob: false,
Expand All @@ -218,6 +215,25 @@ export default {
},

computed: {
// Read directly from the shared store cache so the
// liveUpdatesPlugin's auto-refetch on `or-object-{uuid}` /
// `or-collection-...` events propagates to the rendered UI
// without per-component watcher boilerplate. Pre-migration
// LiveMeeting copied data into local state in fetchData(),
// which made the page non-reactive to live updates: the plugin
// updated the store cache but the local copy never re-read.
meeting() {
return this.objectStore.objects?.meeting?.[this.id] ?? {}
},
allItems() {
const collection = this.objectStore.collections?.['agenda-item'] ?? []
return collection.filter(i => i?.['@self']?.relations?.meeting === this.id || i?.relations?.meeting === this.id)
},
participants() {
const collection = this.objectStore.collections?.participant ?? []
return collection.filter(p => p?.['@self']?.relations?.meeting === this.id || p?.relations?.meeting === this.id)
},

isChair() {
const currentUser = getCurrentUser()
if (!currentUser) return false
Expand Down Expand Up @@ -316,17 +332,22 @@ export default {
},

async fetchData() {
// Trigger initial fetches to populate the shared store cache.
// We deliberately don't assign results to local state — the
// `meeting`, `allItems`, and `participants` computed getters
// read straight from the store, so when the liveUpdatesPlugin
// re-fetches on `or-object-*` / `or-collection-*` events the
// rendered UI updates automatically via Vue reactivity.
try {
const meeting = await this.objectStore.fetchObject('meeting', this.id)
this.meeting = meeting ?? {}
const items = await this.objectStore.fetchCollection('agenda-item', {
'@self.relations.meeting': this.id,
})
this.allItems = items ?? []
const parts = await this.objectStore.fetchCollection('participant', {
'@self.relations.meeting': this.id,
})
this.participants = parts ?? []
await Promise.all([
this.objectStore.fetchObject('meeting', this.id),
this.objectStore.fetchCollection('agenda-item', {
'@self.relations.meeting': this.id,
}),
this.objectStore.fetchCollection('participant', {
'@self.relations.meeting': this.id,
}),
])
} catch (e) {
console.error('Error fetching live meeting data:', e)
} finally {
Expand All @@ -336,10 +357,9 @@ export default {

async refreshItems() {
try {
const items = await this.objectStore.fetchCollection('agenda-item', {
await this.objectStore.fetchCollection('agenda-item', {
'@self.relations.meeting': this.id,
})
this.allItems = items ?? []
} catch (e) {
console.error('Error refreshing items:', e)
}
Expand Down
Loading