Skip to content

Commit

Permalink
feat(manager): support add plugin under group
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jun 7, 2022
1 parent bcf3e1a commit 36f4ed8
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 101 deletions.
8 changes: 4 additions & 4 deletions plugins/frontend/manager/client/settings/global.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<h1 class="config-header">
全局设置
<k-button solid @click="send('manager/app-reload', data.config)">应用配置</k-button>
<k-button solid @click="send('manager/app-reload', current.config)">应用配置</k-button>
</h1>
<k-form :schema="store.packages[''].schema" :initial="data.config" v-model="config"></k-form>
<k-form :schema="store.packages[''].schema" :initial="current.config" v-model="config"></k-form>
</template>

<script lang="ts" setup>
Expand All @@ -13,12 +13,12 @@ import { ref, watch } from 'vue'
import { Tree } from './utils'
const props = defineProps<{
data: Tree
current: Tree
}>()
const config = ref()
watch(() => props.data.config, (value) => {
watch(() => props.current.config, (value) => {
config.value = clone(value)
}, { immediate: true })
Expand Down
25 changes: 20 additions & 5 deletions plugins/frontend/manager/client/settings/group.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
<template>
<h1 class="config-header">
{{ data.label }}
{{ current.label }}
<k-button solid @click="addPlugin">添加插件</k-button>
<!-- <k-button solid @click="execute('unload')">添加分组</k-button> -->
</h1>
</template>

<script lang="ts" setup>
import { send, store, clone } from '@koishijs/client'
import { ref, watch } from 'vue'
import { Tree } from './utils'
import { useRouter } from 'vue-router'
import { Tree, plugins } from './utils'
const router = useRouter()
const props = defineProps<{
data: Tree
current: Tree
}>()
function addPlugin() {
const tree: Tree = {
label: '',
path: props.current.path ? props.current.path + '/$' : '$',
config: {},
disabled: true,
}
props.current.children.push(tree)
plugins.value.paths[tree.path] = tree
router.replace('/plugins/' + tree.path)
}
</script>
28 changes: 17 additions & 11 deletions plugins/frontend/manager/client/settings/index.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
<template>
<k-card-aside class="page-settings">
<template #aside>
<plugin-select v-model="path"></plugin-select>
<tree-view v-model="path"></tree-view>
</template>
<k-content class="plugin-view">
<global-settings v-if="current.path === '@global'" :data="current"></global-settings>
<group-settings v-else-if="current.children" :data="current"></group-settings>
<plugin-settings v-else :current="current"></plugin-settings>
</k-content>
<keep-alive>
<k-content class="plugin-view" :key="path">
<global-settings v-if="current.path === '@global'" :current="current"></global-settings>
<group-settings v-else-if="current.children" :current="current"></group-settings>
<plugin-settings v-else :current="current"></plugin-settings>
</k-content>
</keep-alive>
</k-card-aside>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { plugins } from './utils'
import GlobalSettings from './global.vue'
import GroupSettings from './group.vue'
import PluginSelect from './select.vue'
import TreeView from './tree.vue'
import PluginSettings from './plugin.vue'
function join(source: string | string[]) {
Expand All @@ -31,15 +33,19 @@ const router = useRouter()
const path = computed<string>({
get() {
const name = join(route.params.name)
return name in plugins.value.map ? name : '@global'
return name in plugins.value.paths ? name : '@global'
},
set(name) {
if (!(name in plugins.value.map)) name = '@global'
if (!(name in plugins.value.paths)) name = '@global'
router.replace('/plugins/' + name)
},
})
const current = computed(() => plugins.value.map[path.value])
const current = ref(plugins.value.paths[path.value])
watch(() => path.value, () => {
current.value = plugins.value.paths[path.value]
})
</script>

Expand Down
112 changes: 63 additions & 49 deletions plugins/frontend/manager/client/settings/plugin.vue
Original file line number Diff line number Diff line change
@@ -1,67 +1,81 @@
<template>
<h1 class="config-header">
{{ data.shortname }}
<span class="version">({{ data.workspace ? '工作区' : data.version }})</span>
<template v-if="data.id">
<template v-if="current.path.endsWith('$')">
<el-select v-model="current.label" placeholder="插件选择">
<el-option
v-for="value in Object.values(store.packages).slice(1)"
:key="value.name"
:label="value.shortname"
:value="value.shortname"
></el-option>
</el-select>
</template>
<template v-else>
{{ data.shortname }}
<span class="version">({{ data.workspace ? '工作区' : data.version }})</span>
</template>
<template v-if="!current.disabled">
<k-button solid type="error" @click="execute('unload')">停用插件</k-button>
<k-button solid :disabled="env.invalid" @click="execute('reload')">重载配置</k-button>
</template>
<template v-else>
<template v-else-if="name">
<k-button solid :disabled="env.invalid" @click="execute('reload')">启用插件</k-button>
<k-button solid @click="execute('unload')">保存配置</k-button>
</template>
</h1>

<!-- latest -->
<k-comment v-if="hasUpdate">
当前的插件版本不是最新,<router-link to="/dependencies">点击前往依赖管理</router-link>。
</k-comment>
<template v-if="name">
<!-- latest -->
<k-comment v-if="hasUpdate">
当前的插件版本不是最新,<router-link to="/dependencies">点击前往依赖管理</router-link>。
</k-comment>

<!-- external -->
<k-comment type="warning" v-if="!data.workspace && !store.dependencies[name]">
尚未将当前插件列入依赖,<a @click="send('market/patch', name, data.version)">点击添加</a>。
</k-comment>
<!-- external -->
<k-comment type="warning" v-if="!data.workspace && !store.dependencies[name]">
尚未将当前插件列入依赖,<a @click="send('market/patch', name, data.version)">点击添加</a>。
</k-comment>

<!-- impl -->
<template v-for="name in env.impl" :key="name">
<k-comment v-if="name in store.services && !data.id" type="warning">
此插件将会提供 {{ name }} 服务,但此服务已被其他插件实现。
<!-- impl -->
<template v-for="name in env.impl" :key="name">
<k-comment v-if="name in store.services && !data.id" type="warning">
此插件将会提供 {{ name }} 服务,但此服务已被其他插件实现。
</k-comment>
<k-comment v-else :type="data.id ? 'success' : 'primary'">
此插件{{ data.id ? '提供了' : '将会提供' }} {{ name }} 服务。
</k-comment>
</template>

<!-- using -->
<k-comment
v-for="({ fulfilled, required, available, name }) in env.using" :key="name"
:type="fulfilled ? 'success' : required ? 'error' : 'primary'">
{{ required ? '必需' : '可选' }}服务:{{ name }}
{{ fulfilled ? '(已加载)' : '(未加载,启用下列任一插件可实现此服务)' }}
<template v-if="!fulfilled" #body>
<ul>
<li v-for="name in available">
<k-dep-link :name="name"></k-dep-link> (点击{{ name in store.packages ? '配置' : '添加' }})
</li>
</ul>
</template>
</k-comment>
<k-comment v-else :type="data.id ? 'success' : 'primary'">
此插件{{ data.id ? '提供了' : '将会提供' }} {{ name }} 服务。

<!-- dep -->
<k-comment
v-for="({ fulfilled, required, local, name }) in env.deps" :key="name"
:type="fulfilled ? 'success' : required ? 'error' : 'primary'">
{{ required ? '必需' : '可选' }}依赖:<k-dep-link :name="name"></k-dep-link>
({{ local ? `${fulfilled ? '已' : '未'}启用` : '未安装,点击添加' }})
</k-comment>
</template>

<!-- using -->
<k-comment
v-for="({ fulfilled, required, available, name }) in env.using" :key="name"
:type="fulfilled ? 'success' : required ? 'error' : 'primary'">
{{ required ? '必需' : '可选' }}服务:{{ name }}
{{ fulfilled ? '(已加载)' : '(未加载,启用下列任一插件可实现此服务)' }}
<template v-if="!fulfilled" #body>
<ul>
<li v-for="name in available">
<k-dep-link :name="name"></k-dep-link> (点击{{ name in store.packages ? '配置' : '添加' }})
</li>
</ul>
</template>
</k-comment>

<!-- dep -->
<k-comment
v-for="({ fulfilled, required, local, name }) in env.deps" :key="name"
:type="fulfilled ? 'success' : required ? 'error' : 'primary'">
{{ required ? '必需' : '可选' }}依赖:<k-dep-link :name="name"></k-dep-link>
({{ local ? `${fulfilled ? '已' : '未'}启用` : '未安装,点击添加' }})
</k-comment>

<!-- schema -->
<k-comment v-if="!data.schema" type="warning">
此插件未声明配置项,这可能并非预期行为{{ hint }}。
</k-comment>
<k-form :schema="data.schema" :initial="current.config" v-model="config">
<template #hint>{{ hint }}</template>
</k-form>
<!-- schema -->
<k-comment v-if="!data.schema" type="warning">
此插件未声明配置项,这可能并非预期行为{{ hint }}。
</k-comment>
<k-form :schema="data.schema" :initial="current.config" v-model="config">
<template #hint>{{ hint }}</template>
</k-form>
</template>
</template>

<script lang="ts" setup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
<k-icon name="search"></k-icon>
</el-input>
</div>
<k-tab-item class="k-tab-group-title" label="@global" v-model="model">
全局设置
</k-tab-item>
<k-tab-item class="k-tab-group-title" label="@global" v-model="model">全局设置</k-tab-item>
<el-tree
:data="plugins.data"
ref="tree"
:data="[plugins.root]"
:draggable="true"
:default-expand-all="true"
:expand-on-click-node="false"
default-expand-all draggable
:filter-node-method="filterNode"
:props="{ class: getClass }"
:allow-drag="allowDrag"
:allow-drop="allowDrop"
Expand All @@ -25,8 +26,8 @@

<script lang="ts" setup>
import { ref, computed, onActivated, nextTick } from 'vue'
import { store, send } from '@koishijs/client'
import { ref, computed, onActivated, nextTick, watch } from 'vue'
import { send } from '@koishijs/client'
import { Tree, plugins } from './utils'
const props = defineProps<{
Expand All @@ -40,8 +41,12 @@ const model = computed({
set: val => emits('update:modelValue', val),
})
function allowDrag(node: Tree) {
return node.path !== ''
function filterNode(value: string, data: Tree) {
return data.label.includes(keyword.value)
}
function allowDrag(node: Node) {
return node.data.path !== ''
}
interface Node {
Expand Down Expand Up @@ -70,8 +75,8 @@ function handleDrop(source: Node, target: Node, position: 'before' | 'after' | '
segments2.push(segments1.pop())
const newPath = source.data.path = segments2.join('/')
if (oldPath === newPath) return
plugins.value.map[newPath] = plugins.value.map[oldPath]
delete plugins.value.map[oldPath]
plugins.value.paths[newPath] = plugins.value.paths[oldPath]
delete plugins.value.paths[oldPath]
emits('update:modelValue', newPath)
}
Expand All @@ -83,16 +88,14 @@ function getClass(tree: Tree) {
return words.join(' ')
}
const packages = computed(() => {
return Object.fromEntries(Object.values(store.packages)
.filter(data => data.shortname.includes(keyword.value))
.sort((a, b) => a.shortname < b.shortname ? -1 : 1)
.map(data => [data.name, data]))
})
const root = ref<{ $el: HTMLElement }>(null)
const tree = ref(null)
const keyword = ref('')
watch(keyword, (val) => {
tree.value.filter(val)
})
onActivated(async () => {
const container = root.value.$el
await nextTick()
Expand Down
29 changes: 15 additions & 14 deletions plugins/frontend/manager/client/settings/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dict } from 'koishi'
import { computed } from 'vue'
import { computed, reactive, watch } from 'vue'
import { PackageJson } from '@koishijs/market'
import { MarketProvider } from '@koishijs/plugin-manager'
import { store } from '@koishijs/client'
Expand Down Expand Up @@ -104,7 +104,7 @@ export interface Tree {
children?: Tree[]
}

function getTree(prefix: string, plugins: any, map: Dict<Tree>): Tree[] {
function getTree(prefix: string, plugins: any): Tree[] {
const trees: Tree[] = []
for (const key in plugins) {
if (key.startsWith('$')) continue
Expand All @@ -117,30 +117,31 @@ function getTree(prefix: string, plugins: any, map: Dict<Tree>): Tree[] {
}
if (key.startsWith('+')) {
node.label = '分组:' + label.slice(1)
node.children = getTree(path + '/', config, map)
node.children = getTree(path + '/', config)
}
map[path] = node
trees.push(node)
}
return trees
}

export const plugins = computed(() => {
const map: Dict<Tree> = {
const root: Tree = {
label: '所有插件',
path: '',
config: store.config.plugins,
children: getTree('', store.config.plugins),
}
const paths: Dict<Tree> = {
'@global': {
label: '全局设置',
path: '@global',
config: store.config,
},
'': {
label: '所有插件',
path: '',
config: store.config.plugins,
},
}
map[''].children = getTree('', store.config.plugins, map)
return {
map,
data: [map['']],
function traverse(tree: Tree) {
paths[tree.path] = tree
tree.children?.forEach(traverse)
}
traverse(root)
return { root, paths }
})

0 comments on commit 36f4ed8

Please sign in to comment.