Skip to content

Commit

Permalink
webui: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Mar 4, 2021
1 parent 293b90d commit fb1559e
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 1 deletion.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ temp
/utsuho

/build/*.js
/packages/plugin-webui

todo.md
yarn.lock
Expand Down
3 changes: 3 additions & 0 deletions packages/koishi-core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export class Context {
}

this.state.children.push(plugin)
this.emit('registry', this.app.registry)
return this
}

Expand All @@ -196,6 +197,7 @@ export class Context {
this.app.registry.delete(plugin)
const index = state.parent.children.indexOf(plugin)
if (index >= 0) state.parent.children.splice(index, 1)
this.emit('registry', this.app.registry)
}

async parallel<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): Promise<Await<ReturnType<EventMap[K]>>[]>
Expand Down Expand Up @@ -471,6 +473,7 @@ export interface EventMap extends SessionEventMap {
'before-command'(argv: Argv): Awaitable<void | string>
'command'(argv: Argv): Awaitable<void>
'middleware'(session: Session): void
'registry'(registry: Map<Plugin, Plugin.State>): void
'before-connect'(): Awaitable<void>
'connect'(): void
'before-disconnect'(): Awaitable<void>
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-webui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugin-webui
47 changes: 47 additions & 0 deletions packages/plugin-webui/client/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<h2>All plugins:</h2>
<ul>
<plugin-view :data="data" v-for="(data, index) in plugins" :key="index"/>
</ul>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import PluginView from './components/plugin-view.vue'
interface State {
name: string
disposable: boolean
children: State[]
}
const plugins = ref<State[]>([])
if (import.meta.hot) {
import.meta.hot.on('registry-update', (data) => {
console.log('registry-update', data)
})
}
onMounted(async () => {
const res = await fetch(KOISHI_SERVER + '/plugins')
const data = await res.json()
plugins.value = data
console.log(data)
})
</script>

<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
</style>
Binary file added packages/plugin-webui/client/assets/koishi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions packages/plugin-webui/client/components/plugin-view.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<li>
<span :class="data.sideEffect ? 'indisposable' : 'disposable'">{{ data.name }}</span>
<ul v-if="data.children.length">
<plugin-view :data="data" v-for="(data, index) in data.children" :key="index" />
</ul>
</li>
</template>

<script setup lang="ts">
import { defineProps } from 'vue'
const { data } = defineProps(['data'])
</script>

<style lang="scss" scoped>
.disposable {
color: green;
}
.indisposable {
color: red;
}
</style>
13 changes: 13 additions & 0 deletions packages/plugin-webui/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="./assets/koishi.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Koishi 控制台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.ts"></script>
</body>
</html>
4 changes: 4 additions & 0 deletions packages/plugin-webui/client/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './app.vue'

createApp(App).mount('#app')
16 changes: 16 additions & 0 deletions packages/plugin-webui/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../../../tsconfig.base",
"compilerOptions": {
"rootDir": ".",
"noEmit": true,
"target": "es2020",
"module": "esnext",
"emitDeclarationOnly": false,
"types": [
"vite/client",
],
},
"include": [
".",
],
}
38 changes: 38 additions & 0 deletions packages/plugin-webui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "koishi-plugin-webui",
"version": "0.1.2",
"description": "Web UI for Koishi",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"author": "Shigma <1700011071@pku.edu.cn>",
"license": "MIT",
"files": [
"dist",
"client"
],
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"repository": {
"type": "git",
"url": "git+https://github.com/koishijs/koishi.git"
},
"bugs": {
"url": "https://github.com/koishijs/koishi/issues"
},
"homepage": "https://github.com/koishijs/koishi#readme",
"peerDependencies": {
"koishi-core": "^3.0.0"
},
"dependencies": {
"vue": "^3.0.6"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.1.4",
"@vue/compiler-sfc": "^3.0.6",
"sass": "^1.32.8",
"vite": "^2.0.3"
}
}
67 changes: 67 additions & 0 deletions packages/plugin-webui/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Context, Plugin } from 'koishi-core'
import { assertProperty } from 'koishi-utils'
import { resolve } from 'path'
import { createServer, ViteDevServer } from 'vite'
import vuePlugin from '@vitejs/plugin-vue'

declare module 'koishi-core' {
interface App {
vite: ViteDevServer
}
}

export interface Config {
port?: number
server?: string
}

export interface PluginData {
name: string
sideEffect: boolean
children: PluginData[]
}

export const name = 'webui'

export function apply(ctx: Context, config: Config = {}) {
const koishiPort = assertProperty(ctx.app.options, 'port')
const { port = 8080, server = `http://localhost:${koishiPort}` } = config

ctx.on('connect', async () => {
const vite = await createServer({
root: resolve(__dirname, '../client'),
plugins: [vuePlugin()],
define: {
KOISHI_SERVER: JSON.stringify(server),
},
})

await vite.listen(port)
ctx.app.vite = vite
})

function traverse(plugin: Plugin): PluginData[] {
const state = ctx.app.registry.get(plugin)
const children = state.children.flatMap(traverse, 1)
if (typeof plugin === 'function' || !plugin?.name) return children
const { name } = plugin, { sideEffect } = state
return [{ name, sideEffect, children }]
}

ctx.router.get('/plugins', (ctx) => {
ctx.set('access-control-allow-origin', '*')
ctx.body = traverse(null)
})

ctx.on('registry', () => {
ctx.app.vite?.ws.send({
type: 'custom',
event: 'registry-update',
data: traverse(null),
})
})

ctx.before('disconnect', async () => {
await ctx.app.vite?.close()
})
}
10 changes: 10 additions & 0 deletions packages/plugin-webui/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "server",
"outDir": "dist",
},
"include": [
"server"
],
}

0 comments on commit fb1559e

Please sign in to comment.