Skip to content

Commit

Permalink
feat: add links preview (#7600)
Browse files Browse the repository at this point in the history
Signed-off-by: Denis Tingaikin <[email protected]>
  • Loading branch information
denis-tingaikin authored Jan 15, 2025
1 parent 81dd4cd commit d020053
Show file tree
Hide file tree
Showing 23 changed files with 515 additions and 105 deletions.
5 changes: 3 additions & 2 deletions desktop/src/ui/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { taskId } from '@hcengineering/task'
import telegram, { telegramId } from '@hcengineering/telegram'
import { templatesId } from '@hcengineering/templates'
import tracker, { trackerId } from '@hcengineering/tracker'
import uiPlugin, { getCurrentLocation, locationStorageKeyId, locationToUrl, navigate, parseLocation, setLocationStorageKey } from '@hcengineering/ui'
import uiPlugin, { getCurrentLocation, locationStorageKeyId, navigate, setLocationStorageKey } from '@hcengineering/ui'
import { uploaderId } from '@hcengineering/uploader'
import { viewId } from '@hcengineering/view'
import workbench, { workbenchId } from '@hcengineering/workbench'
Expand Down Expand Up @@ -215,6 +215,7 @@ export async function configurePlatform (): Promise<void> {
setMetadata(presentation.metadata.PreviewConfig, parsePreviewConfig(config.PREVIEW_CONFIG))
setMetadata(presentation.metadata.UploadConfig, parseUploadConfig(config.UPLOAD_CONFIG, config.UPLOAD_URL))
setMetadata(presentation.metadata.FrontUrl, config.FRONT_URL)
setMetadata(presentation.metadata.LinkPreviewUrl, config.LINK_PREVIEW_URL ?? '')
setMetadata(presentation.metadata.StatsUrl, config.STATS_URL)

setMetadata(textEditor.metadata.Collaborator, config.COLLABORATOR ?? '')
Expand All @@ -238,7 +239,7 @@ export async function configurePlatform (): Promise<void> {
setMetadata(notification.metadata.PushPublicKey, config.PUSH_PUBLIC_KEY)

setMetadata(rekoni.metadata.RekoniUrl, config.REKONI_URL)
setMetadata(contactPlugin.metadata.LastNameFirst, myBranding.lastNameFirst === 'true' ?? false)
setMetadata(contactPlugin.metadata.LastNameFirst, myBranding.lastNameFirst === 'true')
setMetadata(love.metadata.ServiceEnpdoint, config.LOVE_ENDPOINT)
setMetadata(love.metadata.WebSocketURL, config.LIVEKIT_WS)
setMetadata(print.metadata.PrintURL, config.PRINT_URL)
Expand Down
46 changes: 23 additions & 23 deletions desktop/src/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,39 @@ import { ScreenSource } from '@hcengineering/love'
*/
export interface Config {
ACCOUNTS_URL: string
AI_URL?: string
ANALYTICS_COLLECTOR_URL?: string
BRANDING_URL?: string
CALENDAR_URL: string
COLLABORATOR?: string
COLLABORATOR_URL: string
FRONT_URL: string
CONFIG_URL: string
DESKTOP_UPDATES_CHANNEL?: string
DESKTOP_UPDATES_URL?: string
DISABLE_SIGNUP?: string
FILES_URL: string
UPLOAD_URL: string
MODEL_VERSION?: string
VERSION?: string
TELEGRAM_URL: string
GMAIL_URL: string
CALENDAR_URL: string
REKONI_URL: string
INITIAL_URL: string
FRONT_URL: string
GITHUB_APP: string
GITHUB_CLIENTID: string
GITHUB_URL: string
CONFIG_URL: string
LOVE_ENDPOINT?: string
GMAIL_URL: string
INITIAL_URL: string
LINK_PREVIEW_URL?: string
LIVEKIT_WS?: string
SIGN_URL?: string
LOVE_ENDPOINT?: string
MODEL_VERSION?: string
PRESENCE_URL?: string
PREVIEW_CONFIG: string
PRINT_URL?: string
PUSH_PUBLIC_KEY: string
ANALYTICS_COLLECTOR_URL?: string
AI_URL?:string
DISABLE_SIGNUP?: string
BRANDING_URL?: string
PREVIEW_CONFIG: string
UPLOAD_CONFIG: string
DESKTOP_UPDATES_URL?: string
DESKTOP_UPDATES_CHANNEL?: string
TELEGRAM_BOT_URL?: string
PRESENCE_URL?: string

REKONI_URL: string
SIGN_URL?: string
STATS_URL?: string
TELEGRAM_BOT_URL?: string
TELEGRAM_URL: string
UPLOAD_CONFIG: string
UPLOAD_URL: string
VERSION?: string
}

export interface Branding {
Expand Down
7 changes: 4 additions & 3 deletions dev/prod/src/platform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright © 2022, 2023 Hardcore Engineering Inc.
// Copyright © 2022, 2023, 2025 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
Expand Down Expand Up @@ -157,6 +157,7 @@ export interface Config {
TELEGRAM_BOT_URL?: string
AI_URL?:string
DISABLE_SIGNUP?: string
LINK_PREVIEW_URL?: string
// Could be defined for dev environment
FRONT_URL?: string
PREVIEW_CONFIG?: string
Expand Down Expand Up @@ -314,7 +315,7 @@ export async function configurePlatform() {
setMetadata(presentation.metadata.PreviewConfig, parsePreviewConfig(config.PREVIEW_CONFIG))
setMetadata(presentation.metadata.UploadConfig, parseUploadConfig(config.UPLOAD_CONFIG, config.UPLOAD_URL))
setMetadata(presentation.metadata.StatsUrl, config.STATS_URL)

setMetadata(presentation.metadata.LinkPreviewUrl, config.LINK_PREVIEW_URL)
setMetadata(textEditor.metadata.Collaborator, config.COLLABORATOR)

if (config.MODEL_VERSION != null) {
Expand All @@ -340,7 +341,7 @@ export async function configurePlatform() {
setMetadata(rekoni.metadata.RekoniUrl, config.REKONI_URL)

setMetadata(uiPlugin.metadata.DefaultApplication, login.component.LoginApp)
setMetadata(contactPlugin.metadata.LastNameFirst, myBranding.lastNameFirst === 'true' ?? false)
setMetadata(contactPlugin.metadata.LastNameFirst, myBranding.lastNameFirst === 'true')
setMetadata(love.metadata.ServiceEnpdoint, config.LOVE_ENDPOINT)
setMetadata(love.metadata.WebSocketURL, config.LIVEKIT_WS)
setMetadata(print.metadata.PrintURL, config.PRINT_URL)
Expand Down
2 changes: 0 additions & 2 deletions packages/presentation/src/drawing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//

export interface DrawingData {
content?: string
}

export interface DrawingProps {
readonly: boolean
autoSize?: boolean
Expand Down
10 changes: 10 additions & 0 deletions packages/presentation/src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,13 @@ async function uploadFileWithSignedUrl (file: File, uuid: string, uploadUrl: str
})
}
}

export async function getJsonOrEmpty (file: string, name: string): Promise<any> {
try {
const fileUrl = getFileUrl(file, name)
const resp = await fetch(fileUrl)
return await resp.json()
} catch {
return {}
}
}
1 change: 1 addition & 0 deletions packages/presentation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ export * from './preview'
export * from './sound'
export * from './stats'
export * from './drawing'
export * from './link-preview'
60 changes: 60 additions & 0 deletions packages/presentation/src/link-preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Copyright © 2025 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.
//
import { getMetadata } from '@hcengineering/platform'
import plugin from './plugin'

export function isLinkPreviewEnabled (): boolean {
return getMetadata(plugin.metadata.LinkPreviewUrl) !== undefined
}
export interface LinkPreviewDetails {
title?: string
description?: string
url?: string
icon?: string
image?: string
charset?: string
hostname?: string
host?: string
}

export function canDisplayLinkPreview (val: LinkPreviewDetails): boolean {
if (val.hostname === undefined) {
return false
}
if (val.image === undefined && val.description === undefined) {
return false
}
if (val.title === undefined && val.description === undefined) {
return false
}
return true
}

export async function fetchLinkPreviewDetails (url: string, timeoutMs = 15000): Promise<LinkPreviewDetails> {
try {
const linkPreviewUrl = getMetadata(plugin.metadata.LinkPreviewUrl)
let token: string = ''
if (getMetadata(plugin.metadata.Token) !== undefined) {
token = getMetadata(plugin.metadata.Token) as string
}
const response = await fetch(`${linkPreviewUrl}/details?q=${url}`, {
headers: { Authorization: 'Bearer ' + token },
signal: AbortSignal.timeout(timeoutMs)
})
return response.json() as LinkPreviewDetails
} catch {
return {}
}
}
1 change: 1 addition & 0 deletions packages/presentation/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export default plugin(presentationId, {
Workspace: '' as Metadata<string>,
WorkspaceId: '' as Metadata<string>,
FrontUrl: '' as Asset,
LinkPreviewUrl: '' as Metadata<string>,
UploadConfig: '' as Metadata<UploadConfig>,
PreviewConfig: '' as Metadata<PreviewConfig | undefined>,
ClientHook: '' as Metadata<ClientHook>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
-->
<script lang="ts">
import { Attachment } from '@hcengineering/attachment'
import core, { type Doc, type Ref, type WithLookup } from '@hcengineering/core'
import { type Doc, type Ref, type WithLookup } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import attachment from '../plugin'
import { AttachmentImageSize } from '../types'
import AttachmentList from './AttachmentList.svelte'
import AttachmentGroup from './AttachmentGroup.svelte'
export let value: Doc & { attachments?: number }
export let attachments: Attachment[] | undefined = undefined
Expand All @@ -39,7 +39,6 @@
resAttachments = attachments
return
}
if (value && value.attachments && value.attachments > 0) {
query.query(
attachment.class.Attachment,
Expand All @@ -60,4 +59,4 @@
})
</script>

<AttachmentList attachments={resAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} />
<AttachmentGroup attachments={resAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} />
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
function openAttachment (): void {
showAttachmentPreviewPopup(value)
}
$: src = getFileUrl(value.file, value.name)
</script>

Expand Down
51 changes: 51 additions & 0 deletions plugins/attachment-resources/src/components/AttachmentGroup.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!-- //
// Copyright © 2025 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 { type Attachment } from '@hcengineering/attachment'
import { type WithLookup, Ref } from '@hcengineering/core'
import { AttachmentImageSize } from '../types'
import AttachmentList from './AttachmentList.svelte'
import LinkPreviewList from './LinkPreviewList.svelte'
export let attachments: WithLookup<Attachment>[]
export let savedAttachmentsIds: Ref<Attachment>[] = []
export let imageSize: AttachmentImageSize = 'auto'
export let videoPreload = true
let otherAttachments: WithLookup<Attachment>[]
let linkPreviewAttachments: WithLookup<Attachment>[]
$: filter(attachments)
function filter (value: WithLookup<Attachment>[]): void {
linkPreviewAttachments = []
otherAttachments = []
for (const attachment of value) {
if (attachment === undefined) {
continue
}
if (attachment.type === 'application/link-preview') {
linkPreviewAttachments.push(attachment)
} else {
otherAttachments.push(attachment)
}
}
}
</script>

<div class="gapV-2">
<AttachmentList attachments={otherAttachments} {savedAttachmentsIds} {imageSize} {videoPreload} />
<LinkPreviewList attachments={linkPreviewAttachments} />
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import { Attachment } from '@hcengineering/attachment'
import { Ref, type WithLookup } from '@hcengineering/core'
import { Scroller } from '@hcengineering/ui'
import { AttachmentImageSize } from '../types'
import AttachmentPreview from './AttachmentPreview.svelte'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import { ActionIcon, IconAdd, Label, Loading } from '@hcengineering/ui'
import type { Doc, WithLookup } from '@hcengineering/core'
import core from '@hcengineering/core'
import { setPlatformStatus, unknownError } from '@hcengineering/platform'
import { AttachmentPresenter } from '..'
import attachment from '../plugin'
Expand Down
Loading

0 comments on commit d020053

Please sign in to comment.