mirror of
https://github.com/misskey-dev/misskey
synced 2024-12-01 08:18:51 +09:00
parent
debc0086fa
commit
9b73e897df
@ -523,6 +523,9 @@ themeEditor: "テーマエディター"
|
|||||||
description: "説明"
|
description: "説明"
|
||||||
author: "作者"
|
author: "作者"
|
||||||
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
||||||
|
manage: "管理"
|
||||||
|
plugins: "プラグイン"
|
||||||
|
pluginInstallWarn: "信頼できないプラグインはインストールしないでください。"
|
||||||
deck: "デッキ"
|
deck: "デッキ"
|
||||||
undeck: "デッキ解除"
|
undeck: "デッキ解除"
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
"@koa/multer": "3.0.0",
|
"@koa/multer": "3.0.0",
|
||||||
"@koa/router": "9.3.1",
|
"@koa/router": "9.3.1",
|
||||||
"@sinonjs/fake-timers": "6.0.1",
|
"@sinonjs/fake-timers": "6.0.1",
|
||||||
"@syuilo/aiscript": "0.7.0",
|
"@syuilo/aiscript": "0.7.2",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/bull": "3.14.0",
|
"@types/bull": "3.14.0",
|
||||||
"@types/cbor": "5.0.0",
|
"@types/cbor": "5.0.0",
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faEllipsisH } from '@fortawesome/free-solid-svg-icons';
|
import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { parse } from '../../mfm/parse';
|
import { parse } from '../../mfm/parse';
|
||||||
import { sum, unique } from '../../prelude/array';
|
import { sum, unique } from '../../prelude/array';
|
||||||
@ -108,7 +108,6 @@ import { url } from '../config';
|
|||||||
import copyToClipboard from '../scripts/copy-to-clipboard';
|
import copyToClipboard from '../scripts/copy-to-clipboard';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
XSub,
|
XSub,
|
||||||
XNoteHeader,
|
XNoteHeader,
|
||||||
@ -145,7 +144,7 @@ export default Vue.extend({
|
|||||||
showContent: false,
|
showContent: false,
|
||||||
hideThisNote: false,
|
hideThisNote: false,
|
||||||
noteBody: this.$refs.noteBody,
|
noteBody: this.$refs.noteBody,
|
||||||
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faEllipsisH
|
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -612,6 +611,16 @@ export default Vue.extend({
|
|||||||
.filter(x => x !== undefined);
|
.filter(x => x !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.$store.state.noteActions.length > 0) {
|
||||||
|
menu = menu.concat([null, ...this.$store.state.noteActions.map(action => ({
|
||||||
|
icon: faPlug,
|
||||||
|
text: action.title,
|
||||||
|
action: () => {
|
||||||
|
action.handler(this.appearNote);
|
||||||
|
}
|
||||||
|
}))]);
|
||||||
|
}
|
||||||
|
|
||||||
this.$root.menu({
|
this.$root.menu({
|
||||||
items: menu,
|
items: menu,
|
||||||
source: this.$refs.menuButton,
|
source: this.$refs.menuButton,
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><fa :icon="faEyeSlash"/></button>
|
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><fa :icon="faEyeSlash"/></button>
|
||||||
<button class="_button" @click="insertMention" v-tooltip="$t('mention')"><fa :icon="faAt"/></button>
|
<button class="_button" @click="insertMention" v-tooltip="$t('mention')"><fa :icon="faAt"/></button>
|
||||||
<button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><fa :icon="faLaughSquint"/></button>
|
<button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><fa :icon="faLaughSquint"/></button>
|
||||||
|
<button class="_button" @click="showActions" v-tooltip="$t('plugin')" v-if="$store.state.postFormActions.length > 0"><fa :icon="faPlug"/></button>
|
||||||
</footer>
|
</footer>
|
||||||
<input ref="file" class="file _button" type="file" multiple="multiple" @change="onChangeFile"/>
|
<input ref="file" class="file _button" type="file" multiple="multiple" @change="onChangeFile"/>
|
||||||
</div>
|
</div>
|
||||||
@ -52,7 +53,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard } from '@fortawesome/free-solid-svg-icons';
|
import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons';
|
import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
@ -133,7 +134,7 @@ export default Vue.extend({
|
|||||||
draghover: false,
|
draghover: false,
|
||||||
quoteId: null,
|
quoteId: null,
|
||||||
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
|
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
|
||||||
faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard
|
faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -580,6 +581,22 @@ export default Vue.extend({
|
|||||||
vm.close();
|
vm.close();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showActions(ev) {
|
||||||
|
this.$root.menu({
|
||||||
|
items: this.$store.state.postFormActions.map(action => ({
|
||||||
|
text: action.title,
|
||||||
|
action: () => {
|
||||||
|
action.handler({
|
||||||
|
text: this.text
|
||||||
|
}, (key, value) => {
|
||||||
|
if (key === 'text') { this.text = value; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
source: ev.currentTarget || ev.target,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
|
import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
||||||
import XMenu from './menu.vue';
|
import XMenu from './menu.vue';
|
||||||
import copyToClipboard from '../scripts/copy-to-clipboard';
|
import copyToClipboard from '../scripts/copy-to-clipboard';
|
||||||
@ -80,6 +80,16 @@ export default Vue.extend({
|
|||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.$store.state.userActions.length > 0) {
|
||||||
|
menu = menu.concat([null, ...this.$store.state.userActions.map(action => ({
|
||||||
|
icon: faPlug,
|
||||||
|
text: action.title,
|
||||||
|
action: () => {
|
||||||
|
action.handler(this.user);
|
||||||
|
}
|
||||||
|
}))]);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: menu
|
items: menu
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,8 @@ import { isDeviceDarkmode } from './scripts/is-device-darkmode';
|
|||||||
import createStore from './store';
|
import createStore from './store';
|
||||||
import { clientDb, get, count } from './db';
|
import { clientDb, get, count } from './db';
|
||||||
import { setI18nContexts } from './scripts/set-i18n-contexts';
|
import { setI18nContexts } from './scripts/set-i18n-contexts';
|
||||||
|
import { createPluginEnv } from './scripts/aiscript/api';
|
||||||
|
import { AiScript } from '@syuilo/aiscript';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
Vue.use(VueHotkey);
|
Vue.use(VueHotkey);
|
||||||
@ -231,6 +233,35 @@ os.init(async () => {
|
|||||||
//store.commit('instance/set', );
|
//store.commit('instance/set', );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const plugin of store.state.deviceUser.plugins) {
|
||||||
|
console.info('Plugin installed:', plugin.name, 'v' + plugin.version);
|
||||||
|
|
||||||
|
const aiscript = new AiScript(createPluginEnv(app, {
|
||||||
|
plugin: plugin,
|
||||||
|
storageKey: 'plugins:' + plugin.id
|
||||||
|
}), {
|
||||||
|
in: (q) => {
|
||||||
|
return new Promise(ok => {
|
||||||
|
app.dialog({
|
||||||
|
title: q,
|
||||||
|
input: {}
|
||||||
|
}).then(({ canceled, result: a }) => {
|
||||||
|
ok(a);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
out: (value) => {
|
||||||
|
console.log(value);
|
||||||
|
},
|
||||||
|
log: (type, params) => {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
store.commit('initPlugin', { plugin, aiscript });
|
||||||
|
|
||||||
|
aiscript.exec(plugin.ast);
|
||||||
|
}
|
||||||
|
|
||||||
if (store.getters.isSignedIn) {
|
if (store.getters.isSignedIn) {
|
||||||
const main = os.stream.useSharedConnection('main');
|
const main = os.stream.useSharedConnection('main');
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
<x-sidebar/>
|
<x-sidebar/>
|
||||||
|
|
||||||
|
<x-plugins/>
|
||||||
|
|
||||||
<section class="_card">
|
<section class="_card">
|
||||||
<div class="_title"><fa :icon="faMusic"/> {{ $t('sounds') }}</div>
|
<div class="_title"><fa :icon="faMusic"/> {{ $t('sounds') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
@ -115,6 +117,7 @@ import MkRadio from '../../components/ui/radio.vue';
|
|||||||
import MkRange from '../../components/ui/range.vue';
|
import MkRange from '../../components/ui/range.vue';
|
||||||
import XTheme from './theme.vue';
|
import XTheme from './theme.vue';
|
||||||
import XSidebar from './sidebar.vue';
|
import XSidebar from './sidebar.vue';
|
||||||
|
import XPlugins from './plugins.vue';
|
||||||
import { langs } from '../../config';
|
import { langs } from '../../config';
|
||||||
import { clientDb, set } from '../../db';
|
import { clientDb, set } from '../../db';
|
||||||
|
|
||||||
@ -146,11 +149,12 @@ export default Vue.extend({
|
|||||||
components: {
|
components: {
|
||||||
XTheme,
|
XTheme,
|
||||||
XSidebar,
|
XSidebar,
|
||||||
|
XPlugins,
|
||||||
MkButton,
|
MkButton,
|
||||||
MkSwitch,
|
MkSwitch,
|
||||||
MkSelect,
|
MkSelect,
|
||||||
MkRadio,
|
MkRadio,
|
||||||
MkRange
|
MkRange,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
134
src/client/pages/preferences/plugins.vue
Normal file
134
src/client/pages/preferences/plugins.vue
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<section class="_card">
|
||||||
|
<div class="_title"><fa :icon="faPlug"/> {{ $t('plugins') }}</div>
|
||||||
|
<div class="_content">
|
||||||
|
<details>
|
||||||
|
<summary><fa :icon="faDownload"/> {{ $t('install') }}</summary>
|
||||||
|
<mk-info warn>{{ $t('pluginInstallWarn') }}</mk-info>
|
||||||
|
<mk-textarea v-model="script" tall>
|
||||||
|
<span>{{ $t('script') }}</span>
|
||||||
|
</mk-textarea>
|
||||||
|
<mk-button @click="install()" primary><fa :icon="faSave"/> {{ $t('install') }}</mk-button>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
<div class="_content">
|
||||||
|
<details>
|
||||||
|
<summary><fa :icon="faFolderOpen"/> {{ $t('manage') }}</summary>
|
||||||
|
<mk-select v-model="selectedPluginId">
|
||||||
|
<option v-for="x in $store.state.deviceUser.plugins" :value="x.id" :key="x.id">{{ x.name }}</option>
|
||||||
|
</mk-select>
|
||||||
|
<template v-if="selectedPlugin">
|
||||||
|
<div class="_keyValue">
|
||||||
|
<div>{{ $t('version') }}:</div>
|
||||||
|
<div>{{ selectedPlugin.version }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="_keyValue">
|
||||||
|
<div>{{ $t('author') }}:</div>
|
||||||
|
<div>{{ selectedPlugin.author }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="_keyValue">
|
||||||
|
<div>{{ $t('description') }}:</div>
|
||||||
|
<div>{{ selectedPlugin.description }}</div>
|
||||||
|
</div>
|
||||||
|
<mk-button @click="uninstall()" style="margin-top: 8px;"><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button>
|
||||||
|
</template>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { faPlug, faSave, faTrashAlt, faFolderOpen, faDownload } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import MkButton from '../../components/ui/button.vue';
|
||||||
|
import MkTextarea from '../../components/ui/textarea.vue';
|
||||||
|
import MkSelect from '../../components/ui/select.vue';
|
||||||
|
import MkInfo from '../../components/ui/info.vue';
|
||||||
|
import { AiScript, parse } from '@syuilo/aiscript';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
MkButton,
|
||||||
|
MkTextarea,
|
||||||
|
MkSelect,
|
||||||
|
MkInfo,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
script: '',
|
||||||
|
selectedPluginId: null,
|
||||||
|
faPlug, faSave, faTrashAlt, faFolderOpen, faDownload
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
selectedPlugin() {
|
||||||
|
if (this.selectedPluginId == null) return null;
|
||||||
|
return this.$store.state.deviceUser.plugins.find(x => x.id === this.selectedPluginId);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
install() {
|
||||||
|
let ast;
|
||||||
|
try {
|
||||||
|
ast = parse(this.script);
|
||||||
|
} catch (e) {
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: 'Syntax error :('
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const meta = AiScript.collectMetadata(ast);
|
||||||
|
console.log(meta);
|
||||||
|
if (meta == null) {
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: 'No metadata found :('
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = meta.get(null);
|
||||||
|
if (data == null) {
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: 'No metadata found :('
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { id, name, version, author, description } = data;
|
||||||
|
if (id == null || name == null || version == null || author == null) {
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: 'Required property not found :('
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$store.commit('deviceUser/installPlugin', {
|
||||||
|
meta: {
|
||||||
|
id, name, version, author, description
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
});
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'success',
|
||||||
|
iconOnly: true, autoClose: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
uninstall() {
|
||||||
|
this.$store.commit('deviceUser/uninstallPlugin', this.selectedPluginId);
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'success',
|
||||||
|
iconOnly: true, autoClose: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -30,7 +30,7 @@ import PrismEditor from 'vue-prism-editor';
|
|||||||
import { AiScript, parse, utils, values } from '@syuilo/aiscript';
|
import { AiScript, parse, utils, values } from '@syuilo/aiscript';
|
||||||
import MkContainer from '../components/ui/container.vue';
|
import MkContainer from '../components/ui/container.vue';
|
||||||
import MkButton from '../components/ui/button.vue';
|
import MkButton from '../components/ui/button.vue';
|
||||||
import { createAiScriptEnv } from '../scripts/create-aiscript-env';
|
import { createAiScriptEnv } from '../scripts/aiscript/api';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
|
@ -40,3 +40,18 @@ export function createAiScriptEnv(vm, opts) {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createPluginEnv(vm, opts) {
|
||||||
|
return {
|
||||||
|
...createAiScriptEnv(vm, opts),
|
||||||
|
'Mk:register_post_form_action': values.FN_NATIVE(([title, handler]) => {
|
||||||
|
vm.$store.commit('registerPostFormAction', { pluginId: opts.plugin.id, title: title.value, handler });
|
||||||
|
}),
|
||||||
|
'Mk:register_user_action': values.FN_NATIVE(([title, handler]) => {
|
||||||
|
vm.$store.commit('registerUserAction', { pluginId: opts.plugin.id, title: title.value, handler });
|
||||||
|
}),
|
||||||
|
'Mk:register_note_action': values.FN_NATIVE(([title, handler]) => {
|
||||||
|
vm.$store.commit('registerNoteAction', { pluginId: opts.plugin.id, title: title.value, handler });
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
@ -3,7 +3,7 @@ import * as seedrandom from 'seedrandom';
|
|||||||
import { Variable, PageVar, envVarsDef, funcDefs, Block, isFnBlock } from '.';
|
import { Variable, PageVar, envVarsDef, funcDefs, Block, isFnBlock } from '.';
|
||||||
import { version } from '../../config';
|
import { version } from '../../config';
|
||||||
import { AiScript, utils, values } from '@syuilo/aiscript';
|
import { AiScript, utils, values } from '@syuilo/aiscript';
|
||||||
import { createAiScriptEnv } from '../create-aiscript-env';
|
import { createAiScriptEnv } from '../aiscript/api';
|
||||||
import { collectPageVars } from '../collect-page-vars';
|
import { collectPageVars } from '../collect-page-vars';
|
||||||
import { initLib } from './lib';
|
import { initLib } from './lib';
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import createPersistedState from 'vuex-persistedstate';
|
|||||||
import * as nestedProperty from 'nested-property';
|
import * as nestedProperty from 'nested-property';
|
||||||
import { faTerminal, faHashtag, faBroadcastTower, faFireAlt, faSearch, faStar, faAt, faListUl, faUserClock, faUsers, faCloud, faGamepad, faFileAlt, faSatellite, faDoorClosed, faColumns } from '@fortawesome/free-solid-svg-icons';
|
import { faTerminal, faHashtag, faBroadcastTower, faFireAlt, faSearch, faStar, faAt, faListUl, faUserClock, faUsers, faCloud, faGamepad, faFileAlt, faSatellite, faDoorClosed, faColumns } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons';
|
import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import { AiScript, utils, values } from '@syuilo/aiscript';
|
||||||
import { apiUrl, deckmode } from './config';
|
import { apiUrl, deckmode } from './config';
|
||||||
import { erase } from '../prelude/array';
|
import { erase } from '../prelude/array';
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ export const defaultDeviceUserSettings = {
|
|||||||
columns: [],
|
columns: [],
|
||||||
layout: [],
|
layout: [],
|
||||||
},
|
},
|
||||||
|
plugins: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultDeviceSettings = {
|
export const defaultDeviceSettings = {
|
||||||
@ -93,7 +95,13 @@ export default () => new Vuex.Store({
|
|||||||
state: {
|
state: {
|
||||||
i: null,
|
i: null,
|
||||||
pendingApiRequestsCount: 0,
|
pendingApiRequestsCount: 0,
|
||||||
spinner: null
|
spinner: null,
|
||||||
|
|
||||||
|
// Plugin
|
||||||
|
pluginContexts: new Map<string, AiScript>(),
|
||||||
|
postFormActions: [],
|
||||||
|
userActions: [],
|
||||||
|
noteActions: [],
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
@ -224,8 +232,38 @@ export default () => new Vuex.Store({
|
|||||||
state.i = x;
|
state.i = x;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateIKeyValue(state, x) {
|
updateIKeyValue(state, { key, value }) {
|
||||||
state.i[x.key] = x.value;
|
state.i[key] = value;
|
||||||
|
},
|
||||||
|
|
||||||
|
initPlugin(state, { plugin, aiscript }) {
|
||||||
|
state.pluginContexts.set(plugin.id, aiscript);
|
||||||
|
},
|
||||||
|
|
||||||
|
registerPostFormAction(state, { pluginId, title, handler }) {
|
||||||
|
state.postFormActions.push({
|
||||||
|
title, handler: (form, update) => {
|
||||||
|
state.pluginContexts.get(pluginId).execFn(handler, [utils.jsToVal(form), values.FN_NATIVE(([key, value]) => {
|
||||||
|
update(key.value, value.value);
|
||||||
|
})]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
registerUserAction(state, { pluginId, title, handler }) {
|
||||||
|
state.userActions.push({
|
||||||
|
title, handler: (user) => {
|
||||||
|
state.pluginContexts.get(pluginId).execFn(handler, [utils.jsToVal(user)]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
registerNoteAction(state, { pluginId, title, handler }) {
|
||||||
|
state.noteActions.push({
|
||||||
|
title, handler: (note) => {
|
||||||
|
state.pluginContexts.get(pluginId).execFn(handler, [utils.jsToVal(note)]);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -546,6 +584,21 @@ export default () => new Vuex.Store({
|
|||||||
column = x;
|
column = x;
|
||||||
},
|
},
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
installPlugin(state, { meta, ast }) {
|
||||||
|
state.plugins.push({
|
||||||
|
id: meta.id,
|
||||||
|
name: meta.name,
|
||||||
|
version: meta.version,
|
||||||
|
author: meta.author,
|
||||||
|
description: meta.description,
|
||||||
|
ast: ast
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
uninstallPlugin(state, id) {
|
||||||
|
state.plugins = state.plugins.filter(x => x.id != id);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -197,10 +197,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^1.7.0"
|
"@sinonjs/commons" "^1.7.0"
|
||||||
|
|
||||||
"@syuilo/aiscript@0.7.0":
|
"@syuilo/aiscript@0.7.2":
|
||||||
version "0.7.0"
|
version "0.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/@syuilo/aiscript/-/aiscript-0.7.0.tgz#1394511a789891e844d32e536a203fe0d92b3039"
|
resolved "https://registry.yarnpkg.com/@syuilo/aiscript/-/aiscript-0.7.2.tgz#2f30adb14ffa9f1180af83c059927ab306b175a5"
|
||||||
integrity sha512-X4TaP/FO7RD8MpFSPDFwKAI4KX7byn8ApqmSSmf2bxcwCTcdevsbyxsLrvkbNaWclIoqTgXwtJjY+2Tc2exeXA==
|
integrity sha512-l8HVTJTq9KLzDqGswOIGlBepkacudUp70EScrLjL7nEL2NKcti7Ui5fwZCrmxazxgGz6NrVNX5UBIOFFyrwr0A==
|
||||||
dependencies:
|
dependencies:
|
||||||
autobind-decorator "2.4.0"
|
autobind-decorator "2.4.0"
|
||||||
chalk "4.0.0"
|
chalk "4.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user