mirror of https://github.com/halo-dev/halo
feat: add plugin loading status panel
Signed-off-by: Ryan Wang <i@ryanc.cc>pull/3445/head
parent
66c1cb69b2
commit
3bdbebfc46
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
76
src/main.ts
76
src/main.ts
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue