Fix team planning event disappear (#5581)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2024-05-11 19:41:00 +05:00 committed by GitHub
parent 7d7e1ef412
commit 75474a6311
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 161 additions and 157 deletions

View File

@ -34,7 +34,6 @@
"@hcengineering/view": "^0.6.9",
"@hcengineering/model-attachment": "^0.6.0",
"@hcengineering/setting": "^0.6.11",
"@hcengineering/model-task": "^0.6.0",
"@hcengineering/calendar": "^0.6.17",
"@hcengineering/calendar-resources": "^0.6.0",
"@hcengineering/platform": "^0.6.9",

View File

@ -25,10 +25,17 @@ import {
type Visibility
} from '@hcengineering/calendar'
import { type Contact } from '@hcengineering/contact'
import { DateRangeMode, type Domain, IndexKind, type Markup, type Ref, type Timestamp } from '@hcengineering/core'
import {
DateRangeMode,
IndexKind,
type SystemSpace,
type Domain,
type Markup,
type Ref,
type Timestamp
} from '@hcengineering/core'
import {
ArrOf,
type Builder,
Collection,
Index,
Mixin,
@ -41,12 +48,12 @@ import {
TypeRef,
TypeString,
TypeTimestamp,
UX
UX,
type Builder
} from '@hcengineering/model'
import attachment from '@hcengineering/model-attachment'
import contact from '@hcengineering/model-contact'
import core, { TAttachedDoc, TClass } from '@hcengineering/model-core'
import { TProject } from '@hcengineering/model-task'
import core, { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core'
import view, { createAction } from '@hcengineering/model-view'
import notification from '@hcengineering/notification'
import setting from '@hcengineering/setting'
@ -59,9 +66,11 @@ export { calendarOperation } from './migration'
export const DOMAIN_CALENDAR = 'calendar' as Domain
@Model(calendar.class.Calendar, core.class.Space)
@Model(calendar.class.Calendar, core.class.Doc, DOMAIN_CALENDAR)
@UX(calendar.string.Calendar, calendar.icon.Calendar)
export class TCalendar extends TProject implements Calendar {
export class TCalendar extends TDoc implements Calendar {
name!: string
hidden!: boolean
visibility!: Visibility
}
@ -76,7 +85,10 @@ export class TExternalCalendar extends TCalendar implements ExternalCalendar {
@Model(calendar.class.Event, core.class.AttachedDoc, DOMAIN_CALENDAR)
@UX(calendar.string.Event, calendar.icon.Calendar)
export class TEvent extends TAttachedDoc implements Event {
declare space: Ref<Calendar>
declare space: Ref<SystemSpace>
@Prop(TypeRef(calendar.class.Calendar), calendar.string.Calendar)
calendar!: Ref<Calendar>
eventId!: string

View File

@ -13,10 +13,10 @@
// limitations under the License.
//
import { calendarId, type Calendar, type Event, type ReccuringEvent } from '@hcengineering/calendar'
import contact from '@hcengineering/contact'
import core, { TxOperations, type Ref } from '@hcengineering/core'
import { calendarId, type Event, type ReccuringEvent } from '@hcengineering/calendar'
import { type Ref, type Space } from '@hcengineering/core'
import {
createDefaultSpace,
tryMigrate,
tryUpgrade,
type MigrateOperation,
@ -24,68 +24,47 @@ import {
type MigrationUpgradeClient
} from '@hcengineering/model'
import { DOMAIN_SPACE } from '@hcengineering/model-core'
import { DOMAIN_SETTING } from '@hcengineering/model-setting'
import { type Integration } from '@hcengineering/setting'
import { DOMAIN_CALENDAR } from '.'
import calendar from './plugin'
async function migrateCalendars (tx: TxOperations): Promise<void> {
const existCalendars = new Set((await tx.findAll(calendar.class.Calendar, {})).map((p) => p._id))
const users = await tx.findAll(contact.class.PersonAccount, {})
for (const user of users) {
if (!existCalendars.has(`${user._id}_calendar` as Ref<Calendar>)) {
await tx.createDoc(
calendar.class.Calendar,
core.space.Space,
{
name: user.email,
description: '',
archived: false,
private: false,
members: [user._id],
visibility: 'public'
},
`${user._id}_calendar` as Ref<Calendar>,
undefined,
user._id
)
}
}
const events = await tx.findAll(calendar.class.Event, { space: calendar.space.PersonalEvents })
for (const event of events) {
await tx.update(event, { space: (event.createdBy ?? event.modifiedBy) as string as Ref<Calendar> })
}
const space = await tx.findOne(calendar.class.Calendar, { _id: calendar.space.PersonalEvents })
if (space !== undefined) {
await tx.remove(space)
}
async function migrateCalendars (client: MigrationClient): Promise<void> {
await client.move(
DOMAIN_SPACE,
{ _class: { $in: [calendar.class.Calendar, calendar.class.ExternalCalendar] } },
DOMAIN_CALENDAR
)
await client.update(
DOMAIN_CALENDAR,
{ _class: { $in: [calendar.class.Calendar, calendar.class.ExternalCalendar] } },
{ space: calendar.space.Calendar }
)
await client.update(
DOMAIN_CALENDAR,
{ _class: { $in: [calendar.class.Calendar, calendar.class.ExternalCalendar] }, archived: true },
{ hidden: true }
)
await client.update(
DOMAIN_CALENDAR,
{ _class: { $in: [calendar.class.Calendar, calendar.class.ExternalCalendar] }, archived: false },
{ hidden: false }
)
await client.update(
DOMAIN_CALENDAR,
{ _class: { $in: [calendar.class.Calendar, calendar.class.ExternalCalendar] } },
{ $unset: { type: true, private: true, members: true, archived: true } }
)
const calendars = await tx.findAll(calendar.class.Calendar, { visibility: { $exists: false } })
for (const calendar of calendars) {
await tx.update(calendar, { visibility: 'public' })
}
}
async function migrateExternalCalendars (client: MigrationClient): Promise<void> {
const calendars = await client.find<Calendar>(DOMAIN_SPACE, { _class: calendar.class.Calendar })
const integrations = await client.find<Integration>(DOMAIN_SETTING, {
type: calendar.integrationType.Calendar,
disabled: false,
value: { $ne: '' }
const events = await client.find<Event>(DOMAIN_CALENDAR, {
space: { $ne: calendar.space.Calendar }
})
for (const val of calendars) {
if (val._id.endsWith('_calendar')) continue
const integration = integrations.find((i) => i.createdBy === val.createdBy)
await client.update(
DOMAIN_SPACE,
{ _id: val._id },
{
_class: calendar.class.ExternalCalendar,
externalId: val._id,
externalUser: integration?.value ?? '',
default: val._id === integration?.value
}
)
const eventByCalendar = new Map<Ref<Space>, Ref<Event>[]>()
for (const event of events) {
const events = eventByCalendar.get(event.space) ?? []
events.push(event._id)
eventByCalendar.set(event.space, events)
}
for (const [_calendar, ids] of eventByCalendar) {
await client.update(DOMAIN_CALENDAR, { _id: { $in: ids } }, { space: calendar.space.Calendar, calendar: _calendar })
}
}
@ -148,23 +127,23 @@ export const calendarOperation: MigrateOperation = {
await migrateReminders(client)
await fillOriginalStartTime(client)
await migrateSync(client)
await migrateExternalCalendars(client)
}
},
{
state: 'timezone',
func: migrateTimezone
},
{
state: 'migrate_calendars',
func: migrateCalendars
}
])
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
await tryUpgrade(client, calendarId, [
{
state: 'u-calendar0002',
func: async (client) => {
const tx = new TxOperations(client, core.account.System)
await migrateCalendars(tx)
}
state: 'default-space',
func: () => createDefaultSpace(client, calendar.space.Calendar, { name: 'Space for all events and calendars' })
}
])
}

View File

@ -16,7 +16,7 @@
let calendars: ExternalCalendar[] = []
const me = getCurrentAccount()
const q = createQuery()
q.query(calendarPlugin.class.ExternalCalendar, { members: me._id, archived: false }, (res) => {
q.query(calendarPlugin.class.ExternalCalendar, { members: me._id, hidden: false }, (res) => {
calendars = res
})

View File

@ -118,7 +118,7 @@
let calendars: Calendar[] = []
calendarsQuery.query(calendar.class.Calendar, { members: me._id }, (res) => {
calendarsQuery.query(calendar.class.Calendar, { createdBy: me._id, hidden: false }, (res) => {
calendars = res
})
@ -132,7 +132,7 @@
): void {
q.query<Event>(
_class,
query ?? { space: { $in: calendars.map((p) => p._id) } },
query ?? { calendar: { $in: calendars.map((p) => p._id) } },
(result) => {
raw = result
},
@ -257,11 +257,12 @@
attachedToClass: dragItem._class,
_class: dragEventClass,
collection: 'events',
space: `${me._id}_calendar` as Ref<Calendar>,
calendar: `${me._id}_calendar` as Ref<Calendar>,
modifiedBy: me._id,
participants: [me.person],
modifiedOn: Date.now(),
date: e.detail.date.getTime(),
space: calendar.space.Calendar,
dueDate: new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
}
raw.push(temp)

View File

@ -65,12 +65,12 @@
let description: Markup = EmptyMarkup
let visibility: Visibility = 'private'
const me = getCurrentAccount()
let space: Ref<Calendar> = `${me._id}_calendar` as Ref<Calendar>
let _calendar: Ref<Calendar> = `${me._id}_calendar` as Ref<Calendar>
const q = createQuery()
q.query(calendar.class.ExternalCalendar, { default: true, members: me._id, archived: false }, (res) => {
q.query(calendar.class.ExternalCalendar, { default: true, members: me._id, hidden: false }, (res) => {
if (res.length > 0) {
space = res[0]._id
_calendar = res[0]._id
}
})
@ -93,27 +93,36 @@
if (date === undefined) return
if (title === '') return
if (rules.length > 0) {
await client.addCollection(calendar.class.ReccuringEvent, space, attachedTo, attachedToClass, 'events', {
eventId: generateEventId(),
date: allDay ? saveUTC(date) : date,
dueDate: allDay ? saveUTC(dueDate) : dueDate,
externalParticipants,
rdate: [],
exdate: [],
rules,
reminders,
description,
participants,
visibility,
title,
location,
allDay,
access: 'owner',
originalStartTime: allDay ? saveUTC(date) : date,
timeZone
})
await client.addCollection(
calendar.class.ReccuringEvent,
calendar.space.Calendar,
attachedTo,
attachedToClass,
'events',
{
calendar: _calendar,
eventId: generateEventId(),
date: allDay ? saveUTC(date) : date,
dueDate: allDay ? saveUTC(dueDate) : dueDate,
externalParticipants,
rdate: [],
exdate: [],
rules,
reminders,
description,
participants,
visibility,
title,
location,
allDay,
access: 'owner',
originalStartTime: allDay ? saveUTC(date) : date,
timeZone
}
)
} else {
await client.addCollection(calendar.class.Event, space, attachedTo, attachedToClass, 'events', {
await client.addCollection(calendar.class.Event, calendar.space.Calendar, attachedTo, attachedToClass, 'events', {
calendar: _calendar,
eventId: generateEventId(),
date: allDay ? saveUTC(date) : date,
dueDate: allDay ? saveUTC(dueDate) : dueDate,
@ -210,7 +219,7 @@
/>
</div>
<div class="block rightCropPadding">
<CalendarSelector bind:value={space} focusIndex={10101} />
<CalendarSelector bind:value={_calendar} focusIndex={10101} />
<div class="flex-row-center flex-gap-1">
<Icon icon={calendar.icon.Hidden} size={'small'} />
<VisibilityEditor bind:value={visibility} kind={'tertiary'} focusIndex={10102} withoutIcon />

View File

@ -44,8 +44,9 @@
let date: number | undefined
if (value != null) date = value
if (date === undefined) return
const space = `${getCurrentAccount()._id}_calendar` as Ref<Calendar>
await client.addCollection(calendar.class.Event, space, attachedTo, attachedToClass, 'events', {
const _calendar = `${getCurrentAccount()._id}_calendar` as Ref<Calendar>
await client.addCollection(calendar.class.Event, calendar.space.Calendar, attachedTo, attachedToClass, 'events', {
calendar: _calendar,
eventId: generateEventId(),
date,
dueDate: date + defaultDuration,

View File

@ -56,7 +56,7 @@
let allDay = object.allDay
let visibility = object.visibility ?? 'public'
let reminders = [...(object.reminders ?? [])]
let space = object.space
let _calendar = object.calendar
let timeZone: string = object.timeZone ?? getUserTimezone()
let description = object.description
@ -88,8 +88,8 @@
if (object.visibility !== visibility) {
update.visibility = visibility
}
if (object.space !== space) {
update.space = space
if (object.calendar !== _calendar) {
update.calendar = _calendar
}
if (object.location !== location) {
update.location = location
@ -216,7 +216,7 @@
</div>
<div class="divider" />
<div class="block rightCropPadding">
<CalendarSelector bind:value={space} focusIndex={10008} />
<CalendarSelector bind:value={_calendar} focusIndex={10008} />
<div class="flex-row-center flex-gap-1">
<Icon icon={calendar.icon.Hidden} size={'small'} />
<VisibilityEditor bind:value={visibility} kind={'tertiary'} withoutIcon focusIndex={10009} />

View File

@ -40,7 +40,7 @@
async function update (calendar: Calendar, value: boolean) {
await client.update(calendar, {
archived: !value
hidden: !value
})
}
@ -69,7 +69,7 @@
{#each calendars as calendar}
<div>{calendar.name}</div>
<div>
<Toggle on={!calendar.archived} on:change={(res) => update(calendar, res.detail)} />
<Toggle on={!calendar.hidden} on:change={(res) => update(calendar, res.detail)} />
</div>
{/each}
</Grid>

View File

@ -90,6 +90,7 @@ async function deleteRecHandler (res: any, object: ReccuringInstance): Promise<v
description: object.description,
date: object.date,
dueDate: object.dueDate,
calendar: object.calendar,
allDay: object.allDay,
participants: object.participants,
externalParticipants: object.externalParticipants,

View File

@ -37,8 +37,8 @@ export function hidePrivateEvents (events: Event[], calendars: IdMap<Calendar>,
res.push(event)
}
} else {
const space = calendars.get(event.space)
if (space != null && space.visibility !== 'private') {
const calendar = calendars.get(event.calendar)
if (calendar != null && calendar.visibility !== 'private') {
res.push(event)
}
}
@ -62,11 +62,11 @@ export function isVisible (value: Event, calendars: IdMap<Calendar>): boolean {
} else if (value.visibility === 'public') {
return true
}
const space = calendars.get(value.space)
if (space == null) {
const calendar = calendars.get(value.calendar)
if (calendar == null) {
return true
} else {
return space.visibility === 'public'
return calendar.visibility === 'public'
}
}
@ -93,7 +93,7 @@ export async function updatePast (ops: DocumentUpdate<Event>, object: ReccuringI
const client = getClient()
const origin = await client.findOne(calendar.class.ReccuringEvent, {
eventId: object.recurringEventId,
space: object.space
calendar: object.calendar
})
if (origin !== undefined) {
await client.addCollection(
@ -158,6 +158,7 @@ export async function updateReccuringInstance (
reminders: object.reminders,
location: object.location,
eventId: object.eventId,
calendar: object.calendar,
access: 'owner',
rules: object.rules,
exdate: object.exdate,
@ -170,7 +171,7 @@ export async function updateReccuringInstance (
resolve(true)
} else if (res.mode === 'all') {
const base = await client.findOne(calendar.class.ReccuringEvent, {
space: object.space,
calendar: object.calendar,
eventId: object.recurringEventId
})
if (base !== undefined) {

View File

@ -12,7 +12,7 @@
// limitations under the License.
import { Contact } from '@hcengineering/contact'
import type { AttachedDoc, Class, Doc, Markup, Mixin, Ref, Space, Timestamp } from '@hcengineering/core'
import type { AttachedDoc, Class, Doc, Markup, Mixin, Ref, SystemSpace, Timestamp } from '@hcengineering/core'
import { NotificationType } from '@hcengineering/notification'
import type { Asset, IntlString, Metadata, Plugin } from '@hcengineering/platform'
import { plugin } from '@hcengineering/platform'
@ -27,7 +27,9 @@ export type Visibility = 'public' | 'freeBusy' | 'private'
/**
* @public
*/
export interface Calendar extends Space {
export interface Calendar extends Doc {
name: string
hidden: boolean
visibility: Visibility
}
@ -76,11 +78,13 @@ export interface ReccuringEvent extends Event {
* @public
*/
export interface Event extends AttachedDoc {
space: Ref<Calendar>
space: Ref<SystemSpace>
eventId: string
title: string
description: Markup
calendar: Ref<Calendar>
location?: string
allDay: boolean
@ -161,8 +165,7 @@ const calendarPlugin = plugin(calendarId, {
Permissions: '' as Asset
},
space: {
// deprecated
PersonalEvents: '' as Ref<Calendar>
Calendar: '' as Ref<SystemSpace>
},
app: {
Calendar: '' as Ref<Doc>

View File

@ -84,14 +84,15 @@
rank: makeRank(undefined, latestTodo?.rank)
}
)
const space = `${acc._id}_calendar` as Ref<Calendar>
const _calendar = `${acc._id}_calendar` as Ref<Calendar>
for (const slot of slots) {
await ops.addCollection(time.class.WorkSlot, space, id, time.class.ToDo, 'workslots', {
await ops.addCollection(time.class.WorkSlot, calendar.space.Calendar, id, time.class.ToDo, 'workslots', {
eventId: generateEventId(),
date: slot.date,
dueDate: slot.dueDate,
description: todo.description,
participants: [acc.person],
calendar: _calendar,
title: todo.title,
allDay: false,
access: 'owner',
@ -107,12 +108,12 @@
}
const currentUser = getCurrentAccount() as PersonAccount
let space: Ref<Calendar> = `${currentUser._id}_calendar` as Ref<Calendar>
let _calendar: Ref<Calendar> = `${currentUser._id}_calendar` as Ref<Calendar>
const q = createQuery()
q.query(calendar.class.ExternalCalendar, { default: true, members: currentUser._id }, (res) => {
if (res.length > 0) {
space = res[0]._id
_calendar = res[0]._id
}
})
@ -142,7 +143,8 @@
access: 'owner',
visibility: todo.visibility,
reminders: [],
space,
calendar: _calendar,
space: calendar.space.Calendar,
_id: generateId(),
_class: time.class.WorkSlot,
attachedTo: generateId(),

View File

@ -45,7 +45,7 @@
let description = object.description
let visibility = object.visibility ?? 'public'
let space = object.space
let _calendar = object.calendar
let _doc: ToDo | undefined
@ -84,8 +84,8 @@
if (object.visibility !== visibility) {
update.visibility = visibility
}
if (object.space !== space) {
update.space = space
if (object.calendar !== _calendar) {
update.calendar = _calendar
}
if (!deepEqual(object.reminders, reminders)) {
update.reminders = reminders
@ -137,7 +137,7 @@
<TaskSelector bind:value={_doc} focusIndex={10006} />
</div>
<div class="block rightCropPadding">
<CalendarSelector bind:value={space} disabled={readOnly} focusIndex={10007} />
<CalendarSelector bind:value={_calendar} disabled={readOnly} focusIndex={10007} />
<div class="flex-row-center flex-gap-1">
<Icon icon={calendar.icon.Hidden} size={'small'} />
<VisibilityEditor bind:value={visibility} kind={'tertiary'} withoutIcon disabled={readOnly} focusIndex={10008} />

View File

@ -53,12 +53,13 @@
const currentUser = getCurrentAccount() as PersonAccount
const extCalendar = await client.findOne(calendar.class.ExternalCalendar, {
members: currentUser._id,
archived: false,
hidden: false,
default: true
})
const space = extCalendar ? extCalendar._id : (`${currentUser._id}_calendar` as Ref<Calendar>)
const _calendar = extCalendar ? extCalendar._id : (`${currentUser._id}_calendar` as Ref<Calendar>)
const dueDate = date + defaultDuration
await client.addCollection(time.class.WorkSlot, space, doc._id, doc._class, 'workslots', {
await client.addCollection(time.class.WorkSlot, calendar.space.Calendar, doc._id, doc._class, 'workslots', {
calendar: _calendar,
eventId: generateEventId(),
date,
dueDate,

View File

@ -55,7 +55,7 @@
let calendars: Calendar[] = []
let todayDate = new Date()
$: calendarsQ.query(calendar.class.Calendar, { members: acc, archived: false }, (res) => {
$: calendarsQ.query(calendar.class.Calendar, { createdBy: acc, hidden: false }, (res) => {
calendars = res
})
@ -65,7 +65,7 @@
function update (calendars: Calendar[]): void {
q.query<Event>(
calendar.class.Event,
{ space: { $in: calendars.map((p) => p._id) } },
{ calendar: { $in: calendars.map((p) => p._id) } },
(result) => {
raw = result
},
@ -115,7 +115,7 @@
current.dueDate = new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
} else {
const me = getCurrentAccount() as PersonAccount
const space = `${me._id}_calendar` as Ref<Calendar>
const _calendar = `${me._id}_calendar` as Ref<Calendar>
const ev: WorkSlot = {
_id: dragItemId,
allDay: false,
@ -128,7 +128,8 @@
_class: time.class.WorkSlot,
collection: 'events',
visibility: 'public',
space,
calendar: _calendar,
space: calendar.space.Calendar,
modifiedBy: me._id,
participants: [me.person],
modifiedOn: Date.now(),

View File

@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { Calendar, generateEventId } from '@hcengineering/calendar'
import calendar, { Calendar, generateEventId } from '@hcengineering/calendar'
import contact, { PersonAccount } from '@hcengineering/contact'
import { Ref, getCurrentAccount } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
@ -55,12 +55,13 @@
const now = Date.now()
const date = Math.ceil(now / (30 * 60 * 1000)) * (30 * 60 * 1000)
const currentUser = getCurrentAccount() as PersonAccount
const space = `${currentUser._id}_calendar` as Ref<Calendar>
const _calendar = `${currentUser._id}_calendar` as Ref<Calendar>
const dueDate = date + defaultDuration
await client.addCollection(time.class.WorkSlot, space, todo._id, todo._class, 'workslots', {
await client.addCollection(time.class.WorkSlot, calendar.space.Calendar, todo._id, todo._class, 'workslots', {
eventId: generateEventId(),
date,
dueDate,
calendar: _calendar,
description: todo.description,
participants: [currentUser.person],
title: todo.title,

View File

@ -60,7 +60,7 @@
calendar.class.Event,
{
_class: { $nin: [calendar.class.ReccuringEvent] },
space: { $in: calendarIds },
calendar: { $in: calendarIds },
date: { $lte: toDate },
dueDate: { $gte: fromDate },
participants: { $in: persons } as any
@ -72,7 +72,7 @@
$: queryR.query(
calendar.class.ReccuringEvent,
{ space: { $in: calendarIds }, participants: { $in: persons } as any },
{ calendar: { $in: calendarIds }, participants: { $in: persons } as any },
(res) => {
rawReq = res
}
@ -98,7 +98,7 @@
)
const calendarQuery = createQuery()
$: calendarQuery.query(calendar.class.Calendar, { archived: false }, (res) => {
$: calendarQuery.query(calendar.class.Calendar, { hidden: false }, (res) => {
calendarIds = res.map((p) => p._id)
calendars = toIdMap(res)
})

View File

@ -91,15 +91,11 @@ export function groupTeamData (
}
for (const event of events) {
const space = calendars.get(event.space)
if (space === undefined) {
const _calendar = calendars.get(event.calendar)
if (_calendar === undefined) {
continue
}
for (const p of event.participants) {
const accounts = personAccounts.filter((it) => it.person === p)
if (!accounts.some((it) => space.members.includes(it._id))) {
continue
}
const mapping: EventPersonMapping = result.get(p) ?? {
busy: {
slots: [],

View File

@ -15,7 +15,7 @@
import calendar, { Calendar, Event } from '@hcengineering/calendar'
import { PersonAccount } from '@hcengineering/contact'
import core, {
import {
Class,
Doc,
DocumentQuery,
@ -85,13 +85,10 @@ export async function OnPersonAccountCreate (tx: Tx, control: TriggerControl): P
const res: TxCreateDoc<Calendar> = control.txFactory.createTxCreateDoc(
calendar.class.Calendar,
core.space.Space,
calendar.space.Calendar,
{
name: user.email,
description: '',
archived: false,
private: false,
members: [user._id],
hidden: false,
visibility: 'public'
},
`${user._id}_calendar` as Ref<Calendar>,