diff --git a/models/calendar/package.json b/models/calendar/package.json index efeb97a6df..54b324efe5 100644 --- a/models/calendar/package.json +++ b/models/calendar/package.json @@ -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", diff --git a/models/calendar/src/index.ts b/models/calendar/src/index.ts index d0c620a02d..ea8735dcbd 100644 --- a/models/calendar/src/index.ts +++ b/models/calendar/src/index.ts @@ -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 + declare space: Ref + + @Prop(TypeRef(calendar.class.Calendar), calendar.string.Calendar) + calendar!: Ref eventId!: string diff --git a/models/calendar/src/migration.ts b/models/calendar/src/migration.ts index eca6bb9862..e00cde0a33 100644 --- a/models/calendar/src/migration.ts +++ b/models/calendar/src/migration.ts @@ -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 { - 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)) { - 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, - 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 }) - } - 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 { + 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 { - const calendars = await client.find(DOMAIN_SPACE, { _class: calendar.class.Calendar }) - const integrations = await client.find(DOMAIN_SETTING, { - type: calendar.integrationType.Calendar, - disabled: false, - value: { $ne: '' } + const events = await client.find(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[]>() + 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 { 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' }) } ]) } diff --git a/plugins/calendar-resources/src/components/CalendarSelector.svelte b/plugins/calendar-resources/src/components/CalendarSelector.svelte index e05727aa92..f3a8eafea3 100644 --- a/plugins/calendar-resources/src/components/CalendarSelector.svelte +++ b/plugins/calendar-resources/src/components/CalendarSelector.svelte @@ -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 }) diff --git a/plugins/calendar-resources/src/components/CalendarView.svelte b/plugins/calendar-resources/src/components/CalendarView.svelte index 0fd0b76ed4..fa3e52cdb7 100644 --- a/plugins/calendar-resources/src/components/CalendarView.svelte +++ b/plugins/calendar-resources/src/components/CalendarView.svelte @@ -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( _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: `${me._id}_calendar` as Ref, 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) diff --git a/plugins/calendar-resources/src/components/CreateEvent.svelte b/plugins/calendar-resources/src/components/CreateEvent.svelte index c5482740c0..e811eb49d8 100644 --- a/plugins/calendar-resources/src/components/CreateEvent.svelte +++ b/plugins/calendar-resources/src/components/CreateEvent.svelte @@ -65,12 +65,12 @@ let description: Markup = EmptyMarkup let visibility: Visibility = 'private' const me = getCurrentAccount() - let space: Ref = `${me._id}_calendar` as Ref + let _calendar: Ref = `${me._id}_calendar` as Ref 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 @@ />
- +
diff --git a/plugins/calendar-resources/src/components/CreateReminder.svelte b/plugins/calendar-resources/src/components/CreateReminder.svelte index 611bc90fbd..99fdf7e035 100644 --- a/plugins/calendar-resources/src/components/CreateReminder.svelte +++ b/plugins/calendar-resources/src/components/CreateReminder.svelte @@ -44,8 +44,9 @@ let date: number | undefined if (value != null) date = value if (date === undefined) return - const space = `${getCurrentAccount()._id}_calendar` as Ref - await client.addCollection(calendar.class.Event, space, attachedTo, attachedToClass, 'events', { + const _calendar = `${getCurrentAccount()._id}_calendar` as Ref + await client.addCollection(calendar.class.Event, calendar.space.Calendar, attachedTo, attachedToClass, 'events', { + calendar: _calendar, eventId: generateEventId(), date, dueDate: date + defaultDuration, diff --git a/plugins/calendar-resources/src/components/EditEvent.svelte b/plugins/calendar-resources/src/components/EditEvent.svelte index d5d6448904..d2bee0b77d 100644 --- a/plugins/calendar-resources/src/components/EditEvent.svelte +++ b/plugins/calendar-resources/src/components/EditEvent.svelte @@ -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 @@
- +
diff --git a/plugins/calendar-resources/src/components/IntegrationConfigure.svelte b/plugins/calendar-resources/src/components/IntegrationConfigure.svelte index 9e99f21291..314eda719b 100644 --- a/plugins/calendar-resources/src/components/IntegrationConfigure.svelte +++ b/plugins/calendar-resources/src/components/IntegrationConfigure.svelte @@ -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}
{calendar.name}
- update(calendar, res.detail)} /> + update(calendar, res.detail)} />
{/each} diff --git a/plugins/calendar-resources/src/index.ts b/plugins/calendar-resources/src/index.ts index d35bd19e25..b9c3377965 100644 --- a/plugins/calendar-resources/src/index.ts +++ b/plugins/calendar-resources/src/index.ts @@ -90,6 +90,7 @@ async function deleteRecHandler (res: any, object: ReccuringInstance): Promise, 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): 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, 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) { diff --git a/plugins/calendar/src/index.ts b/plugins/calendar/src/index.ts index de6611acfb..9fb0843751 100644 --- a/plugins/calendar/src/index.ts +++ b/plugins/calendar/src/index.ts @@ -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 + space: Ref eventId: string title: string description: Markup + calendar: Ref + location?: string allDay: boolean @@ -161,8 +165,7 @@ const calendarPlugin = plugin(calendarId, { Permissions: '' as Asset }, space: { - // deprecated - PersonalEvents: '' as Ref + Calendar: '' as Ref }, app: { Calendar: '' as Ref diff --git a/plugins/time-resources/src/components/CreateToDoPopup.svelte b/plugins/time-resources/src/components/CreateToDoPopup.svelte index 030447c179..e2acfa34a5 100644 --- a/plugins/time-resources/src/components/CreateToDoPopup.svelte +++ b/plugins/time-resources/src/components/CreateToDoPopup.svelte @@ -84,14 +84,15 @@ rank: makeRank(undefined, latestTodo?.rank) } ) - const space = `${acc._id}_calendar` as Ref + const _calendar = `${acc._id}_calendar` as Ref 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 = `${currentUser._id}_calendar` as Ref + let _calendar: Ref = `${currentUser._id}_calendar` as Ref 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(), diff --git a/plugins/time-resources/src/components/EditWorkSlot.svelte b/plugins/time-resources/src/components/EditWorkSlot.svelte index 038e084594..ece40c1ea9 100644 --- a/plugins/time-resources/src/components/EditWorkSlot.svelte +++ b/plugins/time-resources/src/components/EditWorkSlot.svelte @@ -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 @@
- +
diff --git a/plugins/time-resources/src/components/PlanView.svelte b/plugins/time-resources/src/components/PlanView.svelte index 18cba95f20..a3961fb8e8 100644 --- a/plugins/time-resources/src/components/PlanView.svelte +++ b/plugins/time-resources/src/components/PlanView.svelte @@ -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) + const _calendar = extCalendar ? extCalendar._id : (`${currentUser._id}_calendar` as Ref) 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, diff --git a/plugins/time-resources/src/components/PlanningCalendar.svelte b/plugins/time-resources/src/components/PlanningCalendar.svelte index 20bd21f1ae..9a337dcad3 100644 --- a/plugins/time-resources/src/components/PlanningCalendar.svelte +++ b/plugins/time-resources/src/components/PlanningCalendar.svelte @@ -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( 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 + const _calendar = `${me._id}_calendar` as Ref 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(), diff --git a/plugins/time-resources/src/components/TodoWorkslots.svelte b/plugins/time-resources/src/components/TodoWorkslots.svelte index d4c7322353..4f6501215c 100644 --- a/plugins/time-resources/src/components/TodoWorkslots.svelte +++ b/plugins/time-resources/src/components/TodoWorkslots.svelte @@ -13,7 +13,7 @@ // limitations under the License. -->