mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
Chunter: Direct messages (#1472)
Signed-off-by: Denis Bunakalya <denis.bunakalya@xored.com>
This commit is contained in:
parent
ed0a747330
commit
2efc19044e
@ -16,12 +16,14 @@
|
||||
import activity from '@anticrm/activity'
|
||||
import type {
|
||||
Backlink,
|
||||
ChunterSpace,
|
||||
Channel,
|
||||
ChunterMessage,
|
||||
Comment,
|
||||
Message,
|
||||
SavedMessages,
|
||||
ThreadMessage
|
||||
ThreadMessage,
|
||||
DirectMessage
|
||||
} from '@anticrm/chunter'
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import type { Account, Class, Doc, Domain, Ref, Space, Timestamp } from '@anticrm/core'
|
||||
@ -50,20 +52,27 @@ import preference, { TPreference } from '@anticrm/model-preference'
|
||||
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 {
|
||||
@Model(chunter.class.ChunterSpace, core.class.Space)
|
||||
export class TChunterSpace extends TSpace implements ChunterSpace {
|
||||
@Prop(TypeTimestamp(), chunter.string.LastMessage)
|
||||
lastMessage?: Timestamp
|
||||
|
||||
@Prop(ArrOf(TypeRef(chunter.class.ChunterMessage)), chunter.string.PinnedMessages)
|
||||
pinned?: Ref<ChunterMessage>[]
|
||||
}
|
||||
|
||||
@Model(chunter.class.Channel, chunter.class.ChunterSpace)
|
||||
@UX(chunter.string.Channel, chunter.icon.Hashtag)
|
||||
export class TChannel extends TChunterSpace implements Channel {
|
||||
@Prop(TypeString(), chunter.string.Topic)
|
||||
@Index(IndexKind.FullText)
|
||||
topic?: string
|
||||
}
|
||||
|
||||
@Model(chunter.class.DirectMessage, chunter.class.ChunterSpace)
|
||||
@UX(chunter.string.DirectMessage, contact.icon.Person)
|
||||
export class TDirectMessage extends TChunterSpace implements DirectMessage {}
|
||||
|
||||
@Model(chunter.class.ChunterMessage, core.class.AttachedDoc, DOMAIN_CHUNTER)
|
||||
export class TChunterMessage extends TAttachedDoc implements ChunterMessage {
|
||||
@Prop(TypeMarkup(), chunter.string.Content)
|
||||
@ -128,23 +137,49 @@ export class TSavedMessages extends TPreference implements SavedMessages {
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TChannel, TMessage, TThreadMessage, TChunterMessage, TComment, TBacklink, TSavedMessages)
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, workbench.mixin.SpaceView, {
|
||||
view: {
|
||||
class: chunter.class.Message
|
||||
}
|
||||
builder.createModel(
|
||||
TChunterSpace,
|
||||
TChannel,
|
||||
TMessage,
|
||||
TThreadMessage,
|
||||
TChunterMessage,
|
||||
TComment,
|
||||
TBacklink,
|
||||
TDirectMessage,
|
||||
TSavedMessages
|
||||
)
|
||||
const spaceClasses = [chunter.class.Channel, chunter.class.DirectMessage]
|
||||
|
||||
spaceClasses.forEach((spaceClass) => {
|
||||
builder.mixin(spaceClass, core.class.Class, workbench.mixin.SpaceView, {
|
||||
view: {
|
||||
class: chunter.class.Message
|
||||
}
|
||||
})
|
||||
|
||||
builder.mixin(spaceClass, core.class.Class, notification.mixin.SpaceLastEdit, {
|
||||
lastEditField: 'lastMessage'
|
||||
})
|
||||
|
||||
builder.mixin(spaceClass, core.class.Class, view.mixin.ObjectEditor, {
|
||||
editor: chunter.component.EditChannel
|
||||
})
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.SpaceName, {
|
||||
getName: chunter.function.GetDmName
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: chunter.component.DmPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: chunter.component.ChannelPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, notification.mixin.SpaceLastEdit, {
|
||||
lastEditField: 'lastMessage'
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.ObjectEditor, {
|
||||
editor: chunter.component.EditChannel
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.SpaceHeader, {
|
||||
header: chunter.component.DmHeader
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.SpaceHeader, {
|
||||
@ -302,6 +337,12 @@ export function createModel (builder: Builder): void {
|
||||
spaceClass: chunter.class.Channel,
|
||||
addSpaceLabel: chunter.string.CreateChannel,
|
||||
createComponent: chunter.component.CreateChannel
|
||||
},
|
||||
{
|
||||
label: chunter.string.DirectMessages,
|
||||
spaceClass: chunter.class.DirectMessage,
|
||||
addSpaceLabel: chunter.string.NewDirectMessage,
|
||||
createComponent: chunter.component.CreateDirectMessage
|
||||
}
|
||||
],
|
||||
aside: chunter.component.ThreadView
|
||||
|
@ -26,6 +26,7 @@ export default mergeIds(chunterId, chunter, {
|
||||
component: {
|
||||
CommentPresenter: '' as AnyComponent,
|
||||
ChannelPresenter: '' as AnyComponent,
|
||||
DmPresenter: '' as AnyComponent,
|
||||
Threads: '' as AnyComponent,
|
||||
ThreadView: '' as AnyComponent,
|
||||
SavedMessages: '' as AnyComponent
|
||||
|
@ -20,7 +20,8 @@ import core, { TClass, TDoc } from '@anticrm/model-core'
|
||||
import type { Asset, IntlString, Resource, Status } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import type {
|
||||
Action, ActionTarget,
|
||||
Action,
|
||||
ActionTarget,
|
||||
AttributeEditor,
|
||||
AttributePresenter,
|
||||
HTMLPresenter,
|
||||
@ -32,6 +33,7 @@ import type {
|
||||
ObjectValidator,
|
||||
PreviewPresenter,
|
||||
SpaceHeader,
|
||||
SpaceName,
|
||||
TextPresenter,
|
||||
ViewAction,
|
||||
ViewContext,
|
||||
@ -67,7 +69,12 @@ export function createAction (
|
||||
)
|
||||
}
|
||||
|
||||
export function actionTarget (builder: Builder, action: Ref<Action>, target: Ref<Class<Doc>>, context: ViewContext): void {
|
||||
export function actionTarget (
|
||||
builder: Builder,
|
||||
action: Ref<Action>,
|
||||
target: Ref<Class<Doc>>,
|
||||
context: ViewContext
|
||||
): void {
|
||||
builder.createDoc(view.class.ActionTarget, core.space.Model, {
|
||||
target,
|
||||
action,
|
||||
@ -116,6 +123,11 @@ export class TSpaceHeader extends TClass implements SpaceHeader {
|
||||
header!: AnyComponent
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.SpaceName, core.class.Class)
|
||||
export class TSpaceName extends TClass implements SpaceName {
|
||||
getName!: Resource<(client: Client, space: Space) => Promise<string>>
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.ObjectValidator, core.class.Class)
|
||||
export class TObjectValidator extends TClass implements ObjectValidator {
|
||||
validator!: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status<{}>>>
|
||||
@ -189,6 +201,7 @@ export function createModel (builder: Builder): void {
|
||||
TObjectEditorHeader,
|
||||
THTMLPresenter,
|
||||
TSpaceHeader,
|
||||
TSpaceName,
|
||||
TTextPresenter,
|
||||
TIgnoreActions,
|
||||
TPreviewPresenter
|
||||
@ -214,20 +227,34 @@ export function createModel (builder: Builder): void {
|
||||
view.viewlet.Table
|
||||
)
|
||||
|
||||
createAction(builder, view.action.Delete, view.string.Delete, view.actionImpl.Delete, { icon: view.icon.Delete, keyBinding: ['Meta + Backspace'] })
|
||||
createAction(builder, view.action.Delete, view.string.Delete, view.actionImpl.Delete, {
|
||||
icon: view.icon.Delete,
|
||||
keyBinding: ['Meta + Backspace']
|
||||
})
|
||||
actionTarget(builder, view.action.Delete, core.class.Doc, { mode: ['context', 'browser'], group: 'tools' })
|
||||
|
||||
createAction(builder, view.action.Move, view.string.Move, view.actionImpl.Move, { icon: view.icon.Move, singleInput: true })
|
||||
createAction(builder, view.action.Move, view.string.Move, view.actionImpl.Move, {
|
||||
icon: view.icon.Move,
|
||||
singleInput: true
|
||||
})
|
||||
|
||||
// Keyboard actions.
|
||||
createAction(builder, view.action.MoveUp, view.string.MoveUp, view.actionImpl.MoveUp, { keyBinding: ['ArrowUp', 'keyK'] })
|
||||
createAction(builder, view.action.MoveUp, view.string.MoveUp, view.actionImpl.MoveUp, {
|
||||
keyBinding: ['ArrowUp', 'keyK']
|
||||
})
|
||||
actionTarget(builder, view.action.MoveUp, core.class.Doc, { mode: 'browser' })
|
||||
createAction(builder, view.action.MoveDown, view.string.MoveDown, view.actionImpl.MoveDown, { keyBinding: ['ArrowDown', 'keyJ'] })
|
||||
createAction(builder, view.action.MoveDown, view.string.MoveDown, view.actionImpl.MoveDown, {
|
||||
keyBinding: ['ArrowDown', 'keyJ']
|
||||
})
|
||||
actionTarget(builder, view.action.MoveDown, core.class.Doc, { mode: 'browser' })
|
||||
|
||||
createAction(builder, view.action.MoveLeft, view.string.MoveLeft, view.actionImpl.MoveLeft, { keyBinding: ['ArrowLeft'] })
|
||||
createAction(builder, view.action.MoveLeft, view.string.MoveLeft, view.actionImpl.MoveLeft, {
|
||||
keyBinding: ['ArrowLeft']
|
||||
})
|
||||
actionTarget(builder, view.action.MoveLeft, core.class.Doc, { mode: 'browser' })
|
||||
createAction(builder, view.action.MoveRight, view.string.MoveRight, view.actionImpl.MoveRight, { keyBinding: ['ArrowRight'] })
|
||||
createAction(builder, view.action.MoveRight, view.string.MoveRight, view.actionImpl.MoveRight, {
|
||||
keyBinding: ['ArrowRight']
|
||||
})
|
||||
actionTarget(builder, view.action.MoveRight, core.class.Doc, { mode: 'browser' })
|
||||
|
||||
builder.mixin(core.class.Space, core.class.Class, view.mixin.AttributePresenter, {
|
||||
@ -235,19 +262,32 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
// Selection stuff
|
||||
createAction(builder, view.action.SelectItem, view.string.SelectItem, view.actionImpl.SelectItem, { keyBinding: ['keyX'] })
|
||||
createAction(builder, view.action.SelectItem, view.string.SelectItem, view.actionImpl.SelectItem, {
|
||||
keyBinding: ['keyX']
|
||||
})
|
||||
actionTarget(builder, view.action.SelectItem, core.class.Doc, { mode: 'browser' })
|
||||
|
||||
createAction(builder, view.action.SelectItemAll, view.string.SelectItemAll, view.actionImpl.SelectItemAll, { keyBinding: ['meta + keyA'] })
|
||||
createAction(builder, view.action.SelectItemAll, view.string.SelectItemAll, view.actionImpl.SelectItemAll, {
|
||||
keyBinding: ['meta + keyA']
|
||||
})
|
||||
actionTarget(builder, view.action.SelectItemAll, core.class.Doc, { mode: 'browser' })
|
||||
|
||||
createAction(builder, view.action.SelectItemNone, view.string.SelectItemNone, view.actionImpl.SelectItemNone, { keyBinding: ['escape'] })
|
||||
createAction(builder, view.action.SelectItemNone, view.string.SelectItemNone, view.actionImpl.SelectItemNone, {
|
||||
keyBinding: ['escape']
|
||||
})
|
||||
actionTarget(builder, view.action.SelectItemNone, core.class.Doc, { mode: 'browser' })
|
||||
|
||||
createAction(builder, view.action.ShowActions, view.string.ShowActions, view.actionImpl.ShowActions, { keyBinding: ['meta + keyk'] })
|
||||
actionTarget(builder, view.action.ShowActions, core.class.Doc, { mode: ['workbench', 'browser', 'popup', 'panel', 'editor'] })
|
||||
createAction(builder, view.action.ShowActions, view.string.ShowActions, view.actionImpl.ShowActions, {
|
||||
keyBinding: ['meta + keyk']
|
||||
})
|
||||
actionTarget(builder, view.action.ShowActions, core.class.Doc, {
|
||||
mode: ['workbench', 'browser', 'popup', 'panel', 'editor']
|
||||
})
|
||||
|
||||
createAction(builder, view.action.ShowPreview, view.string.ShowPreview, view.actionImpl.ShowPreview, { keyBinding: ['Space'], singleInput: true })
|
||||
createAction(builder, view.action.ShowPreview, view.string.ShowPreview, view.actionImpl.ShowPreview, {
|
||||
keyBinding: ['Space'],
|
||||
singleInput: true
|
||||
})
|
||||
actionTarget(builder, view.action.ShowPreview, core.class.Doc, { mode: 'browser' })
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,6 @@
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
||||
|
||||
export const viewOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
}
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {}
|
||||
}
|
||||
|
@ -3,17 +3,22 @@
|
||||
"ApplicationLabelChunter": "Chat",
|
||||
"LeftComment": "left a comment",
|
||||
"Channels": "Channels",
|
||||
"DirectMessages": "Direct messages",
|
||||
"CreateChannel": "New Channel",
|
||||
"NewDirectMessage": "New Direct Message",
|
||||
"ChannelName": "Name",
|
||||
"ChannelNamePlaceholder": "Channel",
|
||||
"ChannelDescription": "Description",
|
||||
"MakePrivate": "Make private",
|
||||
"MakePrivateDescription": "Only members can see it",
|
||||
"Channel": "Channel",
|
||||
"DirectMessage": "Direct message",
|
||||
"EditUpdate": "Save...",
|
||||
"EditCancel": "Cancel",
|
||||
"Comments" : "Comments",
|
||||
"About": "About",
|
||||
"Members": "Members",
|
||||
"NoMembers": "No members",
|
||||
"MentionedIn": "mentioned this ",
|
||||
"ContactInfo": "Contact Info",
|
||||
"Content": "Content",
|
||||
|
@ -3,17 +3,22 @@
|
||||
"ApplicationLabelChunter": "Чат",
|
||||
"LeftComment": "оставил(а) комментарий",
|
||||
"Channels": "Каналы",
|
||||
"DirectMessages": "Личные сообщения",
|
||||
"CreateChannel": "Создать канал",
|
||||
"NewDirectMessage": "Создать личное сообщение",
|
||||
"ChannelName": "Название",
|
||||
"ChannelNamePlaceholder": "Канал",
|
||||
"ChannelDescription": "Описание",
|
||||
"MakePrivate": "Сделать личным",
|
||||
"MakePrivateDescription": "Только пользователи могут видеть это",
|
||||
"Channel": "Канал ",
|
||||
"DirectMessage": "Личное сообщение",
|
||||
"EditUpdate": "Сохранить...",
|
||||
"EditCancel": "Отменить",
|
||||
"Comments" : "Комментарии",
|
||||
"About": "Информация",
|
||||
"Members": "Участники",
|
||||
"NoMembers": "Нет участников",
|
||||
"MentionedIn": "упомянул(а) ",
|
||||
"ContactInfo": "Контактная информация",
|
||||
"Content": "Содержимое",
|
||||
|
@ -74,7 +74,7 @@
|
||||
(res) => {
|
||||
messages = res
|
||||
newMessagesPos = newMessagesStart(messages)
|
||||
notificationClient.updateLastView(space, chunter.class.Channel)
|
||||
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
|
||||
},
|
||||
{
|
||||
lookup: {
|
||||
|
@ -14,26 +14,16 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Channel } from '@anticrm/chunter'
|
||||
import { Ref, Space } from '@anticrm/core'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { getCurrentLocation, Icon, locationToUrl } from '@anticrm/ui'
|
||||
import chunter from '../plugin'
|
||||
import { Icon } from '@anticrm/ui'
|
||||
|
||||
import { getSpaceLink } from '../utils'
|
||||
|
||||
export let value: Channel
|
||||
const client = getClient()
|
||||
|
||||
$: icon = client.getHierarchy().getClass(value._class).icon
|
||||
|
||||
function getLink (id: Ref<Space>): string {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[1] = chunter.app.Chunter
|
||||
loc.path[2] = id
|
||||
loc.path.length = 3
|
||||
loc.fragment = undefined
|
||||
return locationToUrl(loc)
|
||||
}
|
||||
|
||||
$: link = getLink(value._id)
|
||||
$: link = getSpaceLink(value._id)
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
|
@ -40,7 +40,7 @@
|
||||
space,
|
||||
{
|
||||
attachedTo: space,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
attachedToClass: chunter.class.ChunterSpace,
|
||||
collection: 'messages',
|
||||
content: message,
|
||||
createOn: 0,
|
||||
@ -50,11 +50,11 @@
|
||||
_id
|
||||
)
|
||||
tx.attributes.createOn = tx.modifiedOn
|
||||
await notificationClient.updateLastView(space, chunter.class.Channel, tx.modifiedOn, true)
|
||||
await notificationClient.updateLastView(space, chunter.class.ChunterSpace, tx.modifiedOn, true)
|
||||
await client.tx(tx)
|
||||
|
||||
// Create an backlink to document
|
||||
await createBacklinks(client, space, chunter.class.Channel, _id, message)
|
||||
await createBacklinks(client, space, chunter.class.ChunterSpace, _id, message)
|
||||
|
||||
_id = generateId()
|
||||
}
|
||||
@ -68,7 +68,7 @@
|
||||
const pinnedQuery = createQuery()
|
||||
let pinnedIds: Ref<ChunterMessage>[] = []
|
||||
pinnedQuery.query(
|
||||
chunter.class.Channel,
|
||||
chunter.class.ChunterSpace,
|
||||
{ _id: space },
|
||||
(res) => {
|
||||
pinnedIds = res[0]?.pinned ?? []
|
||||
|
@ -0,0 +1,57 @@
|
||||
<!--
|
||||
// Copyright © 2022 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { createEventDispatcher } from 'svelte'
|
||||
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import core, { getCurrentAccount, Ref } from '@anticrm/core'
|
||||
import { getClient, SpaceCreateCard, UserBoxList } from '@anticrm/presentation'
|
||||
|
||||
import chunter from '../plugin'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const myAccId = getCurrentAccount()._id
|
||||
|
||||
let employeeIds: Ref<Employee>[] = []
|
||||
|
||||
function createDirectMessage () {
|
||||
client.findAll(contact.class.EmployeeAccount, { employee: { $in: employeeIds } }).then((employeeAccounts) => {
|
||||
client.createDoc(chunter.class.DirectMessage, core.space.Space, {
|
||||
name: '',
|
||||
description: '',
|
||||
private: true,
|
||||
archived: false,
|
||||
members: [myAccId, ...employeeAccounts.filter((ea) => ea._id !== myAccId).map((ea) => ea._id)]
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<SpaceCreateCard
|
||||
label={chunter.string.NewDirectMessage}
|
||||
okAction={createDirectMessage}
|
||||
canSave={employeeIds.length > 0}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
label={chunter.string.Members}
|
||||
noItems={chunter.string.NoMembers}
|
||||
on:update={(evt) => (employeeIds = evt.detail)}
|
||||
/>
|
||||
</SpaceCreateCard>
|
46
plugins/chunter-resources/src/components/DmHeader.svelte
Normal file
46
plugins/chunter-resources/src/components/DmHeader.svelte
Normal file
@ -0,0 +1,46 @@
|
||||
<!--
|
||||
// Copyright © 2022 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 { DirectMessage } from '@anticrm/chunter'
|
||||
import type { Ref } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { showPanel } from '@anticrm/ui'
|
||||
import chunter from '../plugin'
|
||||
import { classIcon, getDmName } from '../utils'
|
||||
import Header from './Header.svelte'
|
||||
|
||||
export let spaceId: Ref<DirectMessage> | undefined
|
||||
|
||||
const client = getClient()
|
||||
const query = createQuery()
|
||||
let dm: DirectMessage | undefined
|
||||
|
||||
$: query.query(chunter.class.DirectMessage, { _id: spaceId }, (result) => {
|
||||
dm = result[0]
|
||||
})
|
||||
|
||||
async function onSpaceEdit (): Promise<void> {
|
||||
if (dm === undefined) return
|
||||
showPanel(chunter.component.EditChannel, dm._id, dm._class, 'right')
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header divide full">
|
||||
{#if dm}
|
||||
{#await getDmName(client, dm) then name}
|
||||
<Header icon={classIcon(client, dm._class)} label={name} description={''} on:click={onSpaceEdit} />
|
||||
{/await}
|
||||
{/if}
|
||||
</div>
|
40
plugins/chunter-resources/src/components/DmPresenter.svelte
Normal file
40
plugins/chunter-resources/src/components/DmPresenter.svelte
Normal file
@ -0,0 +1,40 @@
|
||||
<!--
|
||||
// Copyright © 2022 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 { DirectMessage } from '@anticrm/chunter'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { Icon } from '@anticrm/ui'
|
||||
|
||||
import { getSpaceLink, getDmName } from '../utils'
|
||||
|
||||
export let dm: DirectMessage
|
||||
const client = getClient()
|
||||
|
||||
$: icon = client.getHierarchy().getClass(dm._class).icon
|
||||
$: link = getSpaceLink(dm._id)
|
||||
</script>
|
||||
|
||||
{#if dm}
|
||||
{#await getDmName(client, dm) then name}
|
||||
<a class="flex-presenter" href={link}>
|
||||
<div class="icon">
|
||||
{#if icon}
|
||||
<Icon {icon} size={'small'} />
|
||||
{/if}
|
||||
</div>
|
||||
<span class="label">{name}</span>
|
||||
</a>
|
||||
{/await}
|
||||
{/if}
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Channel } from '@anticrm/chunter'
|
||||
import { ChunterSpace } from '@anticrm/chunter'
|
||||
import type { Class, Ref } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { createQuery, getClient, Members } from '@anticrm/presentation'
|
||||
@ -25,10 +25,10 @@
|
||||
import EditChannelDescriptionTab from './EditChannelDescriptionTab.svelte'
|
||||
import EditChannelSettingsTab from './EditChannelSettingsTab.svelte'
|
||||
|
||||
export let _id: Ref<Channel>
|
||||
export let _class: Ref<Class<Channel>>
|
||||
export let _id: Ref<ChunterSpace>
|
||||
export let _class: Ref<Class<ChunterSpace>>
|
||||
|
||||
let channel: Channel | undefined
|
||||
let channel: ChunterSpace
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -36,11 +36,15 @@
|
||||
const clazz = client.getHierarchy().getClass(_class)
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(chunter.class.Channel, { _id }, (result) => {
|
||||
$: query.query(chunter.class.ChunterSpace, { _id }, (result) => {
|
||||
channel = result[0]
|
||||
})
|
||||
|
||||
const tabLabels: IntlString[] = [chunter.string.Channel, chunter.string.Members, chunter.string.Settings]
|
||||
const tabLabels: IntlString[] = [
|
||||
chunter.string.About,
|
||||
chunter.string.Members,
|
||||
...(_class === chunter.class.Channel ? [chunter.string.Settings] : [])
|
||||
]
|
||||
let selectedTabIndex = 0
|
||||
</script>
|
||||
|
||||
|
@ -16,13 +16,13 @@
|
||||
<script lang="ts">
|
||||
import attachment, { Attachment } from '@anticrm/attachment'
|
||||
import { AttachmentPresenter } from '@anticrm/attachment-resources'
|
||||
import { Channel } from '@anticrm/chunter'
|
||||
import { ChunterSpace } from '@anticrm/chunter'
|
||||
import { Doc, SortingOrder } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { Menu } from '@anticrm/view-resources'
|
||||
import { showPopup, IconMoreV, Label } from '@anticrm/ui'
|
||||
|
||||
export let channel: Channel | undefined
|
||||
export let channel: ChunterSpace | undefined
|
||||
|
||||
const query = createQuery()
|
||||
let visibleAttachments: Attachment[] | undefined
|
||||
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Channel } from '@anticrm/chunter'
|
||||
import { Channel, ChunterSpace } from '@anticrm/chunter'
|
||||
import { getCurrentAccount } from '@anticrm/core'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { Button, EditBox } from '@anticrm/ui'
|
||||
@ -22,14 +22,21 @@
|
||||
import chunter from '../plugin'
|
||||
import EditChannelDescriptionAttachments from './EditChannelDescriptionAttachments.svelte'
|
||||
|
||||
export let channel: Channel
|
||||
export let channel: ChunterSpace
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function isCommonChannel (channel?: ChunterSpace): channel is Channel {
|
||||
return channel?._class === chunter.class.Channel
|
||||
}
|
||||
|
||||
function onTopicChange (ev: Event) {
|
||||
if (!isCommonChannel(channel)) {
|
||||
return
|
||||
}
|
||||
const newTopic = (ev.target as HTMLInputElement).value
|
||||
client.update(channel!, { topic: newTopic })
|
||||
client.update(channel, { topic: newTopic })
|
||||
}
|
||||
|
||||
function onDescriptionChange (ev: Event) {
|
||||
@ -47,6 +54,7 @@
|
||||
|
||||
{#if channel}
|
||||
<div class="flex-col flex-gap-3">
|
||||
{#if isCommonChannel(channel)}
|
||||
<EditBox
|
||||
label={chunter.string.Topic}
|
||||
bind:value={channel.topic}
|
||||
@ -71,6 +79,7 @@
|
||||
leaveChannel()
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<EditChannelDescriptionAttachments {channel} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -13,7 +13,7 @@
|
||||
const pinnedQuery = createQuery()
|
||||
let pinnedIds: Ref<ChunterMessage>[] = []
|
||||
pinnedQuery.query(
|
||||
chunter.class.Channel,
|
||||
chunter.class.ChunterSpace,
|
||||
{ _id: space },
|
||||
(res) => {
|
||||
pinnedIds = res[0]?.pinned ?? []
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import attachment from '@anticrm/attachment'
|
||||
import { AttachmentRefInput } from '@anticrm/attachment-resources'
|
||||
import type { Channel, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import type { ChunterSpace, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
||||
import core, { FindOptions, generateId, getCurrentAccount, Ref, SortingOrder, TxFactory } from '@anticrm/core'
|
||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||
@ -24,6 +24,7 @@
|
||||
import { createBacklinks } from '../backlinks'
|
||||
import chunter from '../plugin'
|
||||
import ChannelPresenter from './ChannelPresenter.svelte'
|
||||
import DmPresenter from './DmPresenter.svelte'
|
||||
import MsgView from './Message.svelte'
|
||||
|
||||
const client = getClient()
|
||||
@ -152,22 +153,24 @@
|
||||
await client.tx(tx)
|
||||
|
||||
// Create an backlink to document
|
||||
await createBacklinks(client, parent.space, chunter.class.Channel, commentId, message)
|
||||
await createBacklinks(client, parent.space, chunter.class.ChunterSpace, commentId, message)
|
||||
|
||||
commentId = generateId()
|
||||
}
|
||||
let comments: ThreadMessage[] = []
|
||||
|
||||
async function getChannel (_id: Ref<Channel>): Promise<Channel | undefined> {
|
||||
return await client.findOne(chunter.class.Channel, { _id })
|
||||
async function getChannel (_id: Ref<ChunterSpace>): Promise<ChunterSpace | undefined> {
|
||||
return await client.findOne(chunter.class.ChunterSpace, { _id })
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ml-8 mt-4">
|
||||
{#if parent}
|
||||
{#await getChannel(parent.space) then channel}
|
||||
{#if channel}
|
||||
{#if channel?._class === chunter.class.Channel}
|
||||
<ChannelPresenter value={channel} />
|
||||
{:else if channel}
|
||||
<DmPresenter dm={channel} />
|
||||
{/if}
|
||||
{/await}
|
||||
{#await getParticipants(comments, parent, employees) then participants}
|
||||
@ -208,7 +211,7 @@
|
||||
overflow: hidden;
|
||||
margin: 1rem 1rem 0px;
|
||||
background-color: var(--theme-border-modal);
|
||||
border-radius: .75rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--theme-zone-border);
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@
|
||||
)
|
||||
|
||||
pinnedQuery.query(
|
||||
chunter.class.Channel,
|
||||
chunter.class.ChunterSpace,
|
||||
{ _id: currentSpace },
|
||||
(res) => {
|
||||
pinnedIds = res[0]?.pinned ?? []
|
||||
@ -153,7 +153,7 @@
|
||||
await client.tx(tx)
|
||||
|
||||
// Create an backlink to document
|
||||
await createBacklinks(client, currentSpace, chunter.class.Channel, commentId, message)
|
||||
await createBacklinks(client, currentSpace, chunter.class.ChunterSpace, commentId, message)
|
||||
|
||||
commentId = generateId()
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import core from '@anticrm/core'
|
||||
import chunter, { Channel, ChunterMessage, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import chunter, { ChunterSpace, Channel, ChunterMessage, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||
import { Resources } from '@anticrm/platform'
|
||||
import { getClient, MessageBox } from '@anticrm/presentation'
|
||||
@ -23,23 +23,28 @@ import TxBacklinkCreate from './components/activity/TxBacklinkCreate.svelte'
|
||||
import TxBacklinkReference from './components/activity/TxBacklinkReference.svelte'
|
||||
import TxCommentCreate from './components/activity/TxCommentCreate.svelte'
|
||||
import ChannelPresenter from './components/ChannelPresenter.svelte'
|
||||
import DmPresenter from './components/DmPresenter.svelte'
|
||||
import ChannelView from './components/ChannelView.svelte'
|
||||
import ChannelHeader from './components/ChannelHeader.svelte'
|
||||
import DmHeader from './components/DmHeader.svelte'
|
||||
import CommentInput from './components/CommentInput.svelte'
|
||||
import CommentPresenter from './components/CommentPresenter.svelte'
|
||||
import CommentsPresenter from './components/CommentsPresenter.svelte'
|
||||
import CreateChannel from './components/CreateChannel.svelte'
|
||||
import CreateDirectMessage from './components/CreateDirectMessage.svelte'
|
||||
import EditChannel from './components/EditChannel.svelte'
|
||||
import ThreadView from './components/ThreadView.svelte'
|
||||
import Threads from './components/Threads.svelte'
|
||||
import SavedMessages from './components/SavedMessages.svelte'
|
||||
import preference from '@anticrm/preference'
|
||||
|
||||
import { getDmName } from './utils'
|
||||
|
||||
export { CommentsPresenter }
|
||||
|
||||
async function MarkUnread (object: Message): Promise<void> {
|
||||
const client = NotificationClientImpl.getClient()
|
||||
await client.updateLastView(object.space, chunter.class.Channel, object.createOn - 1, true)
|
||||
await client.updateLastView(object.space, chunter.class.ChunterSpace, object.createOn - 1, true)
|
||||
}
|
||||
|
||||
async function MarkCommentUnread (object: ThreadMessage): Promise<void> {
|
||||
@ -70,7 +75,7 @@ async function UnsubscribeMessage (object: Message): Promise<void> {
|
||||
async function PinMessage (message: ChunterMessage): Promise<void> {
|
||||
const client = getClient()
|
||||
|
||||
await client.updateDoc<Channel>(chunter.class.Channel, core.space.Space, message.space, {
|
||||
await client.updateDoc<ChunterSpace>(chunter.class.ChunterSpace, core.space.Space, message.space, {
|
||||
$push: { pinned: message._id }
|
||||
})
|
||||
}
|
||||
@ -78,7 +83,7 @@ async function PinMessage (message: ChunterMessage): Promise<void> {
|
||||
export async function UnpinMessage (message: ChunterMessage): Promise<void> {
|
||||
const client = getClient()
|
||||
|
||||
await client.updateDoc<Channel>(chunter.class.Channel, core.space.Space, message.space, {
|
||||
await client.updateDoc<ChunterSpace>(chunter.class.ChunterSpace, core.space.Space, message.space, {
|
||||
$pull: { pinned: message._id }
|
||||
})
|
||||
}
|
||||
@ -149,16 +154,22 @@ export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
CommentInput,
|
||||
CreateChannel,
|
||||
CreateDirectMessage,
|
||||
ChannelHeader,
|
||||
DmHeader,
|
||||
ChannelView,
|
||||
CommentPresenter,
|
||||
CommentsPresenter,
|
||||
ChannelPresenter,
|
||||
DmPresenter,
|
||||
EditChannel,
|
||||
Threads,
|
||||
ThreadView,
|
||||
SavedMessages
|
||||
},
|
||||
function: {
|
||||
GetDmName: getDmName
|
||||
},
|
||||
activity: {
|
||||
TxCommentCreate,
|
||||
TxBacklinkCreate,
|
||||
|
@ -14,7 +14,8 @@
|
||||
//
|
||||
|
||||
import chunter, { chunterId } from '@anticrm/chunter'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { Client, Space } from '@anticrm/core'
|
||||
import type { IntlString, Resource } from '@anticrm/platform'
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import { ViewAction } from '@anticrm/view'
|
||||
@ -22,10 +23,15 @@ import { ViewAction } from '@anticrm/view'
|
||||
export default mergeIds(chunterId, chunter, {
|
||||
component: {
|
||||
CreateChannel: '' as AnyComponent,
|
||||
CreateDirectMessage: '' as AnyComponent,
|
||||
ChannelHeader: '' as AnyComponent,
|
||||
DmHeader: '' as AnyComponent,
|
||||
ChannelView: '' as AnyComponent,
|
||||
EditChannel: '' as AnyComponent
|
||||
},
|
||||
function: {
|
||||
GetDmName: '' as Resource<(client: Client, space: Space) => Promise<string>>
|
||||
},
|
||||
actionImpl: {
|
||||
SubscribeMessage: '' as ViewAction,
|
||||
UnsubscribeMessage: '' as ViewAction,
|
||||
@ -36,14 +42,19 @@ export default mergeIds(chunterId, chunter, {
|
||||
},
|
||||
string: {
|
||||
Channel: '' as IntlString,
|
||||
DirectMessage: '' as IntlString,
|
||||
Channels: '' as IntlString,
|
||||
DirectMessages: '' as IntlString,
|
||||
CreateChannel: '' as IntlString,
|
||||
NewDirectMessage: '' as IntlString,
|
||||
ChannelName: '' as IntlString,
|
||||
ChannelNamePlaceholder: '' as IntlString,
|
||||
ChannelDescription: '' as IntlString,
|
||||
MakePrivate: '' as IntlString,
|
||||
MakePrivateDescription: '' as IntlString,
|
||||
About: '' as IntlString,
|
||||
Members: '' as IntlString,
|
||||
NoMembers: '' as IntlString,
|
||||
In: '' as IntlString,
|
||||
Replies: '' as IntlString,
|
||||
Topic: '' as IntlString,
|
||||
|
@ -1,6 +1,9 @@
|
||||
import contact, { EmployeeAccount } from '@anticrm/contact'
|
||||
import { Account, Class, Client, Obj, Ref } from '@anticrm/core'
|
||||
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
||||
import { Account, Class, Client, Obj, Ref, Space, getCurrentAccount } from '@anticrm/core'
|
||||
import { Asset } from '@anticrm/platform'
|
||||
import { getCurrentLocation, locationToUrl } from '@anticrm/ui'
|
||||
|
||||
import chunter from './plugin'
|
||||
|
||||
export async function getUser (
|
||||
client: Client,
|
||||
@ -35,3 +38,28 @@ export function isToday (time: number): boolean {
|
||||
export function classIcon (client: Client, _class: Ref<Class<Obj>>): Asset | undefined {
|
||||
return client.getHierarchy().getClass(_class).icon
|
||||
}
|
||||
|
||||
export async function getDmName (client: Client, dm: Space): Promise<string> {
|
||||
const myAccId = getCurrentAccount()._id
|
||||
|
||||
const employeeAccounts = await client.findAll(contact.class.EmployeeAccount, {
|
||||
_id: { $in: dm.members as Array<Ref<EmployeeAccount>> }
|
||||
})
|
||||
|
||||
const name = (dm.members.length > 1 ? employeeAccounts.filter((a) => a._id !== myAccId) : employeeAccounts)
|
||||
.map((a) => formatName(a.name))
|
||||
.join(', ')
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
export function getSpaceLink (id: Ref<Space>): string {
|
||||
const loc = getCurrentLocation()
|
||||
|
||||
loc.path[1] = chunter.app.Chunter
|
||||
loc.path[2] = id
|
||||
loc.path.length = 3
|
||||
loc.fragment = undefined
|
||||
|
||||
return locationToUrl(loc)
|
||||
}
|
||||
|
@ -23,12 +23,23 @@ import { AnyComponent } from '@anticrm/ui'
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Channel extends Space {
|
||||
export interface ChunterSpace extends Space {
|
||||
lastMessage?: Timestamp
|
||||
pinned?: Ref<ChunterMessage>[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Channel extends ChunterSpace {
|
||||
topic?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface DirectMessage extends ChunterSpace {}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -113,8 +124,10 @@ export default plugin(chunterId, {
|
||||
ThreadMessage: '' as Ref<Class<ThreadMessage>>,
|
||||
Backlink: '' as Ref<Class<Backlink>>,
|
||||
Comment: '' as Ref<Class<Comment>>,
|
||||
ChunterSpace: '' as Ref<Class<ChunterSpace>>,
|
||||
Channel: '' as Ref<Class<Channel>>,
|
||||
SavedMessages: '' as Ref<Class<SavedMessages>>
|
||||
SavedMessages: '' as Ref<Class<SavedMessages>>,
|
||||
DirectMessage: '' as Ref<Class<DirectMessage>>
|
||||
},
|
||||
space: {
|
||||
Backlinks: '' as Ref<Space>
|
||||
|
@ -59,6 +59,13 @@ export interface SpaceHeader extends Class<Doc> {
|
||||
header: AnyComponent
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SpaceName extends Class<Doc> {
|
||||
getName: Resource<(client: Client, space: Space) => Promise<string>>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -244,6 +251,7 @@ const view = plugin(viewId, {
|
||||
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
|
||||
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
|
||||
SpaceHeader: '' as Ref<Mixin<SpaceHeader>>,
|
||||
SpaceName: '' as Ref<Mixin<SpaceName>>,
|
||||
IgnoreActions: '' as Ref<Mixin<IgnoreActions>>,
|
||||
HTMLPresenter: '' as Ref<Mixin<HTMLPresenter>>,
|
||||
TextPresenter: '' as Ref<Mixin<TextPresenter>>,
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Doc, Ref, SortingOrder, Space } from '@anticrm/core'
|
||||
import core, { Doc, Ref, SortingOrder, Space, getCurrentAccount } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Scroller } from '@anticrm/ui'
|
||||
@ -34,6 +34,7 @@
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const query = createQuery()
|
||||
const myAccId = getCurrentAccount()._id
|
||||
|
||||
let spaces: Space[] = []
|
||||
let starred: Space[] = []
|
||||
@ -77,7 +78,7 @@
|
||||
topSpecials = []
|
||||
bottomSpecials = []
|
||||
}
|
||||
shownSpaces = spaces.filter((sp) => !sp.archived && !preferences.has(sp._id))
|
||||
shownSpaces = spaces.filter((sp) => !sp.archived && !preferences.has(sp._id) && (!sp.members.length || sp.members.includes(myAccId)))
|
||||
starred = spaces.filter((sp) => preferences.has(sp._id))
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,20 @@
|
||||
return lastView < value
|
||||
}
|
||||
|
||||
async function getName (space: Space) {
|
||||
const clazz = hierarchy.getClass(space._class)
|
||||
const nameMixin = hierarchy.as(clazz, view.mixin.SpaceName)
|
||||
|
||||
if (nameMixin.getName) {
|
||||
const getSpaceName = await getResource(nameMixin.getName);
|
||||
const name = await getSpaceName(client, space)
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
return space.name
|
||||
}
|
||||
|
||||
function getParentActions(): Action[] {
|
||||
return hasSpaceBrowser ? [browseSpaces, addSpace] : [addSpace]
|
||||
}
|
||||
@ -155,18 +169,20 @@
|
||||
{/each}
|
||||
</TreeNode>
|
||||
{:else}
|
||||
<TreeItem
|
||||
indent={'ml-4'}
|
||||
_id={space._id}
|
||||
title={space.name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={() => getActions(space)}
|
||||
bold={isChanged(space, $lastViews)}
|
||||
on:click={() => {
|
||||
selectSpace(space._id)
|
||||
}}
|
||||
/>
|
||||
{#await getName(space) then name}
|
||||
<TreeItem
|
||||
indent={'ml-4'}
|
||||
_id={space._id}
|
||||
title={name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={() => getActions(space)}
|
||||
bold={isChanged(space, $lastViews)}
|
||||
on:click={() => {
|
||||
selectSpace(space._id)
|
||||
}}
|
||||
/>
|
||||
{/await}
|
||||
{/if}
|
||||
{/each}
|
||||
</TreeNode>
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import chunter, { Channel, Comment, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import chunter, { ChunterSpace, Comment, Message, ThreadMessage } from '@anticrm/chunter'
|
||||
import { EmployeeAccount } from '@anticrm/contact'
|
||||
import core, {
|
||||
Class,
|
||||
@ -39,7 +39,7 @@ import workbench from '@anticrm/workbench'
|
||||
* @public
|
||||
*/
|
||||
export function channelHTMLPresenter (doc: Doc): string {
|
||||
const channel = doc as Channel
|
||||
const channel = doc as ChunterSpace
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
return `<a href="${front}/${workbench.component.WorkbenchApp}/${chunter.app.Chunter}/${channel._id}">${channel.name}</a>`
|
||||
}
|
||||
@ -48,7 +48,7 @@ export function channelHTMLPresenter (doc: Doc): string {
|
||||
* @public
|
||||
*/
|
||||
export function channelTextPresenter (doc: Doc): string {
|
||||
const channel = doc as Channel
|
||||
const channel = doc as ChunterSpace
|
||||
return `${channel.name}`
|
||||
}
|
||||
|
||||
@ -145,12 +145,12 @@ export async function MessageCreate (tx: Tx, control: TriggerControl): Promise<T
|
||||
|
||||
const message = doc as Message
|
||||
|
||||
const channel = (await control.findAll(chunter.class.Channel, {
|
||||
const channel = (await control.findAll(chunter.class.ChunterSpace, {
|
||||
_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, {
|
||||
const res = control.txFactory.createTxUpdateDoc<ChunterSpace>(channel._class, channel.space, channel._id, {
|
||||
lastMessage: message.createOn
|
||||
})
|
||||
return [res]
|
||||
@ -165,7 +165,7 @@ export async function MessageDelete (tx: Tx, control: TriggerControl): Promise<T
|
||||
const hierarchy = control.hierarchy
|
||||
if (tx._class !== core.class.TxCollectionCUD) return []
|
||||
|
||||
const rmTx = (tx as TxCollectionCUD<Channel, Message>).tx
|
||||
const rmTx = (tx as TxCollectionCUD<ChunterSpace, Message>).tx
|
||||
if (!hierarchy.isDerived(rmTx.objectClass, chunter.class.Message)) {
|
||||
return []
|
||||
}
|
||||
@ -175,7 +175,7 @@ export async function MessageDelete (tx: Tx, control: TriggerControl): Promise<T
|
||||
|
||||
const message = TxProcessor.createDoc2Doc(createTx as TxCreateDoc<Message>)
|
||||
|
||||
const channel = (await control.findAll(chunter.class.Channel, {
|
||||
const channel = (await control.findAll(chunter.class.ChunterSpace, {
|
||||
_id: message.space
|
||||
}, { limit: 1 }))[0]
|
||||
|
||||
@ -185,7 +185,7 @@ export async function MessageDelete (tx: Tx, control: TriggerControl): Promise<T
|
||||
})
|
||||
const lastMessageDate = messages.reduce((maxDate, mess) => mess.createOn > maxDate ? mess.createOn : maxDate, 0)
|
||||
|
||||
const updateTx = control.txFactory.createTxUpdateDoc<Channel>(channel._class, channel.space, channel._id, {
|
||||
const updateTx = control.txFactory.createTxUpdateDoc<ChunterSpace>(channel._class, channel.space, channel._id, {
|
||||
lastMessage: lastMessageDate > 0 ? lastMessageDate : undefined
|
||||
})
|
||||
|
||||
|
@ -31,7 +31,17 @@ export default plugin(serverChunterId, {
|
||||
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[]>>,
|
||||
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[]>
|
||||
>,
|
||||
ChannelHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
||||
ChannelTextPresenter: '' as Resource<(doc: Doc) => string>
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user