mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-23 12:05:36 +00:00
UBERF-5012: use flat message view if doc has only one notification (#4410)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
2c207fd13d
commit
77617e85ff
@ -488,3 +488,15 @@ export function getClosestDateSelectorDate (date: Timestamp, scrollElement: HTML
|
||||
|
||||
return closestDate
|
||||
}
|
||||
|
||||
export function isReactionMessage (message?: ActivityMessage): message is DocUpdateMessage {
|
||||
if (message === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (message._class !== activity.class.DocUpdateMessage) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (message as DocUpdateMessage).objectClass === activity.class.Reaction
|
||||
}
|
||||
|
@ -216,7 +216,7 @@
|
||||
overflow: hidden;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
width: calc(100% - 2rem);
|
||||
width: 100%;
|
||||
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
|
@ -17,12 +17,17 @@
|
||||
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { getLocation, navigate } from '@hcengineering/ui'
|
||||
import { Action, getLocation, navigate } from '@hcengineering/ui'
|
||||
|
||||
import ActivityMessagePresenter from '../activity-message/ActivityMessagePresenter.svelte'
|
||||
|
||||
export let message: DisplayActivityMessage
|
||||
export let notification: ActivityInboxNotification
|
||||
export let embedded = false
|
||||
export let showNotify = true
|
||||
export let withActions = true
|
||||
export let actions: Action[] = []
|
||||
export let excludedActions: string[] = []
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
|
||||
const parentQuery = createQuery()
|
||||
@ -43,7 +48,28 @@
|
||||
</script>
|
||||
|
||||
{#if embedded && parentMessage}
|
||||
<ActivityMessagePresenter value={parentMessage} skipLabel embedded onReply={handleReply} {onClick} />
|
||||
<ActivityMessagePresenter
|
||||
value={parentMessage}
|
||||
skipLabel
|
||||
embedded
|
||||
{withActions}
|
||||
{actions}
|
||||
{excludedActions}
|
||||
withFlatActions={false}
|
||||
onReply={handleReply}
|
||||
{onClick}
|
||||
/>
|
||||
{:else if !embedded && message}
|
||||
<ActivityMessagePresenter value={message} skipLabel showEmbedded onReply={handleReply} {onClick} />
|
||||
<ActivityMessagePresenter
|
||||
value={message}
|
||||
skipLabel
|
||||
showEmbedded
|
||||
showNotify={showNotify && !notification.isViewed}
|
||||
{withActions}
|
||||
{actions}
|
||||
{excludedActions}
|
||||
withFlatActions={false}
|
||||
onReply={handleReply}
|
||||
{onClick}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -18,10 +18,11 @@
|
||||
import { location as locationStore } from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import activity, { ActivityMessage, ActivityMessagesFilter } from '@hcengineering/activity'
|
||||
import { ActivityScrolledView } from '@hcengineering/activity-resources'
|
||||
import { ActivityScrolledView, isReactionMessage } from '@hcengineering/activity-resources'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
|
||||
import chunter from '../plugin'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
|
||||
export let context: DocNotifyContext
|
||||
export let object: Doc
|
||||
@ -29,11 +30,20 @@
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const activityInboxNotificationsStore = inboxClient.activityInboxNotifications
|
||||
|
||||
let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
||||
|
||||
const unsubscribe = locationStore.subscribe((newLocation) => {
|
||||
selectedMessageId = newLocation.query?.message as Ref<ActivityMessage> | undefined
|
||||
const selectedMessage = selectedMessageId
|
||||
? $activityInboxNotificationsStore.find(({ attachedTo }) => attachedTo === selectedMessageId)?.$lookup?.attachedTo
|
||||
: undefined
|
||||
|
||||
if (isReactionMessage(selectedMessage)) {
|
||||
selectedMessageId = selectedMessage.attachedTo as Ref<ActivityMessage>
|
||||
}
|
||||
})
|
||||
|
||||
onDestroy(unsubscribe)
|
||||
|
@ -18,6 +18,9 @@
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||
import { ChunterSpace } from '@hcengineering/chunter'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { location as locationStore } from '@hcengineering/ui'
|
||||
import { isReactionMessage } from '@hcengineering/activity-resources'
|
||||
|
||||
import ChannelPresenter from './ChannelView.svelte'
|
||||
import ThreadViewPanel from './threads/ThreadViewPanel.svelte'
|
||||
@ -28,15 +31,29 @@
|
||||
|
||||
const objectQuery = createQuery()
|
||||
const client = getClient()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const activityInboxNotificationsStore = inboxClient.activityInboxNotifications
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
let object: ChunterSpace | undefined = undefined
|
||||
let threadId: Ref<ActivityMessage> | undefined = undefined
|
||||
|
||||
$: threadId = hierarchy.isDerived(context.attachedToClass, activity.class.ActivityMessage)
|
||||
? (context.attachedTo as Ref<ActivityMessage>)
|
||||
let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
||||
|
||||
locationStore.subscribe((newLocation) => {
|
||||
selectedMessageId = newLocation.query?.message as Ref<ActivityMessage> | undefined
|
||||
})
|
||||
|
||||
$: notification = selectedMessageId
|
||||
? $activityInboxNotificationsStore.find(({ attachedTo }) => attachedTo === selectedMessageId)
|
||||
: undefined
|
||||
|
||||
$: threadId =
|
||||
hierarchy.isDerived(context.attachedToClass, activity.class.ActivityMessage) &&
|
||||
!isReactionMessage(notification?.$lookup?.attachedTo)
|
||||
? (context.attachedTo as Ref<ActivityMessage>)
|
||||
: undefined
|
||||
|
||||
$: objectQuery.query(_class, { _id }, (res) => {
|
||||
object = res[0]
|
||||
})
|
||||
|
@ -41,13 +41,13 @@
|
||||
{/if}
|
||||
|
||||
{#if persons.length === 1}
|
||||
<Avatar avatar={persons[0].avatar} {size} />
|
||||
<Avatar avatar={persons[0].avatar} {size} name={persons[0].name} />
|
||||
{/if}
|
||||
|
||||
{#if persons.length > 1 && size === 'medium'}
|
||||
<div class="group">
|
||||
{#each persons.slice(0, visiblePersons - 1) as person}
|
||||
<Avatar avatar={person.avatar} size="tiny" />
|
||||
<Avatar avatar={person.avatar} size="tiny" name={person.name} />
|
||||
{/each}
|
||||
{#if persons.length > visiblePersons}
|
||||
<div class="rect">
|
||||
|
@ -15,12 +15,16 @@
|
||||
<script lang="ts">
|
||||
import { ThreadMessage } from '@hcengineering/chunter'
|
||||
import ThreadMessagePresenter from '../threads/ThreadMessagePresenter.svelte'
|
||||
import { getLocation, navigate } from '@hcengineering/ui'
|
||||
import { Action, getLocation, navigate } from '@hcengineering/ui'
|
||||
import { ActivityInboxNotification } from '@hcengineering/notification'
|
||||
|
||||
export let message: ThreadMessage
|
||||
export let notification: ActivityInboxNotification
|
||||
export let embedded = false
|
||||
export let showNotify = true
|
||||
export let withActions = true
|
||||
export let actions: Action[] = []
|
||||
export let excludedActions: string[] = []
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
|
||||
function handleReply (): void {
|
||||
@ -31,4 +35,15 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<ThreadMessagePresenter value={message} {embedded} showEmbedded={!embedded} onReply={handleReply} {onClick} />
|
||||
<ThreadMessagePresenter
|
||||
value={message}
|
||||
{embedded}
|
||||
showEmbedded={!embedded}
|
||||
{withActions}
|
||||
{actions}
|
||||
{excludedActions}
|
||||
withFlatActions={false}
|
||||
showNotify={showNotify && !notification.isViewed}
|
||||
onReply={handleReply}
|
||||
{onClick}
|
||||
/>
|
||||
|
@ -15,6 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { ThreadMessage } from '@hcengineering/chunter'
|
||||
import ChatMessagePresenter from '../chat-message/ChatMessagePresenter.svelte'
|
||||
import { Action } from '@hcengineering/ui'
|
||||
|
||||
export let value: ThreadMessage | undefined
|
||||
export let showNotify: boolean = false
|
||||
@ -26,6 +27,8 @@
|
||||
export let showEmbedded = false
|
||||
export let skipLabel = false
|
||||
export let withFlatActions: boolean = true
|
||||
export let actions: Action[] = []
|
||||
export let excludedActions: string[] = []
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
export let onReply: (() => void) | undefined = undefined
|
||||
</script>
|
||||
@ -41,6 +44,8 @@
|
||||
{embedded}
|
||||
{skipLabel}
|
||||
{withFlatActions}
|
||||
{excludedActions}
|
||||
{actions}
|
||||
{onClick}
|
||||
{onReply}
|
||||
/>
|
||||
|
@ -58,6 +58,7 @@
|
||||
value.attachedToClass,
|
||||
notification.mixin.NotificationContextPresenter
|
||||
)
|
||||
$: isCompact = notifications.length === 1
|
||||
</script>
|
||||
|
||||
{#if visibleNotification}
|
||||
@ -66,69 +67,88 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="card"
|
||||
class:compact={isCompact}
|
||||
on:click={() => {
|
||||
dispatch('click', { context: value, notification: visibleNotification })
|
||||
}}
|
||||
>
|
||||
<div class="header">
|
||||
<!-- <CheckBox-->
|
||||
<!-- circle-->
|
||||
<!-- kind="primary"-->
|
||||
<!-- on:value={(event) => {-->
|
||||
<!-- dispatch('check', event.detail)-->
|
||||
<!-- }}-->
|
||||
<!-- />-->
|
||||
<NotifyContextIcon {value} />
|
||||
|
||||
{#if presenterMixin?.labelPresenter}
|
||||
<Component is={presenterMixin.labelPresenter} props={{ notification: visibleNotification, context: value }} />
|
||||
{:else}
|
||||
<div class="labels">
|
||||
{#await getDocIdentifier(client, value.attachedTo, value.attachedToClass) then title}
|
||||
{#if title}
|
||||
{title}
|
||||
{:else}
|
||||
<Label label={hierarchy.getClass(value.attachedToClass).label} />
|
||||
{/if}
|
||||
{/await}
|
||||
{#await getDocTitle(client, value.attachedTo, value.attachedToClass) then title}
|
||||
<div class="title overflow-label" {title}>
|
||||
{title ?? hierarchy.getClass(value.attachedToClass).label}
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="actions">
|
||||
{#if isCompact}
|
||||
<InboxNotificationPresenter value={visibleNotification} {viewlets} showNotify={false} withActions={false} />
|
||||
<div class="actions compact">
|
||||
<ActionIcon icon={IconMoreH} size="small" action={showMenu} />
|
||||
</div>
|
||||
|
||||
<div class="notifyMarker">
|
||||
<div class="notifyMarker compact">
|
||||
<NotifyMarker count={unreadCount} />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="header">
|
||||
<!-- <CheckBox-->
|
||||
<!-- circle-->
|
||||
<!-- kind="primary"-->
|
||||
<!-- on:value={(event) => {-->
|
||||
<!-- dispatch('check', event.detail)-->
|
||||
<!-- }}-->
|
||||
<!-- />-->
|
||||
<NotifyContextIcon {value} />
|
||||
|
||||
<div class="notification">
|
||||
<InboxNotificationPresenter value={visibleNotification} {viewlets} embedded skipLabel />
|
||||
</div>
|
||||
{#if presenterMixin?.labelPresenter}
|
||||
<Component is={presenterMixin.labelPresenter} props={{ notification: visibleNotification, context: value }} />
|
||||
{:else}
|
||||
<div class="labels">
|
||||
{#await getDocIdentifier(client, value.attachedTo, value.attachedToClass) then title}
|
||||
{#if title}
|
||||
{title}
|
||||
{:else}
|
||||
<Label label={hierarchy.getClass(value.attachedToClass).label} />
|
||||
{/if}
|
||||
{/await}
|
||||
{#await getDocTitle(client, value.attachedTo, value.attachedToClass) then title}
|
||||
<div class="title overflow-label" {title}>
|
||||
{title ?? hierarchy.getClass(value.attachedToClass).label}
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="actions">
|
||||
<ActionIcon icon={IconMoreH} size="small" action={showMenu} />
|
||||
</div>
|
||||
|
||||
<div class="notifyMarker">
|
||||
<NotifyMarker count={unreadCount} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notification">
|
||||
<InboxNotificationPresenter value={visibleNotification} {viewlets} embedded skipLabel />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
padding: 0 1rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
&.compact {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
gap: 1.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
@ -144,18 +164,28 @@
|
||||
|
||||
.notification {
|
||||
margin-top: 1rem;
|
||||
margin-left: 5.5rem;
|
||||
margin-left: 4rem;
|
||||
}
|
||||
|
||||
.notifyMarker {
|
||||
position: absolute;
|
||||
right: 1.875rem;
|
||||
top: 0;
|
||||
|
||||
&.compact {
|
||||
right: 2.875rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
&.compact {
|
||||
right: 1rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -33,6 +33,8 @@
|
||||
export let value: DisplayActivityInboxNotification
|
||||
export let embedded = false
|
||||
export let skipLabel = false
|
||||
export let showNotify = true
|
||||
export let withActions = true
|
||||
export let viewlets: ActivityNotificationViewlet[] = []
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
|
||||
@ -120,14 +122,27 @@
|
||||
|
||||
{#if displayMessage !== undefined}
|
||||
{#if viewlet}
|
||||
<Component is={viewlet.presenter} props={{ message: displayMessage, notification: value, embedded, onClick }} />
|
||||
<Component
|
||||
is={viewlet.presenter}
|
||||
props={{
|
||||
message: displayMessage,
|
||||
notification: value,
|
||||
embedded,
|
||||
withActions,
|
||||
showNotify,
|
||||
actions,
|
||||
excludedActions: [chunter.action.ReplyToThread],
|
||||
onClick
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<ActivityMessagePresenter
|
||||
value={displayMessage}
|
||||
showNotify={!value.isViewed && !embedded}
|
||||
showNotify={showNotify ? !value.isViewed && !embedded : false}
|
||||
isSelected={displayMessage._id === selectedMessageId}
|
||||
excludedActions={[chunter.action.ReplyToThread]}
|
||||
showEmbedded
|
||||
{withActions}
|
||||
{embedded}
|
||||
{skipLabel}
|
||||
{actions}
|
||||
|
@ -26,7 +26,7 @@
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import notification, { CommonInboxNotification } from '@hcengineering/notification'
|
||||
import { ActionIcon, CheckBox, IconMoreH, Label, showPopup } from '@hcengineering/ui'
|
||||
import { ActionIcon, IconMoreH, Label, showPopup } from '@hcengineering/ui'
|
||||
import { getDocLinkTitle, Menu } from '@hcengineering/view-resources'
|
||||
import { ActivityDocLink } from '@hcengineering/activity-resources'
|
||||
import view from '@hcengineering/view'
|
||||
@ -36,6 +36,8 @@
|
||||
export let value: CommonInboxNotification
|
||||
export let embedded = false
|
||||
export let skipLabel = false
|
||||
export let showNotify = true
|
||||
export let withActions = true
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
|
||||
const objectQuery = createQuery()
|
||||
@ -53,9 +55,7 @@
|
||||
personAccount?.person !== undefined
|
||||
? $employeeByIdStore.get(personAccount.person as Ref<Employee>) ?? $personByIdStore.get(personAccount.person)
|
||||
: undefined
|
||||
|
||||
$: context = $docNotifyContextsStore.find(({ _id }) => _id === value.docNotifyContext)
|
||||
|
||||
$: context &&
|
||||
objectQuery.query(context.attachedToClass, { _id: context.attachedTo }, (result) => {
|
||||
object = result[0]
|
||||
@ -95,7 +95,7 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="root clear-mins flex-grow" on:click={onClick}>
|
||||
{#if !embedded}
|
||||
{#if !value.isViewed}
|
||||
{#if !value.isViewed && showNotify}
|
||||
<div class="notify" />
|
||||
{/if}
|
||||
|
||||
@ -142,7 +142,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if !embedded}
|
||||
{#if !embedded && withActions}
|
||||
<div class="actions clear-mins flex flex-gap-2 items-center" class:opened={isActionMenuOpened}>
|
||||
<ActionIcon icon={IconMoreH} size="small" action={showMenu} />
|
||||
</div>
|
||||
|
@ -154,7 +154,7 @@
|
||||
|
||||
if (selectedContext !== undefined) {
|
||||
loc.fragment = selectedContext._id
|
||||
loc.query = { message: event?.detail?.notification?.attachedTo }
|
||||
loc.query = { message: event?.detail?.notification?.attachedTo ?? null }
|
||||
} else {
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
@ -283,7 +283,8 @@
|
||||
}
|
||||
|
||||
.notifications {
|
||||
margin: 0 0.5rem;
|
||||
margin: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,11 +17,13 @@
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Component } from '@hcengineering/ui'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { ActivityNotificationViewlet, DisplayInboxNotification } from '@hcengineering/notification'
|
||||
import { ActivityNotificationViewlet, DisplayInboxNotification, DocNotifyContext } from '@hcengineering/notification'
|
||||
|
||||
export let value: DisplayInboxNotification
|
||||
export let embedded = false
|
||||
export let skipLabel = false
|
||||
export let showNotify = true
|
||||
export let withActions = true
|
||||
export let viewlets: ActivityNotificationViewlet[] = []
|
||||
export let onClick: (() => void) | undefined = undefined
|
||||
export let onCheck: ((isChecked: boolean) => void) | undefined = undefined
|
||||
@ -33,5 +35,8 @@
|
||||
</script>
|
||||
|
||||
{#if objectPresenter}
|
||||
<Component is={objectPresenter.presenter} props={{ value, embedded, skipLabel, viewlets, onClick, onCheck }} />
|
||||
<Component
|
||||
is={objectPresenter.presenter}
|
||||
props={{ value, embedded, skipLabel, viewlets, showNotify, withActions, onClick, onCheck }}
|
||||
/>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user