mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-09-03 22:01:00 +00:00
refactor(ai): extract assistant into an official module (#749)
* feat(modules): expose host data boundaries * feat(modules): add frontend extension surfaces * refactor(ai): remove assistant from core * chore(ai): prepare the module extraction * fix(modules): load extension styles after the host bundle * chore(modules): lock SDK 3.3.0
This commit is contained in:
@@ -37,6 +37,10 @@
|
||||
{{ button.text }}
|
||||
</span>
|
||||
</button>
|
||||
<ExtensionSlot
|
||||
name="rich-editor-toolbar-actions"
|
||||
:context="editorContext"
|
||||
/>
|
||||
</div>
|
||||
</BaseDropdown>
|
||||
</div>
|
||||
@@ -58,6 +62,10 @@
|
||||
{{ button.text }}
|
||||
</span>
|
||||
</button>
|
||||
<ExtensionSlot
|
||||
name="rich-editor-toolbar-actions"
|
||||
:context="editorContext"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content
|
||||
@@ -94,11 +102,10 @@ import {
|
||||
Bars3BottomRightIcon,
|
||||
Bars3Icon,
|
||||
LinkIcon,
|
||||
SparklesIcon,
|
||||
} from '@heroicons/vue/24/solid'
|
||||
import { ContentPlaceholder, ContentPlaceholderBox } from '../layout'
|
||||
import { useGlobalStore } from '@/scripts/stores/global.store'
|
||||
import { useModalStore } from '@/scripts/stores/modal.store'
|
||||
import ExtensionSlot from '@/scripts/extensions/ExtensionSlot.vue'
|
||||
import type { RichEditorContext } from '@/scripts/extensions/types'
|
||||
|
||||
interface EditorButton {
|
||||
name: string
|
||||
@@ -170,39 +177,21 @@ const editorButtons = ref<EditorButton[]>([
|
||||
},
|
||||
])
|
||||
|
||||
// AI text-generation button — shown only when the feature is enabled
|
||||
// for the current company. The flag is set once at bootstrap time so a
|
||||
// one-shot push is fine; no reactivity needed.
|
||||
const globalStore = useGlobalStore()
|
||||
const modalStore = useModalStore()
|
||||
if (globalStore.ai?.enabled && globalStore.ai?.text_generation_enabled) {
|
||||
editorButtons.value.push({
|
||||
name: 'aiGenerate',
|
||||
icon: markRaw(SparklesIcon) as Component,
|
||||
action: () => {
|
||||
modalStore.openModal({
|
||||
componentName: 'AiTextGenerationModal',
|
||||
title: 'AI Text Generation',
|
||||
size: 'md',
|
||||
data: {
|
||||
currentContent: editor.value?.getHTML() ?? '',
|
||||
onInsert: (text: string) => {
|
||||
editor.value?.chain().focus().insertContent(text).run()
|
||||
},
|
||||
onReplace: (text: string) => {
|
||||
editor.value?.chain().focus().selectAll().deleteSelection().insertContent(text).run()
|
||||
},
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
const editorContext: RichEditorContext = {
|
||||
getHtml: () => editor.value?.getHTML() ?? '',
|
||||
insertContent: (content: string) => {
|
||||
editor.value?.chain().focus().insertContent(content).run()
|
||||
},
|
||||
replaceContent: (content: string) => {
|
||||
editor.value?.chain().focus().selectAll().deleteSelection().insertContent(content).run()
|
||||
},
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue: string) => {
|
||||
if (editor.value && newValue !== editor.value.getHTML()) {
|
||||
editor.value.commands.setContent(newValue, false)
|
||||
editor.value.commands.setContent(newValue, { emitUpdate: false })
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user