From d30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sun, 9 Mar 2025 12:34:08 +0900
Subject: Refine preferences (#15597)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* wip

* wip

* test

* wip rollup pluginでsearchIndexの情報生成

* wip

* SPDX

* wip: markerIdを自動付与

* rollupでビルド時・devモード時に毎回uuidを生成するように

* 開発サーバーでだけ必要な挙動は開発サーバーのみで

* 条件が逆

* wip: childrenの生成

* update comment

* update comment

* rename auto generated file

* hashをパスと行数から決定

* Update privacy.vue

* Update privacy.vue

* wip

* Update general.vue

* Update general.vue

* wip

* wip

* Update SearchMarker.vue

* wip

* Update profile.vue

* Update mute-block.vue

* Update mute-block.vue

* Update general.vue

* Update general.vue

* childrenがduplicate key errorを吐く問題をいったん解決

* マーカーの形を成形

* loggerを置きかえ

* とりあえず省略記法に対応

* Refactor and Format codes

* wip

* Update settings-search-index.ts

* wip

* wip

* とりあえず不確定要因の仮置きidを削除

* hashの生成を正規化（絶対パスになっていたのを緩和）

* pathの入力を省略可能に

* adminでもパス生成できるように

* Update settings-search-index.ts

* Update privacy.vue

* wip

* build searchIndex

* wip

* build

* Update general.vue

* build

* Update sounds.vue

* build

* build

* Update sounds.vue

* 🎨

* 🎨

* Update privacy.vue

* Update privacy.vue

* Update security.vue

* create-search-indexを多少改善

* build

* Update 2fa.vue

* wip

* 必ずtransformCodeCacheを利用するように, キャッシュの明確な受け渡しを定義

* キャッシュはdevServerでなくても更新

* Revert "wip"

This reverts commit 41bffd3a13f55618bf939dc1c9acb2a77ead4054.

* inlining

* wip

* Update theme.vue

* 🎨

* wip normalize

* Update theme.vue

* キャッシュのパス変換

* build

* wip

* wip

* Update SearchMarker.vue

* i18n.ts['key'] の形式が取り出せない問題のFix

* build

* 仮でpath入れ

* 必ず絶対パスが使われるように

* wip

* 🎨

* storybookビルド時はcreateSearchIndexをしない

* inliningの構造化

* format code

* Update index.vue

* wip

* wip

* 🎨

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* clean up

* wip

* wip

* wip

* Update rollup-plugin-unwind-css-module-class-name.test.ts

* Update navbar.vue

* clean up

* wip

* wip

* wip

* wip

* wip

* Update preferences-backups.vue

* Update common.ts

* Update preferences.ts

* wip

* wip

* wip

* wip

* Update MkPreferenceContainer.vue

* Update MkPreferenceContainer.vue

* Update MkPreferenceContainer.vue

* enhance: 検索で上下矢印を使用することで検索結果を移動できるように

* Update main-boot.ts

* refactor

* wip

* Update sounds.vue

* fix(frontend): PageWindowでSearchMarkerが動作するように

* enhance(frontend): SearchMarkerの点滅を一定時間で止める

* wip

* lint fix

* fix: 子要素監視が抜けていたのを修正

* アニメーションの回数はCSSで制御するように

* refactor

* enhance(frontend): 検索インデックス作成時のログを削減

* revert

* fix

* fix

* Update preferences.ts

* Update preferences.ts

* wip

* Update preferences.ts

* wip

* 🎨

* wip

* Update MkPreferenceContainer.vue

* wip

* Update preferences.ts

* wip

* Update preferences.ts

* Update preferences.ts

* wip

* wip

* Update preferences.ts

* wip

* wip

* Update preferences.ts

* Update CHANGELOG.md

* Update preferences.ts

* Update deck-store.ts

* deckStoreをdefaultStoreに統合

* wip

* defaultStore -> store

* Update profile.ts

* wip

* refactor

* wip: plugin

* plugin

* plugin

* plugin

* Update plugin.ts

* wip

* Update plugin.vue

* Update preferences.ts

* Update main-boot.ts

* wip

* fix test

* Update plugin.vue

* Update plugin.vue

* Update utility.ts

* wip

* wip

* Update utility.ts

* wip

* wip

* clean up

* Update utility.ts

---------

Co-authored-by: tai-cha <dev@taichan.site>
Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
---
 packages/frontend/src/pages/settings/plugin.vue | 164 ++++++++++++------------
 1 file changed, 83 insertions(+), 81 deletions(-)

(limited to 'packages/frontend/src/pages/settings/plugin.vue')

diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue
index 3c3dcfe41e..fe57812a1d 100644
--- a/packages/frontend/src/pages/settings/plugin.vue
+++ b/packages/frontend/src/pages/settings/plugin.vue
@@ -4,72 +4,92 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div class="_gaps_m">
-	<FormLink to="/settings/plugin/install"><template #icon><i class="ti ti-download"></i></template>{{ i18n.ts._plugin.install }}</FormLink>
-
-	<FormSection>
-		<template #label>{{ i18n.ts.manage }}</template>
-		<div class="_gaps_s">
-			<div v-for="plugin in plugins" :key="plugin.id" class="_panel _gaps_m" style="padding: 20px;">
-				<div class="_gaps_s">
-					<span style="display: flex; align-items: center;"><b>{{ plugin.name }}</b><span style="margin-left: auto;">v{{ plugin.version }}</span></span>
-					<MkSwitch :modelValue="plugin.active" @update:modelValue="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</MkSwitch>
-				</div>
-
-				<div class="_gaps_s">
-					<MkKeyValue>
-						<template #key>{{ i18n.ts.author }}</template>
-						<template #value>{{ plugin.author }}</template>
-					</MkKeyValue>
-					<MkKeyValue>
-						<template #key>{{ i18n.ts.description }}</template>
-						<template #value>{{ plugin.description }}</template>
-					</MkKeyValue>
-					<MkKeyValue>
-						<template #key>{{ i18n.ts.permission }}</template>
-						<template #value>
-							<ul style="margin-top: 0; margin-bottom: 0;">
-								<li v-for="permission in plugin.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
-								<li v-if="!plugin.permissions || plugin.permissions.length === 0">{{ i18n.ts.none }}</li>
-							</ul>
-						</template>
-					</MkKeyValue>
-				</div>
-
-				<div class="_buttons">
-					<MkButton v-if="plugin.config" inline @click="config(plugin)"><i class="ti ti-settings"></i> {{ i18n.ts.settings }}</MkButton>
-					<MkButton inline danger @click="uninstall(plugin)"><i class="ti ti-trash"></i> {{ i18n.ts.uninstall }}</MkButton>
-				</div>
-
-				<MkFolder>
-					<template #icon><i class="ti ti-terminal-2"></i></template>
-					<template #label>{{ i18n.ts._plugin.viewLog }}</template>
-
-					<div class="_gaps_s">
+<SearchMarker path="/settings/plugin" :label="i18n.ts.plugins" :keywords="['plugin']" icon="ti ti-plug">
+	<div class="_gaps_m">
+		<FormLink to="/settings/plugin/install"><template #icon><i class="ti ti-download"></i></template>{{ i18n.ts._plugin.install }}</FormLink>
+
+		<FormSection>
+			<template #label>{{ i18n.ts.manage }}</template>
+			<div class="_gaps_s">
+				<MkFolder v-for="plugin in plugins" :key="plugin.installId">
+					<template #icon><i class="ti ti-plug"></i></template>
+					<template #suffix>
+						<i v-if="plugin.active" class="ti ti-player-play" style="color: var(--MI_THEME-accent);"></i>
+						<i v-else class="ti ti-player-pause" style="opacity: 0.7;"></i>
+					</template>
+					<template #label>
+						<div :style="plugin.active ? '' : 'opacity: 0.7;'">
+							{{ plugin.name }}
+							<span style="margin-left: 1em; opacity: 0.7;">v{{ plugin.version }}</span>
+						</div>
+					</template>
+					<template #caption>
+						{{ plugin.description }}
+					</template>
+					<template #footer>
 						<div class="_buttons">
-							<MkButton inline @click="copy(pluginLogs.get(plugin.id)?.join('\n'))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+							<MkButton v-if="plugin.config" inline @click="config(plugin)"><i class="ti ti-settings"></i> {{ i18n.ts.settings }}</MkButton>
+							<MkButton inline danger @click="uninstall(plugin)"><i class="ti ti-trash"></i> {{ i18n.ts.uninstall }}</MkButton>
 						</div>
+					</template>
 
-						<MkCode :code="pluginLogs.get(plugin.id)?.join('\n') ?? ''"/>
-					</div>
-				</MkFolder>
-
-				<MkFolder>
-					<template #icon><i class="ti ti-code"></i></template>
-					<template #label>{{ i18n.ts._plugin.viewSource }}</template>
+					<div class="_gaps_m">
+						<div class="_gaps_s">
+							<span style="display: flex; align-items: center;"><b>{{ plugin.name }}</b><span style="margin-left: auto;">v{{ plugin.version }}</span></span>
+							<MkSwitch :modelValue="plugin.active" @update:modelValue="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</MkSwitch>
+						</div>
 
-					<div class="_gaps_s">
-						<div class="_buttons">
-							<MkButton inline @click="copy(plugin.src)"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+						<div class="_gaps_s">
+							<MkKeyValue>
+								<template #key>{{ i18n.ts.author }}</template>
+								<template #value>{{ plugin.author }}</template>
+							</MkKeyValue>
+							<MkKeyValue>
+								<template #key>{{ i18n.ts.description }}</template>
+								<template #value>{{ plugin.description }}</template>
+							</MkKeyValue>
+							<MkKeyValue>
+								<template #key>{{ i18n.ts.permission }}</template>
+								<template #value>
+									<ul style="margin-top: 0; margin-bottom: 0;">
+										<li v-for="permission in plugin.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
+										<li v-if="!plugin.permissions || plugin.permissions.length === 0">{{ i18n.ts.none }}</li>
+									</ul>
+								</template>
+							</MkKeyValue>
 						</div>
 
-						<MkCode :code="plugin.src ?? ''" lang="is"/>
+						<MkFolder>
+							<template #icon><i class="ti ti-terminal-2"></i></template>
+							<template #label>{{ i18n.ts._plugin.viewLog }}</template>
+
+							<div class="_gaps_s">
+								<div class="_buttons">
+									<MkButton inline @click="copy(pluginLogs.get(plugin.installId)?.join('\n'))"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+								</div>
+
+								<MkCode :code="pluginLogs.get(plugin.installId)?.join('\n') ?? ''"/>
+							</div>
+						</MkFolder>
+
+						<MkFolder>
+							<template #icon><i class="ti ti-code"></i></template>
+							<template #label>{{ i18n.ts._plugin.viewSource }}</template>
+
+							<div class="_gaps_s">
+								<div class="_buttons">
+									<MkButton inline @click="copy(plugin.src)"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
+								</div>
+
+								<MkCode :code="plugin.src ?? ''" lang="ais"/>
+							</div>
+						</MkFolder>
 					</div>
 				</MkFolder>
 			</div>
-		</div>
-	</FormSection>
-</div>
+		</FormSection>
+	</div>
+</SearchMarker>
 </template>
 
 <script lang="ts" setup>
@@ -83,19 +103,16 @@ import MkFolder from '@/components/MkFolder.vue';
 import MkKeyValue from '@/components/MkKeyValue.vue';
 import * as os from '@/os.js';
 import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
-import { ColdDeviceStorage } from '@/store.js';
 import { unisonReload } from '@/scripts/unison-reload.js';
 import { i18n } from '@/i18n.js';
 import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { pluginLogs } from '@/plugin.js';
+import { changePluginActive, configPlugin, pluginLogs, uninstallPlugin } from '@/plugin.js';
+import { prefer } from '@/preferences.js';
 
-const plugins = ref(ColdDeviceStorage.get('plugins'));
+const plugins = prefer.r.plugins;
 
 async function uninstall(plugin) {
-	ColdDeviceStorage.set('plugins', plugins.value.filter(x => x.id !== plugin.id));
-	await os.apiWithDialog('i/revoke-token', {
-		token: plugin.token,
-	});
+	await uninstallPlugin(plugin);
 	nextTick(() => {
 		unisonReload();
 	});
@@ -106,30 +123,15 @@ function copy(text) {
 	os.success();
 }
 
-// TODO: この処理をstore側にactionとして移動し、設定画面を開くAiScriptAPIを実装できるようにする
 async function config(plugin) {
-	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;
-
-	const coldPlugins = ColdDeviceStorage.get('plugins');
-	coldPlugins.find(p => p.id === plugin.id)!.configData = result;
-	ColdDeviceStorage.set('plugins', coldPlugins);
-
+	await configPlugin(plugin);
 	nextTick(() => {
 		location.reload();
 	});
 }
 
 function changeActive(plugin, active) {
-	const coldPlugins = ColdDeviceStorage.get('plugins');
-	coldPlugins.find(p => p.id === plugin.id)!.active = active;
-	ColdDeviceStorage.set('plugins', coldPlugins);
-
+	changePluginActive(plugin, active);
 	nextTick(() => {
 		location.reload();
 	});
-- 
cgit v1.2.3-freya

