Skip to content

Commit

Permalink
refa(commands): migrate to rpc entry API
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 24, 2024
1 parent 3e11380 commit 3637f6b
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 134 deletions.
23 changes: 20 additions & 3 deletions plugins/commands/client/commands.vue
Expand Up @@ -26,7 +26,7 @@
<el-tree
ref="tree"
:draggable="true"
:data="store.commands"
:data="data"
:props="{ label: 'name', class: getClass }"
:filter-node-method="filterNode"
:default-expand-all="true"
Expand Down Expand Up @@ -111,17 +111,19 @@
<script lang="ts" setup>
import { clone, Dict, pick, Schema, send, store, valueMap } from '@koishijs/client'
import { clone, Dict, pick, Schema, send, store, useRpc, valueMap } from '@koishijs/client'
import { useRoute, useRouter } from 'vue-router'
import { computed, nextTick, onActivated, ref, watch } from 'vue'
import { CommandData, CommandState } from '@koishijs/plugin-commands'
import {} from '@koishijs/plugin-locales'
import {} from '@koishijs/plugin-config'
import { commands, createSchema } from './utils'
import { createSchema } from './utils'
const route = useRoute()
const router = useRouter()
const data = useRpc<CommandData[]>()
const inputEl = ref()
const title = ref('')
const alias = ref('')
Expand All @@ -134,6 +136,21 @@ const schema = ref<{
options: Dict<Schema>
}>()
function getCommands(data: CommandData[]) {
const result: CommandData[] = []
for (const item of data) {
result.push(item)
if (!item.children) continue
result.push(...getCommands(item.children))
}
return result
}
const commands = computed<Dict<CommandData>>(() => {
if (!data.value) return {}
return Object.fromEntries(getCommands(data.value).map((item) => [item.name, item]))
})
const aliases = computed(() => {
return Object.values(commands.value).flatMap(command => command.override.aliases)
})
Expand Down
1 change: 0 additions & 1 deletion plugins/commands/client/index.ts
Expand Up @@ -20,7 +20,6 @@ export default (ctx: Context) => {
icon: 'activity:commands',
order: 500,
authority: 4,
fields: ['commands'],
component: Commands,
})

Expand Down
11 changes: 7 additions & 4 deletions plugins/commands/client/locales.vue
@@ -1,5 +1,5 @@
<template>
<div v-if="active && active.startsWith('commands.') && store.commands" class="navigation flex flex-wrap gap-x-4 gap-y-2 my-8">
<div v-if="active && active.startsWith('commands.') && data" class="navigation flex flex-wrap gap-x-4 gap-y-2 my-8">
<router-link
class="el-button"
:to="'/commands/' + active.slice(9).replace(/\./, '/')"
Expand All @@ -9,10 +9,13 @@

<script lang="ts" setup>
import { store } from '@koishijs/client'
import { inject, Computed } from 'vue'
import { useRpc } from '@koishijs/client'
import { inject, ComputedRef } from 'vue'
import { CommandData } from '../lib';
const active = inject<Computed<string>>('locale:prefix')
const active = inject<ComputedRef<string>>('locale:prefix')
const data = useRpc<CommandData[]>()
</script>

