mirror of
https://github.com/rubickCenter/rubick
synced 2026-03-06 13:53:40 +08:00
ref: ini
This commit is contained in:
18
src/main/api.js
Normal file
18
src/main/api.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import {app} from 'electron';
|
||||
export default {
|
||||
getPath(arg) {
|
||||
return app.getPath(arg.name);
|
||||
},
|
||||
hideMainWindow(arg, mainWindow) {
|
||||
mainWindow.hide();
|
||||
},
|
||||
showMainWindow(arg, mainWindow) {
|
||||
mainWindow.show();
|
||||
},
|
||||
onPluginEnter(arg) {
|
||||
return arg
|
||||
},
|
||||
setExpendHeight({height}, mainWindow) {
|
||||
mainWindow.setSize(788, height);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import {BrowserWindow, globalShortcut, ipcMain} from 'electron';
|
||||
import {globalShortcut, ipcMain} from 'electron';
|
||||
import Api from './api';
|
||||
|
||||
export default function init(mainWindow) {
|
||||
ipcMain.on('changeWindowSize', (event, arg) => {
|
||||
@@ -12,6 +13,11 @@ export default function init(mainWindow) {
|
||||
globalShortcut.register('Alt+R', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
|
||||
ipcMain.on('msg-trigger', async (event, arg) => {
|
||||
const data = Api[arg.type](arg, mainWindow);
|
||||
event.sender.send(`msg-back-${arg.type}`, data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
</a-tag>
|
||||
</div>
|
||||
<a-input
|
||||
id="search"
|
||||
placeholder="Hi, Rubick"
|
||||
class="main-input"
|
||||
@change="onSearch"
|
||||
:value="searchValue"
|
||||
:maxLength="selected ? 0 : 1000"
|
||||
>
|
||||
<a-icon class="icon-tool" type="tool" slot="suffix" @click="() => {
|
||||
showMainUI();
|
||||
@@ -24,7 +26,7 @@
|
||||
}"/>
|
||||
}
|
||||
</a-input>
|
||||
<div class="options" v-show="options.length && !showMain">
|
||||
<div class="options" v-show="showOptions">
|
||||
<a-list item-layout="horizontal" :data-source="options">
|
||||
<a-list-item @click="() => item.click($router)" class="op-item" slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item-meta
|
||||
@@ -49,9 +51,19 @@ import {ipcRenderer} from "electron";
|
||||
import {getWindowHeight} from "./assets/common/utils";
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
document.getElementById('search').addEventListener('keydown', this.checkNeedInit)
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
methods: {
|
||||
...mapActions('main', ['onSearch', 'showMainUI']),
|
||||
...mapMutations('main', ['commonUpdate']),
|
||||
checkNeedInit(e) {
|
||||
if (this.searchValue === '' && e.keyCode === 8) {
|
||||
this.closeTag();
|
||||
}
|
||||
},
|
||||
changePath({key}) {
|
||||
this.$router.push({path: `/home/${key}`});
|
||||
this.commonUpdate({
|
||||
@@ -72,7 +84,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('main', ['showMain', 'current', 'options', 'selected', 'searchValue'])
|
||||
...mapState('main', ['showMain', 'current', 'options', 'selected', 'searchValue']),
|
||||
showOptions() {
|
||||
// 有选项值,且不在显示主页
|
||||
if (this.options.length && !this.showMain) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default {
|
||||
development: 'http://localhost:7001',
|
||||
// development: 'http://kaer-server.qa.91jkys.com',
|
||||
production: 'http://localhost:7001',
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const WINDOW_MAX_HEIGHT = 766;
|
||||
const WINDOW_MAX_HEIGHT = 600;
|
||||
const WINDOW_MIN_HEIGHT = 60;
|
||||
const PRE_ITEM_HEIGHT = 60;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ function getWindowHeight(searchList) {
|
||||
}
|
||||
|
||||
function searchKeyValues(lists, value){
|
||||
console.log(lists);
|
||||
return lists.filter(item => item.indexOf(value) >= 0)
|
||||
}
|
||||
|
||||
@@ -83,6 +84,9 @@ const sysFile = {
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
removeAllPlugins() {
|
||||
store.delete('user-plugins');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<webview style="width: 100%;height: 100vh" id="webview" :src="path"></webview>
|
||||
<webview style="width: 100%;height: 100vh" id="webview" :src="path" :preload="preload"></webview>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {getlocalDataFile} from '../../../common/utils';
|
||||
import { remote } from 'electron';
|
||||
// import process from 'child_process';
|
||||
|
||||
import {ipcRenderer} from 'electron';
|
||||
export default {
|
||||
name: "index.vue",
|
||||
data() {
|
||||
return {
|
||||
path: `File://${this.$route.query.sourceFile}`,
|
||||
preload: path.join(process.cwd(), './api/index.js')
|
||||
preload: `File://${path.join(__static, './preload.js')}`
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(1111, this.$route.query)
|
||||
// const webview = document.querySelector('webview')
|
||||
// webview.addEventListener('dom-ready', () => {
|
||||
// webview.openDevTools()
|
||||
// })
|
||||
const webview = document.querySelector('webview');
|
||||
webview.addEventListener('dom-ready', () => {
|
||||
webview.openDevTools();
|
||||
webview.send('onPluginReady', this.$route.query);
|
||||
webview.send('onPluginEnter', this.$route.query)
|
||||
});
|
||||
},
|
||||
beforeRouteUpdate() {
|
||||
this.path = `File://${this.$route.query.sourceFile}`
|
||||
},
|
||||
beforeDestroy() {
|
||||
const webview = document.querySelector('webview');
|
||||
webview.send('onPluginOut', this.$route.query)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<a-icon type="appstore"/>
|
||||
插件中心
|
||||
</a-menu-item>
|
||||
<a-menu-item key="favo">
|
||||
<a-menu-item key="plugin">
|
||||
<a-icon type="heart"/>
|
||||
已安装
|
||||
</a-menu-item>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="dev-container">
|
||||
<div class="dev-detail" v-if="devPlugins.length">
|
||||
<div class="dev-detail" v-if="devPlugin.length">
|
||||
<a-menu v-model="currentSelect" style="width: 256px; height: 100%" mode="vertical">
|
||||
<a-menu-item @click="currentSelect = [index]" v-for="(plugin, index) in devPlugins" :key="index">
|
||||
<a-menu-item @click="currentSelect = [index]" v-for="(plugin, index) in devPlugin" :key="index">
|
||||
<div>{{ plugin.pluginName }}</div>
|
||||
<div>{{ plugin.description }}</div>
|
||||
</a-menu-item>
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-switch />
|
||||
<a-switch :checked="pluginDetail.status" @change="devPluginStatusChange(pluginDetail)" />
|
||||
</div>
|
||||
</div>
|
||||
<a-tabs default-active-key="1">
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="desc-item">
|
||||
<div class="desc-title">
|
||||
<p>重新加载</p>
|
||||
<a-button type="link">重载</a-button>
|
||||
<a-button type="link" @click="reloadDevPlugin(pluginDetail)">重载</a-button>
|
||||
</div>
|
||||
<div class="desc-info">
|
||||
如果你修改了plugin.json文件需要重新加载以应用最近版本
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="desc-item">
|
||||
<div class="desc-title">
|
||||
<p>发布</p>
|
||||
<a-button type="link">发布</a-button>
|
||||
<a-button @click="release(pluginDetail)" type="link">发布</a-button>
|
||||
</div>
|
||||
<div class="desc-info">
|
||||
发布后用户可以通过插件中心下载,且享受最新的更新
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="desc-item">
|
||||
<div class="desc-title">
|
||||
<p>删除</p>
|
||||
<a-button type="link">删除</a-button>
|
||||
<a-button type="link" @click="deleteDevPlugin(pluginDetail)">删除</a-button>
|
||||
</div>
|
||||
<div class="desc-info">
|
||||
删除这个插件不可以恢复
|
||||
@@ -61,22 +61,50 @@
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty" v-else>
|
||||
<a-empty description="暂无开发中的插件" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import {mapState, mapMutations, mapActions} from 'vuex';
|
||||
import api from "../../../assets/api";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentSelect: [0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('main', ['deleteDevPlugin', 'devPluginStatusChange']),
|
||||
...mapActions('main', ['releasePlugin', 'reloadDevPlugin']),
|
||||
release(plugin) {
|
||||
if (!plugin.author) return this.$message.error('请填写作者!');
|
||||
if (!plugin.status) return this.$message.error('请开启插件!');
|
||||
api.plugin.add({
|
||||
pluginName: plugin.pluginName,
|
||||
author: plugin.author,
|
||||
logo: plugin.logo,
|
||||
gitUrl: plugin.gitUrl,
|
||||
title: plugin.title,
|
||||
description: plugin.description,
|
||||
version: plugin.version,
|
||||
name: plugin.name
|
||||
}).then(res => {
|
||||
this.$message.success('发布成功!')
|
||||
}).catch(e => {
|
||||
this.$message.error(e);
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('main', ['devPlugins']),
|
||||
pluginDetail() {
|
||||
console.log(this.$store)
|
||||
return this.devPlugins[this.currentSelect]
|
||||
return this.devPlugin[this.currentSelect]
|
||||
},
|
||||
devPlugin() {
|
||||
return this.devPlugins.filter(plugin => plugin.type === 'dev')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,5 +149,8 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.empty {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<h2>插件</h2>
|
||||
<a-list item-layout="horizontal" style="width: 100%" :grid="{ gutter: 16, column: 2 }" :data-source="pluginList">
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-button :loading="loading[index]" type="link" slot="actions" @click="download(index, item)">
|
||||
<a-button v-if="showButton(item)" :loading="loading[index]" type="link" slot="actions" @click="download(index, item)">
|
||||
<a-icon v-show="!loading[index]" style="font-size: 20px;" type="cloud-download" />
|
||||
</a-button>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<script>
|
||||
import api from '../../../assets/api';
|
||||
import {mapActions} from 'vuex';
|
||||
import {mapActions, mapState} from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -60,13 +60,16 @@ export default {
|
||||
async download(index, item) {
|
||||
if (this.loading[index]) return;
|
||||
this.$set(this.loading, index, true);
|
||||
console.log(this.loading);
|
||||
await this.downloadPlugin(item);
|
||||
this.$set(this.loading, index, false);
|
||||
console.log(this.loading);
|
||||
|
||||
},
|
||||
showButton(item) {
|
||||
return !this.devPlugins.filter(plugin => (plugin.name === item.name && plugin.type === 'prod')).length;
|
||||
},
|
||||
...mapActions('main', ['downloadPlugin'])
|
||||
},
|
||||
computed: {
|
||||
...mapState('main', ['devPlugins'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
113
src/renderer/pages/search/subpages/plugin.vue
Normal file
113
src/renderer/pages/search/subpages/plugin.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="dev-container">
|
||||
<div class="dev-detail" v-if="prodPlugin.length">
|
||||
<a-menu v-model="currentSelect" style="width: 256px; height: 100%" mode="vertical">
|
||||
<a-menu-item @click="currentSelect = [index]" v-for="(plugin, index) in devPlugins" :key="index">
|
||||
<div>{{ plugin.pluginName }}</div>
|
||||
<div>{{ plugin.description }}</div>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
<div class="plugin-detail">
|
||||
<div class="plugin-top">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{pluginDetail.pluginName}}
|
||||
<a-tag>{{pluginDetail.version}}</a-tag>
|
||||
</div>
|
||||
<div class="desc">
|
||||
开发者:{{`${pluginDetail.author || '未知'}`}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{pluginDetail.description}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-button type="danger" size="small" shape="round" @click="deleteProdPlugin(pluginDetail)">移除</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-tabs default-active-key="1">
|
||||
<a-tab-pane key="1" tab="功能关键字">
|
||||
<div class="desc-item" v-for="item in pluginDetail.features">
|
||||
<div>{{item.explain}}</div>
|
||||
<a-tag v-for="cmd in item.cmds">{{cmd}}</a-tag>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="详情介绍">
|
||||
Content of Tab Pane 2
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty" v-else>
|
||||
<a-empty description="暂无已安装插件" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState, mapMutations} from 'vuex';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentSelect: [0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('main', ['deleteProdPlugin'])
|
||||
},
|
||||
computed: {
|
||||
...mapState('main', ['devPlugins']),
|
||||
pluginDetail() {
|
||||
return this.devPlugins[this.currentSelect]
|
||||
},
|
||||
prodPlugin() {
|
||||
return this.devPlugins.filter(plugin => plugin.type === 'prod')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.dev-container {
|
||||
height: calc(100vh - 110px);
|
||||
.dev-detail {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
height: 100%;
|
||||
}
|
||||
.plugin-detail {
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
.plugin-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.desc {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.desc-item {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px 0;
|
||||
.desc-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.desc-info {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
.empty {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@ import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Market from '../pages/search/subpages/market';
|
||||
import Dev from '../pages/search/subpages/dev';
|
||||
import Installed from '../pages/search/subpages/plugin';
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
@@ -20,6 +21,10 @@ export default new Router({
|
||||
path: 'dev',
|
||||
component: Dev
|
||||
},
|
||||
{
|
||||
path: 'plugin',
|
||||
component: Installed
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {clipboard, ipcRenderer} from "electron";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {getWindowHeight, searchKeyValues, downloadFunc, sysFile} from '../../assets/common/utils';
|
||||
|
||||
import fs from "fs";
|
||||
import path from 'path';
|
||||
|
||||
@@ -22,6 +22,24 @@ const mutations = {
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteDevPlugin(state, payload) {
|
||||
state.devPlugins = state.devPlugins.filter(plugin => plugin.name !== payload.name);
|
||||
sysFile.savePlugins(state.devPlugins);
|
||||
},
|
||||
deleteProdPlugin(state, payload) {
|
||||
state.devPlugins = state.devPlugins.filter(plugin => plugin.name !== payload.name);
|
||||
sysFile.savePlugins(state.devPlugins);
|
||||
// todo 删除 static 目录下的对应插件
|
||||
},
|
||||
devPluginStatusChange(state, payload) {
|
||||
state.devPlugins.forEach(plugin => {
|
||||
if (plugin.name === payload.name) {
|
||||
plugin.status = !plugin.status;
|
||||
}
|
||||
});
|
||||
state.devPlugins = [...state.devPlugins];
|
||||
sysFile.savePlugins(state.devPlugins);
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
@@ -37,7 +55,30 @@ const actions = {
|
||||
height: getWindowHeight(),
|
||||
});
|
||||
},
|
||||
reloadDevPlugin({ commit }, payload) {
|
||||
const config = JSON.parse(fs.readFileSync(path.join(payload.sourceFile, '../plugin.json'), 'utf-8'));
|
||||
const pluginConfig = {
|
||||
...config,
|
||||
sourceFile: path.join(payload.sourceFile, `../${config.main}`),
|
||||
};
|
||||
const devPlugins = [...state.devPlugins];
|
||||
commit('commonUpdate', {
|
||||
devPlugins: devPlugins.map(plugin => {
|
||||
if (plugin.name === payload.name) {
|
||||
return {
|
||||
...plugin,
|
||||
...pluginConfig,
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
})
|
||||
})
|
||||
},
|
||||
onSearch ({ commit }, paylpad) {
|
||||
if (state.selected) {
|
||||
commit('commonUpdate', {searchValue: ''});
|
||||
return;
|
||||
}
|
||||
const value = paylpad.target.value;
|
||||
const fileUrl = clipboard.read('public.file-url').replace('file://', '');
|
||||
commit('commonUpdate', {searchValue: value})
|
||||
@@ -46,8 +87,10 @@ const actions = {
|
||||
const config = JSON.parse(fs.readFileSync(fileUrl, 'utf-8'));
|
||||
|
||||
const pluginConfig = {
|
||||
...JSON.parse(fs.readFileSync(fileUrl, 'utf-8')),
|
||||
sourceFile: path.join(fileUrl, `../${config.main}`)
|
||||
...config,
|
||||
sourceFile: path.join(fileUrl, `../${config.main}`),
|
||||
name: uuidv4(),
|
||||
type: 'dev'
|
||||
};
|
||||
commit('commonUpdate', {
|
||||
selected: {
|
||||
@@ -98,39 +141,46 @@ const actions = {
|
||||
let options = [];
|
||||
|
||||
// check 是否是插件
|
||||
state.devPlugins.forEach((plugin) => {
|
||||
const feature = plugin.features;
|
||||
feature.forEach(fe => {
|
||||
const cmds = searchKeyValues(fe.cmds, value);
|
||||
|
||||
options = [
|
||||
...options,
|
||||
...cmds.map((cmd) => ({
|
||||
name: cmd,
|
||||
value: 'plugin',
|
||||
icon: 'plus-circle',
|
||||
desc: fe.explain,
|
||||
click: (router) => {
|
||||
commit('commonUpdate', {
|
||||
selected: {
|
||||
key: cmd,
|
||||
name: cmd
|
||||
},
|
||||
searchValue: '',
|
||||
showMain: true,
|
||||
});
|
||||
ipcRenderer.send('changeWindowSize', {
|
||||
height: getWindowHeight(),
|
||||
});
|
||||
router.push({
|
||||
path: '/plugin',
|
||||
query: plugin,
|
||||
})
|
||||
}
|
||||
}))
|
||||
]
|
||||
})
|
||||
});
|
||||
if (value) {
|
||||
state.devPlugins.forEach((plugin) => {
|
||||
// dev 插件未开启
|
||||
if (plugin.type === 'dev' && !plugin.status) return;
|
||||
const feature = plugin.features;
|
||||
feature.forEach(fe => {
|
||||
const cmds = searchKeyValues(fe.cmds, value);
|
||||
console.log(plugin);
|
||||
options = [
|
||||
...options,
|
||||
...cmds.map((cmd) => ({
|
||||
name: cmd,
|
||||
value: 'plugin',
|
||||
icon: 'plus-circle',
|
||||
desc: fe.explain,
|
||||
click: (router) => {
|
||||
commit('commonUpdate', {
|
||||
selected: {
|
||||
key: cmd,
|
||||
name: cmd
|
||||
},
|
||||
searchValue: '',
|
||||
showMain: true,
|
||||
});
|
||||
ipcRenderer.send('changeWindowSize', {
|
||||
height: getWindowHeight(),
|
||||
});
|
||||
router.push({
|
||||
path: '/plugin',
|
||||
query: {
|
||||
...plugin,
|
||||
detail: JSON.stringify(fe)
|
||||
},
|
||||
})
|
||||
}
|
||||
}))
|
||||
]
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
commit('commonUpdate', {
|
||||
options
|
||||
@@ -146,7 +196,8 @@ const actions = {
|
||||
const config = JSON.parse(fs.readFileSync(`${fileUrl}/plugin.json`, 'utf-8'));
|
||||
const pluginConfig = {
|
||||
...config,
|
||||
sourceFile: `${fileUrl}/${config.main}`
|
||||
sourceFile: `${fileUrl}/${config.main}`,
|
||||
type: 'prod'
|
||||
};
|
||||
commit('commonUpdate', {
|
||||
devPlugins: [pluginConfig, ...state.devPlugins],
|
||||
|
||||
Reference in New Issue
Block a user