Skip to content
Draft
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
20 changes: 19 additions & 1 deletion src/components/AssistantTextProcessingForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
@update:model-value="onTaskTypeUserChange" />
<div class="task-input-output-form">
<ChattyLLMInputForm v-if="mySelectedTaskTypeId === 'chatty-llm'" class="chatty-inputs" />
<div v-else class="container chatty-inputs">
<div v-else
ref="container"
class="container chatty-inputs"
:class="{ 'container--history-collapsed': narrow }">
<NcAppNavigation>
<NcAppNavigationList>
<NcAppNavigationNew :text="t('assistant', 'New task')"
Expand Down Expand Up @@ -179,6 +182,8 @@
import '@nextcloud/dialogs/style.css'

import { saveLastSelectedTaskType } from '../assistant.js'
import { HISTORY_BREAKPOINT, useElementNarrow } from '../composables/useElementNarrow.js'
import { ref } from 'vue'

const TEXT2TEXT_TASK_TYPE_ID = 'core:text2text'
const CHAT_TASK_TYPE_ID = 'chatty-llm'
Expand Down Expand Up @@ -212,12 +217,18 @@
ChattyLLMInputForm,
EditableTextField,
},

setup() {
const container = ref(null)
const narrow = useElementNarrow(container, HISTORY_BREAKPOINT)
return { container, narrow }
},
provide() {

Check warning on line 226 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM lint

The "provide" property should be above the "setup" property on line 221

Check warning on line 226 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "provide" property should be above the "setup" property on line 221

Check warning on line 226 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "provide" property should be above the "setup" property on line 221
return {
providedCurrentTaskId: () => this.selectedTaskId,
}
},
props: {

Check warning on line 231 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM lint

The "props" property should be above the "setup" property on line 221

Check warning on line 231 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "props" property should be above the "setup" property on line 221

Check warning on line 231 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "props" property should be above the "setup" property on line 221
loading: {
type: Boolean,
default: false,
Expand Down Expand Up @@ -275,7 +286,7 @@
default: null,
},
},
emits: [

Check warning on line 289 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM lint

The "emits" property should be above the "setup" property on line 221

Check warning on line 289 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "emits" property should be above the "setup" property on line 221

Check warning on line 289 in src/components/AssistantTextProcessingForm.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "emits" property should be above the "setup" property on line 221
'sync-submit',
'action-button-clicked',
'try-again',
Expand Down Expand Up @@ -696,6 +707,13 @@
min-height: 0;
overflow: hidden;

// the assistant lives in a resizable/draggable dialog, so the task
// history visibility has to follow the dialog width rather than the
// viewport
&--history-collapsed :deep(.app-navigation) {
display: none;
}

:deep(.app-navigation-new) {
padding: 0;
}
Expand Down
36 changes: 33 additions & 3 deletions src/components/AssistantTextProcessingModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
:closable="false"
:dismissable-mask="false"
:close-on-escape="false"
:draggable="true"
:draggable="!isSmallMobile"
append-to="self"
:base-z-index="isInsideViewer ? 9998 : 5000"
class="assistant-modal">
:class="['assistant-modal', { 'assistant-modal--fullscreen': isSmallMobile }]">
<div ref="modal_content"
class="assistant-modal--wrapper">
<div class="assistant-modal--content">
Expand Down Expand Up @@ -57,6 +57,7 @@
import PrimeDialog from 'primevue/dialog'

import NcButton from '@nextcloud/vue/components/NcButton'
import { useIsSmallMobile } from '@nextcloud/vue/composables/useIsMobile'

import AssistantTextProcessingForm from './AssistantTextProcessingForm.vue'

Expand All @@ -70,7 +71,10 @@
NcButton,
CloseIcon,
},
setup() {
return { isSmallMobile: useIsSmallMobile() }
},
props: {

Check warning on line 77 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM lint

The "props" property should be above the "setup" property on line 74

Check warning on line 77 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "props" property should be above the "setup" property on line 74

Check warning on line 77 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "props" property should be above the "setup" property on line 74
/**
* If true, add the modal content to the Viewer trap elements via the event-bus
*/
Expand Down Expand Up @@ -103,7 +107,7 @@
default: null,
},
},
emits: [

Check warning on line 110 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM lint

The "emits" property should be above the "setup" property on line 74

Check warning on line 110 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "emits" property should be above the "setup" property on line 74

Check warning on line 110 in src/components/AssistantTextProcessingModal.vue

View workflow job for this annotation

GitHub Actions / NPM build

The "emits" property should be above the "setup" property on line 74
'cancel',
'cancel-task',
'background-notify',
Expand Down Expand Up @@ -210,7 +214,7 @@
height: calc(100vh - 32px);
max-height: calc(100vh - 32px);
height: 80%;
width: 50%;
width: min(1220px, 90vw);
resize: both;
overflow: hidden;
filter: drop-shadow(0 0 15px rgba(77, 77, 77, 0.5));
Expand All @@ -219,6 +223,24 @@
border: 0;
}

