feat: add plugin loading status panel

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/591/head
Ryan Wang 2 years ago
parent 2a1be5603d
commit f99deaec83

@ -26,6 +26,7 @@
],
"dependencies": {
"@formkit/addons": "1.0.0-beta.9",
"@formkit/auto-animate": "1.0.0-beta.1",
"@formkit/core": "1.0.0-beta.9",
"@formkit/i18n": "1.0.0-beta.9",
"@formkit/inputs": "1.0.0-beta.9",

@ -6,6 +6,7 @@ importers:
specifiers:
'@changesets/cli': ^2.24.0
'@formkit/addons': 1.0.0-beta.9
'@formkit/auto-animate': 1.0.0-beta.1
'@formkit/core': 1.0.0-beta.9
'@formkit/i18n': 1.0.0-beta.9
'@formkit/inputs': 1.0.0-beta.9
@ -75,6 +76,7 @@ importers:
yaml: ^2.1.1
dependencies:
'@formkit/addons': 1.0.0-beta.9_vue@3.2.37
'@formkit/auto-animate': 1.0.0-beta.1_vue@3.2.37
'@formkit/core': 1.0.0-beta.9
'@formkit/i18n': 1.0.0-beta.9
'@formkit/inputs': 1.0.0-beta.9

@ -0,0 +1,64 @@
<script lang="ts" setup>
import type { PropType } from "vue";
import { onMounted, ref } from "vue";
import AutoAnimate from "@formkit/auto-animate";
import type { LoadingMessage } from "@/loading-message";
defineProps({
messages: {
type: Array as PropType<LoadingMessage[]>,
default: () => [],
},
});
const list = ref<HTMLElement>();
onMounted(() => {
if (list.value) {
AutoAnimate(list.value, {});
}
});
</script>
<template>
<div id="loader"></div>
<div class="absolute right-0 bottom-10 w-96">
<ul ref="list" class="space-y-2 text-gray-500">
<li
v-for="(message, index) in messages"
:key="index"
:class="{
'text-red-600': message.type === 'error',
}"
>
{{ message.message }}
</li>
</ul>
</div>
</template>
<style>
body {
height: 100%;
background-color: #f5f5f5;
}
#loader {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
border: solid 3px #e5e5e5;
border-top-color: #333;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 0.6s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>

@ -0,0 +1,4 @@
export interface LoadingMessage {
type: "error" | "info";
message: string;
}

@ -1,7 +1,8 @@
import type { DirectiveBinding } from "vue";
import { createApp } from "vue";
import { createApp, ref } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
import LoadingMessageContainer from "./LoadingMessageContainer.vue";
import router from "./router";
import type {
MenuGroupType,
@ -10,10 +11,10 @@ import type {
} from "@halo-dev/admin-shared";
import { apiClient, setApiUrl } from "@halo-dev/admin-shared";
import { menus, minimenus, registerMenu } from "./router/menus.config";
import type { LoadingMessage } from "@/loading-message";
// setup
import "./setup/setupStyles";
import { setupComponents } from "./setup/setupComponents";
// core modules
import { coreModules } from "./modules";
import { useScriptTag } from "@vueuse/core";
@ -22,6 +23,20 @@ import type { User } from "@halo-dev/api-client";
import { hasPermission } from "@/utils/permission";
import { useRoleStore } from "@/stores/role";
// TODO 实验性
const messages = ref<LoadingMessage[]>([]);
const messageContainerApp = createApp({
data: () => ({
messages: messages,
}),
components: {
LoadingMessageContainer,
},
template: `
<LoadingMessageContainer :messages="messages"/>`,
});
messageContainerApp.mount("#app");
const app = createApp(App);
setupComponents(app);
@ -67,7 +82,16 @@ function registerModule(pluginModule: Plugin) {
}
function loadCoreModules() {
const coreLoadStartTime = Date.now();
messages.value.push({
type: "info",
message: "Loading core modules...",
});
coreModules.forEach(registerModule);
messages.value.push({
type: "info",
message: `All core modules loaded(${Date.now() - coreLoadStartTime}ms)`,
});
}
const pluginStore = usePluginStore();
@ -103,6 +127,11 @@ function loadStyle(href: string) {
const pluginErrorMessages: Array<string> = [];
async function loadPluginModules() {
messages.value.push({
type: "info",
message: "Loading plugins...",
});
const { data } =
await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin();
@ -119,10 +148,26 @@ async function loadPluginModules() {
if (entry) {
try {
messages.value.push({
type: "info",
message: `${plugin.metadata.name}: Loading entry module...`,
});
const { load } = useScriptTag(
`${import.meta.env.VITE_API_URL}${plugin.status?.entry}`
);
const entryLoadStartTime = Date.now();
await load();
messages.value.push({
type: "info",
message: `${plugin.metadata.name}: Loaded entry module(${
Date.now() - entryLoadStartTime
}ms)`,
});
const pluginModule = window[plugin.metadata.name];
if (pluginModule) {
@ -132,6 +177,10 @@ async function loadPluginModules() {
}
} catch (e) {
const message = `${plugin.metadata.name}: Failed load plugin entry module`;
messages.value.push({
type: "error",
message,
});
console.error(message, e);
pluginErrorMessages.push(message);
}
@ -139,9 +188,26 @@ async function loadPluginModules() {
if (stylesheet) {
try {
messages.value.push({
type: "info",
message: `${plugin.metadata.name}: Loading stylesheet...`,
});
const styleLoadStartTime = Date.now();
await loadStyle(`${import.meta.env.VITE_API_URL}${stylesheet}`);
messages.value.push({
type: "info",
message: `${plugin.metadata.name}: Loaded stylesheet(${
Date.now() - styleLoadStartTime
}ms)`,
});
} catch (e) {
const message = `${plugin.metadata.name}: Failed load plugin stylesheet`;
messages.value.push({
type: "error",
message,
});
console.error(message, e);
pluginErrorMessages.push(message);
}
@ -150,6 +216,11 @@ async function loadPluginModules() {
pluginStore.registerPlugin(plugin);
}
messages.value.push({
type: "info",
message: "All plugins loaded",
});
if (pluginErrorMessages.length > 0) {
alert(pluginErrorMessages.join("\n"));
}
@ -199,6 +270,7 @@ async function initApp() {
await loadCurrentUser();
app.provide<MenuGroupType[]>("menus", menus);
app.provide<MenuItemType[]>("minimenus", minimenus);
messageContainerApp.unmount();
} catch (e) {
console.error(e);
} finally {

Loading…
Cancel
Save