feat: add plugin loading status panel

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/3445/head
Ryan Wang 2022-07-25 21:14:56 +08:00
parent 66c1cb69b2
commit 3bdbebfc46
5 changed files with 145 additions and 2 deletions

View File

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

View File

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

View File

@ -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>

4
src/loading-message.d.ts vendored Normal file
View File

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

View File

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