Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration improvements #18

Merged
merged 3 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 44 additions & 7 deletions src/assistant.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,21 @@ __webpack_public_path__ = linkTo('assistant', 'js/') // eslint-disable-line
* appId: 'my_app_id',
* identifier: 'my task identifier',
* taskType: 'OCP\\TextProcessing\\FreePromptTaskType',
* input: 'count to 3'
* input: 'count to 3',
* actionButtons: [
* {
* label: 'Label 1',
* title: 'Title 1',
* type: 'warning',
* iconSvg: cogSvg,
* onClick: (output) => { console.debug('first button clicked', output) },
* },
* {
* label: 'Label 2',
* title: 'Title 2',
* onClick: (output) => { console.debug('second button clicked', output) },
* },
* ],
* }).then(r => {console.debug('scheduled task', r.data.ocs.data.task)})
*
* @param {object} params parameters for the assistant
Expand All @@ -20,9 +34,14 @@ __webpack_public_path__ = linkTo('assistant', 'js/') // eslint-disable-line
* @param {string} params.taskType the task type class
* @param {string} params.input optional initial input text
* @param {boolean} params.isInsideViewer Should be true if this function is called while the Viewer is displayed
* @param {boolean} params.closeOnResult If true, the modal will be closed when getting a sync result
* @param {Array} params.actionButtons List of extra buttons to show in the assistant result form (only if closeOnResult is false)
* @return {Promise<unknown>}
*/
export async function openAssistantForm({ appId, identifier = '', taskType = null, input = '', isInsideViewer = undefined }) {
export async function openAssistantForm({
appId, identifier = '', taskType = null, input = '',
isInsideViewer = undefined, closeOnResult = false, actionButtons = undefined,
}) {
const { default: Vue } = await import(/* webpackChunkName: "vue-lazy" */'vue')
const { default: AssistantModal } = await import(/* webpackChunkName: "assistant-modal-lazy" */'./components/AssistantModal.vue')
Vue.mixin({ methods: { t, n } })
Expand All @@ -44,8 +63,10 @@ export async function openAssistantForm({ appId, identifier = '', taskType = nul
selectedTaskTypeId,
showScheduleConfirmation: false,
showSyncTaskRunning: false,
actionButtons,
},
}).$mount(modalElement)
let lastTask = null

view.$on('cancel', () => {
view.$destroy()
Expand All @@ -56,7 +77,9 @@ export async function openAssistantForm({ appId, identifier = '', taskType = nul
.then((response) => {
view.input = data.input
view.showScheduleConfirmation = true
resolve(response.data?.ocs?.data?.task)
const task = response.data?.ocs?.data?.task
lastTask = task
resolve(task)
})
.catch(error => {
view.$destroy()
Expand All @@ -72,15 +95,20 @@ export async function openAssistantForm({ appId, identifier = '', taskType = nul
runOrScheduleTask(appId, identifier, data.taskTypeId, data.input)
.then((response) => {
const task = response.data?.task
lastTask = task
resolve(task)
view.input = task.input
if (task.status === STATUS.successfull) {
view.output = task?.output
if (closeOnResult) {
view.$destroy()
} else {
view.output = task?.output
}
} else if (task.status === STATUS.scheduled) {
view.input = task.input
view.showScheduleConfirmation = true
}
view.loading = false
view.showSyncTaskRunning = false
resolve(task)
})
.catch(error => {
if (error?.code === 'ERR_CANCELED') {
Expand All @@ -100,14 +128,23 @@ export async function openAssistantForm({ appId, identifier = '', taskType = nul
.then((response) => {
view.showSyncTaskRunning = false
view.showScheduleConfirmation = true
resolve(response.data?.ocs?.data?.task)
const task = response.data?.ocs?.data?.task
lastTask = task
resolve(task)
})
.catch(error => {
view.$destroy()
console.error('Assistant scheduling error', error)
reject(new Error('Assistant scheduling error'))
})
})
view.$on('action-button-clicked', (data) => {
if (data.button?.onClick) {
lastTask.output = data.output
data.button.onClick(lastTask)
}
view.$destroy()
})
})
}

Expand Down
41 changes: 35 additions & 6 deletions src/components/AssistantForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@
:type="submitButtonType"
class="submit-button"
:disabled="!canSubmit"
:aria-label="t('assistant', 'Run an assistant task')"
:title="t('assistant', 'Run')"
:title="t('assistant', 'Run a task')"
@click="onSyncSubmit">
{{ syncSubmitButtonLabel }}
<template #icon>
Expand All @@ -80,18 +79,31 @@
</template>
</NcButton-->
<NcButton
v-if="showCopy"
v-if="hasOutput"
type="primary"
class="copy-button"
:aria-label="t('assistant', 'Copy task output')"
:title="t('assistant', 'Copy')"
:title="t('assistant', 'Copy output')"
@click="onCopy">
{{ t('assistant', 'Copy') }}
<template #icon>
<ClipboardCheckOutlineIcon v-if="copied" />
<ContentCopyIcon v-else />
</template>
</NcButton>
<div v-if="hasOutput"
class="action-buttons">
<NcButton
v-for="(b, i) in actionButtons"
:key="i"
:type="b.type ?? 'secondary'"
:title="b.title"
@click="onActionButtonClick(b)">
{{ b.label }}
<template v-if="b.iconSvg" #icon>
<NcIconSvgWrapper :svg="b.iconSvg" />
</template>
</NcButton>
</div>
</div>
</div>
</template>
Expand All @@ -105,6 +117,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcRichContenteditable from '@nextcloud/vue/dist/Components/NcRichContenteditable.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'

import TaskTypeSelect from './TaskTypeSelect.vue'

Expand All @@ -123,6 +136,7 @@ export default {
NcButton,
NcRichContenteditable,
NcLoadingIcon,
NcIconSvgWrapper,
CreationIcon,
ContentCopyIcon,
ClipboardCheckOutlineIcon,
Expand All @@ -145,10 +159,15 @@ export default {
type: [String, null],
default: null,
},
actionButtons: {
type: Array,
default: () => [],
},
},
emits: [
'sync-submit',
'submit',
'action-button-clicked',
],
data() {
return {
Expand Down Expand Up @@ -189,7 +208,7 @@ export default {
? t('assistant', 'Send request')
: this.selectedTaskType.name
},
showCopy() {
hasOutput() {
return !!this.myOutput.trim()
},
},
Expand Down Expand Up @@ -230,6 +249,9 @@ export default {
showError(t('assistant', 'Result could not be copied to clipboard'))
}
},
onActionButtonClick(button) {
this.$emit('action-button-clicked', { button, output: this.myOutput.trim() })
},
},
}
</script>
Expand Down Expand Up @@ -303,8 +325,15 @@ export default {
.footer {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: end;
gap: 4px;
.action-buttons {
display: flex;
flex-wrap: wrap;
justify-content: end;
gap: 4px;
}
}

.success-icon {
Expand Down
11 changes: 10 additions & 1 deletion src/components/AssistantModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
:output="output"
:selected-task-type-id="selectedTaskTypeId"
:loading="loading"
:action-buttons="actionButtons"
@submit="onSubmit"
@sync-submit="onSyncSubmit" />
@sync-submit="onSyncSubmit"
@action-button-clicked="onActionButtonClicked" />
</div>
</div>
</NcModal>
Expand Down Expand Up @@ -93,6 +95,10 @@ export default {
type: Boolean,
required: true,
},
actionButtons: {
type: Array,
default: () => [],
},
},
emits: [
'cancel',
Expand Down Expand Up @@ -135,6 +141,9 @@ export default {
onCancelNSchedule() {
this.$emit('cancel-sync-n-schedule')
},
onActionButtonClicked(data) {
this.$emit('action-button-clicked', data)
},
},
}
</script>
Expand Down