diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index 43e3525849..6ecccaea78 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -204,10 +204,34 @@ export function createModel (builder: Builder, options = { addApplication: true fields: ['members'] }) + builder.mixin(chunter.class.Channel, core.class.Class, notification.mixin.ClassCollaborators, { + fields: ['members'] + }) + + builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.ObjectPanel, { + component: chunter.component.ChannelViewPanel + }) + + builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.ObjectPanel, { + component: chunter.component.ChannelViewPanel + }) + builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.ObjectPresenter, { presenter: chunter.component.DmPresenter }) + builder.mixin(chunter.class.Message, core.class.Class, notification.mixin.NotificationObjectPresenter, { + presenter: chunter.component.ThreadParentPresenter + }) + + builder.mixin(chunter.class.ThreadMessage, core.class.Class, view.mixin.ObjectPresenter, { + presenter: chunter.component.MessagePresenter + }) + + builder.mixin(chunter.class.Message, core.class.Class, view.mixin.ObjectPanel, { + component: chunter.component.ThreadViewPanel + }) + builder.mixin(chunter.class.Message, core.class.Class, view.mixin.ObjectPresenter, { presenter: chunter.component.MessagePresenter }) diff --git a/models/chunter/src/plugin.ts b/models/chunter/src/plugin.ts index a66f05a97a..c5991777ba 100644 --- a/models/chunter/src/plugin.ts +++ b/models/chunter/src/plugin.ts @@ -26,6 +26,7 @@ export default mergeIds(chunterId, chunter, { component: { CommentPresenter: '' as AnyComponent, ChannelPresenter: '' as AnyComponent, + DirectMessagePresenter: '' as AnyComponent, MessagePresenter: '' as AnyComponent, DmPresenter: '' as AnyComponent, Threads: '' as AnyComponent, diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index 5a51ad86f8..8a40413842 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -108,6 +108,7 @@ export class TContact extends TDoc implements Contact { @UX(contact.string.Channel, contact.icon.Person) export class TChannel extends TAttachedDoc implements Channel { @Prop(TypeRef(contact.class.ChannelProvider), contact.string.ChannelProvider) + @Index(IndexKind.Indexed) provider!: Ref @Prop(TypeString(), contact.string.Value) diff --git a/models/notification/package.json b/models/notification/package.json index 7c6eff9bdb..5ace97396b 100644 --- a/models/notification/package.json +++ b/models/notification/package.json @@ -30,6 +30,7 @@ "@hcengineering/ui": "^0.6.3", "@hcengineering/platform": "^0.6.8", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/workbench": "^0.6.2", "@hcengineering/notification": "^0.6.8", "@hcengineering/setting": "^0.6.3" } diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index 81c2a8f86c..51246d79ed 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -14,14 +14,17 @@ // limitations under the License. // -import { Account, Doc, Domain, DOMAIN_MODEL, IndexKind, Ref, TxCUD } from '@hcengineering/core' +import { Account, Class, Doc, Domain, DOMAIN_MODEL, IndexKind, Ref, Timestamp, TxCUD } from '@hcengineering/core' import { ArrOf, Builder, Index, Mixin, Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model' import core, { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core' -import type { +import { AnotherUserNotifications, + DocUpdates, EmailNotification, LastView, Notification, + notificationId, + NotificationObjectPresenter, NotificationProvider, NotificationSetting, NotificationStatus, @@ -30,7 +33,9 @@ import type { } from '@hcengineering/notification' import type { IntlString } from '@hcengineering/platform' import setting from '@hcengineering/setting' +import workbench from '@hcengineering/workbench' import notification from './plugin' +import { AnyComponent } from '@hcengineering/ui' export const DOMAIN_NOTIFICATION = 'notification' as Domain @@ -121,9 +126,29 @@ export class TTrackedDoc extends TClass {} @UX(notification.string.Collaborators) export class TCollaborators extends TDoc { @Prop(ArrOf(TypeRef(core.class.Account)), notification.string.Collaborators) + @Index(IndexKind.Indexed) collaborators!: Ref[] } +@Mixin(notification.mixin.NotificationObjectPresenter, core.class.Class) +export class TNotificationObjectPresenter extends TClass implements NotificationObjectPresenter { + presenter!: AnyComponent +} + +@Model(notification.class.DocUpdates, core.class.Doc, DOMAIN_NOTIFICATION) +export class TDocUpdates extends TDoc implements DocUpdates { + @Index(IndexKind.Indexed) + user!: Ref + + @Index(IndexKind.Indexed) + attachedTo!: Ref + + attachedToClass!: Ref> + lastTx?: Ref> + lastTxTime?: Timestamp + txes!: [Ref>, Timestamp][] +} + export function createModel (builder: Builder): void { builder.createModel( TLastView, @@ -136,7 +161,9 @@ export function createModel (builder: Builder): void { TAnotherUserNotifications, TClassCollaborators, TTrackedDoc, - TCollaborators + TCollaborators, + TDocUpdates, + TNotificationObjectPresenter ) builder.createDoc( @@ -165,19 +192,6 @@ export function createModel (builder: Builder): void { notification.ids.DMNotification ) - builder.createDoc( - notification.class.NotificationType, - core.space.Model, - { - label: notification.string.Notification, - hidden: true, - textTemplate: '', - htmlTemplate: '', - subjectTemplate: '' - }, - notification.ids.CollaboratorNotification - ) - // Temporarily disabled, we should think about it // builder.createDoc( // notification.class.NotificationProvider, @@ -213,6 +227,20 @@ export function createModel (builder: Builder): void { }, notification.ids.NotificationSettings ) + + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: notification.string.Inbox, + icon: notification.icon.Notifications, + alias: notificationId, + position: 'bottom', + hidden: false, + component: notification.component.Inbox + }, + notification.app.Notification + ) } export { notificationOperation } from './migration' diff --git a/models/notification/src/plugin.ts b/models/notification/src/plugin.ts index 0c79e0dfbc..91b1ca14b1 100644 --- a/models/notification/src/plugin.ts +++ b/models/notification/src/plugin.ts @@ -14,6 +14,8 @@ // limitations under the License. // +import { Ref } from '@hcengineering/core' +import { Application } from '@hcengineering/workbench' import notification, { notificationId } from '@hcengineering/notification' import { IntlString, mergeIds } from '@hcengineering/platform' import { AnyComponent } from '@hcengineering/ui' @@ -29,6 +31,9 @@ export default mergeIds(notificationId, notification, { EmailNotification: '' as IntlString, Collaborators: '' as IntlString }, + app: { + Notification: '' as Ref + }, component: { NotificationSettings: '' as AnyComponent } diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index ad67a93184..83ed1fa560 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -44,11 +44,11 @@ export function createModel (builder: Builder): void { }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.CreateCollaboratorDoc + trigger: serverNotification.trigger.CollaboratorDocHandler }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.UpdateCollaboratorDoc + trigger: serverNotification.trigger.OnUpdateLastView }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { diff --git a/models/telegram/src/migration.ts b/models/telegram/src/migration.ts index 43a6836cf2..fe7cdd6832 100644 --- a/models/telegram/src/migration.ts +++ b/models/telegram/src/migration.ts @@ -13,31 +13,9 @@ // limitations under the License. // -import core, { SortingOrder, TxOperations } from '@hcengineering/core' -import telegram from './plugin' +import core, { TxOperations } from '@hcengineering/core' import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model' -import contact from '@hcengineering/model-contact' - -async function updateChannlLastMessage (client: TxOperations): Promise { - const channels = await client.findAll(contact.class.Channel, { - provider: contact.channelProvider.Telegram - }) - const targets = channels.filter((p) => p.lastMessage === undefined) - for (const channel of targets) { - const lastMessage = await client.findOne( - telegram.class.Message, - { - attachedTo: channel._id - }, - { sort: { sendOn: SortingOrder.Descending } } - ) - if (lastMessage !== undefined) { - await client.updateDoc(channel._class, channel.space, channel._id, { - lastMessage: lastMessage.sendOn - }) - } - } -} +import telegram from './plugin' export const telegramOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise {}, @@ -60,7 +38,5 @@ export const telegramOperation: MigrateOperation = { telegram.space.Telegram ) } - - await updateChannlLastMessage(tx) } } diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index ad6a92392e..0f49ee74f1 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -827,6 +827,10 @@ export function createModel (builder: Builder): void { presenter: tracker.component.IssuePresenter }) + builder.mixin(tracker.class.Issue, core.class.Class, notification.mixin.NotificationObjectPresenter, { + presenter: tracker.component.NotificationIssuePresenter + }) + builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.IssueTemplatePresenter }) diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index 22ca7df6e2..1cf7576e57 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -42,7 +42,8 @@ export default mergeIds(trackerId, tracker, { Nope: '' as AnyComponent, SprintSelector: '' as AnyComponent, IssueStatistics: '' as AnyComponent, - TimeSpendReportPopup: '' as AnyComponent + TimeSpendReportPopup: '' as AnyComponent, + NotificationIssuePresenter: '' as AnyComponent }, app: { Tracker: '' as Ref diff --git a/models/workbench/src/index.ts b/models/workbench/src/index.ts index a8d19860e6..003cf19710 100644 --- a/models/workbench/src/index.ts +++ b/models/workbench/src/index.ts @@ -32,6 +32,7 @@ export class TApplication extends TDoc implements Application { label!: IntlString icon!: Asset alias!: string + position?: 'top' | 'bottom' hidden!: boolean } diff --git a/packages/core/src/tx.ts b/packages/core/src/tx.ts index e7fa57f180..6114320274 100644 --- a/packages/core/src/tx.ts +++ b/packages/core/src/tx.ts @@ -464,7 +464,10 @@ export abstract class TxProcessor implements WithTx { * @public */ export class TxFactory { - constructor (readonly account: Ref) {} + private readonly txSpace: Ref + constructor (readonly account: Ref, readonly isDerived: boolean = false) { + this.txSpace = isDerived ? core.space.DerivedTx : core.space.Tx + } createTxCreateDoc( _class: Ref>, @@ -477,7 +480,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxCreateDoc, - space: core.space.Tx, + space: this.txSpace, objectId: objectId ?? generateId(), objectClass: _class, objectSpace: space, @@ -500,7 +503,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxCollectionCUD, - space: core.space.Tx, + space: this.txSpace, objectId, objectClass: _class, objectSpace: space, @@ -523,7 +526,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxUpdateDoc, - space: core.space.Tx, + space: this.txSpace, modifiedBy: modifiedBy ?? this.account, modifiedOn: modifiedOn ?? Date.now(), objectId, @@ -544,7 +547,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxRemoveDoc, - space: core.space.Tx, + space: this.txSpace, modifiedBy: modifiedBy ?? this.account, modifiedOn: modifiedOn ?? Date.now(), objectId, @@ -565,7 +568,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxMixin, - space: core.space.Tx, + space: this.txSpace, modifiedBy: modifiedBy ?? this.account, modifiedOn: modifiedOn ?? Date.now(), objectId, @@ -587,7 +590,7 @@ export class TxFactory { return { _id: generateId(), _class: core.class.TxApplyIf, - space: core.space.Tx, + space: this.txSpace, modifiedBy: modifiedBy ?? this.account, modifiedOn: modifiedOn ?? Date.now(), objectSpace: space, diff --git a/packages/panel/src/components/Panel.svelte b/packages/panel/src/components/Panel.svelte index 66768351db..38fa886dec 100644 --- a/packages/panel/src/components/Panel.svelte +++ b/packages/panel/src/components/Panel.svelte @@ -45,6 +45,7 @@ export let allowClose = true export let useMaxWidth: boolean | undefined = undefined export let isFullSize = false + export let embedded = false diff --git a/packages/presentation/src/utils.ts b/packages/presentation/src/utils.ts index 1db4a12837..20c6350c2a 100644 --- a/packages/presentation/src/utils.ts +++ b/packages/presentation/src/utils.ts @@ -341,7 +341,6 @@ export async function getAttributeEditor ( _class: Ref>, key: KeyedAttribute | string ): Promise { - console.log('get attribute editor', _class, key) const hierarchy = client.getHierarchy() const attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr const presenterClass = attribute !== undefined ? getAttributePresenterClass(hierarchy, attribute) : undefined diff --git a/packages/theme/styles/panel.scss b/packages/theme/styles/panel.scss index acb80eb01a..d9038f2d77 100644 --- a/packages/theme/styles/panel.scss +++ b/packages/theme/styles/panel.scss @@ -61,8 +61,15 @@ flex-direction: column; min-height: 0; height: 100%; - border-radius: .5rem; - box-shadow: var(--popup-panel-shadow); + + &.embedded { + width: 100%; + } + + &:not(.embedded) { + border-radius: .5rem; + box-shadow: var(--popup-panel-shadow); + } .popupPanel-title { display: flex; @@ -109,7 +116,9 @@ height: 100%; background-color: var(--body-color); border: 1px solid var(--divider-color); - border-radius: 0 0 .5rem .5rem; + &:not(.embedded) { + border-radius: 0 0 .5rem .5rem; + } &.main { justify-content: stretch; diff --git a/packages/ui/src/components/Panel.svelte b/packages/ui/src/components/Panel.svelte index c051df0878..553da4fd34 100644 --- a/packages/ui/src/components/Panel.svelte +++ b/packages/ui/src/components/Panel.svelte @@ -34,6 +34,7 @@ export let floatAside = false export let allowClose = true export let useMaxWidth: boolean | undefined = undefined + export let embedded = false const dispatch = createEventDispatcher() @@ -79,74 +80,77 @@
{ panelWidth = element.clientWidth checkPanel() }} > -
-
- {#if allowClose} -
+
+ {#if twoRows && !withoutTitle} +
{/if} - {#if $$slots.navigator}{/if} -
- {#if !twoRows && !withoutTitle}{/if} -
-
- - {#if isFullSize || useMaxWidth !== undefined || ($$slots.aside && isAside)} -
- {/if} - {#if $$slots.aside && isAside} -
- {#if twoRows && !withoutTitle} -
- {/if} -
-
+ {/if} +
{#if $deviceInfo.isMobile}
{ - const doc = dtx.doc - if (doc === undefined) { - return - } - const docClass: Class = client.getModel().getObject(doc._class) + const docClass: Class = client.getModel().getObject(dtx.tx.objectClass) let trLabel = docClass.label !== undefined ? await translate(docClass.label, {}) : undefined if (dtx.collectionAttribute !== undefined) { @@ -56,7 +52,7 @@ async function createPseudoViewlet ( } // Check if it is attached doc and collection have title override. - const presenter = await getObjectPresenter(client, doc._class, { key: 'doc-presenter' }) + const presenter = await getObjectPresenter(client, dtx.tx.objectClass, { key: 'doc-presenter' }) if (presenter !== undefined) { let collection = '' if (dtx.collectionAttribute?.label !== undefined) { diff --git a/plugins/activity/src/index.ts b/plugins/activity/src/index.ts index 562f242e80..95a6262db5 100644 --- a/plugins/activity/src/index.ts +++ b/plugins/activity/src/index.ts @@ -113,7 +113,13 @@ export default plugin(activityId, { Delete: '' as IntlString, Edit: '' as IntlString, Edited: '' as IntlString, - Activity: '' as IntlString + Activity: '' as IntlString, + Changed: '' as IntlString, + To: '' as IntlString, + Unset: '' as IntlString, + Added: '' as IntlString, + From: '' as IntlString, + Removed: '' as IntlString }, class: { TxViewlet: '' as Ref>, diff --git a/plugins/chunter-resources/src/components/ChannelViewPanel.svelte b/plugins/chunter-resources/src/components/ChannelViewPanel.svelte new file mode 100644 index 0000000000..e92bede09a --- /dev/null +++ b/plugins/chunter-resources/src/components/ChannelViewPanel.svelte @@ -0,0 +1,24 @@ + + + +
+ +
diff --git a/plugins/chunter-resources/src/components/DirectMessagePresenter.svelte b/plugins/chunter-resources/src/components/DirectMessagePresenter.svelte new file mode 100644 index 0000000000..26a78bb3f9 --- /dev/null +++ b/plugins/chunter-resources/src/components/DirectMessagePresenter.svelte @@ -0,0 +1,25 @@ + + +{#if dm} + {#await getDmName(client, dm) then name} + + {name} + +
+ {/await} +{/if} diff --git a/plugins/chunter-resources/src/components/MessagePresenter.svelte b/plugins/chunter-resources/src/components/MessagePresenter.svelte index 26a78bb3f9..c824a4118d 100644 --- a/plugins/chunter-resources/src/components/MessagePresenter.svelte +++ b/plugins/chunter-resources/src/components/MessagePresenter.svelte @@ -1,25 +1,22 @@ + -{#if dm} - {#await getDmName(client, dm) then name} - - {name} - -
- {/await} -{/if} +
diff --git a/plugins/chunter-resources/src/components/ThreadParentPresenter.svelte b/plugins/chunter-resources/src/components/ThreadParentPresenter.svelte new file mode 100644 index 0000000000..aa65d4f049 --- /dev/null +++ b/plugins/chunter-resources/src/components/ThreadParentPresenter.svelte @@ -0,0 +1,20 @@ + + + +