Fix inbox ui (#9688)

This commit is contained in:
Kristina
2025-08-19 02:22:39 +07:00
committed by GitHub
parent 21e49e833c
commit d2a5a2ef53
17 changed files with 135 additions and 45 deletions
+2 -1
View File
@@ -28,7 +28,8 @@ export function buildApplets (builder: Builder): void {
createLabel: communication.string.CreatePoll,
createComponent: communication.poll.CreatePoll,
previewComponent: communication.poll.PollPreview,
createFn: communication.poll.CreatePollFn
createFn: communication.poll.CreatePollFn,
getTitleFn: communication.poll.GetPollTitleFn
},
communication.ids.PollApplet
)
+3 -1
View File
@@ -24,7 +24,8 @@ import {
type PollAnswer,
type Poll,
type CustomActivityPresenter,
type GuestCommunicationSettings
type GuestCommunicationSettings,
type AppletGetTitleFnResource
} from '@hcengineering/communication'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
import { type AppletType } from '@hcengineering/communication-types'
@@ -58,6 +59,7 @@ class TApplet extends TDoc implements Applet {
createLabel!: IntlString
createComponent!: AnyComponent
previewComponent!: AnyComponent
getTitleFn!: AppletGetTitleFnResource
createFn?: AppletCreateFnResource
}
@@ -424,8 +424,9 @@
style:transform={options.transform}
style:visibility={options.visibility}
style:z-index={($modals.findIndex((t) => t.type === 'tooltip') ?? 1) + 10000}
style:text-align={$tooltip.textAlign}
>
<span class="label">
<span class="label l1">
<Label label={$tooltip.label} params={$tooltip.props ?? {}} />
</span>
{#if $tooltip.keys !== undefined}
+12 -6
View File
@@ -14,7 +14,8 @@ const emptyTooltip: LabelAndProps = {
keys: undefined,
kind: 'tooltip',
style: undefined,
noArrow: false
noArrow: false,
textAlign: undefined
}
let storedValue: LabelAndProps = emptyTooltip
export const tooltipstore = derived(modalStore, (modals) => {
@@ -50,7 +51,8 @@ export function tooltip (node: HTMLElement, options?: LabelAndProps): any {
opt.kind,
opt.keys,
opt.style,
opt.noArrow
opt.noArrow,
opt.textAlign
)
}, opt.timeout ?? 10)
} else {
@@ -65,7 +67,8 @@ export function tooltip (node: HTMLElement, options?: LabelAndProps): any {
opt.kind,
opt.keys,
opt.style,
opt.noArrow
opt.noArrow,
opt.textAlign
)
}
}
@@ -92,7 +95,8 @@ export function tooltip (node: HTMLElement, options?: LabelAndProps): any {
opt.kind,
opt.keys,
opt.style,
opt.noArrow
opt.noArrow,
opt.textAlign
)
}
},
@@ -119,7 +123,8 @@ export function showTooltip (
kind?: 'tooltip' | 'submenu' | 'popup',
keys?: string[],
style?: 'default' | 'modern',
noArrow?: boolean
noArrow?: boolean,
textAlign?: 'left' | 'center' | 'right'
): void {
storedValue = {
label,
@@ -133,7 +138,8 @@ export function showTooltip (
keys,
type: 'tooltip',
style,
noArrow
noArrow,
textAlign
}
modalStore.update((old) => {
const tooltip = old.find((m) => m?.type === 'tooltip') as LabelAndProps | undefined
+1
View File
@@ -312,6 +312,7 @@ export interface LabelAndProps {
timeout?: number
style?: 'default' | 'modern'
noArrow?: boolean
textAlign?: 'left' | 'center' | 'right'
}
export interface ListItem {
+2 -1
View File
@@ -38,7 +38,7 @@ import {
showOriginalMessage,
translateMessage
} from './actions'
import { createPoll } from './poll'
import { createPoll, getPollTitle } from './poll'
export { isActivityMessage } from './activity'
export * from './stores'
@@ -56,6 +56,7 @@ export default async (): Promise<Resources> => ({
CreatePoll,
PollPreview,
CreatePollFn: createPoll,
GetPollTitleFn: getPollTitle,
UserVoteActivityPresenter,
UserVotesPresenter
},
@@ -17,7 +17,8 @@ import communication, {
type MessageAction,
type MessageActionFunctionResource,
type MessageActionVisibilityTesterResource,
type AppletCreateFnResource
type AppletCreateFnResource,
type AppletGetTitleFnResource
} from '@hcengineering/communication'
import { type AnyComponent } from '@hcengineering/ui'
import { type Ref } from '@hcengineering/core'
@@ -31,6 +32,7 @@ export default mergeIds(communicationId, communication, {
CreatePoll: '' as AnyComponent,
PollPreview: '' as AnyComponent,
CreatePollFn: '' as AppletCreateFnResource,
GetPollTitleFn: '' as AppletGetTitleFnResource,
UserVoteActivityPresenter: '' as AnyComponent,
UserVotesPresenter: '' as AnyComponent
},
+6 -1
View File
@@ -25,7 +25,7 @@ import { type Poll, type PollAnswer } from '@hcengineering/communication'
import { getClient } from '@hcengineering/presentation'
import card, { type Card } from '@hcengineering/card'
import { makeRank } from '@hcengineering/rank'
import { type MessageID } from '@hcengineering/communication-types'
import { type AppletAttachment, type MessageID } from '@hcengineering/communication-types'
import communication from './plugin'
@@ -87,6 +87,11 @@ export async function createPoll (parent: Card, message: MessageID, params: Poll
await client.createDoc(communication.type.Poll, parent.space, filledData, params.id)
}
export function getPollTitle (attachment: AppletAttachment): string {
const params = attachment.params as PollConfig
return params.question
}
export function isVotedByMe (result: Poll | undefined, anonymous: boolean = false, answers: PollAnswer[] = []): boolean {
if (result == null) return false
if (anonymous) {
+12 -1
View File
@@ -11,7 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AccountID, AppletParams, AppletType, Message, MessageID } from '@hcengineering/communication-types'
import {
AccountID,
AppletAttachment,
AppletParams,
AppletType,
Message,
MessageID
} from '@hcengineering/communication-types'
import { AttachedDoc, Configuration, Doc, Ref } from '@hcengineering/core'
import { Asset, IntlString, Resource } from '@hcengineering/platform'
import { Card, MasterTag } from '@hcengineering/card'
@@ -59,12 +66,16 @@ export interface Applet extends Doc {
createLabel: IntlString
createComponent: AnyComponent
previewComponent: AnyComponent
getTitleFn: AppletGetTitleFnResource
createFn?: AppletCreateFnResource
}
export type AppletCreateFn = (parent: Card, message: MessageID, params: AppletParams) => Promise<void>
export type AppletCreateFnResource = Resource<AppletCreateFn>
export type AppletGetTitleFn = (attachment: AppletAttachment) => string
export type AppletGetTitleFnResource = Resource<AppletGetTitleFn>
export interface PollAnswer extends AttachedDoc<Poll> {
options: string[]
space: Ref<PersonSpace>
@@ -104,7 +104,7 @@
&__header {
display: flex;
align-items: center;
gap: 0.75rem;
gap: 0.5rem;
margin-left: var(--spacing-0_5);
}
@@ -45,7 +45,10 @@
{#if notification.message}
<div class="reaction-notification">
<PreviewTemplate socialId={content.creator} date={notification.created} color="secondary" showSeparator={false}>
<Label label={inbox.string.ReactedToYourMessage} />
<svelte:fragment slot="content">
<span class="ml-1-5" />
<Label label={inbox.string.ReactedToYourMessage} />
</svelte:fragment>
</PreviewTemplate>
<div class="reaction-notification__body">
@@ -0,0 +1,43 @@
<!-- 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 { Attachment } from '@hcengineering/communication-types'
import { Label } from '@hcengineering/ui'
import { isAppletAttachment, isBlobAttachment } from '@hcengineering/communication-shared'
import { getResource } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import communication from '@hcengineering/communication'
export let attachment: Attachment
export let lower: boolean = false
const client = getClient()
const applets = client.getModel().findAllSync(communication.class.Applet, {})
</script>
{#if isBlobAttachment(attachment)}
{attachment.params.fileName}
{/if}
{#if isAppletAttachment(attachment)}
{@const applet = applets.find((it) => it.type === attachment.type)}
{#if applet}
<span class:lower>
<Label label={applet.label} />:
</span>
{#await getResource(applet.getTitleFn) then fn}
{fn(attachment)}
{/await}
{/if}
{/if}
@@ -15,27 +15,33 @@
import { Message } from '@hcengineering/communication-types'
import { Icon, Label, tooltip } from '@hcengineering/ui'
import communication from '@hcengineering/communication'
import { isBlobAttachment } from '@hcengineering/communication-shared'
import { isAppletAttachment, isBlobAttachment } from '@hcengineering/communication-shared'
import { getEmbeddedLabel } from '@hcengineering/platform'
import AttachmentsTooltip from './AttachmentsTooltip.svelte'
import AttachmentName from './AttachmentName.svelte'
export let message: Message
$: blobs = message.attachments.filter(isBlobAttachment) ?? []
$: showFiles = blobs.length > 0
$: attachments = message.attachments.filter((it) => isBlobAttachment(it) || isAppletAttachment(it)) ?? []
</script>
{#if showFiles}
{#if attachments.length > 0}
{#if message.content.trim().length > 0}
<span class="attachments" use:tooltip={{ component: AttachmentsTooltip, props: { attachments: blobs } }}>
{blobs.length}
<span class="attachments" use:tooltip={{ component: AttachmentsTooltip, props: { attachments } }}>
{attachments.length}
<Icon icon={communication.icon.File} size="small" />
</span>
{:else}
<span class="attachments-text font-normal overflow-label">
<Label label={communication.string.Files} />:
<span class="ml-1 overflow-label" use:tooltip={{ component: AttachmentsTooltip, props: { attachments: blobs } }}>
{blobs.map((it) => it.params.fileName).join(', ')}
<Label label={getEmbeddedLabel('Attachments')} />:
<span class="ml-1 overflow-label" use:tooltip={{ component: AttachmentsTooltip, props: { attachments } }}>
{#each attachments as att, i}
<AttachmentName attachment={att} lower={i > 0} />
{#if i < attachments.length - 1}
,
{/if}
{/each}
</span>
</span>
{/if}
@@ -61,5 +67,6 @@
white-space: nowrap;
min-width: 0;
max-width: 100%;
margin-left: -0.25rem;
}
</style>
@@ -13,17 +13,16 @@
<script lang="ts">
import { Attachment } from '@hcengineering/communication-types'
import { isBlobAttachment } from '@hcengineering/communication-shared'
import AttachmentName from './AttachmentName.svelte'
export let attachments: Attachment[] = []
$: blobs = attachments.filter(isBlobAttachment)
</script>
<div class="tooltip">
{#each blobs as blob}
{#each attachments as attachment, i}
<div>
{blob.params.fileName}
<AttachmentName {attachment} lower={i > 0} />
</div>
{/each}
</div>
@@ -23,7 +23,7 @@
import { jsonToMarkup, markupToText } from '@hcengineering/text'
import { ActivityMessageViewer, isActivityMessage } from '@hcengineering/communication-resources'
import AttachmentPreview from './AttachmentPreview.svelte'
import AttachmentsPreview from './AttachmentsPreview.svelte'
import PreviewTemplate from './PreviewTemplate.svelte'
export let card: Card
@@ -62,13 +62,15 @@
fixHeight={message.type !== MessageType.Activity}
tooltipLabel={getTooltipLabel(message)}
>
{#if isActivityMessage(message)}
<ActivityMessageViewer {message} {card} author={person} />
{:else}
<LiteMessageViewer message={markdownToMarkup(message.content)} />
{/if}
<svelte:fragment slot="content">
{#if isActivityMessage(message)}
<ActivityMessageViewer {message} {card} author={person} />
{:else}
<LiteMessageViewer message={markdownToMarkup(message.content)} />
{/if}
</svelte:fragment>
<svelte:fragment slot="after">
<AttachmentPreview {message} />
<AttachmentsPreview {message} />
</svelte:fragment>
</PreviewTemplate>
@@ -100,18 +100,24 @@
<span class="message-preview-template__name overflow-label {color}">{formatName(_person?.name ?? '')}</span>
{/if}
{#if showSeparator}
<span class="message-preview-template__separator"></span>
{#if showPersonName}
<span class="message-preview-template__separator"></span>
{:else}
<span class="mr-0-5" />
{/if}
{/if}
</span>
</PersonPreviewProvider>
<span
class="message-preview-template__content overflow-label {color}"
class:fixHeight
use:tooltip={tooltipLabel ? { label: tooltipLabel } : undefined}
>
<slot />
</span>
{#if $$slots.content}
<span
class="message-preview-template__content overflow-label {color}"
class:fixHeight
use:tooltip={tooltipLabel ? { label: tooltipLabel, textAlign: 'left' } : undefined}
>
<slot name="content" />
</span>
{/if}
<slot name="after" />
</span>