diff --git a/src/assistant.js b/src/assistant.js
index c4b53c62..8fae72a4 100644
--- a/src/assistant.js
+++ b/src/assistant.js
@@ -137,13 +137,63 @@ export async function openAssistantForm({
view.$on('load-task', (task) => {
if (!view.loading) {
console.debug('[assistant] loading task', task)
+ cancelTaskPolling()
+
view.selectedTaskTypeId = task.type
view.inputs = task.input
view.outputs = task.status === TASK_STATUS_STRING.successful ? task.output : null
view.selectedTaskId = task.id
lastTask = task
+
+ if ([TASK_STATUS_STRING.scheduled, TASK_STATUS_STRING.running].includes(task?.status)) {
+ getTask(task.id).then(response => {
+ const updatedTask = response.data?.ocs?.data?.task
+
+ if (![TASK_STATUS_STRING.scheduled, TASK_STATUS_STRING.running].includes(updatedTask?.status)) {
+ view.selectedTaskTypeId = updatedTask.type
+ view.inputs = updatedTask.input
+ view.outputs = updatedTask.status === TASK_STATUS_STRING.successful ? updatedTask.output : null
+ view.selectedTaskId = updatedTask.id
+ lastTask = updatedTask
+ return
+ }
+
+ view.loading = true
+ view.showSyncTaskRunning = true
+ view.progress = null
+ view.expectedRuntime = (updatedTask?.completionExpectedAt - updatedTask?.scheduledAt) || null
+
+ const setProgress = (progress) => {
+ view.progress = progress
+ }
+ pollTask(updatedTask.id, setProgress).then(finishedTask => {
+ console.debug('pollTask.then', finishedTask)
+ if (finishedTask.status === TASK_STATUS_STRING.successful) {
+ view.outputs = finishedTask?.output
+ view.selectedTaskId = finishedTask?.id
+ } else if (finishedTask.status === TASK_STATUS_STRING.failed) {
+ showError(t('assistant', 'Your task with ID {id} has failed', { id: finishedTask.id }))
+ console.error('[assistant] Task failed', finishedTask)
+ view.outputs = null
+ }
+ // resolve(finishedTask)
+ view.loading = false
+ view.showSyncTaskRunning = false
+ }).catch(error => {
+ console.debug('[assistant] poll error', error)
+ })
+ }).catch(error => {
+ console.error(error)
+ })
+ }
}
})
+ view.$on('new-task', () => {
+ console.debug('[assistant] new task')
+ view.outputs = null
+ view.selectedTaskId = null
+ lastTask = null
+ })
view.$on('background-notify', () => {
cancelTaskPolling()
view.showScheduleConfirmation = true
@@ -166,6 +216,7 @@ export async function openAssistantForm({
view.$destroy()
})
view.$on('back-to-assistant', () => {
+ cancelTaskPolling()
view.showScheduleConfirmation = false
view.showSyncTaskRunning = false
view.loading = false
@@ -430,13 +481,63 @@ export async function openAssistantTask(task, { isInsideViewer = undefined, acti
})
view.$on('load-task', (task) => {
if (!view.loading) {
+ cancelTaskPolling()
+
view.selectedTaskTypeId = task.type
view.inputs = task.input
view.outputs = task.status === TASK_STATUS_STRING.successful ? task.output : null
view.selectedTaskId = task.id
lastTask = task
+
+ if ([TASK_STATUS_STRING.scheduled, TASK_STATUS_STRING.running].includes(task?.status)) {
+ getTask(task.id).then(response => {
+ const updatedTask = response.data?.ocs?.data?.task
+
+ if (![TASK_STATUS_STRING.scheduled, TASK_STATUS_STRING.running].includes(updatedTask?.status)) {
+ view.selectedTaskTypeId = updatedTask.type
+ view.inputs = updatedTask.input
+ view.outputs = updatedTask.status === TASK_STATUS_STRING.successful ? updatedTask.output : null
+ view.selectedTaskId = updatedTask.id
+ lastTask = updatedTask
+ return
+ }
+
+ view.loading = true
+ view.showSyncTaskRunning = true
+ view.progress = null
+ view.expectedRuntime = (updatedTask?.completionExpectedAt - updatedTask?.scheduledAt) || null
+
+ const setProgress = (progress) => {
+ view.progress = progress
+ }
+ pollTask(updatedTask.id, setProgress).then(finishedTask => {
+ console.debug('pollTask.then', finishedTask)
+ if (finishedTask.status === TASK_STATUS_STRING.successful) {
+ view.outputs = finishedTask?.output
+ view.selectedTaskId = finishedTask?.id
+ } else if (finishedTask.status === TASK_STATUS_STRING.failed) {
+ showError(t('assistant', 'Your task with ID {id} has failed', { id: finishedTask.id }))
+ console.error('[assistant] Task failed', finishedTask)
+ view.outputs = null
+ }
+ // resolve(finishedTask)
+ view.loading = false
+ view.showSyncTaskRunning = false
+ }).catch(error => {
+ console.debug('[assistant] poll error', error)
+ })
+ }).catch(error => {
+ console.error(error)
+ })
+ }
}
})
+ view.$on('new-task', () => {
+ console.debug('[assistant] new task')
+ view.outputs = null
+ view.selectedTaskId = null
+ lastTask = null
+ })
view.$on('background-notify', () => {
cancelTaskPolling()
view.showScheduleConfirmation = true
@@ -457,6 +558,7 @@ export async function openAssistantTask(task, { isInsideViewer = undefined, acti
view.$destroy()
})
view.$on('back-to-assistant', () => {
+ cancelTaskPolling()
view.showScheduleConfirmation = false
view.showSyncTaskRunning = false
view.loading = false
diff --git a/src/components/AssistantFormInputs.vue b/src/components/AssistantFormInputs.vue
index d4086ab9..50d9ff73 100644
--- a/src/components/AssistantFormInputs.vue
+++ b/src/components/AssistantFormInputs.vue
@@ -3,8 +3,7 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
-
-
@@ -26,7 +25,6 @@
@@ -468,6 +482,11 @@ export default {
> * {
margin-right: 6px;
}
+
+ .chatty-inputs {
+ margin-top: 8px;
+ height: 8000px;
+ }
}
.assistant-bubble {
@@ -522,7 +541,6 @@ export default {
&--list {
width: 100%;
- overflow: auto;
}
&--title {
@@ -542,4 +560,166 @@ export default {
color: var(--color-success);
}
}
+
+.container {
+ overflow: auto;
+ display: flex;
+ height: 100%;
+
+ :deep .app-navigation-new {
+ padding: 0;
+ }
+
+ .unloaded-sessions {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 1em;
+ font-weight: bold;
+ padding: 1em;
+ height: 100%;
+ }
+
+ :deep .app-navigation {
+ --app-navigation-max-width: calc(100vw - (var(--app-navigation-padding) + 24px + var(--default-grid-baseline)));
+ background-color: var(--color-primary-element-light);
+ color: var(--color-primary-element-light-text);
+ border-radius: var(--border-radius-large);
+
+ @media only screen and (max-width: 1024px) {
+ position: relative !important;
+ }
+
+ .app-navigation-toggle-wrapper {
+ margin-right: -49px !important;
+ top: var(--default-grid-baseline);
+ }
+
+ &--close {
+ .app-navigation-toggle-wrapper {
+ margin-right: -33px !important;
+ }
+ }
+
+ &--close ~ .session-area {
+ .session-area__chat-area, .session-area__input-area {
+ padding-left: 0 !important;
+ }
+ .session-area__top-bar {
+ padding-left: 36px !important;
+ }
+ }
+ }
+
+ :deep .app-navigation-list {
+ padding: var(--default-grid-baseline) !important;
+ box-sizing: border-box;
+ height: 100%;
+
+ .app-navigation-input-confirm > form {
+ align-items: center;
+ height: var(--default-clickable-area);
+
+ > button {
+ scale: calc(36/44);
+ }
+ }
+
+ .app-navigation-entry-wrapper .app-navigation-entry-link {
+ .app-navigation-entry-icon {
+ display: none;
+ }
+ .app-navigation-entry__name {
+ margin-left: 16px;
+ }
+ }
+
+ .app-navigation-entry {
+ &-link {
+ padding-right: 0.3em;
+ }
+
+ &.active {
+ font-weight: bold;
+
+ &:hover {
+ background-color: var(--color-primary-element) !important;
+ }
+ }
+
+ &:hover {
+ background-color: var(--color-primary-element-light-hover);
+ }
+
+ .app-navigation-entry-button {
+ border: none !important;
+ padding-right: 0 !important;
+
+ > span {
+ font-size: 100% !important;
+ padding-left: 0;
+ }
+ }
+
+ .editingContainer {
+ margin: 0 !important;
+ width: 100% !important;
+ padding-left: 24px;
+ }
+ }
+ }
+
+ .session-area {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ &__top-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 4px;
+ position: sticky;
+ top: 0;
+ height: calc(var(--default-clickable-area) + var(--default-grid-baseline) * 2);
+ box-sizing: border-box;
+ border-bottom: 1px solid var(--color-border);
+ padding-left: 52px;
+ padding-right: 0.5em;
+ font-weight: bold;
+ background-color: var(--color-main-background);
+
+ &__title {
+ width: 100%;
+ }
+ }
+
+ &__chat-area {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+ padding: 1em;
+
+ &__active-session__utility-button {
+ display: flex;
+ justify-content: center;
+ padding: 1em;
+ }
+ }
+
+ &__chat-area, &__input-area {
+ padding-left: 1em;
+ }
+
+ &__agency-confirmation {
+ margin-left: 1em;
+ }
+
+ &__input-area {
+ position: sticky;
+ bottom: 0;
+ }
+ }
+}
diff --git a/src/components/AssistantTextProcessingModal.vue b/src/components/AssistantTextProcessingModal.vue
index 43ab5af5..83cb3d88 100644
--- a/src/components/AssistantTextProcessingModal.vue
+++ b/src/components/AssistantTextProcessingModal.vue
@@ -48,7 +48,8 @@
@sync-submit="onSyncSubmit"
@action-button-clicked="onActionButtonClicked"
@try-again="$emit('try-again', $event)"
- @load-task="$emit('load-task', $event)" />
+ @load-task="$emit('load-task', $event)"
+ @new-task="$emit('new-task')" />
@@ -134,6 +135,7 @@ export default {
'action-button-clicked',
'try-again',
'load-task',
+ 'new-task',
'back-to-assistant',
],
data() {
diff --git a/src/components/TaskList.vue b/src/components/TaskList.vue
index 405575e3..702f8220 100644
--- a/src/components/TaskList.vue
+++ b/src/components/TaskList.vue
@@ -9,6 +9,7 @@
@@ -52,6 +54,10 @@ export default {
type: [Object, null],
default: null,
},
+ selectedTaskId: {
+ type: [Number, null],
+ default: null,
+ },
loading: {
type: Boolean,
default: false,
@@ -92,6 +98,9 @@ export default {
taskType() {
this.getTasks()
},
+ selectedTaskId() {
+ this.getTasks()
+ },
},
mounted() {
@@ -143,5 +152,10 @@ export default {
&--item {
width: 99% !important;
}
+
+ &--empty {
+ text-align: center;
+ margin: 5vh 0.5vw;
+ }
}
diff --git a/src/components/TaskListItem.vue b/src/components/TaskListItem.vue
index f79bea78..118647bc 100644
--- a/src/components/TaskListItem.vue
+++ b/src/components/TaskListItem.vue
@@ -8,7 +8,7 @@
:name="mainName"
:title="subName"
:bold="false"
- :active="false"
+ :active="active"
:details="details"
@click="$emit('load')">
@@ -120,6 +120,10 @@ export default {
},
props: {
+ active: {
+ type: Boolean,
+ default: false,
+ },
task: {
type: Object,
required: true,
@@ -157,21 +161,21 @@ export default {
return this.task.type === 'core:text2image'
},
mainName() {
- return t('assistant', 'Input') + ': ' + this.textInputPreview
+ return this.textInputPreview
},
subName() {
if (this.task.status === TASK_STATUS_STRING.successful) {
if (this.isText2Image) {
const nbGeneratedImages = this.task.output?.length ?? 0
- return n('assistant', '{n} image has been generated', '{n} images have been generated', nbGeneratedImages, { n: nbGeneratedImages })
+ return n('assistant', '{n} image generated', '{n} images generated', nbGeneratedImages, { n: nbGeneratedImages })
}
- return t('assistant', 'Result') + ': ' + this.textOutputPreview
+ return this.textOutputPreview
} else if (this.task.status === TASK_STATUS_STRING.scheduled) {
if (this.isText2Image) {
const nbImageAsked = this.task.input.numberOfImages
- return n('assistant', 'Generation of {n} image is scheduled', 'Generation of {n} images is scheduled', nbImageAsked, { n: nbImageAsked })
+ return n('assistant', '{n} image scheduled', '{n} images scheduled', nbImageAsked, { n: nbImageAsked })
}
- return t('assistant', 'This task is scheduled')
+ return t('assistant', 'Task scheduled')
}
return statusTitles[this.task.status] ?? t('assistant', 'Unknown status')
},
diff --git a/src/views/AssistantPage.vue b/src/views/AssistantPage.vue
index 9deef6e9..c6ab394d 100644
--- a/src/views/AssistantPage.vue
+++ b/src/views/AssistantPage.vue
@@ -29,7 +29,8 @@
:loading="loading"
@sync-submit="onSyncSubmit"
@try-again="onTryAgain"
- @load-task="onLoadTask" />
+ @load-task="onLoadTask"
+ @new-task="onNewTask" />
@@ -170,6 +171,11 @@ export default {
this.task.id = task.id
}
},
+ onNewTask() {
+ this.task.status = TASK_STATUS_STRING.unknown
+ this.task.output = null
+ this.task.id = null
+ },
},
}