Skip to content

Commit

Permalink
feat(manager): support edit config
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jun 2, 2024
1 parent 89a15b8 commit 0ee56de
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 55 deletions.
43 changes: 18 additions & 25 deletions plugins/manager/client/components/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@
{{ currentEntry.label || currentEntry.name }}
</span>
<span class="divider"></span>
<el-popover popper-class="k-menu">
<el-popover popper-class="k-menu" v-model:visible="visible">
<template #reference>
<span class="nav-button">
<span class="flex items-center cursor-pointer h-full">
<span>{{ currentRoute!.name }}</span>
<svg class="h-4 ml-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<svg class="h-4 ml-2 transition" :class="{ 'rotate-90': visible }" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path fill="currentColor" d="M384 192v640l384-320.064z"></path>
</svg>
</span>
</template>
<div
v-for="route in ctx.manager.routes"
class="k-menu-item pl-8"
@click="gotoRoute(route)"
>
<span class="absolute left-3 top-0 bottom-0 flex items-center" v-if="route === currentRoute">
<span class="w-6px h-6px rounded bg-current"></span>
</span>
<span>{{ route.name }}</span>
</div>
<template v-for="route in ctx.manager.routes">
<div
v-if="!route.hidden?.(currentEntry)"
class="k-menu-item pl-8"
@click="gotoRoute(route)"
>
<span class="absolute left-3 top-0 bottom-0 flex items-center" v-if="route === currentRoute">
<span class="w-6px h-6px rounded bg-current"></span>
</span>
<span>{{ route.name }}</span>
</div>
</template>
</el-popover>
</template>
</template>
Expand Down Expand Up @@ -76,6 +78,7 @@ const currentEntry = computed(() => ctx.manager.currentEntry)
const currentRoute = computed(() => ctx.manager.currentRoute)
const local = computed(() => ctx.manager.data.value.packages[ctx.manager.currentEntry?.name!])
const visible = ref(false)
const tree = ref<InstanceType<typeof TreeView>>()
ctx.define('config.tree', currentEntry)
Expand Down Expand Up @@ -122,18 +125,8 @@ function gotoRoute(route: SubRoute) {
}
}
.nav-button {
display: flex;
align-items: center;
cursor: pointer;
height: 100%;
}
.nav-menu-item {
transition: all 0.3s ease;
&:hover {
background-color: var(--k-hover-bg);
}
svg.rotate-90 {
transform: rotate(90deg);
}
</style>
23 changes: 15 additions & 8 deletions plugins/manager/client/components/tree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
<div class="label" :title="getLabel(node)">
{{ getLabel(node) }}
</div>
<!-- FIXME: subpath, relative, etc. -->
<div class="right">
<span class="status-light" :class="getStatusClass(node.data.status)"></span>
<span class="status-light" :class="getStatusClass(node.data)"></span>
</div>
</div>
</el-tree>
Expand All @@ -42,7 +41,7 @@ import { useRoute } from 'vue-router'
import type { ElScrollbar, ElTree } from 'element-plus'
import type { FilterNodeMethodFunction, TreeOptionProps } from 'element-plus/es/components/tree/src/tree.type'
import type TreeNode from 'element-plus/es/components/tree/src/model/node'
import { send, router, useContext, useMenu } from '@cordisjs/client'
import { send, router, useContext, useMenu, deepEqual } from '@cordisjs/client'
import { getStatusClass } from '../utils'
import { EntryData } from '../../src'
Expand Down Expand Up @@ -143,11 +142,15 @@ function handleDrop(source: EntryNode, target: EntryNode, position: 'before' | '
const optionProps: TreeOptionProps = {
class(tree: any, node) {
const data = tree as EntryData
const entry = tree as EntryData
const words: string[] = []
if (data.isGroup) words.push('is-group')
if (!data.isGroup && !(data.name in ctx.manager.data.value.packages)) words.push('is-disabled')
if (data.id === ctx.manager.currentEntry?.id) words.push('is-active')
if (entry.isGroup) words.push('is-group')
if (!entry.isGroup && !(entry.name in ctx.manager.data.value.packages)) words.push('not-found')
if (entry.id === ctx.manager.currentEntry?.id) words.push('is-active')
const change = ctx.manager.changes[entry.id]
if (!deepEqual(change.config, entry.config)) {
words.push('is-edited')
}
return words.join(' ')
},
}
Expand Down Expand Up @@ -179,11 +182,15 @@ watch(keyword, (val) => {
}
.el-tree-node {
&.is-edited > .el-tree-node__content {
color: var(--warning);
}
&.is-group > .el-tree-node__content {
font-weight: bold;
}
&.is-disabled {
&.not-found {
.el-tree-node__content .status-light {
display: none;
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/manager/client/dialogs/forks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<table>
<tr v-for="id in plugins.forks[ctx.manager.dialogFork!]" :key="id">
<td class="text-left">
<span class="status-light" :class="getStatusClass(plugins.entries[id].status)"></span>
<span class="status-light" :class="getStatusClass(plugins.entries[id])"></span>
<span class="path">{{ getFullPath(plugins.entries[id]) }}</span>
</td>
<td class="text-right">
Expand Down
40 changes: 30 additions & 10 deletions plugins/manager/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Context, Dict, message, remove, router, Schema, send, Service } from '@cordisjs/client'
import { computed, reactive, ref, Ref } from 'vue'
import { clone, Context, Dict, message, remove, router, Schema, send, Service } from '@cordisjs/client'
import { computed, reactive, ref, Ref, watch } from 'vue'
import type { Data, EntryData } from '../src'
import Settings from './components/index.vue'
import Forks from './dialogs/forks.vue'
Expand Down Expand Up @@ -48,13 +48,16 @@ export interface SubRoute {
path: string
name: string
component: any
hidden?(entry: EntryData): boolean
}

export default class Manager extends Service {
static inject = {
optional: ['manager'],
}

changes = reactive<Dict<Partial<EntryData>>>({})

_dialogFork = ref<string>()
_dialogSelect = ref<EntryData>()
_dialogRemove = ref<EntryData>()
Expand Down Expand Up @@ -156,6 +159,20 @@ export default class Manager extends Service {

constructor(ctx: Context, public data: Ref<Data>) {
super(ctx, 'manager', true)

watch(data, (value) => {
const old = { ...this.changes }
for (const entry of value.entries) {
delete old[entry.id]
this.changes[entry.id] ??= {
config: clone(entry.config),
intercept: clone(entry.intercept),
}
}
for (const key in old) {
delete this.changes[key]
}
}, { immediate: true })
}

start() {
Expand Down Expand Up @@ -204,6 +221,9 @@ export default class Manager extends Service {
path: 'config',
name: '配置',
component: Config,
hidden: ({ name }) => {
return !this.data.value.packages[name]?.runtime?.schema
},
})

this.ctx.menu('config.tree', [{
Expand Down Expand Up @@ -294,11 +314,11 @@ export default class Manager extends Service {
},
})

const checkConfig = (name: string) => {
const schema = this.data.value.packages[name]?.runtime?.schema
const checkConfig = (entry: EntryData) => {
const schema = this.data.value.packages[entry.name]?.runtime?.schema
if (!schema) return true
try {
(new Schema(schema))(config.value)
(new Schema(schema))(this.changes[entry.id].config)
return true
} catch {
message.error('当前配置项不满足约束,请检查配置!')
Expand All @@ -308,10 +328,10 @@ export default class Manager extends Service {

this.ctx.action('config.tree.save', {
shortcut: 'ctrl+s',
disabled: (scope) => !scope?.config?.tree || !['config'].includes(router.currentRoute.value?.meta?.activity?.id!),
disabled: (scope) => !scope.config?.tree,
action: async ({ config: { tree } }) => {
const { disabled } = tree
if (!disabled && !checkConfig(tree.name)) return
if (!disabled && !checkConfig(tree)) return
try {
await execute(tree, disabled || null)
message.success(disabled ? '配置已保存。' : '配置已重载。')
Expand All @@ -325,7 +345,7 @@ export default class Manager extends Service {
disabled: ({ config }) => !config.tree || this.hasCoreDeps(config.tree),
action: async ({ config: { tree } }) => {
const { disabled, name } = tree
if (disabled && !checkConfig(tree.name)) return
if (disabled && !checkConfig(tree)) return
try {
await execute(tree, !disabled || null)
message.success((name === 'group' ? '分组' : '插件') + (disabled ? '已启用。' : '已停用。'))
Expand All @@ -335,11 +355,11 @@ export default class Manager extends Service {
},
})

async function execute(data: EntryData, disabled: true | null) {
const execute = async (data: EntryData, disabled: true | null) => {
await send('manager.config.update', {
id: data.id,
disabled,
config: config.value,
config: this.changes[data.id].config,
})
}
}
Expand Down
12 changes: 3 additions & 9 deletions plugins/manager/client/routes/config.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<k-content v-if="currentEntry && local.runtime?.schema">
<k-form :schema="local.runtime.schema" :initial="currentEntry.config" v-model="config">
<k-form :schema="local.runtime.schema" :initial="currentEntry.config" v-model="ctx.manager.changes[currentEntry.id].config">
</k-form>
</k-content>
<k-empty v-else>
Expand All @@ -10,20 +10,14 @@

<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { clone, useContext, useRpc } from '@cordisjs/client'
import { computed } from 'vue'
import { useContext, useRpc } from '@cordisjs/client'
import { Data } from '../../src'
const ctx = useContext()
const data = useRpc<Data>()
const config = ref()
const currentEntry = computed(() => ctx.manager.currentEntry)
const local = computed(() => data.value.packages[currentEntry.value?.name!])
watch(currentEntry, (value) => {
if (!value) return
config.value = clone(value.config)
}, { immediate: true })
</script>
5 changes: 3 additions & 2 deletions plugins/manager/client/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ScopeStatus } from '@cordisjs/client'
import { nextTick, Ref } from 'vue'
import { EntryData } from '../src'

export function getStatusClass(status?: ScopeStatus) {
switch (status) {
export function getStatusClass(entry: EntryData) {
switch (entry?.status) {
case ScopeStatus.PENDING: return 'pending'
case ScopeStatus.LOADING: return 'loading'
case ScopeStatus.ACTIVE: return 'active'
Expand Down

0 comments on commit 0ee56de

Please sign in to comment.