mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
parent
e92918c6c7
commit
30f255fa7c
@ -50,8 +50,8 @@ import view, { createAction } from '@hcengineering/model-view'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
import notification from '@hcengineering/notification'
|
||||
import setting from '@hcengineering/setting'
|
||||
import calendar from './plugin'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import calendar from './plugin'
|
||||
|
||||
export * from '@hcengineering/calendar'
|
||||
export { calendarId } from '@hcengineering/calendar'
|
||||
@ -62,13 +62,16 @@ export const DOMAIN_CALENDAR = 'calendar' as Domain
|
||||
@Model(calendar.class.Calendar, core.class.Space)
|
||||
@UX(calendar.string.Calendar, calendar.icon.Calendar)
|
||||
export class TCalendar extends TSpaceWithStates implements Calendar {
|
||||
@Prop(TypeString(), calendar.string.HideDetails)
|
||||
hideDetails?: boolean
|
||||
visibility!: 'public' | 'freeBusy' | 'private'
|
||||
|
||||
sync?: boolean
|
||||
}
|
||||
|
||||
@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>
|
||||
|
||||
eventId!: string
|
||||
|
||||
@Prop(TypeString(), calendar.string.Title)
|
||||
@ -106,6 +109,8 @@ export class TEvent extends TAttachedDoc implements Event {
|
||||
externalParticipants?: string[]
|
||||
|
||||
access!: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
|
||||
visibility?: 'public' | 'freeBusy' | 'private'
|
||||
}
|
||||
|
||||
@Model(calendar.class.ReccuringEvent, calendar.class.Event)
|
||||
@ -174,7 +179,8 @@ export function createModel (builder: Builder): void {
|
||||
icon: calendar.component.CalendarIntegrationIcon,
|
||||
createComponent: calendar.component.IntegrationConnect,
|
||||
onDisconnect: calendar.handler.DisconnectHandler,
|
||||
reconnectComponent: calendar.component.IntegrationConnect
|
||||
reconnectComponent: calendar.component.IntegrationConnect,
|
||||
configureComponent: calendar.component.IntegrationConfigure
|
||||
},
|
||||
calendar.integrationType.Calendar
|
||||
)
|
||||
|
@ -33,7 +33,8 @@ async function migrateCalendars (tx: TxOperations): Promise<void> {
|
||||
description: '',
|
||||
archived: false,
|
||||
private: false,
|
||||
members: [user._id]
|
||||
members: [user._id],
|
||||
visibility: 'public'
|
||||
},
|
||||
`${user._id}_calendar` as Ref<Calendar>,
|
||||
undefined,
|
||||
@ -49,6 +50,11 @@ async function migrateCalendars (tx: TxOperations): Promise<void> {
|
||||
if (space !== undefined) {
|
||||
await tx.remove(space)
|
||||
}
|
||||
|
||||
const calendars = await tx.findAll(calendar.class.Calendar, { visibility: { $exists: false } })
|
||||
for (const calendar of calendars) {
|
||||
await tx.update(calendar, { visibility: 'public' })
|
||||
}
|
||||
}
|
||||
|
||||
async function fixEventDueDate (client: MigrationClient): Promise<void> {
|
||||
|
@ -29,7 +29,8 @@ export default mergeIds(calendarId, calendar, {
|
||||
CreateCalendar: '' as AnyComponent,
|
||||
EventPresenter: '' as AnyComponent,
|
||||
CalendarIntegrationIcon: '' as AnyComponent,
|
||||
CalendarEventPresenter: '' as AnyComponent
|
||||
CalendarEventPresenter: '' as AnyComponent,
|
||||
IntegrationConfigure: '' as AnyComponent
|
||||
},
|
||||
action: {
|
||||
SaveEventReminder: '' as Ref<Action>,
|
||||
|
@ -73,6 +73,8 @@
|
||||
"SundayShort": "Su",
|
||||
"OnUntil": "On",
|
||||
"Times": "{count, plural, one {time} other {times}}",
|
||||
"AddParticipants": "Add participants"
|
||||
"AddParticipants": "Add participants",
|
||||
"Sync": "Synchronization",
|
||||
"Busy": "Busy"
|
||||
}
|
||||
}
|
@ -73,7 +73,8 @@
|
||||
"SundayShort": "Вс",
|
||||
"OnUntil": "До",
|
||||
"Times": "{count, plural, one {раз} few {раза} other {раз}}",
|
||||
"AddParticipants": "Добавить участников"
|
||||
|
||||
"AddParticipants": "Добавить участников",
|
||||
"Sync": "Синхронизация",
|
||||
"Busy": "Занято"
|
||||
}
|
||||
}
|
@ -14,9 +14,11 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import { addZero } from '@hcengineering/ui'
|
||||
import { Label, addZero } from '@hcengineering/ui'
|
||||
import calendar from '../plugin'
|
||||
|
||||
export let event: Event
|
||||
export let hideDetails: boolean = false
|
||||
export let oneRow: boolean = false
|
||||
export let narrow: boolean = false
|
||||
export let size: { width: number; height: number }
|
||||
@ -30,7 +32,13 @@
|
||||
</script>
|
||||
|
||||
{#if !narrow}
|
||||
<b class="overflow-label">{event.title}</b>
|
||||
{#if !hideDetails}
|
||||
<b class="overflow-label">
|
||||
{event.title}
|
||||
</b>
|
||||
{:else}
|
||||
<span class="content-dark-color"><Label label={calendar.string.Busy} /></span>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if !oneRow}
|
||||
<span class="overflow-label text-sm">{getTime(startDate)}-{getTime(endDate)}</span>
|
||||
|
@ -39,7 +39,7 @@
|
||||
getMonday,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { CalendarMode, DayCalendar } from '../index'
|
||||
import { CalendarMode, DayCalendar, calendarStore, hidePrivateEvents } from '../index'
|
||||
import calendar from '../plugin'
|
||||
import Day from './Day.svelte'
|
||||
|
||||
@ -66,6 +66,7 @@
|
||||
let selectedDate: Date = new Date()
|
||||
|
||||
let raw: Event[] = []
|
||||
let visible: Event[] = []
|
||||
let objects: Event[] = []
|
||||
|
||||
function getFrom (date: Date, mode: CalendarMode): Timestamp {
|
||||
@ -116,7 +117,7 @@
|
||||
|
||||
let calendars: Calendar[] = []
|
||||
|
||||
calendarsQuery.query(calendar.class.Calendar, { createdBy: me._id }, (res) => {
|
||||
calendarsQuery.query(calendar.class.Calendar, { members: me._id }, (res) => {
|
||||
calendars = res
|
||||
})
|
||||
|
||||
@ -138,7 +139,8 @@
|
||||
)
|
||||
}
|
||||
$: update(_class, query, calendars, options)
|
||||
$: objects = getAllEvents(raw, from, to)
|
||||
$: visible = hidePrivateEvents(raw, $calendarStore)
|
||||
$: objects = getAllEvents(visible, from, to)
|
||||
|
||||
function inRange (start: Date, end: Date, startPeriod: Date, period: 'day' | 'hour'): boolean {
|
||||
const endPeriod =
|
||||
@ -242,7 +244,7 @@
|
||||
current.dueDate = new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
|
||||
} else {
|
||||
const me = getCurrentAccount() as PersonAccount
|
||||
raw.push({
|
||||
const temp: Event = {
|
||||
_id: dragItemId,
|
||||
allDay: false,
|
||||
eventId: generateEventId(),
|
||||
@ -253,13 +255,14 @@
|
||||
attachedToClass: dragItem._class,
|
||||
_class: dragEventClass,
|
||||
collection: 'events',
|
||||
space: dragItem.space,
|
||||
space: `${me._id}_calendar` as Ref<Calendar>,
|
||||
modifiedBy: me._id,
|
||||
participants: [me.person],
|
||||
modifiedOn: Date.now(),
|
||||
date: e.detail.date.getTime(),
|
||||
dueDate: new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
|
||||
})
|
||||
}
|
||||
raw.push(temp)
|
||||
}
|
||||
raw = raw
|
||||
}
|
||||
@ -270,7 +273,8 @@
|
||||
function clear (dragItem: Doc | undefined) {
|
||||
if (dragItem === undefined) {
|
||||
raw = raw.filter((p) => p._id !== dragItemId)
|
||||
objects = getAllEvents(raw, from, to)
|
||||
visible = hidePrivateEvents(raw, $calendarStore)
|
||||
objects = getAllEvents(visible, from, to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
import { Button, CheckBox, DAY, EditBox, Icon, IconClose, Label, closePopup, showPopup } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import { saveUTC } from '../utils'
|
||||
import { isReadOnly, saveUTC } from '../utils'
|
||||
import EventParticipants from './EventParticipants.svelte'
|
||||
import EventTimeEditor from './EventTimeEditor.svelte'
|
||||
import RRulePresenter from './RRulePresenter.svelte'
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
export let object: Event
|
||||
|
||||
$: readOnly = isReadOnly(object)
|
||||
|
||||
let title = object.title
|
||||
|
||||
const defaultDuration = 60 * 60 * 1000
|
||||
@ -54,6 +56,9 @@
|
||||
}
|
||||
|
||||
async function saveEvent () {
|
||||
if (readOnly) {
|
||||
return
|
||||
}
|
||||
const update: DocumentUpdate<Event> = {}
|
||||
if (object.title !== title) {
|
||||
update.title = title.trim()
|
||||
@ -97,6 +102,9 @@
|
||||
}
|
||||
|
||||
function setRecurrance () {
|
||||
if (readOnly) {
|
||||
return
|
||||
}
|
||||
showPopup(ReccurancePopup, { rules }, undefined, (res) => {
|
||||
if (res) {
|
||||
rules = res
|
||||
@ -196,7 +204,7 @@
|
||||
<div class="container">
|
||||
<div class="header flex-between">
|
||||
{#if object.attachedTo === calendar.ids.NoAttached}
|
||||
<EditBox bind:value={title} placeholder={calendar.string.NewEvent} />
|
||||
<EditBox bind:value={title} placeholder={calendar.string.NewEvent} disabled={readOnly} />
|
||||
{:else}
|
||||
<div />
|
||||
{/if}
|
||||
@ -213,7 +221,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="time">
|
||||
<EventTimeEditor {allDay} bind:startDate bind:dueDate />
|
||||
<EventTimeEditor {allDay} bind:startDate bind:dueDate disabled={readOnly} />
|
||||
<div>
|
||||
{#if !allDay && rules.length === 0}
|
||||
<div class="flex-row-center flex-gap-3 ext">
|
||||
@ -232,7 +240,7 @@
|
||||
{:else}
|
||||
<div>
|
||||
<div class="flex-row-center flex-gap-2 mt-1">
|
||||
<CheckBox bind:checked={allDay} accented on:value={allDayChangeHandler} />
|
||||
<CheckBox bind:checked={allDay} accented on:value={allDayChangeHandler} readonly={readOnly} />
|
||||
<Label label={calendar.string.AllDay} />
|
||||
</div>
|
||||
<div class="flex-row-center flex-gap-2 mt-1">
|
||||
@ -255,24 +263,19 @@
|
||||
</div>
|
||||
<div class="divider" />
|
||||
<div>
|
||||
<EventParticipants bind:participants bind:externalParticipants />
|
||||
<EventParticipants bind:participants bind:externalParticipants disabled={readOnly} />
|
||||
</div>
|
||||
<div class="divider" />
|
||||
<div class="block">
|
||||
<div class="flex-row-center flex-gap-2">
|
||||
<Icon icon={calendar.icon.Description} size="small" />
|
||||
<EditBox bind:value={description} placeholder={calendar.string.Description} />
|
||||
<EditBox bind:value={description} placeholder={calendar.string.Description} disabled={readOnly} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider" />
|
||||
<div class="flex-between pool">
|
||||
<div />
|
||||
<Button
|
||||
kind="accented"
|
||||
label={presentation.string.Save}
|
||||
on:click={saveEvent}
|
||||
disabled={title === '' && object.attachedTo === calendar.ids.NoAttached}
|
||||
/>
|
||||
<Button kind="accented" label={presentation.string.Save} disabled={readOnly} on:click={saveEvent} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -25,9 +25,10 @@
|
||||
tooltip
|
||||
} from '@hcengineering/ui'
|
||||
import view, { ObjectEditor } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import EventPresenter from './EventPresenter.svelte'
|
||||
import { Menu } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { calendarStore, isReadOnly, isVisible } from '../utils'
|
||||
import EventPresenter from './EventPresenter.svelte'
|
||||
|
||||
export let event: Event
|
||||
export let hourHeight: number
|
||||
@ -38,9 +39,11 @@
|
||||
$: empty = size.width < 44
|
||||
|
||||
function click () {
|
||||
const editor = hierarchy.classHierarchyMixin<Doc, ObjectEditor>(event._class, view.mixin.ObjectEditor)
|
||||
if (editor?.editor !== undefined) {
|
||||
showPopup(editor.editor, { object: event })
|
||||
if (visible) {
|
||||
const editor = hierarchy.classHierarchyMixin<Doc, ObjectEditor>(event._class, view.mixin.ObjectEditor)
|
||||
if (editor?.editor !== undefined) {
|
||||
showPopup(editor.editor, { object: event })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +61,7 @@
|
||||
$: fontSize = $deviceOptionsStore.fontSize
|
||||
|
||||
function dragStart (e: DragEvent) {
|
||||
if (readOnly) return
|
||||
if (event.allDay) return
|
||||
originDate = event.date
|
||||
originDueDate = event.dueDate
|
||||
@ -87,6 +91,7 @@
|
||||
let dragDirection: 'bottom' | 'mid' | 'top' | undefined
|
||||
|
||||
function drag (e: DragEvent) {
|
||||
if (readOnly) return
|
||||
if (event.allDay) return
|
||||
if (dragInitY !== undefined) {
|
||||
const diff = Math.floor((e.y - dragInitY) / pixelPer15Min)
|
||||
@ -135,6 +140,9 @@
|
||||
ev.preventDefault()
|
||||
showPopup(Menu, { object: event }, getEventPositionElement(ev))
|
||||
}
|
||||
|
||||
$: visible = isVisible(event, $calendarStore)
|
||||
$: readOnly = isReadOnly(event)
|
||||
</script>
|
||||
|
||||
{#if event}
|
||||
@ -145,7 +153,7 @@
|
||||
class:oneRow
|
||||
class:empty
|
||||
draggable={!event.allDay}
|
||||
use:tooltip={{ component: EventPresenter, props: { value: event } }}
|
||||
use:tooltip={{ component: EventPresenter, props: { value: event, hideDetails: !visible } }}
|
||||
on:click|stopPropagation={click}
|
||||
on:contextmenu={showMenu}
|
||||
on:dragstart={dragStart}
|
||||
@ -154,7 +162,7 @@
|
||||
on:drop
|
||||
>
|
||||
{#if !empty && presenter?.presenter}
|
||||
<Component is={presenter.presenter} props={{ event, narrow, oneRow }} />
|
||||
<Component is={presenter.presenter} props={{ event, narrow, oneRow, hideDetails: !visible }} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
export let participants: Ref<Person>[]
|
||||
export let externalParticipants: string[]
|
||||
export let disabled: boolean = false
|
||||
|
||||
$: placeholder =
|
||||
participants.length > 0 || externalParticipants.length > 0
|
||||
|
@ -14,10 +14,11 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import { DatePresenter, DateTimeRangePresenter, showPopup } from '@hcengineering/ui'
|
||||
import { DatePresenter, DateTimeRangePresenter, Label, showPopup } from '@hcengineering/ui'
|
||||
import calendar from '../plugin'
|
||||
|
||||
export let value: Event
|
||||
export let hideDetails: boolean = false
|
||||
export let inline: boolean = false
|
||||
|
||||
function click (): void {
|
||||
@ -29,7 +30,11 @@
|
||||
<div class="antiSelect w-full cursor-pointer flex-center flex-between" on:click={click}>
|
||||
{#if value}
|
||||
<div class="mr-4">
|
||||
{value.title}
|
||||
{#if !hideDetails}
|
||||
{value.title}
|
||||
{:else}
|
||||
<Label label={calendar.string.Busy} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if !inline}
|
||||
{#if value.allDay}
|
||||
|
@ -20,6 +20,7 @@
|
||||
export let startDate: number
|
||||
export let dueDate: number
|
||||
export let allDay: boolean
|
||||
export let disabled: boolean = false
|
||||
|
||||
$: sameDate = areDatesEqual(new Date(startDate), new Date(dueDate))
|
||||
|
||||
@ -46,7 +47,7 @@
|
||||
<div class="flex-row-center flex-gap-1 mt-2 mb-2">
|
||||
<Icon icon={calendar.icon.Watch} size="small" />
|
||||
{#if sameDate}
|
||||
<DateEditor bind:date={startDate} direction="horizontal" withoutTime={allDay} on:update={dateChange} />
|
||||
<DateEditor bind:date={startDate} direction="horizontal" withoutTime={allDay} on:update={dateChange} {disabled} />
|
||||
<div class="content-dark-color">
|
||||
<IconArrowRight size="small" />
|
||||
</div>
|
||||
@ -55,13 +56,14 @@
|
||||
direction="horizontal"
|
||||
withoutTime={allDay}
|
||||
showDate={false}
|
||||
{disabled}
|
||||
on:update={dueChange}
|
||||
/>
|
||||
{:else}
|
||||
<DateEditor bind:date={startDate} direction="vertical" withoutTime={allDay} on:update={dateChange} />
|
||||
<DateEditor bind:date={startDate} direction="vertical" withoutTime={allDay} on:update={dateChange} {disabled} />
|
||||
<div class="content-dark-color">
|
||||
<IconArrowRight size="small" />
|
||||
</div>
|
||||
<DateEditor bind:date={dueDate} direction="vertical" withoutTime={allDay} on:update={dueChange} />
|
||||
<DateEditor bind:date={dueDate} direction="vertical" withoutTime={allDay} on:update={dueChange} {disabled} />
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -0,0 +1,71 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 { Calendar } from '@hcengineering/calendar'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import presentation, { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Grid, Label, Toggle } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
|
||||
const client = getClient()
|
||||
|
||||
let calendars: Calendar[] = []
|
||||
const query = createQuery()
|
||||
query.query(
|
||||
calendar.class.Calendar,
|
||||
{
|
||||
createdBy: getCurrentAccount()._id
|
||||
},
|
||||
(res) => (calendars = res)
|
||||
)
|
||||
|
||||
async function update (calendar: Calendar, value: boolean) {
|
||||
await client.update(calendar, {
|
||||
sync: value
|
||||
})
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<Card
|
||||
label={calendar.string.Calendars}
|
||||
okAction={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
canSave={true}
|
||||
fullSize
|
||||
okLabel={presentation.string.Ok}
|
||||
on:close={() => dispatch('close')}
|
||||
on:changeContent
|
||||
>
|
||||
<div style="width: 25rem;">
|
||||
<Grid rowGap={1}>
|
||||
<div>
|
||||
<Label label={calendar.string.Calendar} />
|
||||
</div>
|
||||
<div>
|
||||
<Label label={calendar.string.Sync} />
|
||||
</div>
|
||||
{#each calendars as calendar}
|
||||
<div>{calendar.name}</div>
|
||||
<div>
|
||||
<Toggle bind:on={calendar.sync} on:change={(res) => update(calendar, res.detail)} />
|
||||
</div>
|
||||
{/each}
|
||||
</Grid>
|
||||
</div>
|
||||
</Card>
|
@ -34,12 +34,15 @@ import CalendarIntegrationIcon from './components/icons/Calendar.svelte'
|
||||
import EventElement from './components/EventElement.svelte'
|
||||
import CalendarEventPresenter from './components/CalendarEventPresenter.svelte'
|
||||
import DayCalendar from './components/DayCalendar.svelte'
|
||||
import IntegrationConfigure from './components/IntegrationConfigure.svelte'
|
||||
import calendar from './plugin'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { deleteObjects } from '@hcengineering/view-resources'
|
||||
|
||||
export { EventElement, CalendarView, DayCalendar }
|
||||
|
||||
export * from './utils'
|
||||
|
||||
async function saveEventReminder (object: Doc): Promise<void> {
|
||||
showPopup(SaveEventReminder, { objectId: object._id, objectClass: object._class })
|
||||
}
|
||||
@ -70,7 +73,8 @@ async function deleteRecHandler (res: any, object: ReccuringInstance): Promise<v
|
||||
rdate: object.rdate,
|
||||
rules: object.rules,
|
||||
exdate: object.exdate,
|
||||
access: 'owner'
|
||||
visibility: object.visibility,
|
||||
access: object.access
|
||||
},
|
||||
object._id
|
||||
)
|
||||
@ -152,7 +156,8 @@ export default async (): Promise<Resources> => ({
|
||||
CreateEvent,
|
||||
IntegrationConnect,
|
||||
CalendarIntegrationIcon,
|
||||
CalendarEventPresenter
|
||||
CalendarEventPresenter,
|
||||
IntegrationConfigure
|
||||
},
|
||||
activity: {
|
||||
ReminderViewlet
|
||||
|
@ -75,6 +75,8 @@ export default mergeIds(calendarId, calendar, {
|
||||
SaturdayShort: '' as IntlString,
|
||||
SundayShort: '' as IntlString,
|
||||
Times: '' as IntlString,
|
||||
AddParticipants: '' as IntlString
|
||||
AddParticipants: '' as IntlString,
|
||||
Sync: '' as IntlString,
|
||||
Busy: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { Timestamp } from '@hcengineering/core'
|
||||
import { Calendar, Event } from '@hcengineering/calendar'
|
||||
import { IdMap, Timestamp, getCurrentAccount, toIdMap } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { writable } from 'svelte/store'
|
||||
import calendar from './plugin'
|
||||
|
||||
export function saveUTC (date: Timestamp): Timestamp {
|
||||
const utcdate = new Date(date)
|
||||
@ -12,3 +16,63 @@ export function saveUTC (date: Timestamp): Timestamp {
|
||||
utcdate.getMilliseconds()
|
||||
)
|
||||
}
|
||||
|
||||
export function hidePrivateEvents (events: Event[], calendars: IdMap<Calendar>): Event[] {
|
||||
const me = getCurrentAccount()._id
|
||||
const res: Event[] = []
|
||||
for (const event of events) {
|
||||
if ((event.createdBy ?? event.modifiedBy) === me) {
|
||||
res.push(event)
|
||||
} else {
|
||||
if (event.visibility !== undefined) {
|
||||
if (event.visibility !== 'private') {
|
||||
res.push(event)
|
||||
}
|
||||
} else {
|
||||
const space = calendars.get(event.space)
|
||||
if (space != null && space.visibility !== 'private') {
|
||||
res.push(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export function isReadOnly (value: Event): boolean {
|
||||
const me = getCurrentAccount()._id
|
||||
if (value.createdBy !== me) return true
|
||||
if (['owner', 'writer'].includes(value.access)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
export function isVisible (value: Event, calendars: IdMap<Calendar>): boolean {
|
||||
const me = getCurrentAccount()._id
|
||||
if (value.createdBy === me) return true
|
||||
if (value.visibility === 'freeBusy') {
|
||||
return false
|
||||
}
|
||||
const space = calendars.get(value.space)
|
||||
if (space == null) {
|
||||
return true
|
||||
} else {
|
||||
return space.visibility === 'public'
|
||||
}
|
||||
}
|
||||
|
||||
export const calendarStore = writable<IdMap<Calendar>>(new Map())
|
||||
|
||||
function fillStores (): void {
|
||||
const client = getClient()
|
||||
|
||||
if (client !== undefined) {
|
||||
const query = createQuery(true)
|
||||
query.query(calendar.class.Calendar, {}, (res) => {
|
||||
calendarStore.set(toIdMap(res))
|
||||
})
|
||||
} else {
|
||||
setTimeout(() => fillStores(), 50)
|
||||
}
|
||||
}
|
||||
|
||||
fillStores()
|
||||
|
@ -22,7 +22,10 @@ import { AnyComponent } from '@hcengineering/ui'
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Calendar extends Space {}
|
||||
export interface Calendar extends Space {
|
||||
visibility: 'public' | 'freeBusy' | 'private'
|
||||
sync?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -58,6 +61,7 @@ export interface ReccuringEvent extends Event {
|
||||
* @public
|
||||
*/
|
||||
export interface Event extends AttachedDoc {
|
||||
space: Ref<Calendar>
|
||||
eventId: string
|
||||
title: string
|
||||
description: Markup
|
||||
@ -80,6 +84,8 @@ export interface Event extends AttachedDoc {
|
||||
|
||||
reminders?: Timestamp[]
|
||||
|
||||
visibility?: 'public' | 'freeBusy' | 'private'
|
||||
|
||||
access: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
}
|
||||
|
||||
@ -132,7 +138,7 @@ const calendarPlugin = plugin(calendarId, {
|
||||
},
|
||||
space: {
|
||||
// deprecated
|
||||
PersonalEvents: '' as Ref<Space>
|
||||
PersonalEvents: '' as Ref<Calendar>
|
||||
},
|
||||
app: {
|
||||
Calendar: '' as Ref<Doc>
|
||||
|
@ -94,7 +94,8 @@ export async function OnPersonAccountCreate (tx: Tx, control: TriggerControl): P
|
||||
description: '',
|
||||
archived: false,
|
||||
private: false,
|
||||
members: [user._id]
|
||||
members: [user._id],
|
||||
visibility: 'public'
|
||||
},
|
||||
`${user._id}_calendar` as Ref<Calendar>,
|
||||
undefined,
|
||||
@ -108,11 +109,10 @@ async function onEventCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const ev = TxProcessor.createDoc2Doc(ctx)
|
||||
|
||||
const res: Tx[] = []
|
||||
const accounts = await control.modelDb.findAll(contact.class.PersonAccount, {})
|
||||
const participants = accounts.filter(
|
||||
(p) => (p._id !== ev.createdBy ?? ev.modifiedBy) && ev.participants.includes(p.person)
|
||||
)
|
||||
for (const acc of participants) {
|
||||
for (const participant of ev.participants) {
|
||||
const acc = (await control.modelDb.findAll(contact.class.PersonAccount, { person: participant }))[0]
|
||||
if (acc === undefined) continue
|
||||
if (acc._id === ev.createdBy ?? ev.modifiedBy) continue
|
||||
const { _id, _class, space, modifiedBy, modifiedOn, ...data } = ev
|
||||
const innerTx = control.txFactory.createTxCreateDoc(_class, `${acc._id}_calendar` as Ref<Calendar>, {
|
||||
...data,
|
||||
|
Loading…
Reference in New Issue
Block a user