mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-14 11:24:06 +00:00
UBERF-9759 Scroll attachments in chat (#8523)
* UBERF-9759 Scroll attachments in chat Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix: use Array.from(...) Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> --------- Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
afbaf26078
commit
11232c503c
@ -166,6 +166,7 @@
|
|||||||
updateToolbarPosition(readonly, board, toolbar)
|
updateToolbarPosition(readonly, board, toolbar)
|
||||||
}}
|
}}
|
||||||
use:drawing={{
|
use:drawing={{
|
||||||
|
autoSize: imageWidth === undefined || imageHeight === undefined,
|
||||||
readonly,
|
readonly,
|
||||||
imageWidth,
|
imageWidth,
|
||||||
imageHeight,
|
imageHeight,
|
||||||
|
@ -47,10 +47,9 @@
|
|||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
onMount(() => {
|
$: void loadDrawings(file)
|
||||||
if (fullSize) {
|
|
||||||
dispatch('fullsize')
|
async function loadDrawings (file: Ref<Blob> | undefined): Promise<void> {
|
||||||
}
|
|
||||||
if (props.drawingAvailable === true) {
|
if (props.drawingAvailable === true) {
|
||||||
if (props.loadDrawings !== undefined) {
|
if (props.loadDrawings !== undefined) {
|
||||||
drawingLoading = true
|
drawingLoading = true
|
||||||
@ -66,6 +65,14 @@
|
|||||||
console.error('Failed to load drawings for file', file, error)
|
console.error('Failed to load drawings for file', file, error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (fullSize) {
|
||||||
|
dispatch('fullsize')
|
||||||
|
}
|
||||||
|
if (props.drawingAvailable === true) {
|
||||||
if (props.createDrawing !== undefined) {
|
if (props.createDrawing !== undefined) {
|
||||||
createDrawing = props.createDrawing
|
createDrawing = props.createDrawing
|
||||||
props.createDrawing = async (data: any): Promise<any> => {
|
props.createDrawing = async (data: any): Promise<any> => {
|
||||||
|
@ -57,7 +57,7 @@ export function updatePopup (id: string, props: Partial<CompAndProps>): void {
|
|||||||
(p: CompAndProps) => p.id === id
|
(p: CompAndProps) => p.id === id
|
||||||
)
|
)
|
||||||
if (popupIndex !== -1) {
|
if (popupIndex !== -1) {
|
||||||
;(modals[popupIndex] as CompAndProps).update?.(props)
|
;(modals[popupIndex] as CompAndProps).update?.(props.props)
|
||||||
}
|
}
|
||||||
return modals
|
return modals
|
||||||
})
|
})
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Attachment } from '@hcengineering/attachment'
|
import { Attachment } from '@hcengineering/attachment'
|
||||||
import { Ref, type WithLookup } from '@hcengineering/core'
|
import { Ref, type WithLookup } from '@hcengineering/core'
|
||||||
import { Scroller } from '@hcengineering/ui'
|
import { ListSelectionProvider } from '@hcengineering/view-resources'
|
||||||
|
import { Scroller, updatePopup } from '@hcengineering/ui'
|
||||||
import { AttachmentImageSize } from '../types'
|
import { AttachmentImageSize } from '../types'
|
||||||
import AttachmentPreview from './AttachmentPreview.svelte'
|
import AttachmentPreview from './AttachmentPreview.svelte'
|
||||||
|
|
||||||
@ -23,6 +24,22 @@
|
|||||||
export let savedAttachmentsIds: Ref<Attachment>[] = []
|
export let savedAttachmentsIds: Ref<Attachment>[] = []
|
||||||
export let imageSize: AttachmentImageSize | undefined = undefined
|
export let imageSize: AttachmentImageSize | undefined = undefined
|
||||||
export let videoPreload = false
|
export let videoPreload = false
|
||||||
|
|
||||||
|
let attachmentPopupId = ''
|
||||||
|
|
||||||
|
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0) => {
|
||||||
|
const current = listProvider.current()
|
||||||
|
if (current === undefined) return
|
||||||
|
let pos = current + offset
|
||||||
|
if (pos < 0) pos = 0
|
||||||
|
if (pos >= attachments.length) pos = attachments.length - 1
|
||||||
|
const doc = listProvider.docs()[pos] as Attachment
|
||||||
|
if (doc !== undefined && attachmentPopupId !== '') {
|
||||||
|
listProvider.updateFocus(doc)
|
||||||
|
updatePopup(attachmentPopupId, { props: { value: doc } })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$: listProvider.update(attachments.filter((p) => p.type.startsWith('image/')))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if attachments.length}
|
{#if attachments.length}
|
||||||
@ -33,6 +50,8 @@
|
|||||||
isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false}
|
isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false}
|
||||||
{imageSize}
|
{imageSize}
|
||||||
{videoPreload}
|
{videoPreload}
|
||||||
|
{listProvider}
|
||||||
|
on:open={(res) => (attachmentPopupId = res.detail)}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
|
@ -99,7 +99,8 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (value.type.startsWith('image/') || value.type.startsWith('video/') || value.type.startsWith('audio/')) {
|
if (value.type.startsWith('image/') || value.type.startsWith('video/') || value.type.startsWith('audio/')) {
|
||||||
showAttachmentPreviewPopup(value)
|
const popup = showAttachmentPreviewPopup(value)
|
||||||
|
dispatch('open', popup.id)
|
||||||
} else {
|
} else {
|
||||||
await openAttachmentInSidebar(value)
|
await openAttachmentInSidebar(value)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2024 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import attachment, { type Attachment, type Drawing } from '@hcengineering/attachment'
|
||||||
|
import core, { SortingOrder } from '@hcengineering/core'
|
||||||
|
import { DrawingData, FilePreviewPopup, getClient } from '@hcengineering/presentation'
|
||||||
|
import { isAttachment } from '../utils'
|
||||||
|
|
||||||
|
export let value: Attachment
|
||||||
|
|
||||||
|
export let fullSize = false
|
||||||
|
export let showIcon = true
|
||||||
|
|
||||||
|
$: drawingAvailable = value?.type?.startsWith('image/') && isAttachment(value)
|
||||||
|
|
||||||
|
async function loadDrawings (): Promise<Drawing[]> {
|
||||||
|
const client = getClient()
|
||||||
|
const drawings = await client.findAll(
|
||||||
|
attachment.class.Drawing,
|
||||||
|
{
|
||||||
|
parent: value.file,
|
||||||
|
space: value.space
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sort: {
|
||||||
|
createdOn: SortingOrder.Descending
|
||||||
|
},
|
||||||
|
limit: 1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Array.from(drawings ?? [])
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createDrawing (data: DrawingData): Promise<DrawingData> {
|
||||||
|
const client = getClient()
|
||||||
|
const newId = await client.createDoc(attachment.class.Drawing, value.space, {
|
||||||
|
parent: value.file,
|
||||||
|
parentClass: core.class.Blob,
|
||||||
|
content: data.content
|
||||||
|
})
|
||||||
|
const newDrawing = await client.findOne(attachment.class.Drawing, { _id: newId })
|
||||||
|
if (newDrawing === undefined) {
|
||||||
|
throw new Error('Unable to find just created drawing')
|
||||||
|
}
|
||||||
|
return newDrawing
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FilePreviewPopup
|
||||||
|
file={value.file}
|
||||||
|
name={value.name}
|
||||||
|
metadata={value.metadata}
|
||||||
|
contentType={value.type}
|
||||||
|
props={{
|
||||||
|
drawingAvailable,
|
||||||
|
loadDrawings,
|
||||||
|
createDrawing
|
||||||
|
}}
|
||||||
|
{fullSize}
|
||||||
|
{showIcon}
|
||||||
|
on:open
|
||||||
|
on:close
|
||||||
|
on:update
|
||||||
|
on:fullsize
|
||||||
|
/>
|
@ -34,7 +34,7 @@
|
|||||||
const sel = listProvider.docs()[selected] as Attachment
|
const sel = listProvider.docs()[selected] as Attachment
|
||||||
if (sel !== undefined && attachmentPopupId !== '') {
|
if (sel !== undefined && attachmentPopupId !== '') {
|
||||||
listProvider.updateFocus(sel)
|
listProvider.updateFocus(sel)
|
||||||
updatePopup(attachmentPopupId, { props: { file: sel.file, name: sel.name, contentType: sel.type } })
|
updatePopup(attachmentPopupId, { props: { value: sel } })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
$: listProvider.update(attachments.filter((p) => p.type.startsWith('image/')))
|
$: listProvider.update(attachments.filter((p) => p.type.startsWith('image/')))
|
||||||
@ -52,7 +52,13 @@
|
|||||||
on:open={(res) => (attachmentPopupId = res.detail)}
|
on:open={(res) => (attachmentPopupId = res.detail)}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<AttachmentPresenter value={attachment} removable={!readonly} showPreview on:remove />
|
<AttachmentPresenter
|
||||||
|
value={attachment}
|
||||||
|
removable={!readonly}
|
||||||
|
showPreview
|
||||||
|
on:remove
|
||||||
|
on:open={(res) => (attachmentPopupId = res.detail)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{#if progress}
|
{#if progress}
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { type Attachment, type Drawing } from '@hcengineering/attachment'
|
import { type Attachment } from '@hcengineering/attachment'
|
||||||
import core, {
|
import {
|
||||||
type BlobMetadata,
|
type BlobMetadata,
|
||||||
SortingOrder,
|
|
||||||
type Blob,
|
type Blob,
|
||||||
type Class,
|
type Class,
|
||||||
type TxOperations as Client,
|
type TxOperations as Client,
|
||||||
@ -30,19 +29,18 @@ import core, {
|
|||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { getResource, setPlatformStatus, unknownError } from '@hcengineering/platform'
|
import { getResource, setPlatformStatus, unknownError } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
type DrawingData,
|
|
||||||
type FileOrBlob,
|
type FileOrBlob,
|
||||||
getClient,
|
getClient,
|
||||||
getFileMetadata,
|
getFileMetadata,
|
||||||
getPreviewAlignment,
|
getPreviewAlignment,
|
||||||
uploadFile,
|
uploadFile
|
||||||
FilePreviewPopup
|
|
||||||
} from '@hcengineering/presentation'
|
} from '@hcengineering/presentation'
|
||||||
import { closeTooltip, showPopup, type PopupResult } from '@hcengineering/ui'
|
import { closeTooltip, showPopup, type PopupResult } from '@hcengineering/ui'
|
||||||
import workbench, { type WidgetTab } from '@hcengineering/workbench'
|
import workbench, { type WidgetTab } from '@hcengineering/workbench'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
|
|
||||||
import attachment from './plugin'
|
import attachment from './plugin'
|
||||||
|
import AttachmentPreviewPopup from './components/AttachmentPreviewPopup.svelte'
|
||||||
|
|
||||||
export async function createAttachments (
|
export async function createAttachments (
|
||||||
client: Client,
|
client: Client,
|
||||||
@ -158,60 +156,8 @@ export function isAttachment (value: Attachment | BlobType): value is WithLookup
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function showAttachmentPreviewPopup (value: WithLookup<Attachment> | BlobType): PopupResult {
|
export function showAttachmentPreviewPopup (value: WithLookup<Attachment> | BlobType): PopupResult {
|
||||||
const props: Record<string, any> = {}
|
|
||||||
|
|
||||||
if (value?.type?.startsWith('image/') && isAttachment(value)) {
|
|
||||||
props.drawingAvailable = true
|
|
||||||
props.loadDrawings = async (): Promise<Drawing[] | undefined> => {
|
|
||||||
const client = getClient()
|
|
||||||
const drawings = await client.findAll(
|
|
||||||
attachment.class.Drawing,
|
|
||||||
{
|
|
||||||
parent: value.file,
|
|
||||||
space: value.space
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sort: {
|
|
||||||
createdOn: SortingOrder.Descending
|
|
||||||
},
|
|
||||||
limit: 1
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const result = []
|
|
||||||
if (drawings !== undefined) {
|
|
||||||
for (const drawing of drawings) {
|
|
||||||
result.push(drawing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
props.createDrawing = async (data: DrawingData): Promise<DrawingData> => {
|
|
||||||
const client = getClient()
|
|
||||||
const newId = await client.createDoc(attachment.class.Drawing, value.space, {
|
|
||||||
parent: value.file,
|
|
||||||
parentClass: core.class.Blob,
|
|
||||||
content: data.content
|
|
||||||
})
|
|
||||||
const newDrawing = await client.findOne(attachment.class.Drawing, { _id: newId })
|
|
||||||
if (newDrawing === undefined) {
|
|
||||||
throw new Error('Unable to find just created drawing')
|
|
||||||
}
|
|
||||||
return newDrawing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closeTooltip()
|
closeTooltip()
|
||||||
return showPopup(
|
return showPopup(AttachmentPreviewPopup, { value }, getPreviewAlignment(value.type ?? ''))
|
||||||
FilePreviewPopup,
|
|
||||||
{
|
|
||||||
file: value.file,
|
|
||||||
contentType: value.type,
|
|
||||||
name: value.name,
|
|
||||||
metadata: value.metadata,
|
|
||||||
props
|
|
||||||
},
|
|
||||||
getPreviewAlignment(value.type ?? '')
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImageDimensions {
|
interface ImageDimensions {
|
||||||
|
Loading…
Reference in New Issue
Block a user