enhance(frontend): improve plugin management

This commit is contained in:
syuilo 2025-03-09 21:57:56 +09:00
parent 8e3304344f
commit c76afce9a7
5 changed files with 51 additions and 38 deletions

View File

@ -6,6 +6,7 @@
### Client ### Client
- Feat: 設定の管理が強化されました - Feat: 設定の管理が強化されました
- 自動でバックアップされるように - 自動でバックアップされるように
- Enhance: プラグインの管理が強化されました
### Server ### Server
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正 - Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正

View File

@ -27,7 +27,7 @@ import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import { misskeyApi } from '@/utility/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { deckStore } from '@/ui/deck/deck-store.js'; import { deckStore } from '@/ui/deck/deck-store.js';
import { launchPlugin } from '@/plugin.js'; import { launchPlugins } from '@/plugin.js';
export async function mainBoot() { export async function mainBoot() {
const { isClientUpdated } = await common(() => { const { isClientUpdated } = await common(() => {
@ -105,9 +105,7 @@ export async function mainBoot() {
removeCustomEmojis(emojiData.emojis); removeCustomEmojis(emojiData.emojis);
}); });
for (const plugin of prefer.s.plugins.filter(p => p.active)) { launchPlugins();
launchPlugin(plugin);
}
try { try {
if (prefer.s.enableSeasonalScreenEffect) { if (prefer.s.enableSeasonalScreenEffect) {

View File

@ -36,10 +36,6 @@ async function install() {
try { try {
await installPlugin(code.value); await installPlugin(code.value);
os.success(); os.success();
nextTick(() => {
unisonReload();
});
} catch (err) { } catch (err) {
os.alert({ os.alert({
type: 'error', type: 'error',

View File

@ -94,7 +94,6 @@ import MkButton from '@/components/MkButton.vue';
import MkCode from '@/components/MkCode.vue'; import MkCode from '@/components/MkCode.vue';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue'; import MkKeyValue from '@/components/MkKeyValue.vue';
import { unisonReload } from '@/utility/unison-reload.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/utility/page-metadata.js'; import { definePageMetadata } from '@/utility/page-metadata.js';
import { changePluginActive, configPlugin, pluginLogs, uninstallPlugin, reloadPlugin } from '@/plugin.js'; import { changePluginActive, configPlugin, pluginLogs, uninstallPlugin, reloadPlugin } from '@/plugin.js';
@ -104,9 +103,6 @@ const plugins = prefer.r.plugins;
async function uninstall(plugin: Plugin) { async function uninstall(plugin: Plugin) {
await uninstallPlugin(plugin); await uninstallPlugin(plugin);
nextTick(() => {
unisonReload();
});
} }
function reload(plugin: Plugin) { function reload(plugin: Plugin) {
@ -119,9 +115,6 @@ async function config(plugin: Plugin) {
function changeActive(plugin: Plugin, active: boolean) { function changeActive(plugin: Plugin, active: boolean) {
changePluginActive(plugin, active); changePluginActive(plugin, active);
nextTick(() => {
location.reload();
});
} }
const headerActions = computed(() => []); const headerActions = computed(() => []);

View File

@ -144,9 +144,12 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) {
prefer.set('plugins', prefer.s.plugins.concat(plugin)); prefer.set('plugins', prefer.s.plugins.concat(plugin));
await authorizePlugin(plugin); await authorizePlugin(plugin);
await launchPlugin(installId);
} }
export async function uninstallPlugin(plugin: Plugin) { export async function uninstallPlugin(plugin: Plugin) {
abortPlugin(plugin);
prefer.set('plugins', prefer.s.plugins.filter(x => x.installId !== plugin.installId)); prefer.set('plugins', prefer.s.plugins.filter(x => x.installId !== plugin.installId));
if (Object.hasOwn(store.state.pluginTokens, plugin.installId)) { if (Object.hasOwn(store.state.pluginTokens, plugin.installId)) {
await os.apiWithDialog('i/revoke-token', { await os.apiWithDialog('i/revoke-token', {
@ -158,26 +161,6 @@ export async function uninstallPlugin(plugin: Plugin) {
} }
} }
export async function configPlugin(plugin: Plugin) {
if (plugin.config == null) {
throw new Error('This plugin does not have a config');
}
const config = plugin.config;
for (const key in plugin.configData) {
config[key].default = plugin.configData[key];
}
const { canceled, result } = await os.form(plugin.name, config);
if (canceled) return;
prefer.set('plugins', prefer.s.plugins.map(x => x.installId === plugin.installId ? { ...x, configData: result } : x));
}
export function changePluginActive(plugin: Plugin, active: boolean) {
prefer.set('plugins', prefer.s.plugins.map(x => x.installId === plugin.installId ? { ...x, active } : x));
}
const pluginContexts = new Map<string, Interpreter>(); const pluginContexts = new Map<string, Interpreter>();
export const pluginLogs = ref(new Map<string, string[]>()); export const pluginLogs = ref(new Map<string, string[]>());
@ -217,7 +200,18 @@ function addPluginHandler<K extends keyof HandlerDef>(installId: Plugin['install
pluginHandlers.push({ pluginInstallId: installId, type, ctx }); pluginHandlers.push({ pluginInstallId: installId, type, ctx });
} }
export async function launchPlugin(plugin: Plugin): Promise<void> { export function launchPlugins() {
for (const plugin of prefer.s.plugins) {
if (plugin.active) {
launchPlugin(plugin.installId);
}
}
}
async function launchPlugin(id: Plugin['installId']): Promise<void> {
const plugin = prefer.s.plugins.find(x => x.installId === id);
if (!plugin) return;
// 後方互換性のため // 後方互換性のため
if (plugin.src == null) return; if (plugin.src == null) return;
@ -254,7 +248,7 @@ export async function launchPlugin(plugin: Plugin): Promise<void> {
); );
} }
export function reloadPlugin(plugin: Plugin): void { export function abortPlugin(plugin: Plugin): void {
const pluginContext = pluginContexts.get(plugin.installId); const pluginContext = pluginContexts.get(plugin.installId);
if (!pluginContext) return; if (!pluginContext) return;
@ -262,8 +256,39 @@ export function reloadPlugin(plugin: Plugin): void {
pluginContexts.delete(plugin.installId); pluginContexts.delete(plugin.installId);
pluginLogs.value.delete(plugin.installId); pluginLogs.value.delete(plugin.installId);
pluginHandlers = pluginHandlers.filter(x => x.pluginInstallId !== plugin.installId); pluginHandlers = pluginHandlers.filter(x => x.pluginInstallId !== plugin.installId);
}
launchPlugin(plugin); export function reloadPlugin(plugin: Plugin): void {
abortPlugin(plugin);
launchPlugin(plugin.installId);
}
export async function configPlugin(plugin: Plugin) {
if (plugin.config == null) {
throw new Error('This plugin does not have a config');
}
const config = plugin.config;
for (const key in plugin.configData) {
config[key].default = plugin.configData[key];
}
const { canceled, result } = await os.form(plugin.name, config);
if (canceled) return;
prefer.set('plugins', prefer.s.plugins.map(x => x.installId === plugin.installId ? { ...x, configData: result } : x));
reloadPlugin(plugin);
}
export function changePluginActive(plugin: Plugin, active: boolean) {
prefer.set('plugins', prefer.s.plugins.map(x => x.installId === plugin.installId ? { ...x, active } : x));
if (active) {
launchPlugin(plugin.installId);
} else {
abortPlugin(plugin);
}
} }
function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<string, values.Value> { function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<string, values.Value> {