Skip to content

Commit

Permalink
UBERF-6353: Extensible preview (hcengineering#5264)
Browse files Browse the repository at this point in the history
  • Loading branch information
lexiv0re authored and Nima committed Apr 9, 2024
1 parent a558436 commit b196546
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 45 deletions.
3 changes: 2 additions & 1 deletion models/attachment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@hcengineering/model-view": "^0.6.0",
"@hcengineering/platform": "^0.6.9",
"@hcengineering/ui": "^0.6.11",
"@hcengineering/view": "^0.6.9"
"@hcengineering/view": "^0.6.9",
"@hcengineering/model-presentation": "^0.6.0"
}
}
57 changes: 55 additions & 2 deletions models/attachment/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
//

import activity from '@hcengineering/activity'
import type { Attachment, AttachmentMetadata, Photo, SavedAttachments } from '@hcengineering/attachment'
import type {
Attachment,
AttachmentMetadata,
Photo,
SavedAttachments,
AttachmentPreviewExtension
} from '@hcengineering/attachment'
import presentation, { TComponentPointExtension } from '@hcengineering/model-presentation'
import { type Domain, IndexKind, type Ref } from '@hcengineering/core'
import {
type Builder,
Expand All @@ -31,6 +38,7 @@ import {
import core, { TAttachedDoc } from '@hcengineering/model-core'
import preference, { TPreference } from '@hcengineering/model-preference'
import view, { createAction } from '@hcengineering/model-view'
import { type Resource } from '@hcengineering/platform'

import attachment from './plugin'

Expand Down Expand Up @@ -78,8 +86,17 @@ export class TSavedAttachments extends TPreference implements SavedAttachments {
declare attachedTo: Ref<Attachment>
}

@Model(attachment.class.AttachmentPreviewExtension, presentation.class.ComponentPointExtension)
export class TAttachmentPreviewExtension extends TComponentPointExtension implements AttachmentPreviewExtension {
@Prop(TypeString(), attachment.string.ContentType)
contentType!: string | string[]

alignment?: string
availabilityChecker?: Resource<() => Promise<boolean>>
}

export function createModel (builder: Builder): void {
builder.createModel(TAttachment, TPhoto, TSavedAttachments)
builder.createModel(TAttachment, TPhoto, TSavedAttachments, TAttachmentPreviewExtension)

builder.mixin(attachment.class.Attachment, core.class.Class, view.mixin.ObjectPresenter, {
presenter: attachment.component.AttachmentPresenter
Expand Down Expand Up @@ -164,6 +181,42 @@ export function createModel (builder: Builder): void {
attachment.category.Attachments
)

builder.createDoc(
attachment.class.AttachmentPreviewExtension,
core.space.Model,
{
contentType: 'image/*',
alignment: 'centered',
component: attachment.component.PDFViewer,
extension: attachment.extension.AttachmentPreview
},
attachment.previewExtension.Image
)

builder.createDoc(
attachment.class.AttachmentPreviewExtension,
core.space.Model,
{
contentType: ['video/*', 'audio/*'],
alignment: 'float',
component: attachment.component.MediaViewer,
extension: attachment.extension.AttachmentPreview
},
attachment.previewExtension.Media
)

builder.createDoc(
attachment.class.AttachmentPreviewExtension,
core.space.Model,
{
contentType: ['application/pdf', 'application/json', 'text/*'],
alignment: 'float',
component: attachment.component.PDFViewer,
extension: attachment.extension.AttachmentPreview
},
attachment.previewExtension.PDF
)

createAction(builder, {
action: view.actionImpl.ShowEditor,
actionProps: {
Expand Down
3 changes: 2 additions & 1 deletion models/attachment/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export default mergeIds(attachmentId, attachment, {
PinAttachment: '' as IntlString,
UnPinAttachment: '' as IntlString,
FilterAttachments: '' as IntlString,
RemovedAttachment: '' as IntlString
RemovedAttachment: '' as IntlString,
ContentType: '' as IntlString
},
ids: {
TxAttachmentCreate: '' as Ref<TxViewlet>,
Expand Down
22 changes: 17 additions & 5 deletions packages/presentation/src/components/PDFViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
export let showIcon = true
export let fullSize = false
export let isLoading = false
export let css: string | undefined = undefined
const dispatch = createEventDispatcher()
Expand All @@ -45,6 +46,19 @@
let download: HTMLAnchorElement
$: src = file === undefined ? '' : getFileUrl(file, 'full', name)
$: isImage = contentType !== undefined && contentType.startsWith('image/')
let frame: HTMLIFrameElement | undefined = undefined
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
$: if (css !== undefined && frame !== undefined && frame !== null) {
frame.onload = () => {
const head = frame?.contentDocument?.querySelector('head')
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (css !== undefined && head !== undefined && head !== null) {
head.appendChild(document.createElement('style')).textContent = css
}
}
}
</script>

<ActionContext context={{ mode: 'browser' }} />
Expand All @@ -69,7 +83,7 @@
</svelte:fragment>

<svelte:fragment slot="utils">
{#if !isLoading && isImage && src !== ''}
{#if !isLoading && src !== ''}
<a class="no-line" href={src} download={name} bind:this={download}>
<Button
icon={Download}
Expand All @@ -93,7 +107,7 @@
<img class="img-fit" {src} alt="" />
</div>
{:else}
<iframe class="pdfviewer-content" src={src + '#view=FitH&navpanes=0'} title="" />
<iframe bind:this={frame} class="pdfviewer-content" src={src + '#view=FitH&navpanes=0'} title="" />
{/if}
{:else}
<div class="centered">
Expand All @@ -119,9 +133,7 @@
.pdfviewer-content {
flex-grow: 1;
overflow: auto;
border-style: none;
border-radius: 0.5rem;
background-color: var(--theme-bg-color);
border: none;
&.img {
display: flex;
Expand Down
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"PinAttachment": "Mark important",
"UnPinAttachment": "Mark less important",
"FilterAttachments": "Attachments",
"RemovedAttachment": "Removed attachment"
"RemovedAttachment": "Removed attachment",
"ContentType": "Content type"
},
"status": {
"FileTooLarge": "File too large"
Expand Down
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"PinAttachment": "Marcar como importante",
"UnPinAttachment": "Marcar como menos importante",
"FilterAttachments": "Adjuntos",
"RemovedAttachment": "Adjunto eliminado"
"RemovedAttachment": "Adjunto eliminado",
"ContentType": "Tipo de contenido"
},
"status": {
"FileTooLarge": "Archivo demasiado grande"
Expand Down
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"PinAttachment": "Marcar como importante",
"UnPinAttachment": "Marcar como menos importante",
"FilterAttachments": "Anexos",
"RemovedAttachment": "Anexo removido"
"RemovedAttachment": "Anexo removido",
"ContentType": "Tipo de conteúdo"
},
"status": {
"FileTooLarge": "Ficheiro demasiado grande"
Expand Down
3 changes: 2 additions & 1 deletion plugins/attachment-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"PinAttachment": "Пометить как важное",
"UnPinAttachment": "Убрать пометку важное",
"FilterAttachments": "Вложения",
"RemovedAttachment": "Удалил(а) вложение"
"RemovedAttachment": "Удалил(а) вложение",
"ContentType": "Тип контента"
},
"status": {
"FileTooLarge": "Файл слишком большой"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@
// limitations under the License.
-->
<script lang="ts">
import type { Attachment } from '@hcengineering/attachment'
import { AttachmentPreviewExtension, type Attachment } from '@hcengineering/attachment'
import { getResource } from '@hcengineering/platform'
import { PDFViewer, getFileUrl } from '@hcengineering/presentation'
import { Action as UIAction, ActionIcon, IconMoreH, IconOpen, Menu, closeTooltip, showPopup } from '@hcengineering/ui'
import { getFileUrl } from '@hcengineering/presentation'
import {
Action as UIAction,
ActionIcon,
IconMoreH,
IconOpen,
Menu,
closeTooltip,
showPopup,
PopupAlignment
} from '@hcengineering/ui'
import view, { Action } from '@hcengineering/view'
import MediaViewer from './MediaViewer.svelte'
import { previewTypes, getPreviewType, isOpenable } from '../utils'
import attachmentPlugin from '../plugin'
import FileDownload from './icons/FileDownload.svelte'
Expand All @@ -30,21 +39,39 @@
let download: HTMLAnchorElement
$: contentType = attachment?.type ?? ''
$: openable =
contentType.includes('application/pdf') || contentType.startsWith('image/') || contentType.startsWith('video/')
let openable = false
$: {
void isOpenable(contentType, $previewTypes).then((res) => {
openable = res
})
}
let previewType: AttachmentPreviewExtension | undefined = undefined
$: if (openable) {
void getPreviewType(contentType, $previewTypes).then((res) => {
previewType = res
})
} else {
previewType = undefined
}
function showPreview (e: MouseEvent): void {
if (!openable || previewType === undefined) {
return
}
e.preventDefault()
e.stopPropagation()
if (e.metaKey || e.ctrlKey) {
window.open((e.target as HTMLAnchorElement).href, '_blank')
return
}
closeTooltip()
showPopup(
contentType.startsWith('video/') ? MediaViewer : PDFViewer,
{ file: attachment.file, name: attachment.name, contentType, value: attachment },
contentType.startsWith('image/') ? 'centered' : 'float'
previewType.component,
{ ...(previewType.props ?? {}), file: attachment.file, name: attachment.name, contentType, value: attachment },
(previewType.alignment ?? 'center') as PopupAlignment
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { Attachment } from '@hcengineering/attachment'
import { showPopup, closeTooltip, Label, getIconSize2x, Loading } from '@hcengineering/ui'
import presentation, { PDFViewer, getFileUrl } from '@hcengineering/presentation'
import type { Attachment, AttachmentPreviewExtension } from '@hcengineering/attachment'
import { showPopup, closeTooltip, Label, getIconSize2x, Loading, PopupAlignment } from '@hcengineering/ui'
import presentation, { getFileUrl } from '@hcengineering/presentation'
import filesize from 'filesize'
import core from '@hcengineering/core'
import { permissionsStore } from '@hcengineering/view-resources'
import MediaViewer from './MediaViewer.svelte'
import { getType } from '../utils'
import { getType, isOpenable, previewTypes, getPreviewType } from '../utils'
import AttachmentName from './AttachmentName.svelte'
Expand Down Expand Up @@ -54,18 +53,29 @@
function isImage (contentType: string): boolean {
return getType(contentType) === 'image'
}
function isPlayable (contentType: string) {
const type = getType(contentType)
return type === 'video' || type === 'audio'
let openable = false
$: if (value !== undefined) {
void isOpenable(value.type, $previewTypes).then((res) => {
openable = res
})
} else {
openable = false
}
function openEmbedded (contentType: string): boolean {
return getType(contentType) !== 'other'
let previewType: AttachmentPreviewExtension | undefined = undefined
$: if (openable && value !== undefined) {
void getPreviewType(value.type, $previewTypes).then((res) => {
previewType = res
})
} else {
previewType = undefined
}
function clickHandler (e: MouseEvent): void {
if (value === undefined) return
if (!openEmbedded(value.type)) return
if (!openable || previewType === undefined) return
e.preventDefault()
e.stopPropagation()
if (e.metaKey || e.ctrlKey) {
Expand All @@ -74,9 +84,9 @@
}
closeTooltip()
showPopup(
isPlayable(value.type) ? MediaViewer : PDFViewer,
{ file: value.file, name: value.name, contentType: value.type, value },
isImage(value.type) ? 'centered' : 'float'
previewType.component,
{ ...(previewType.props ?? {}), file: value.file, name: value.name, contentType: value.type, value },
(previewType.alignment ?? 'center') as PopupAlignment
)
}
Expand Down
7 changes: 5 additions & 2 deletions plugins/attachment-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import attachment, { type Attachment } from '@hcengineering/attachment'
import { type ObjQueryType, SortingOrder, type SortingQuery, type Markup } from '@hcengineering/core'
import { type IntlString, type Resources } from '@hcengineering/platform'
import preference from '@hcengineering/preference'
import { getClient } from '@hcengineering/presentation'
import { getClient, PDFViewer } from '@hcengineering/presentation'
import activity, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/activity'

import TxAttachmentCreate from './components/activity/TxAttachmentCreate.svelte'
Expand All @@ -42,6 +42,7 @@ import IconAttachment from './components/icons/Attachment.svelte'
import AttachmentPreview from './components/AttachmentPreview.svelte'
import AttachmentsUpdatedMessage from './components/activity/AttachmentsUpdatedMessage.svelte'
import AttachmentsTooltip from './components/AttachmentsTooltip.svelte'
import MediaViewer from './components/MediaViewer.svelte'
import { deleteFile, uploadFile } from './utils'

export * from './types'
Expand Down Expand Up @@ -258,7 +259,9 @@ export default async (): Promise<Resources> => ({
AttachmentGalleryPresenter,
Attachments,
FileBrowser,
Photos
Photos,
PDFViewer,
MediaViewer
},
activity: {
TxAttachmentCreate,
Expand Down
Loading

0 comments on commit b196546

Please sign in to comment.