.assistant-modal.p-dialog.assistant-modal--fullscreen,
.assistant-modal.p-dialog.p-dialog-maximized {
inset: 0;
width: 100vw;
max-width: none;
height: 100vh;
max-height: none;
margin: 0;
border-radius: 0;
resize: none;
filter: none;
transform: none;
}

.assistant-modal.p-dialog.assistant-modal--fullscreen .p-dialog-header .p-dialog-maximize-button {
display: none;
}

.assistant-modal .p-dialog-header {
position: absolute;
top: 0;
Expand All @@ -234,10 +256,18 @@
cursor: grabbing;
}
.p-dialog-maximize-button {
position: absolute;
top: 10px;
left: 10px;
z-index: 3;
margin: 0 !important;
color: var(--color-main-text);
background-color: var(--color-main-background);
border-radius: var(--border-radius-element);
width: var(--default-clickable-area);
height: var(--default-clickable-area);
&:hover {
color: var(--color-main-text) !important;
background-color: var(--color-background-hover) !important;
border: none !important;
}
Expand Down
58 changes: 23 additions & 35 deletions src/components/ChattyLLM/ChattyLLMInputForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,11 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="container">
<NcAppNavigation>
<div ref="container"
class="container"
:class="{ 'container--history-collapsed': narrow }">
<NcAppNavigation :aria-label="t('assistant', 'Conversation history')">
<NcAppNavigationList>
<NcAppNavigationNew :text="t('assistant', 'New conversation')"
variant="secondary"
@click="newSession">
<template #icon>
<PlusIcon :size="20" />
</template>
</NcAppNavigationNew>
<div v-if="sessions == null" class="unloaded-sessions">
<NcLoadingIcon :size="30" />
{{ t('assistant', 'Loading conversations…') }}
Expand Down Expand Up @@ -187,7 +182,6 @@
<script>
import AutoFixIcon from 'vue-material-design-icons/AutoFix.vue'
import PencilOutlineIcon from 'vue-material-design-icons/PencilOutline.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'
import TrashCanOutlineIcon from 'vue-material-design-icons/TrashCanOutline.vue'
import MemoryIcon from 'vue-material-design-icons/Memory.vue'

Expand All @@ -200,7 +194,6 @@ import NcAppContent from '@nextcloud/vue/components/NcAppContent'
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
import NcAppNavigationList from '@nextcloud/vue/components/NcAppNavigationList'
import NcAppNavigationNew from '@nextcloud/vue/components/NcAppNavigationNew'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
import NcDialog from '@nextcloud/vue/components/NcDialog'
Expand All @@ -217,6 +210,8 @@ import { generateUrl, generateOcsUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
import moment from 'moment'
import { SHAPE_TYPE_NAMES } from '../../constants.js'
import { HISTORY_BREAKPOINT, useElementNarrow } from '../../composables/useElementNarrow.js'
import { ref } from 'vue'

// future: type (text, image, file, etc), attachments, etc support

Expand All @@ -234,7 +229,6 @@ export default {
AutoFixIcon,
TrashCanOutlineIcon,
PencilOutlineIcon,
PlusIcon,
MemoryIcon,

AssistantIcon,
Expand All @@ -246,7 +240,6 @@ export default {
NcAppNavigation,
NcAppNavigationItem,
NcAppNavigationList,
NcAppNavigationNew,
NcButton,
NcLoadingIcon,
NcDialog,
Expand All @@ -257,6 +250,12 @@ export default {
NoSession,
},

setup() {
const container = ref(null)
const narrow = useElementNarrow(container, HISTORY_BREAKPOINT)
return { container, narrow }
},

data: () => {
return {
// { id: number, title: string, user_id: string, timestamp: number }
Expand Down Expand Up @@ -916,6 +915,7 @@ export default {
height: 100%;
min-height: 0;
overflow: hidden;
position: relative;

:deep(.app-navigation-new) {
padding: 0;
Expand All @@ -940,30 +940,17 @@ export default {
height: 100%;
min-height: 0;
overflow: visible;

@media only screen and (max-width: 1024px) {
position: relative !important;
}

.app-navigation-toggle-wrapper {
margin-right: -49px !important;
top: var(--default-grid-baseline);
}
}

:deep(.app-navigation--close) {
.app-navigation-toggle-wrapper {
margin-right: -33px !important;
}
// NcAppNavigation slides itself away based on the viewport width
// (its internal "mobile" state); we drive visibility from the dialog
// width instead, so cancel the library's viewport-driven offset
:deep(.app-navigation--closed) {
margin-inline-start: 0;
}

:deep(.app-navigation--close ~ .session-area) {
.session-area__chat-area, .session-area__input-area {
padding-left: 0 !important;
}
.session-area__top-bar {
padding-left: 36px !important;
}
&--history-collapsed :deep(.app-navigation) {
display: none;
}

:deep(.app-navigation-list) {
Expand Down Expand Up @@ -1051,8 +1038,9 @@ export default {
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;
padding-left: 0.5em;
// leave room for the dialog close button overlapping the top-right
padding-right: calc(var(--default-clickable-area) + 0.5em);
font-weight: bold;
background-color: var(--color-main-background);

Expand Down
47 changes: 47 additions & 0 deletions src/composables/useElementNarrow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { onBeforeUnmount, readonly, ref, watch } from 'vue'

// minimum dialog width (px) at which the task history sidebar is shown
// side by side; below it the sidebar is hidden
export const HISTORY_BREAKPOINT = 900

/**
* Reactive flag tracking whether an element's content-box width is below
* a breakpoint. Drives the dialog-width-based collapse of the task
* history sidebar across task types (the assistant dialog is resizable,
* so a CSS media query on the viewport would not be enough).
*
* The template ref may be re-bound across the component lifetime when
* the target lives inside a `v-if`/`v-else` branch, so the observer is
* (re)attached via a watcher rather than a one-shot mounted hook.
*
* @param {import('vue').Ref<HTMLElement | null>} elementRef Template ref
* @param {number} breakpointPx Width threshold in pixels
* @return {Readonly<import('vue').Ref<boolean>>}
*/
export function useElementNarrow(elementRef, breakpointPx) {
const narrow = ref(false)
let observer = null

watch(elementRef, (el) => {
observer?.disconnect()
observer = null
if (!el) {
return
}
observer = new ResizeObserver((entries) => {
narrow.value = entries[0].contentRect.width < breakpointPx
})
observer.observe(el)
}, { immediate: true, flush: 'post' })

onBeforeUnmount(() => {
observer?.disconnect()
})

return readonly(narrow)
}
Loading