Merge remote-tracking branch 'origin/develop' into staging

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-10-26 03:09:04 +07:00
commit d6d4ba1633
No known key found for this signature in database
GPG Key ID: BD80F68D68D8F7F2
14 changed files with 100 additions and 81 deletions

View File

@ -15,30 +15,30 @@
import activity, { type ActivityMessageControl } from '@hcengineering/activity' import activity, { type ActivityMessageControl } from '@hcengineering/activity'
import { chunterId, type ChunterSpace } from '@hcengineering/chunter' import { chunterId, type ChunterSpace } from '@hcengineering/chunter'
import presentation from '@hcengineering/model-presentation' import contact from '@hcengineering/contact'
import { type Builder } from '@hcengineering/model' import { type Builder } from '@hcengineering/model'
import core from '@hcengineering/model-core' import core from '@hcengineering/model-core'
import presentation from '@hcengineering/model-presentation'
import view from '@hcengineering/model-view' import view from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench' import workbench from '@hcengineering/model-workbench'
import { WidgetType } from '@hcengineering/workbench' import { WidgetType } from '@hcengineering/workbench'
import contact from '@hcengineering/contact'
import chunter from './plugin'
import { defineActions } from './actions' import { defineActions } from './actions'
import { defineNotifications } from './notifications' import { defineNotifications } from './notifications'
import chunter from './plugin'
import { import {
DOMAIN_CHUNTER, DOMAIN_CHUNTER,
TChannel, TChannel,
TChatMessage, TChatMessage,
TChatMessageViewlet, TChatMessageViewlet,
TChatSyncInfo, TChatSyncInfo,
TChunterExtension,
TChunterSpace, TChunterSpace,
TDirectMessage, TDirectMessage,
TInlineButton, TInlineButton,
TObjectChatPanel, TObjectChatPanel,
TThreadMessage, TThreadMessage,
TTypingInfo, TTypingInfo
TChunterExtension
} from './types' } from './types'
export { chunterId } from '@hcengineering/chunter' export { chunterId } from '@hcengineering/chunter'
@ -161,6 +161,10 @@ export function createModel (builder: Builder): void {
presenter: chunter.component.ThreadMessagePresenter presenter: chunter.component.ThreadMessagePresenter
}) })
builder.mixin(chunter.class.TypingInfo, core.class.Class, core.mixin.TransientConfiguration, {
broadcastOnly: true
})
builder.createDoc( builder.createDoc(
view.class.Viewlet, view.class.Viewlet,
core.space.Model, core.space.Model,

View File

@ -14,8 +14,6 @@
// //
import { import {
type Card,
type CollaborativeDoc,
DOMAIN_BLOB, DOMAIN_BLOB,
DOMAIN_CONFIGURATION, DOMAIN_CONFIGURATION,
DOMAIN_DOC_INDEX_STATE, DOMAIN_DOC_INDEX_STATE,
@ -27,8 +25,10 @@ import {
type ArrOf, type ArrOf,
type AttachedDoc, type AttachedDoc,
type Blob, type Blob,
type Card,
type Class, type Class,
type ClassifierKind, type ClassifierKind,
type CollaborativeDoc,
type Collection, type Collection,
type Configuration, type Configuration,
type ConfigurationElement, type ConfigurationElement,
@ -50,6 +50,7 @@ import {
type RefTo, type RefTo,
type Space, type Space,
type Timestamp, type Timestamp,
type TransientConfiguration,
type Type, type Type,
type TypeAny, type TypeAny,
type Version type Version
@ -403,3 +404,9 @@ export class TTypeCollaborativeDocVersion extends TType {}
@UX(core.string.Rank) @UX(core.string.Rank)
@Model(core.class.TypeRank, core.class.Type) @Model(core.class.TypeRank, core.class.Type)
export class TTypeRank extends TType {} export class TTypeRank extends TType {}
@MMixin(core.mixin.TransientConfiguration, core.class.Class)
export class TTransientConfiguration extends TClass implements TransientConfiguration {
@Prop(TypeBoolean(), core.string.Private)
broadcastOnly!: boolean
}

View File

@ -39,12 +39,12 @@ import {
TAttachedDoc, TAttachedDoc,
TAttribute, TAttribute,
TBlob, TBlob,
TCard,
TClass, TClass,
TCollection, TCollection,
TConfiguration, TConfiguration,
TConfigurationElement, TConfigurationElement,
TDoc, TDoc,
TCard,
TDocIndexState, TDocIndexState,
TDomainIndexConfiguration, TDomainIndexConfiguration,
TEnum, TEnum,
@ -57,6 +57,7 @@ import {
TObj, TObj,
TPluginConfiguration, TPluginConfiguration,
TRefTo, TRefTo,
TTransientConfiguration,
TType, TType,
TTypeAny, TTypeAny,
TTypeBlob, TTypeBlob,
@ -173,7 +174,8 @@ export function createModel (builder: Builder): void {
TMigrationState, TMigrationState,
TBlob, TBlob,
TDomainIndexConfiguration, TDomainIndexConfiguration,
TBenchmarkDoc TBenchmarkDoc,
TTransientConfiguration
) )
builder.createDoc( builder.createDoc(

View File

@ -15,8 +15,8 @@
// //
import type { Asset, IntlString, Plugin } from '@hcengineering/platform' import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
import type { DocumentQuery } from './storage'
import { CollaborativeDoc } from './collaboration' import { CollaborativeDoc } from './collaboration'
import type { DocumentQuery } from './storage'
/** /**
* @public * @public
@ -346,6 +346,14 @@ export const DOMAIN_MIGRATION = '_migrations' as Domain
*/ */
export const DOMAIN_TRANSIENT = 'transient' as Domain export const DOMAIN_TRANSIENT = 'transient' as Domain
/**
* @public
*/
export interface TransientConfiguration extends Class<Doc> {
// If set will not store transient objects into memdb
broadcastOnly: boolean
}
/** /**
* Special domain to access s3 blob data. * Special domain to access s3 blob data.
* @public * @public

View File

@ -48,6 +48,7 @@ import type {
SpaceTypeDescriptor, SpaceTypeDescriptor,
SystemSpace, SystemSpace,
Timestamp, Timestamp,
TransientConfiguration,
Type, Type,
TypeAny, TypeAny,
TypedSpace, TypedSpace,
@ -148,7 +149,8 @@ export default plugin(coreId, {
mixin: { mixin: {
ConfigurationElement: '' as Ref<Mixin<ConfigurationElement>>, ConfigurationElement: '' as Ref<Mixin<ConfigurationElement>>,
IndexConfiguration: '' as Ref<Mixin<IndexingConfiguration<Doc>>>, IndexConfiguration: '' as Ref<Mixin<IndexingConfiguration<Doc>>>,
SpacesTypeData: '' as Ref<Mixin<Space>> SpacesTypeData: '' as Ref<Mixin<Space>>,
TransientConfiguration: '' as Ref<Mixin<TransientConfiguration>>
}, },
space: { space: {
Tx: '' as Ref<Space>, Tx: '' as Ref<Space>,

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { getResource, getResourceP } from '@hcengineering/platform' import { getResourceP } from '@hcengineering/platform'
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { SvelteComponent } from 'svelte' import { SvelteComponent } from 'svelte'
import type { AnyComponent, AnySvelteComponent } from '../types' import type { AnyComponent, AnySvelteComponent } from '../types'
@ -70,6 +70,7 @@
} }
}) })
} else { } else {
loading = false
Ctor = component Ctor = component
} }
} else { } else {

View File

@ -14,9 +14,9 @@
--> -->
<script lang="ts"> <script lang="ts">
import { DirectMessage } from '@hcengineering/chunter' import { DirectMessage } from '@hcengineering/chunter'
import contact, { Person, PersonAccount } from '@hcengineering/contact' import contact, { Person } from '@hcengineering/contact'
import { Avatar, CombineAvatars, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources' import { Avatar, CombineAvatars, personByIdStore } from '@hcengineering/contact-resources'
import { Account, IdMap, Ref } from '@hcengineering/core' import { Ref } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { Icon, IconSize } from '@hcengineering/ui' import { Icon, IconSize } from '@hcengineering/ui'
import { classIcon } from '@hcengineering/view-resources' import { classIcon } from '@hcengineering/view-resources'
@ -54,10 +54,6 @@
$: if (size === 'small') { $: if (size === 'small') {
avatarSize = 'x-small' avatarSize = 'x-small'
} }
function getAccountByPerson (accountById: IdMap<PersonAccount>, person: Person): Account | undefined {
return Array.from(accountById.values()).find((account) => account.person === person._id)
}
</script> </script>
{#if persons.length === 0} {#if persons.length === 0}
@ -65,13 +61,7 @@
{/if} {/if}
{#if persons.length === 1} {#if persons.length === 1}
<Avatar <Avatar person={persons[0]} size={avatarSize} name={persons[0].name} {showStatus} />
person={persons[0]}
size={avatarSize}
name={persons[0].name}
{showStatus}
account={getAccountByPerson($personAccountByIdStore, persons[0])?._id}
/>
{/if} {/if}
{#if persons.length > 1 && size === 'medium'} {#if persons.length > 1 && size === 'medium'}

View File

@ -31,8 +31,7 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import { getAvatarProviderId, getFirstName, getLastName } from '@hcengineering/contact' import { Employee, getAvatarProviderId, getFirstName, getLastName, Person } from '@hcengineering/contact'
import { Account } from '@hcengineering/core'
import { Asset, getMetadata, getResource } from '@hcengineering/platform' import { Asset, getMetadata, getResource } from '@hcengineering/platform'
import { getBlobURL, reduceCalls } from '@hcengineering/presentation' import { getBlobURL, reduceCalls } from '@hcengineering/presentation'
import { import {
@ -45,10 +44,11 @@
themeStore themeStore
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { loadUsersStatus, statusByUserStore } from '../utils'
import { loadUsersStatus, employeeByIdStore, personAccountByPersonId, statusByUserStore } from '../utils'
import AvatarInstance from './AvatarInstance.svelte' import AvatarInstance from './AvatarInstance.svelte'
export let person: Data<WithLookup<AvatarInfo>> | undefined = undefined export let person: (Data<WithLookup<AvatarInfo>> & { _id?: Ref<Person> }) | undefined = undefined
export let name: string | null | undefined = undefined export let name: string | null | undefined = undefined
export let direct: Blob | undefined = undefined export let direct: Blob | undefined = undefined
export let size: IconSize export let size: IconSize
@ -56,7 +56,6 @@
export let variant: 'circle' | 'roundedRect' | 'none' = 'roundedRect' export let variant: 'circle' | 'roundedRect' | 'none' = 'roundedRect'
export let borderColor: number | undefined = undefined export let borderColor: number | undefined = undefined
export let showStatus: boolean = true export let showStatus: boolean = true
export let account: Ref<Account> | undefined = undefined
export function pulse (): void { export function pulse (): void {
avatarInst.pulse() avatarInst.pulse()
@ -126,10 +125,14 @@
loadUsersStatus() loadUsersStatus()
}) })
$: userStatus = account !== undefined ? $statusByUserStore.get(account) : undefined let employee: Employee | undefined = undefined
$: employee = person?._id && showStatus ? $employeeByIdStore.get(person._id as Ref<Employee>) : undefined
$: accounts = employee?.active ? $personAccountByPersonId.get(employee._id) ?? [] : []
$: isOnline = accounts.some((account) => $statusByUserStore.get(account._id)?.online === true)
</script> </script>
{#if showStatus && account} {#if showStatus && accounts.length > 0}
<div class="relative"> <div class="relative">
<AvatarInstance <AvatarInstance
bind:this={avatarInst} bind:this={avatarInst}
@ -144,7 +147,7 @@
bind:element bind:element
withStatus withStatus
/> />
<div class="hulyAvatar-statusMarker {size}" class:online={userStatus?.online} class:offline={!userStatus?.online} /> <div class="hulyAvatar-statusMarker {size}" class:online={isOnline} class:offline={!isOnline} />
</div> </div>
{:else} {:else}
<AvatarInstance <AvatarInstance

View File

@ -15,10 +15,11 @@
<script lang="ts"> <script lang="ts">
import contact, { type Contact, type Employee } from '@hcengineering/contact' import contact, { type Contact, type Employee } from '@hcengineering/contact'
import core, { Account, type Ref, type WithLookup } from '@hcengineering/core' import { type Ref, type WithLookup } from '@hcengineering/core'
import { Asset } from '@hcengineering/platform' import { Asset } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { AnySvelteComponent, IconSize } from '@hcengineering/ui' import { AnySvelteComponent, IconSize } from '@hcengineering/ui'
import { employeeByIdStore, personByIdStore } from '../utils' import { employeeByIdStore, personByIdStore } from '../utils'
import Avatar from './Avatar.svelte' import Avatar from './Avatar.svelte'
@ -30,7 +31,6 @@
export let variant: 'circle' | 'roundedRect' | 'none' = 'roundedRect' export let variant: 'circle' | 'roundedRect' | 'none' = 'roundedRect'
export let borderColor: number | undefined = undefined export let borderColor: number | undefined = undefined
export let showStatus: boolean = true export let showStatus: boolean = true
export let account: Ref<Account> | undefined = undefined
$: empValue = $employeeByIdStore.get(_id as Ref<Employee>) ?? $personByIdStore.get(_id) $: empValue = $employeeByIdStore.get(_id as Ref<Employee>) ?? $personByIdStore.get(_id)
@ -47,4 +47,4 @@
} }
</script> </script>
<Avatar person={_contact} {name} {size} {icon} {variant} {borderColor} {showStatus} {account} /> <Avatar person={_contact} {name} {size} {icon} {variant} {borderColor} {showStatus} />

View File

@ -13,14 +13,12 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import contact, { Employee, Person } from '@hcengineering/contact' import { Employee, Person } from '@hcengineering/contact'
import { IconSize, LabelAndProps, tooltip } from '@hcengineering/ui' import { IconSize, LabelAndProps, tooltip } from '@hcengineering/ui'
import { DocNavLink, ObjectMention } from '@hcengineering/view-resources' import { DocNavLink, ObjectMention } from '@hcengineering/view-resources'
import { ObjectPresenterType } from '@hcengineering/view' import { ObjectPresenterType } from '@hcengineering/view'
import Avatar from './Avatar.svelte' import Avatar from './Avatar.svelte'
import { personAccountByIdStore } from '../utils'
import { getClient } from '@hcengineering/presentation'
export let value: Person | Employee | undefined | null export let value: Person | Employee | undefined | null
export let name: string export let name: string
@ -39,12 +37,6 @@
export let type: ObjectPresenterType = 'link' export let type: ObjectPresenterType = 'link'
export let showStatus = true export let showStatus = true
export let overflowLabel = true export let overflowLabel = true
const client = getClient()
const hierarchy = client.getHierarchy()
$: showStatus = showStatus && !!value && hierarchy.hasMixin(value, contact.mixin.Employee)
$: account = value && Array.from($personAccountByIdStore.values()).find((account) => account.person === value?._id)
</script> </script>
{#if value} {#if value}
@ -64,7 +56,7 @@
class:mr-2={shouldShowName && !enlargedText} class:mr-2={shouldShowName && !enlargedText}
class:mr-3={shouldShowName && enlargedText} class:mr-3={shouldShowName && enlargedText}
> >
<Avatar size={avatarSize} person={value} name={value.name} {showStatus} account={account?._id} /> <Avatar size={avatarSize} person={value} name={value.name} {showStatus} />
</span> </span>
{/if} {/if}
{#if shouldShowName} {#if shouldShowName}

View File

@ -15,37 +15,23 @@
<script lang="ts"> <script lang="ts">
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { IconSize } from '@hcengineering/ui' import { IconSize } from '@hcengineering/ui'
import { Person, getName, PersonAccount } from '@hcengineering/contact' import { Person, getName } from '@hcengineering/contact'
import { Account, IdMap } from '@hcengineering/core'
import Avatar from './Avatar.svelte' import Avatar from './Avatar.svelte'
import { personAccountByIdStore } from '../utils'
export let person: Person export let person: Person
export let avatarSize: IconSize = 'x-small' export let avatarSize: IconSize = 'x-small'
export let showStatus = true export let showStatus = true
const client = getClient() const client = getClient()
const hierarchy = client.getHierarchy()
function getAccountByPerson (accountById: IdMap<PersonAccount>, person: Person): Account | undefined {
return Array.from(accountById.values()).find((account) => account.person === person._id)
}
</script> </script>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="flex-row-center" on:click> <div class="flex-row-center" on:click>
<Avatar <Avatar {person} size={avatarSize} name={person.name} on:accent-color {showStatus} />
{person}
size={avatarSize}
name={person.name}
on:accent-color
{showStatus}
account={getAccountByPerson($personAccountByIdStore, person)?._id}
/>
<div class="flex-col min-w-0 {avatarSize === 'tiny' || avatarSize === 'inline' ? 'ml-1' : 'ml-3'}"> <div class="flex-col min-w-0 {avatarSize === 'tiny' || avatarSize === 'inline' ? 'ml-1' : 'ml-3'}">
<div class="label overflow-label text-left">{getName(hierarchy, person)}</div> <div class="label overflow-label text-left">{getName(client.getHierarchy(), person)}</div>
</div> </div>
</div> </div>

View File

@ -15,11 +15,10 @@
<script lang="ts"> <script lang="ts">
import Avatar from './Avatar.svelte' import Avatar from './Avatar.svelte'
import contact, { getName, Person } from '@hcengineering/contact' import { getName, Person } from '@hcengineering/contact'
import { Asset } from '@hcengineering/platform' import { Asset } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { AnySvelteComponent, IconSize } from '@hcengineering/ui' import { AnySvelteComponent, IconSize } from '@hcengineering/ui'
import { personAccountByIdStore } from '../utils'
export let value: Person export let value: Person
export let subtitle: string | undefined = undefined export let subtitle: string | undefined = undefined
@ -29,16 +28,12 @@
export let showStatus = true export let showStatus = true
const client = getClient() const client = getClient()
const hierarchy = client.getHierarchy()
$: showStatus = showStatus && !!value && hierarchy.hasMixin(value, contact.mixin.Employee)
$: account = value && Array.from($personAccountByIdStore.values()).find((account) => account.person === value?._id)
</script> </script>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="flex-row-center" on:click> <div class="flex-row-center" on:click>
<Avatar person={value} {size} {icon} name={value.name} on:accent-color {showStatus} account={account?._id} /> <Avatar person={value} {size} {icon} name={value.name} on:accent-color {showStatus} />
<div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}" class:max-w-20={short}> <div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}" class:max-w-20={short}>
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if} {#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
<div class="label text-left overflow-label">{getName(client.getHierarchy(), value)}</div> <div class="label text-left overflow-label">{getName(client.getHierarchy(), value)}</div>

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
// //
import { Analytics } from '@hcengineering/analytics'
import core, { import core, {
BaseWorkspaceInfo, BaseWorkspaceInfo,
DOMAIN_TX, DOMAIN_TX,
@ -81,7 +82,7 @@ class BackupWorker {
`**************************************** `****************************************
backup statistics:`, backup statistics:`,
{ {
backuped: stats.processed, processed: stats.processed,
notChanges: stats.skipped, notChanges: stats.skipped,
failed: stats.failedWorkspaces.length failed: stats.failedWorkspaces.length
} }
@ -91,15 +92,23 @@ class BackupWorker {
async schedule (ctx: MeasureContext): Promise<void> { async schedule (ctx: MeasureContext): Promise<void> {
console.log('schedule backup with interval', this.config.Interval, 'seconds') console.log('schedule backup with interval', this.config.Interval, 'seconds')
while (!this.canceled) { while (!this.canceled) {
const res = await this.backup(ctx) try {
this.printStats(ctx, res) const res = await this.backup(ctx, this.config.CoolDown * 1000)
this.printStats(ctx, res)
} catch (err: any) {
Analytics.handleError(err)
ctx.error('error retry in cool down/5', { cooldown: this.config.CoolDown, error: err })
await new Promise<void>((resolve) => setTimeout(resolve, (this.config.CoolDown / 5) * 1000))
continue
}
console.log('cool down', this.config.CoolDown, 'seconds') console.log('cool down', this.config.CoolDown, 'seconds')
await new Promise<void>((resolve) => setTimeout(resolve, this.config.CoolDown * 1000)) await new Promise<void>((resolve) => setTimeout(resolve, this.config.CoolDown * 1000))
} }
} }
async backup ( async backup (
ctx: MeasureContext ctx: MeasureContext,
recheckTimeout: number
): Promise<{ failedWorkspaces: BaseWorkspaceInfo[], processed: number, skipped: number }> { ): Promise<{ failedWorkspaces: BaseWorkspaceInfo[], processed: number, skipped: number }> {
const workspacesIgnore = new Set(this.config.SkipWorkspaces.split(';')) const workspacesIgnore = new Set(this.config.SkipWorkspaces.split(';'))
ctx.info('skipped workspaces', { workspacesIgnore }) ctx.info('skipped workspaces', { workspacesIgnore })
@ -135,19 +144,21 @@ class BackupWorker {
workspaces: workspaces.map((it) => it.workspace) workspaces: workspaces.map((it) => it.workspace)
}) })
return await this.doBackup(ctx, workspaces) return await this.doBackup(ctx, workspaces, recheckTimeout)
} }
async doBackup ( async doBackup (
rootCtx: MeasureContext, rootCtx: MeasureContext,
workspaces: BaseWorkspaceInfo[] workspaces: BaseWorkspaceInfo[],
recheckTimeout: number
): Promise<{ failedWorkspaces: BaseWorkspaceInfo[], processed: number, skipped: number }> { ): Promise<{ failedWorkspaces: BaseWorkspaceInfo[], processed: number, skipped: number }> {
let index = 0 let index = 0
const failedWorkspaces: BaseWorkspaceInfo[] = [] const failedWorkspaces: BaseWorkspaceInfo[] = []
let processed = 0 let processed = 0
const startTime = Date.now()
for (const ws of workspaces) { for (const ws of workspaces) {
if (this.canceled) { if (this.canceled || Date.now() - startTime > recheckTimeout) {
return { failedWorkspaces, processed, skipped: workspaces.length - processed } return { failedWorkspaces, processed, skipped: workspaces.length - processed }
} }
index++ index++

View File

@ -30,10 +30,12 @@ import core, {
type StorageIterator, type StorageIterator,
toFindResult, toFindResult,
type Tx, type Tx,
type TxCUD,
TxProcessor,
type TxResult, type TxResult,
type WorkspaceId type WorkspaceId
} from '@hcengineering/core' } from '@hcengineering/core'
import { type DbAdapterHandler, type DbAdapter, type DomainHelperOperations } from './adapter' import { type DbAdapter, type DbAdapterHandler, type DomainHelperOperations } from './adapter'
/** /**
* @public * @public
@ -119,7 +121,7 @@ export class DummyDbAdapter implements DbAdapter {
class InMemoryAdapter extends DummyDbAdapter implements DbAdapter { class InMemoryAdapter extends DummyDbAdapter implements DbAdapter {
private readonly modeldb: ModelDb private readonly modeldb: ModelDb
constructor (hierarchy: Hierarchy) { constructor (readonly hierarchy: Hierarchy) {
super() super()
this.modeldb = new ModelDb(hierarchy) this.modeldb = new ModelDb(hierarchy)
} }
@ -138,7 +140,23 @@ class InMemoryAdapter extends DummyDbAdapter implements DbAdapter {
} }
async tx (ctx: MeasureContext, ...tx: Tx[]): Promise<TxResult[]> { async tx (ctx: MeasureContext, ...tx: Tx[]): Promise<TxResult[]> {
return await this.modeldb.tx(...tx) // Filter transactions with broadcast only flags
const ftx = tx.filter((it) => {
if (TxProcessor.isExtendsCUD(it._class)) {
const cud = it as TxCUD<Doc>
const objClass = this.hierarchy.getClass(cud.objectClass)
const mix = this.hierarchy.hasMixin(objClass, core.mixin.TransientConfiguration)
if (mix && this.hierarchy.as(objClass, core.mixin.TransientConfiguration).broadcastOnly) {
// We do not need to store a broadcast only transactions into model.
return false
}
}
return true
})
if (ftx.length === 0) {
return []
}
return await this.modeldb.tx(...ftx)
} }
} }