Expand Down
24 changes: 18 additions & 6 deletions plugins/commands/client/settings.vue
@@ -1,8 +1,8 @@
<template>
<k-comment type="success" v-if="data.length">
<k-comment type="success" v-if="list.length">
<p>此插件提供了下列指令:</p>
<ul>
<li v-for="item in data" :key="item.name">
<li v-for="item in list" :key="item.name">
<router-link :to="'/commands/' + item.name.replace(/\./g, '/')">{{ item.name }}</router-link>
</li>
</ul>
Expand All @@ -12,17 +12,29 @@
<script lang="ts" setup>
import { computed, inject } from 'vue'
import { commands } from './utils'
import { CommandData } from '../lib'
import { useRpc } from '@koishijs/client'
const current: any = inject('manager.settings.current')
const data = computed(() => {
return Object
.values(commands.value)
const data = useRpc<CommandData[]>()
const list = computed(() => {
return getCommands(data.value)
.filter(item => item.paths.includes(current.value.path))
.sort((a, b) => a.name.localeCompare(b.name))
})
function getCommands(data: CommandData[]) {
const result: CommandData[] = []
for (const item of data) {
result.push(item)
if (!item.children) continue
result.push(...getCommands(item.children))
}
return result
}
</script>

<style lang="scss" scoped>
Expand Down
19 changes: 1 addition & 18 deletions plugins/commands/client/utils.ts
@@ -1,21 +1,4 @@
import { computed } from 'vue'
import { Dict, Schema, store } from '@koishijs/client'
import { CommandData } from '@koishijs/plugin-commands'

function getCommands(data: CommandData[]) {
const result: CommandData[] = []
for (const item of data) {
result.push(item)
if (!item.children) continue
result.push(...getCommands(item.children))
}
return result
}

export const commands = computed<Dict<CommandData>>(() => {
if (!store.commands) return {}
return Object.fromEntries(getCommands(store.commands).map((item) => [item.name, item]))
})
import { Schema, store } from '@koishijs/client'

export function assignSchema(schema: Schema, value: any) {
if (['intersect', 'union'].includes(schema.type)) {
Expand Down
98 changes: 0 additions & 98 deletions plugins/commands/src/console.ts

This file was deleted.

94 changes: 90 additions & 4 deletions plugins/commands/src/index.ts
@@ -1,8 +1,17 @@
import { Argv, clone, Command, Context, deepEqual, Dict, filterKeys, mapValues, remove, Schema } from 'koishi'
import ConsoleExtension from './console'
import CommandExtension from './command'

export * from './console'
import { resolve } from 'path'
import { Entry } from '@koishijs/console'

declare module '@koishijs/console' {
interface Events {
'command/create'(name: string): void
'command/remove'(name: string): void
'command/update'(name: string, config: Pick<CommandState, 'config' | 'options'>): void
'command/teleport'(name: string, parent: string): void
'command/aliases'(name: string, aliases: Dict<false | Command.Alias>): void
}
}

interface Override extends Partial<CommandState> {
name?: string
Expand Down Expand Up @@ -49,10 +58,18 @@ export class CommandManager {
static schema: Schema<Dict<string | Config>, Dict<Config>> = Schema.dict(Config).hidden()

private _tasks: Dict<() => void> = Object.create(null)
private _cache: CommandData[]
private entry: Entry<CommandData[]>
private refresh: () => void

public snapshots: Dict<Snapshot> = Object.create(null)

constructor(private ctx: Context, private config: Dict<Config>) {
this.refresh = this.ctx.debounce(() => {
this._cache = null
this.entry?.refresh()
}, 0)

for (const key in config) {
const command = ctx.$commander.get(key, true)
if (command) {
Expand Down Expand Up @@ -87,6 +104,7 @@ export class CommandManager {
if (!parent || parent === cmd) continue
this._teleport(command, parent)
}
this.refresh()
})

ctx.on('dispose', () => {
Expand All @@ -101,8 +119,9 @@ export class CommandManager {
}
}, true)

ctx.plugin(ConsoleExtension, this)
ctx.plugin(CommandExtension, this)

this.installWebUI()
}

init(command: Command) {
Expand Down Expand Up @@ -247,6 +266,8 @@ export class CommandManager {
...target._aliases,
...override.aliases,
})

this.refresh()
}

write(...commands: Command[]) {
Expand Down Expand Up @@ -279,6 +300,71 @@ export class CommandManager {
}
this.ctx.scope.update(this.config, false)
}

installWebUI() {
this.ctx.inject(['console'], (ctx) => {
ctx.on('dispose', () => this.entry = undefined)

this.entry = ctx.console.addEntry(process.env.KOISHI_BASE ? [
process.env.KOISHI_BASE + '/dist/index.js',
process.env.KOISHI_BASE + '/dist/style.css',
] : process.env.KOISHI_ENV === 'browser' ? [
// @ts-ignore
import.meta.url.replace(/\/src\/[^/]+$/, '/client/index.ts'),
] : {
dev: resolve(__dirname, '../client/index.ts'),
prod: resolve(__dirname, '../dist'),
}, () => this._cache ||= this.traverse(this.ctx.$commander._commandList.filter(cmd => !cmd.parent)))

ctx.console.addListener('command/update', (name, config) => {
const { command } = this.ensure(name)
this.update(command, config, true)
this.refresh()
}, { authority: 4 })

ctx.console.addListener('command/teleport', (name, parent) => {
const { command } = this.ensure(name)
this.teleport(command, parent, true)
this.refresh()
}, { authority: 4 })

ctx.console.addListener('command/aliases', (name, aliases) => {
const { command } = this.ensure(name)
this.alias(command, aliases, true)
this.refresh()
}, { authority: 4 })

ctx.console.addListener('command/create', (name) => {
this.create(name)
this.refresh()
}, { authority: 4 })

ctx.console.addListener('command/remove', (name) => {
this.remove(name)
this.refresh()
}, { authority: 4 })
})
}

traverse(commands: Command[]): CommandData[] {
return commands.map((command) => ({
name: command.name,
children: this.traverse(command.children),
create: this.snapshots[command.name]?.create,
initial: this.snapshots[command.name]?.initial || { aliases: command._aliases, config: command.config, options: command._options },
override: this.snapshots[command.name]?.override || { aliases: command._aliases, config: null, options: {} },
paths: this.ctx.get('loader')?.paths(command.ctx.scope) || [],
})).sort((a, b) => a.name.localeCompare(b.name))
}
}

export interface CommandData {
create: boolean
name: string
paths: string[]
children: CommandData[]
initial: CommandState
override: CommandState
}

export default CommandManager

0 comments on commit 3637f6b

Please sign in to comment.