Asynchronous plugin panel view registration?

Iā€™m making a plugin that creates a panel view. Since I canā€™t easily pass data to the pluginā€™s front end, I have to fetch the necessary data and then initialize the plugin. However, nothing happens. I get a blank panel page. Hereā€™s what I do:

import axios from 'axios'
import App from './App.vue'

axios({
  url: panel.api + '/myplugin/data',
  headers: {
    'X-CSRF': panel.csrf
  }
}).then(response => {
  window.mydata = response.data

  panel.plugin('hdodov/myplugin', {
    views: {
      myplugin: {
        label: 'MyPlugin',
        component: App
      }
    }
  })
})

Same happens even if I simply put the plugin registration in a setTimeout:

import axios from 'axios'
import App from './App.vue'

setTimeout(() => {
  panel.plugin('hdodov/myplugin', {
    views: {
      myplugin: {
        label: 'MyPlugin',
        component: App
      }
    }
  })
}, 200)

If I move the registration out of the timeout, the panel loads, the plugin loads, and everything works as expected. Why am I unable to register the plugin asynchronously?

How do I initialize my plugin only after the necessary data for it is available?

Why exactly do you need to do this?
I would register the view component directly and in the component, start the API call in Vueā€™s created() method.

1 Like

Yep, thatā€™s what I would do too. But I have a Vuex store attached to my root component and its state depends on the initial data. If I initialize the store state after itā€™s created, I get a bunch of errors from its getters. Therefore, I wanted to initialize the whole plugin app after that data is present.

The real question is why canā€™t Kirby handle the plugin being initialized asynchronously. :thinking:

I remember once an issue about no semicolon at line ends (since Kirbz merges plugin JS files). Just to rule that out, could you try it with

axios({
...
});

Nope, doesnā€™t fix it. I just tested with the following:

import axios from 'axios'
import App from './App.vue'

axios({
  url: panel.api + '/memsource/langs',
  headers: {
    'X-CSRF': panel.csrf
  }
}).then(response => {
  window.memsource = response.data

  var result = panel.plugin('oblik/memsource', {
    views: {
      memsource: {
        label: 'Memsource',
        icon: 'globe',
        component: App
      }
    }
  })

  console.log(result)
  console.log(window.memsource)
});

The request is successful and the first log returns undefined, while the second one returns the expected data.

If I move the panel.plugin() call outside the promise, the plugin is registered as usual.

Ok, I think i probably know what happens:
panel.plugin() basically only does some transformations and then stores all of it to an object in window.panel. Once the Panel gets loaded, it looks for this objects and actually registers the components etc. in its Vue instance (this way we can bridge between the Panelā€™s Vue isntance and plugins).

Now your call probably takes so long (not saying that its slow, just longer than the rest of the code), that the Panel has already checked and registered everything before your plugin calls panel.plugin().

I donā€™t see an easy way around this at the moment.

Same problem here.

I am trying to make plugin that would generate panel views.

index.js

fetch("/api/iframeview", {
	headers: {
		'x-csrf': panel.csrf
	}
}).then(res =>  res.json())
.then(data => {
	let viewGroup = {};
	Object.entries(data.views).forEach(entry => {
		viewGroup[entry[0]] = createIframeView(entry[0], entry[1]);
	});
	panel.plugin("floriankarsten/iframeview", {
		views: viewGroup
        });
})
.catch(error => console.log(error));


function createIframeView(id, view) {
	return {
		label: view.label,
		icon: view.icon,
		component: {
			template: `
			<k-view class="k-iframeview-view">
				<h1>label: ${view.label}</h1>
			</k-view>`,
		},
	}
}

Those panel views are never created. The code works if i move it out of the promise but yeah that doesnā€™t help me.
Is there any other way register panel plugins dynamicaly or pass them data upfront?