Skip to content

Commit

Permalink
feat(market): on-demand loading for versions
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jun 23, 2023
1 parent e929f57 commit dc1ba28
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 88 deletions.
23 changes: 17 additions & 6 deletions plugins/market/client/components/install.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<span :id="titleId" :class="[titleClass, '']">
{{ active.replace(/(koishi-|^@koishijs\/)plugin-/, '') + (workspace ? ' (工作区)' : '') }}
</span>
<el-select v-if="!workspace" :disabled="workspace" v-model="selectVersion">
<el-select v-if="data" :disabled="workspace" v-model="selectVersion">
<el-option v-for="({ result }, version) in data" :key="version" :value="version">
{{ version }}
<template v-if="version === current">(当前)</template>
Expand All @@ -16,7 +16,11 @@
<p class="danger" v-if="danger">{{ danger }}</p>
<p class="warning" v-if="warning">{{ warning }}</p>

<el-scrollbar v-if="active && !workspace && data[version] && Object.keys(data[version].peers).length">
<div v-if="!data && active && !workspace">
<p>正在加载版本数据……</p>
</div>

<el-scrollbar v-if="data?.[version] && Object.keys(data[version].peers).length">
<table>
<tr>
<td>依赖名称</td>
Expand Down Expand Up @@ -62,7 +66,7 @@
<el-button v-if="current" @click="installDep('')">移除</el-button>
<el-button v-else @click="installDep(version)" :disabled="unchanged">添加</el-button>
</template>
<template v-else>
<template v-else-if="data">
<el-button v-if="current" @click="installDep('')">移除</el-button>
<el-button :type="result" @click="installDep(version)" :disabled="unchanged">
{{ current ? '更新' : '安装' }}
Expand Down Expand Up @@ -107,8 +111,15 @@ const selectVersion = computed({
})
const unchanged = computed(() => version.value === store.dependencies[active.value]?.request)
const current = computed(() => store.dependencies[active.value]?.resolved)
const current = computed(() => store.dependencies?.[active.value]?.resolved)
const local = computed(() => store.packages?.[active.value])
const versions = computed(() => store.registry?.[active.value])
watch(active, (name) => {
if (name && !workspace.value && !versions.value) {
send('market/registry', name)
}
}, { immediate: true })
const workspace = computed(() => {
// workspace plugins: dependencies ? packages √
Expand All @@ -123,7 +134,7 @@ const data = computed(() => {
const danger = computed(() => {
if (workspace.value) return
const deprecated = store.dependencies[active.value]?.versions?.[version.value]?.deprecated
const deprecated = versions.value?.[version.value]?.deprecated
if (deprecated) return deprecated
if (store.market?.data[active.value]?.insecure) {
return '警告:从此插件的最新版本中检测出安全性问题。安装或升级此插件可能导致严重问题。'
Expand Down Expand Up @@ -154,7 +165,7 @@ watch(() => active.value, (value) => {
if (!value) return
version.value = config.value.override[active.value]
|| store.dependencies[active.value]?.request
|| store.market.data[value].version
|| store.market.data[value].package.version
}, { immediate: true })
function* find(target: string, plugins: {}, prefix: string): IterableIterator<[string, boolean]> {
Expand Down
12 changes: 6 additions & 6 deletions plugins/market/client/components/market.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ import { router, store, global } from '@koishijs/client'
import { computed, provide, ref, watch } from 'vue'
import { refresh, active } from '../utils'
import { getSorted, kConfig, MarketFilter, MarketList, MarketSearch } from '@koishijs/market'
import { AnalyzedPackage } from '@koishijs/registry'
import { SearchObject } from '@koishijs/registry'
function installed(data: AnalyzedPackage) {
function installed(data: SearchObject) {
if (store.packages) {
return !!store.packages[data.name]
return !!store.packages[data.package.name]
} else {
return !!store.dependencies?.[data.name]
return !!store.dependencies?.[data.package.name]
}
}
Expand Down Expand Up @@ -86,8 +86,8 @@ watch(prompt, (value) => {
}
}, { deep: true })
function handleClick(data: AnalyzedPackage) {
active.value = data.name
function handleClick(data: SearchObject) {
active.value = data.package.name
}
const menu = computed(() => [refresh.value])
Expand Down
9 changes: 4 additions & 5 deletions plugins/market/client/components/package.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
</td>

<td>
<el-button v-if="local.workspace || local.versions" @click="active = name">修改</el-button>
<template v-else-if="local.invalid">暂不支持</template>
<template v-if="local.invalid">暂不支持</template>
<el-button v-else-if="local.workspace || remote" @click="active = name">修改</el-button>
<template v-else>版本获取失败</template>
</td>
</tr>
Expand All @@ -43,9 +43,8 @@ const props = defineProps({
name: String,
})
const local = computed(() => {
return store.dependencies[props.name]
})
const local = computed(() => store.dependencies[props.name])
const remote = computed(() => store.registry[props.name])
const compare = computed(() => {
if (local.value.invalid) return
Expand Down
3 changes: 2 additions & 1 deletion plugins/market/client/components/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { satisfies } from 'semver'
import { ref, watch } from 'vue'

export function analyzeVersions(name: string) {
const { versions = {} } = store.dependencies[name] || store.market?.data[name]
const versions = store.registry?.[name]
if (!versions) return
return valueMap(versions, (item) => {
const peers = valueMap({ ...item.peerDependencies }, (request, name) => {
const resolved = store.dependencies[name]?.resolved || store.packages?.[name]?.version
Expand Down
4 changes: 2 additions & 2 deletions plugins/market/client/extensions/dependency.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ const getImplements = (name: string) => ({
const getAvailable = (name: string) => Object
.values(store.market.data ?? {})
.filter(data => getImplements(data.name).includes(name))
.map(data => data.name)
.filter(data => getImplements(data.package.name).includes(name))
.map(data => data.package.name)
const available = computed(() => {
const available: Dict<string[]> = {}
Expand Down
8 changes: 4 additions & 4 deletions plugins/market/client/extensions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ export default (ctx: Context) => {
ctx.slot({
type: 'plugin-dependency',
component: Dependency,
when: () => !!(store.market && store.dependencies),
disabled: () => !(store.market && store.dependencies && store.registry),
})

ctx.slot({
type: 'plugin-details',
component: Version,
when: () => !!(store.market && store.dependencies),
disabled: () => !(store.market && store.dependencies && store.registry),
order: 1000,
})

ctx.slot({
type: 'plugin-missing',
component: Missing,
when: () => !!(store.market && store.dependencies),
disabled: () => !(store.market && store.dependencies && store.registry),
})

ctx.slot({
type: 'plugin-select',
component: Select,
when: () => !!store.market,
disabled: () => !store.market,
})
}
29 changes: 15 additions & 14 deletions plugins/market/client/extensions/version.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<template>
<!-- navigation -->
<div class="navigation" v-if="remote">
<div class="navigation" v-if="object">
<a class="el-button" target="_blank"
v-if="remote.links.homepage"
:href="remote.links.homepage"
v-if="object.package.links.homepage"
:href="object.package.links.homepage"
>插件主页</a>
<a class="el-button" target="_blank"
v-if="remote.links.npm && data.local.version"
:href="remote.links.npm + '/v/' + data.local.version"
v-if="object.package.links.npm && data.local.version"
:href="object.package.links.npm + '/v/' + data.local.version"
>当前版本:{{ data.local.version }}</a>
<a class="el-button" target="_blank"
v-if="remote.links.repository"
:href="remote.links.repository"
v-if="object.package.links.repository"
:href="object.package.links.repository"
>存储库</a>
<a class="el-button" target="_blank"
v-if="remote.links.bugs"
:href="remote.links.bugs"
v-if="object.package.links.bugs"
:href="object.package.links.bugs"
>问题反馈</a>
</div>

Expand All @@ -25,8 +25,8 @@
</k-comment>

<!-- deprecated -->
<k-comment v-if="dep?.versions?.[dep?.resolved]?.deprecated" type="danger">
<p>此版本已废弃,请尽快迁移:{{ dep.versions[dep.resolved].deprecated }}</p>
<k-comment v-if="versions?.[dep?.resolved]?.deprecated" type="danger">
<p>此版本已废弃,请尽快迁移:{{ versions[dep.resolved].deprecated }}</p>
</k-comment>

<!-- external -->
Expand All @@ -46,13 +46,14 @@ const props = defineProps<{
data: SettingsData
}>()
const remote = computed(() => store.market.data?.[props.data.name])
const object = computed(() => store.market.data?.[props.data.name])
const dep = computed(() => store.dependencies[props.data.name])
const versions = computed(() => store.registry[props.data.name])
const hasUpdate = computed(() => {
if (!remote.value?.versions || props.data.local.workspace) return
if (!versions.value || props.data.local.workspace) return
try {
return gt(remote.value.version, props.data.local.version)
return gt(object.value.package.version, props.data.local.version)
} catch {}
})
Expand Down
9 changes: 8 additions & 1 deletion plugins/market/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ receive('market/patch', (data) => {
}
})

receive('market/registry', (data) => {
store.registry = {
...store.registry,
...data,
}
})

export default (ctx: Context) => {
ctx.plugin(extensions)

Expand Down Expand Up @@ -61,7 +68,7 @@ export default (ctx: Context) => {
icon: 'activity:deps',
order: 700,
authority: 4,
fields: ['dependencies'],
fields: ['dependencies', 'registry'],
component: Dependencies,
})
}
Expand Down
42 changes: 15 additions & 27 deletions plugins/market/src/node/deps.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,37 @@
import { Context, Dict, Schema } from 'koishi'
import { Context, Dict } from 'koishi'
import { DataService } from '@koishijs/plugin-console'
import { DependencyMetaKey, RemotePackage } from '@koishijs/registry'
import { Dependency } from './installer'
import { throttle } from 'throttle-debounce'

declare module '@koishijs/plugin-console' {
interface Events {
'market/install'(deps: Dict<string>): Promise<number>
class DependencyProvider extends DataService<Dict<Dependency>> {
constructor(public ctx: Context) {
super(ctx, 'dependencies', { authority: 4 })
}
}

class Dependencies extends DataService<Dependencies.Payload> {
constructor(public ctx: Context, public config: Dependencies.Config) {
super(ctx, 'dependencies', { authority: 4 })
async get() {
return this.ctx.installer.getDeps()
}
}

ctx.console.addListener('market/install', async (deps) => {
const code = await ctx.installer.install(deps)
this.refresh()
this.ctx.console.packages?.refresh()
return code
}, { authority: 4 })
class RegistryProvider extends DataService<Dict<Dict<Pick<RemotePackage, DependencyMetaKey>>>> {
constructor(public ctx: Context) {
super(ctx, 'registry', { authority: 4 })
}

stop() {
this.flushData.cancel()
}

flushData = throttle(500, () => {
console.log(this.ctx.installer.tempCache)
this.ctx.console.broadcast('market/registry', this.ctx.installer.tempCache)
this.ctx.installer.tempCache = {}
})

async get(force = false) {
return this.ctx.installer.get(force)
}
}

namespace Dependencies {
export interface Config {}
export const Config: Schema<Config> = Schema.object({})

export interface Payload {
dependencies: Dict<Dependency>
registry: Dict<Dict<Pick<RemotePackage, DependencyMetaKey>>>
async get() {
return this.ctx.installer.fullCache
}
}

export default Dependencies
export { DependencyProvider, RegistryProvider }
29 changes: 24 additions & 5 deletions plugins/market/src/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Context, pick, Schema } from 'koishi'
import { Context, Dict, pick, Schema } from 'koishi'
import { gt } from 'semver'
import { resolve } from 'path'
import Dependencies from './deps'
import { DependencyProvider, RegistryProvider } from './deps'
import Installer from './installer'
import MarketProvider from './market'

export * from '../shared'

export { Dependencies, Installer }
export { Installer }

declare module 'koishi' {
interface Context {
Expand All @@ -18,9 +18,15 @@ declare module 'koishi' {
declare module '@koishijs/plugin-console' {
namespace Console {
interface Services {
dependencies: Dependencies
dependencies: DependencyProvider
registry: RegistryProvider
}
}

interface Events {
'market/install'(deps: Dict<string>): Promise<number>
'market/registry'(name: string): Promise<void>
}
}

export const name = 'market'
Expand Down Expand Up @@ -137,12 +143,25 @@ export function apply(ctx: Context, config: Config) {
})

ctx.using(['console', 'installer'], (ctx) => {
ctx.plugin(Dependencies)
ctx.plugin(DependencyProvider)
ctx.plugin(RegistryProvider)
ctx.plugin(MarketProvider, config.search)

ctx.console.addEntry({
dev: resolve(__dirname, '../../client/index.ts'),
prod: resolve(__dirname, '../../dist'),
})

ctx.console.addListener('market/install', async (deps) => {
const code = await ctx.installer.install(deps)
ctx.console.dependencies?.refresh()
ctx.console.registry?.refresh()
ctx.console.packages?.refresh()
return code
}, { authority: 4 })

ctx.console.addListener('market/registry', async (name) => {
await ctx.installer.getPackage(name)
}, { authority: 4 })
})
}
Loading

0 comments on commit dc1ba28

Please sign in to comment.