mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-11 12:57:59 +00:00
Bold chunter spaces (#1282)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
07062c37b9
commit
3a19d46590
@ -37,6 +37,7 @@
|
||||
"@anticrm/model-core": "~0.6.0",
|
||||
"@anticrm/model-view": "~0.6.0",
|
||||
"@anticrm/model-workbench": "~0.6.1",
|
||||
"@anticrm/model-notification": "~0.6.0",
|
||||
"@anticrm/activity": "~0.6.0",
|
||||
"@anticrm/workbench": "~0.6.1"
|
||||
}
|
||||
|
@ -24,13 +24,17 @@ import view from '@anticrm/model-view'
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
import chunter from './plugin'
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import notification from '@anticrm/model-notification'
|
||||
|
||||
export const DOMAIN_CHUNTER = 'chunter' as Domain
|
||||
export const DOMAIN_COMMENT = 'comment' as Domain
|
||||
|
||||
@Model(chunter.class.Channel, core.class.Space)
|
||||
@UX(chunter.string.Channel, chunter.icon.Hashtag)
|
||||
export class TChannel extends TSpace implements Channel {}
|
||||
export class TChannel extends TSpace implements Channel {
|
||||
@Prop(TypeTimestamp(), chunter.string.LastMessage)
|
||||
lastMessage?: Timestamp
|
||||
}
|
||||
|
||||
@Model(chunter.class.Message, core.class.Doc, DOMAIN_CHUNTER)
|
||||
export class TMessage extends TDoc implements Message {
|
||||
@ -84,6 +88,10 @@ export function createModel (builder: Builder): void {
|
||||
presenter: chunter.component.ChannelPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, notification.mixin.SpaceLastEdit, {
|
||||
lastEditField: 'lastMessage'
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.ViewletDescriptor, core.space.Model, {
|
||||
label: chunter.string.Chat,
|
||||
icon: view.icon.Table,
|
||||
|
@ -47,7 +47,8 @@ export default mergeIds(chunterId, chunter, {
|
||||
Chat: '' as IntlString,
|
||||
CreateBy: '' as IntlString,
|
||||
Create: '' as IntlString,
|
||||
MarkUnread: '' as IntlString
|
||||
MarkUnread: '' as IntlString,
|
||||
LastMessage: '' as IntlString
|
||||
},
|
||||
viewlet: {
|
||||
Chat: '' as Ref<ViewletDescriptor>
|
||||
|
@ -15,9 +15,9 @@
|
||||
//
|
||||
|
||||
import { Account, Doc, Domain, DOMAIN_MODEL, Ref, Timestamp, TxCUD } from '@anticrm/core'
|
||||
import { ArrOf, Builder, Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
|
||||
import core, { TAttachedDoc, TDoc } from '@anticrm/model-core'
|
||||
import type { EmailNotification, LastView, NotificationType, NotificationProvider, NotificationSetting, Notification, NotificationStatus } from '@anticrm/notification'
|
||||
import { ArrOf, Builder, Mixin, Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
|
||||
import core, { TAttachedDoc, TClass, TDoc } from '@anticrm/model-core'
|
||||
import type { EmailNotification, LastView, NotificationType, NotificationProvider, NotificationSetting, Notification, NotificationStatus, SpaceLastEdit } from '@anticrm/notification'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import notification from './plugin'
|
||||
import setting from '@anticrm/setting'
|
||||
@ -81,8 +81,13 @@ export class TNotificationSetting extends TDoc implements NotificationSetting {
|
||||
enabled!: boolean
|
||||
}
|
||||
|
||||
@Mixin(notification.mixin.SpaceLastEdit, core.class.Class)
|
||||
export class TSpaceLastEdit extends TClass implements SpaceLastEdit {
|
||||
lastEditField!: string
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TLastView, TNotification, TEmaiNotification, TNotificationType, TNotificationProvider, TNotificationSetting)
|
||||
builder.createModel(TLastView, TNotification, TEmaiNotification, TNotificationType, TNotificationProvider, TNotificationSetting, TSpaceLastEdit)
|
||||
|
||||
builder.createDoc(notification.class.NotificationType, core.space.Model, {
|
||||
label: notification.string.MentionNotification
|
||||
@ -108,3 +113,4 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
|
||||
export { notificationOperation } from './migration'
|
||||
export { notification as default }
|
||||
|
@ -35,6 +35,6 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverChunter.trigger.CommentCreate
|
||||
trigger: serverChunter.trigger.ChunterTrigger
|
||||
})
|
||||
}
|
||||
|
@ -86,6 +86,10 @@
|
||||
font-weight: 500;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
&.bold {
|
||||
font-weight: 600;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
.an-element__icon-arrow {
|
||||
margin-left: .5rem;
|
||||
|
@ -22,7 +22,9 @@ import { AnyComponent } from '@anticrm/ui'
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Channel extends Space {}
|
||||
export interface Channel extends Space {
|
||||
lastMessage?: Timestamp
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Account, AttachedDoc, Class, Doc, Ref, Space, Timestamp, TxCUD } from '@anticrm/core'
|
||||
import type { Account, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestamp, TxCUD } from '@anticrm/core'
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import { AnyComponent } from '@anticrm/ui'
|
||||
@ -79,6 +79,13 @@ export interface NotificationSetting extends Doc {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SpaceLastEdit extends Class<Doc> {
|
||||
lastEditField: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -89,6 +96,7 @@ export const notificationId = 'notification' as Plugin
|
||||
*/
|
||||
export interface NotificationClient {
|
||||
updateLastView: (_id: Ref<Doc>, _class: Ref<Class<Doc>>, time?: Timestamp, force?: boolean) => Promise<void>
|
||||
unsubscribe: (_id: Ref<Doc>) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,6 +108,9 @@ export type NotificationClientFactoy = () => NotificationClient
|
||||
* @public
|
||||
*/
|
||||
const notification = plugin(notificationId, {
|
||||
mixin: {
|
||||
SpaceLastEdit: '' as Ref<Mixin<SpaceLastEdit>>
|
||||
},
|
||||
class: {
|
||||
LastView: '' as Ref<Class<LastView>>,
|
||||
Notification: '' as Ref<Class<Notification>>,
|
||||
|
@ -15,6 +15,8 @@
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, Ref, Space } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import notification from '@anticrm/notification'
|
||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { Action, AnyComponent, IconAdd, IconEdit, showPanel, showPopup } from '@anticrm/ui'
|
||||
@ -80,6 +82,23 @@
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const notificationClient = NotificationClientImpl.getClient()
|
||||
const lastViews = notificationClient.getLastViews()
|
||||
const hierarchy = client.getHierarchy()
|
||||
$: clazz = hierarchy.getClass(model.spaceClass)
|
||||
$: lastEditMixin = hierarchy.as(clazz, notification.mixin.SpaceLastEdit)
|
||||
|
||||
function isChanged (space: Space, lastViews: Map<Ref<Doc>, number>): boolean {
|
||||
const field = lastEditMixin?.lastEditField
|
||||
const lastView = lastViews.get(space._id)
|
||||
if (lastView === undefined || lastView === -1) return false
|
||||
if (field === undefined) return false
|
||||
const value = (space as any)[field]
|
||||
if (isNaN(value)) return false
|
||||
|
||||
return lastView < value
|
||||
}
|
||||
</script>
|
||||
|
||||
<TreeNode label={model.label} parent actions={async () => [addSpace]} indent={'ml-2'}>
|
||||
@ -107,6 +126,7 @@
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={() => getActions(space)}
|
||||
bold={isChanged(space, $lastViews)}
|
||||
on:click={() => {
|
||||
selectSpace(space._id)
|
||||
}}
|
||||
|
@ -28,6 +28,7 @@
|
||||
export let parent = false
|
||||
export let collapsed = false
|
||||
export let selected = false
|
||||
export let bold = false
|
||||
export let actions: () => Promise<Action[]> = async () => []
|
||||
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
||||
|
||||
@ -57,7 +58,7 @@
|
||||
dispatch('click')
|
||||
}}
|
||||
>
|
||||
<span class="an-element__label" class:title={node}>
|
||||
<span class="an-element__label" class:bold class:title={node}>
|
||||
<div class="flex-row-center">
|
||||
{#if icon && !parent}
|
||||
<div class="an-element__icon">
|
||||
|
@ -26,10 +26,11 @@
|
||||
export let notifications = 0
|
||||
export let actions: () => Promise<Action[]> = async () => []
|
||||
export let selected: boolean = false
|
||||
export let bold = false
|
||||
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
</script>
|
||||
|
||||
<TreeElement {_id} {icon} {title} {notifications} {selected} {actions} collapsed {indent} on:click={() => { dispatch('click') }}/>
|
||||
<TreeElement {_id} {icon} {title} {notifications} {selected} {actions} {bold} collapsed {indent} on:click={() => { dispatch('click') }}/>
|
||||
|
@ -80,10 +80,48 @@ export async function CommentCreate (tx: Tx, control: TriggerControl): Promise<T
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function MessageCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const hierarchy = control.hierarchy
|
||||
if (tx._class !== core.class.TxCreateDoc) return []
|
||||
const doc = TxProcessor.createDoc2Doc(tx as TxCreateDoc<Doc>)
|
||||
if (!hierarchy.isDerived(doc._class, chunter.class.Message)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const message = doc as Message
|
||||
|
||||
const channel = (await control.findAll(chunter.class.Channel, {
|
||||
_id: message.space
|
||||
}, { limit: 1 }))[0]
|
||||
|
||||
if (channel.lastMessage === undefined || channel.lastMessage < message.createOn) {
|
||||
const res = control.txFactory.createTxUpdateDoc<Channel>(channel._class, channel.space, channel._id, {
|
||||
lastMessage: message.createOn
|
||||
})
|
||||
return [res]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function ChunterTrigger (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const promises = [
|
||||
MessageCreate(tx, control),
|
||||
CommentCreate(tx, control)
|
||||
]
|
||||
const res = await Promise.all(promises)
|
||||
return res.flat()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
CommentCreate
|
||||
ChunterTrigger
|
||||
},
|
||||
function: {
|
||||
CommentRemove,
|
||||
|
@ -28,7 +28,7 @@ export const serverChunterId = 'server-chunter' as Plugin
|
||||
*/
|
||||
export default plugin(serverChunterId, {
|
||||
trigger: {
|
||||
CommentCreate: '' as Resource<TriggerFunc>
|
||||
ChunterTrigger: '' as Resource<TriggerFunc>
|
||||
},
|
||||
function: {
|
||||
CommentRemove: '' as Resource<(doc: Doc, hiearachy: Hierarchy, findAll: <T extends Doc> (clazz: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T>) => Promise<FindResult<T>>) => Promise<Doc[]>>,
|
||||
|
Loading…
Reference in New Issue
Block a user