From 6f7e95e233f1c8c03975ff8380a5c560218b3c21 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev <haiodo@users.noreply.github.com> Date: Wed, 23 Mar 2022 16:03:41 +0700 Subject: [PATCH] Upcoming events (#1195) Signed-off-by: Andrey Sobolev <haiodo@gmail.com> --- models/recruit/src/index.ts | 14 ++- models/recruit/src/review.ts | 78 ++++++------ packages/core/src/storage.ts | 13 +- packages/core/src/tx.ts | 2 +- packages/query/src/__tests__/minmodel.ts | 12 +- packages/query/src/__tests__/query.test.ts | 55 ++++++++- packages/query/src/index.ts | 12 +- plugins/calendar-assets/lang/en.json | 7 +- plugins/calendar-assets/lang/ru.json | 7 +- .../src/components/CalendarView.svelte | 86 +++++++++---- .../src/components/DateTimePresenter.svelte | 59 +++++++++ .../src/components/UpcomingEvents.svelte | 116 ++++++++++++++++++ plugins/calendar-resources/src/index.ts | 6 +- plugins/calendar-resources/src/plugin.ts | 7 +- plugins/calendar/src/index.ts | 4 +- .../src/components/review/CreateReview.svelte | 9 +- .../src/components/review/Reviews.svelte | 5 +- 17 files changed, 408 insertions(+), 84 deletions(-) create mode 100644 plugins/calendar-resources/src/components/DateTimePresenter.svelte create mode 100644 plugins/calendar-resources/src/components/UpcomingEvents.svelte diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index b87603a794..37cafe75a0 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -41,7 +41,8 @@ import workbench from '@anticrm/model-workbench' import { Applicant, Candidate, Candidates, Vacancy } from '@anticrm/recruit' import { TOpinion, TReview, TReviewCategory } from './review-model' import recruit from './plugin' -import { createReviewModel } from './review' +import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review' +import calendar from '@anticrm/model-calendar' @Model(recruit.class.Vacancy, task.class.SpaceWithStates) @UX(recruit.string.Vacancy, recruit.icon.Vacancy) @@ -192,7 +193,18 @@ export function createModel (builder: Builder): void { componentProps: { labelTasks: recruit.string.Applications, _class: recruit.class.Applicant + } + }, + { + id: 'upcoming', + component: calendar.component.UpcomingEvents, + componentProps: { + _class: recruit.class.Review, + options: reviewTableOptions, + config: reviewTableConfig }, + icon: calendar.icon.Calendar, + label: calendar.string.UpcomingEvents, position: 'top' } ] diff --git a/models/recruit/src/review.ts b/models/recruit/src/review.ts index 934f4751bf..d5e34645c1 100644 --- a/models/recruit/src/review.ts +++ b/models/recruit/src/review.ts @@ -1,12 +1,38 @@ -import { Doc, FindOptions } from '@anticrm/core' +import { FindOptions } from '@anticrm/core' import { Builder } from '@anticrm/model' +import calendar from '@anticrm/model-calendar' import contact from '@anticrm/model-contact' import core from '@anticrm/model-core' import task from '@anticrm/model-task' import view from '@anticrm/model-view' import workbench from '@anticrm/model-workbench' +import { Review } from '@anticrm/recruit' +import { BuildModelKey } from '@anticrm/view' import recruit from './plugin' -import calendar from '@anticrm/model-calendar' + +export const reviewTableOptions: FindOptions<Review> = { + lookup: { + attachedTo: recruit.mixin.Candidate, + participants: contact.class.Employee, + company: contact.class.Organization + } +} +export const reviewTableConfig: (BuildModelKey | string)[] = [ + '', + 'title', + '$lookup.attachedTo', + // 'verdict', + { key: '', presenter: recruit.component.OpinionsPresenter, label: recruit.string.Opinions, sortingKey: 'opinions' }, + { + key: '$lookup.participants', + presenter: calendar.component.PersonsPresenter, + label: calendar.string.Participants, + sortingKey: '$lookup.participants' + }, + '$lookup.company', + { key: '', presenter: calendar.component.DateTimePresenter, label: calendar.string.Date, sortingKey: 'date' }, + 'modifiedOn' +] export function createReviewModel (builder: Builder): void { builder.mixin(recruit.class.ReviewCategory, core.class.Class, workbench.mixin.SpaceView, { @@ -82,27 +108,20 @@ export function createReviewModel (builder: Builder): void { } }) + const reviewOptions: FindOptions<Review> = { + lookup: { + attachedTo: recruit.mixin.Candidate, + participants: contact.class.Employee, + company: contact.class.Organization + } + } + builder.createDoc(view.class.Viewlet, core.space.Model, { attachTo: recruit.class.Review, descriptor: calendar.viewlet.Calendar, // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - options: { - lookup: { - attachedTo: recruit.mixin.Candidate, - participants: contact.class.Employee, - company: contact.class.Organization - } - } as FindOptions<Doc>, - config: [ - '', - 'title', - '$lookup.attachedTo', - 'verdict', - { key: '', presenter: recruit.component.OpinionsPresenter, label: recruit.string.Opinions, sortingKey: 'opinions' }, - { key: '$lookup.participants', presenter: calendar.component.PersonsPresenter, label: calendar.string.Participants, sortingKey: '$lookup.participants' }, - '$lookup.company', - 'modifiedOn' - ] + options: reviewOptions, + config: reviewTableConfig }) } @@ -111,25 +130,8 @@ function createTableViewlet (builder: Builder): void { attachTo: recruit.class.Review, descriptor: view.viewlet.Table, // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - options: { - lookup: { - attachedTo: recruit.mixin.Candidate, - participants: contact.class.Employee, - company: contact.class.Organization - } - } as FindOptions<Doc>, - config: [ - '', - 'title', - '$lookup.attachedTo', - 'verdict', - { key: '', presenter: recruit.component.OpinionsPresenter, label: recruit.string.Opinions, sortingKey: 'opinions' }, - { key: '$lookup.participants', presenter: calendar.component.PersonsPresenter, label: calendar.string.Participants, sortingKey: '$lookup.participants' }, - '$lookup.company', - 'date', - 'dueDate', - 'modifiedOn' - ] + options: reviewTableOptions, + config: reviewTableConfig }) builder.mixin(recruit.class.Opinion, core.class.Class, view.mixin.AttributeEditor, { diff --git a/packages/core/src/storage.ts b/packages/core/src/storage.ts index d36c7d016a..90c9a48949 100644 --- a/packages/core/src/storage.ts +++ b/packages/core/src/storage.ts @@ -32,7 +32,7 @@ export type QuerySelector<T> = { /** * @public */ -export type ObjQueryType<T> = T | QuerySelector<T> +export type ObjQueryType<T> = (T extends Array<infer U> ? U | U[] : T) | QuerySelector<T> /** * @public @@ -50,23 +50,26 @@ export type DocumentQuery<T extends Doc> = { * @public */ export type ToClassRefT<T extends object, P extends keyof T> = T[P] extends Ref<infer X> | null | undefined ? Ref<Class<X>> | [Ref<Class<X>>, Lookup<X>] : never - +/** + * @public + */ +export type ToClassRefTA<T extends object, P extends keyof T> = T[P] extends Array<Ref<infer X>> | null | undefined ? Ref<Class<X>> | [Ref<Class<X>>, Lookup<X>] : never /** * @public */ export type ToClassRef<T extends object> = { - [P in keyof T]?: ToClassRefT<T, P> + [P in keyof T]?: ToClassRefT<T, P> | ToClassRefTA<T, P> } /** * @public */ -export type RefKeys<T extends Doc> = Pick<T, KeysByType<T, NullableRef>> +export type NullableRef = Ref<Doc> | Array<Ref<Doc>> | null | undefined /** * @public */ -export type NullableRef = Ref<Doc> | null | undefined +export type RefKeys<T extends Doc> = Pick<T, KeysByType<T, NullableRef>> /** * @public diff --git a/packages/core/src/tx.ts b/packages/core/src/tx.ts index 924e286321..0aef96dabc 100644 --- a/packages/core/src/tx.ts +++ b/packages/core/src/tx.ts @@ -116,7 +116,7 @@ export interface MoveDescriptor<X extends PropertyType> { * @public */ export type ArrayAsElementPosition<T extends object> = { - [P in keyof T]: T[P] extends Arr<infer X> ? X | Position<X> : never + [P in keyof T]-?: T[P] extends Arr<infer X> ? X | Position<X> : never } /** diff --git a/packages/query/src/__tests__/minmodel.ts b/packages/query/src/__tests__/minmodel.ts index d2d2309856..93bdc84f8e 100644 --- a/packages/query/src/__tests__/minmodel.ts +++ b/packages/query/src/__tests__/minmodel.ts @@ -58,10 +58,18 @@ export const test = plugin('test' as Plugin, { TestMixin: '' as Ref<Mixin<TestMixin>> }, class: { - TestComment: '' as Ref<Class<AttachedComment>> + TestComment: '' as Ref<Class<AttachedComment>>, + ParticipantsHolder: '' as Ref<Class<ParticipantsHolder>> } }) +/** + * @public + */ +export interface ParticipantsHolder extends Doc { + participants?: Ref<Doc>[] +} + const DOMAIN_TEST: Domain = 'test' as Domain /** @@ -90,6 +98,8 @@ export function genMinModel (): TxCUD<Doc>[] { txes.push(createClass(test.class.TestComment, { label: 'TestComment' as IntlString, extends: core.class.AttachedDoc, kind: ClassifierKind.CLASS, domain: DOMAIN_TEST })) + txes.push(createClass(test.class.ParticipantsHolder, { label: 'ParticipantsHolder' as IntlString, extends: core.class.Doc, kind: ClassifierKind.CLASS, domain: DOMAIN_TEST })) + const u1 = 'User1' as Ref<Account> const u2 = 'User2' as Ref<Account> txes.push( diff --git a/packages/query/src/__tests__/query.test.ts b/packages/query/src/__tests__/query.test.ts index c532a956f1..7a48a2d239 100644 --- a/packages/query/src/__tests__/query.test.ts +++ b/packages/query/src/__tests__/query.test.ts @@ -14,9 +14,9 @@ // import core, { createClient, Doc, generateId, Ref, SortingOrder, Space, Tx, TxCreateDoc, TxOperations, WithLookup } from '@anticrm/core' -import { AttachedComment, test, genMinModel } from './minmodel' import { LiveQuery } from '..' import { connect } from './connection' +import { AttachedComment, genMinModel, ParticipantsHolder, test } from './minmodel' interface Channel extends Space { x: number @@ -49,12 +49,12 @@ describe('query', () => { } } - await new Promise((resolve) => { + const result = await new Promise((resolve) => { liveQuery.query<Space>(core.class.Space, { private: false }, (result) => { - expect(result).toHaveLength(expectedLength) - resolve(null) + resolve(result) }) }) + expect(result).toHaveLength(expectedLength) }) it('query should be live', async () => { @@ -743,4 +743,51 @@ describe('query', () => { // } // await pp // }) + + it('update-array-value', async () => { + const { liveQuery, factory } = await getClient() + + const spaces = await liveQuery.findAll(core.class.Space, {}) + await factory.createDoc(test.class.ParticipantsHolder, spaces[0]._id, { + participants: ['a' as Ref<Doc>] + }) + const a2 = await factory.createDoc(test.class.ParticipantsHolder, spaces[0]._id, { + participants: ['b' as Ref<Doc>] + }) + + const holderBefore = await liveQuery.findAll(test.class.ParticipantsHolder, { participants: 'a' as Ref<Doc> }) + expect(holderBefore.length).toEqual(1) + + let attempt = 0 + let resolvePpv: (value: Doc[] | PromiseLike<Doc[]>) => void + + const resolveP = new Promise<Doc[]>((resolve) => { + resolvePpv = resolve + }) + const pp = await new Promise((resolve) => { + liveQuery.query<Space>( + test.class.ParticipantsHolder, + { participants: 'a' as Ref<Doc> }, + (result) => { + if (attempt > 0) { + resolvePpv(result) + } else { + resolve(null) + } + }, + { sort: { private: SortingOrder.Ascending } } + ) + }) + + await pp // We have first value returned + + attempt++ + await factory.updateDoc<ParticipantsHolder>(test.class.ParticipantsHolder, spaces[0]._id, a2, { + $push: { + participants: 'a' as Ref<Doc> + } + }) + const result = await resolveP + expect(result.length).toEqual(2) + }) }) diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index da83b669c7..d7f86c77c6 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -338,9 +338,19 @@ export class LiveQuery extends TxProcessor implements Client { return false } + const doc: Doc = { + _id: tx.objectId, + _class: tx.objectClass, + modifiedBy: tx.modifiedBy, + modifiedOn: tx.modifiedOn, + space: tx.objectSpace + } + + TxProcessor.updateDoc2Doc(doc, tx) + for (const key in q.query) { const value = (q.query as any)[key] - const res = findProperty([tx.operations as unknown as Doc], key, value) + const res = findProperty([doc], key, value) if (res.length === 1) { return true } diff --git a/plugins/calendar-assets/lang/en.json b/plugins/calendar-assets/lang/en.json index e28eca5466..c590a3dbbb 100644 --- a/plugins/calendar-assets/lang/en.json +++ b/plugins/calendar-assets/lang/en.json @@ -20,6 +20,11 @@ "ModeWeek": "Week", "ModeMonth": "Month", "ModeYear": "Year", - "Today": "Today" + "Today": "Today", + "UpcomingEvents": "Upcoming events", + "TableView": "Table", + "DueMinutes": "{minutes, plural, =0 {less than a minute} =1 {a minute} other {# minutes}}", + "DueHours": "{hours, plural, =0 {less than an hour} =1 {1 hour} other {# hours}}", + "DueDays": "{days, plural, =0 {today} =1 {1 day} other {# days}}" } } \ No newline at end of file diff --git a/plugins/calendar-assets/lang/ru.json b/plugins/calendar-assets/lang/ru.json index 19be55c791..a0eae53111 100644 --- a/plugins/calendar-assets/lang/ru.json +++ b/plugins/calendar-assets/lang/ru.json @@ -20,6 +20,11 @@ "ModeWeek": "Неделя", "ModeMonth": "Месяц", "ModeYear": "Год", - "Today": "Сегодня" + "Today": "Сегодня", + "UpcomingEvents": "Предстоящие события", + "TableView": "Таблица", + "DueMinutes": "{minutes, plural, =0 {меньше минуты} =1 {минута} other {# минут}}", + "DueHours": "{hours, plural, =0 {меньше часа} =1 {1 час} other {# часы}}", + "DueDays": "{days, plural, =0 {сегодня} =1 {1 день} other {# дня}}" } } \ No newline at end of file diff --git a/plugins/calendar-resources/src/components/CalendarView.svelte b/plugins/calendar-resources/src/components/CalendarView.svelte index 7ef1f1108d..3738c28320 100644 --- a/plugins/calendar-resources/src/components/CalendarView.svelte +++ b/plugins/calendar-resources/src/components/CalendarView.svelte @@ -38,7 +38,8 @@ let loading = false let resultQuery: DocumentQuery<Event> - $: resultQuery = search === '' ? { ...query, space } : { ...query, $search: search, space } + $: spaceOpt = (space ? { space } : {}) + $: resultQuery = search === '' ? { ...query, ...spaceOpt } : { ...query, $search: search, ...spaceOpt } let objects: Event[] = [] @@ -73,14 +74,16 @@ } function findEvents (events: Event[], date: Date): Event[] { - return events.filter((it) => areDatesLess(new Date(it.date), date) && areDatesLess(date, new Date(it.dueDate ?? it.date))) + return events.filter( + (it) => areDatesLess(new Date(it.date), date) && areDatesLess(date, new Date(it.dueDate ?? it.date)) + ) } interface ShiftType { yearShift: number monthShift: number dayShift: number - weekShift:number + weekShift: number } let shifts: ShiftType = { @@ -134,7 +137,12 @@ return res } - enum CalendarMode { Day, Week, Month, Year } + enum CalendarMode { + Day, + Week, + Month, + Year + } let mode: CalendarMode = CalendarMode.Year @@ -156,7 +164,7 @@ } </script> -<div class='fs-title ml-2 mb-2 flex-row-center'> +<div class="fs-title ml-2 mb-2 flex-row-center"> {label(currentDate(date, shifts), mode)} </div> @@ -202,29 +210,63 @@ } mode = CalendarMode.Year }} - /> + /> <div class="flex ml-4 gap-1"> - <Button icon={IconBack} size={'small'} on:click={() => { inc(-1) } }/> - <Button size={'small'} label={calendar.string.Today} on:click={() => { inc(0) }}/> - <Button icon={IconForward} size={'small'} on:click={() => { inc(1) }}/> + <Button + icon={IconBack} + size={'small'} + on:click={() => { + inc(-1) + }} + /> + <Button + size={'small'} + label={calendar.string.Today} + on:click={() => { + inc(0) + }} + /> + <Button + icon={IconForward} + size={'small'} + on:click={() => { + inc(1) + }} + /> </div> </div> - {#if mode === CalendarMode.Year} -<ScrollBox bothScroll> - <YearCalendar {mondayStart} cellHeight={'2.5rem'} bind:value={value} currentDate={currentDate(date, shifts)}> + <ScrollBox bothScroll> + <YearCalendar {mondayStart} cellHeight={'2.5rem'} bind:value currentDate={currentDate(date, shifts)}> <svelte:fragment slot="cell" let:date> - <Day events={findEvents(objects, date)} {date} {_class} {baseMenuClass} {options} {config} query={resultQuery} /> + <Day + events={findEvents(objects, date)} + {date} + {_class} + {baseMenuClass} + {options} + {config} + query={resultQuery} + /> </svelte:fragment> </YearCalendar> </ScrollBox> - {:else if mode === CalendarMode.Month} - <div class='flex flex-grow'> - <MonthCalendar {mondayStart} cellHeight={'8.5rem'} bind:value={value} currentDate={currentDate(date, shifts)}> - <svelte:fragment slot="cell" let:date={date}> - <Day events={findEvents(objects, date)} {date} size={'huge'} {_class} {baseMenuClass} {options} {config} query={resultQuery}/> - </svelte:fragment> - </MonthCalendar> - </div> - {/if} +{:else if mode === CalendarMode.Month} + <div class="flex flex-grow"> + <MonthCalendar {mondayStart} cellHeight={'8.5rem'} bind:value currentDate={currentDate(date, shifts)}> + <svelte:fragment slot="cell" let:date> + <Day + events={findEvents(objects, date)} + {date} + size={'huge'} + {_class} + {baseMenuClass} + {options} + {config} + query={resultQuery} + /> + </svelte:fragment> + </MonthCalendar> + </div> +{/if} diff --git a/plugins/calendar-resources/src/components/DateTimePresenter.svelte b/plugins/calendar-resources/src/components/DateTimePresenter.svelte new file mode 100644 index 0000000000..044e112bd1 --- /dev/null +++ b/plugins/calendar-resources/src/components/DateTimePresenter.svelte @@ -0,0 +1,59 @@ +<!-- +// Copyright © 2022 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 { Event } from '@anticrm/calendar' + import { translate } from '@anticrm/platform' + import { DatePresenter } from '@anticrm/ui' + import calendar from '../plugin' + + export let value: Event + + $: date = value ? new Date(value.date) : undefined + $: dueDate = value ? new Date(value.dueDate ?? value.date) : undefined + + $: interval = (value.dueDate ?? value.date) - value.date + + const SECOND = 1000 + const MINUTE = SECOND * 60 + const HOUR = MINUTE * 60 + const DAY = HOUR * 24 + + async function formatDueDate (interval: number): Promise<string> { + let passed = interval + if (interval < 0) passed = 0 + if (passed < HOUR) { + return await translate(calendar.string.DueMinutes, { minutes: Math.floor(passed / MINUTE) }) + } else if (passed < DAY) { + return await translate(calendar.string.DueHours, { hours: Math.floor(passed / HOUR) }) + } else { + return await translate(calendar.string.DueDays, { days: Math.floor(passed / DAY) }) + } + } + +</script> + +<div class="antiSelect"> + {#if date} + <DatePresenter value={date} withTime={date.getMinutes() !== 0 && date.getHours() !== 0 && interval < DAY} /> + {#if interval > 0} + {#await formatDueDate(interval) then t} + <span class='ml-2 mr-1 whitespace-nowrap'>({t})</span> + {/await} + {/if} + {:else} + No date + {/if} +</div> \ No newline at end of file diff --git a/plugins/calendar-resources/src/components/UpcomingEvents.svelte b/plugins/calendar-resources/src/components/UpcomingEvents.svelte new file mode 100644 index 0000000000..b8a8fce62d --- /dev/null +++ b/plugins/calendar-resources/src/components/UpcomingEvents.svelte @@ -0,0 +1,116 @@ +<!-- +// Copyright © 2022 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 { Event } from '@anticrm/calendar' + import { EmployeeAccount } from '@anticrm/contact' + import { Class, DocumentQuery, FindOptions, getCurrentAccount, Ref } from '@anticrm/core' + import { Asset, IntlString } from '@anticrm/platform' + import { AnySvelteComponent, Icon, Label, SearchEdit, Tooltip } from '@anticrm/ui' + import { Table } from '@anticrm/view-resources' + import view from '@anticrm/view' + import calendar from '../plugin' + import CalendarView from './CalendarView.svelte' + + export let _class: Ref<Class<Event>> + export let query: DocumentQuery<Event> = {} + export let options: FindOptions<Event> | undefined = undefined + export let baseMenuClass: Ref<Class<Event>> | undefined = undefined + export let config: string[] + + const currentUser = getCurrentAccount() as EmployeeAccount + + let search = '' + let resultQuery: DocumentQuery<Event> = {} + + function updateResultQuery (search: string): void { + resultQuery = search === '' ? { ...query } : { ...query, $search: search } + + resultQuery.participants = currentUser.employee + } + + $: updateResultQuery(search) + + interface CalendarViewlet { + component: AnySvelteComponent + props: Record<string, any> + label: IntlString + icon: Asset + } + + $: viewlets = [{ + component: CalendarView, + icon: calendar.icon.Calendar, + label: calendar.string.Calendar, + props: { + _class, + space: undefined, + query: resultQuery, + options, + baseMenuClass, + config, + search + } + }, + { + component: Table, + icon: view.icon.Table, + label: calendar.string.TableView, + props: { + _class, + query: resultQuery, + options, + baseMenuClass, + config, + search + } + }] as CalendarViewlet[] + let selectedViewlet = 0 +</script> + +<div class="ac-header full"> + <div class="ac-header__wrap-title"> + <div class="ac-header__icon"><Icon icon={calendar.icon.Calendar} size={'small'} /></div> + <span class="ac-header__title"><Label label={calendar.string.UpcomingEvents} /></span> + </div> + + {#if viewlets.length > 1} + <div class="flex"> + {#each viewlets as viewlet, i} + <Tooltip label={viewlet.label} direction={'top'}> + <button + class="ac-header__icon-button" + class:selected={selectedViewlet === i} + on:click={() => { + selectedViewlet = i + }} + > + <Icon icon={viewlet.icon} size={'small'} /> + </button> + </Tooltip> + {/each} + </div> + {/if} + + <SearchEdit + bind:value={search} + on:change={() => { + updateResultQuery(search) + }} + /> +</div> + +{#if viewlets[selectedViewlet]} + <svelte:component this={viewlets[selectedViewlet].component} {...(viewlets[selectedViewlet].props)} /> +{/if} diff --git a/plugins/calendar-resources/src/index.ts b/plugins/calendar-resources/src/index.ts index 4e28eb0e1d..060b7eeda6 100644 --- a/plugins/calendar-resources/src/index.ts +++ b/plugins/calendar-resources/src/index.ts @@ -17,10 +17,14 @@ import { Resources } from '@anticrm/platform' import PersonsPresenter from './components/PersonsPresenter.svelte' import CalendarView from './components/CalendarView.svelte' +import UpcomingEvents from './components/UpcomingEvents.svelte' +import DateTimePresenter from './components/DateTimePresenter.svelte' export default async (): Promise<Resources> => ({ component: { PersonsPresenter, - CalendarView + CalendarView, + UpcomingEvents, + DateTimePresenter } }) diff --git a/plugins/calendar-resources/src/plugin.ts b/plugins/calendar-resources/src/plugin.ts index dfa411cc62..87b7e1eaf2 100644 --- a/plugins/calendar-resources/src/plugin.ts +++ b/plugins/calendar-resources/src/plugin.ts @@ -25,6 +25,11 @@ export default mergeIds(calendarId, calendar, { ModeWeek: '' as IntlString, ModeMonth: '' as IntlString, ModeYear: '' as IntlString, - Today: '' as IntlString + Today: '' as IntlString, + UpcomingEvents: '' as IntlString, + TableView: '' as IntlString, + DueMinutes: '' as IntlString, + DueHours: '' as IntlString, + DueDays: '' as IntlString } }) diff --git a/plugins/calendar/src/index.ts b/plugins/calendar/src/index.ts index acaec40e3e..8a158aff7e 100644 --- a/plugins/calendar/src/index.ts +++ b/plugins/calendar/src/index.ts @@ -69,7 +69,9 @@ const calendarPlugin = plugin(calendarId, { Calendar: '' as Ref<Doc> }, component: { - PersonsPresenter: '' as AnyComponent + PersonsPresenter: '' as AnyComponent, + UpcomingEvents: '' as AnyComponent, + DateTimePresenter: '' as AnyComponent }, string: { Title: '' as IntlString, diff --git a/plugins/recruit-resources/src/components/review/CreateReview.svelte b/plugins/recruit-resources/src/components/review/CreateReview.svelte index 7726e27786..0a71605825 100644 --- a/plugins/recruit-resources/src/components/review/CreateReview.svelte +++ b/plugins/recruit-resources/src/components/review/CreateReview.svelte @@ -13,10 +13,10 @@ // limitations under the License. --> <script lang="ts"> - import type { Contact, Organization, Person } from '@anticrm/contact' + import type { Contact, EmployeeAccount, Organization, Person } from '@anticrm/contact' import contact from '@anticrm/contact' import { OrganizationSelector } from '@anticrm/contact-resources' - import { Account, Class, Client, Doc, generateId, Ref } from '@anticrm/core' + import { Account, Class, Client, Doc, generateId, getCurrentAccount, Ref } from '@anticrm/core' import { getResource, OK, Resource, Severity, Status } from '@anticrm/platform' import { Card, getClient, UserBox } from '@anticrm/presentation' import type { Candidate, Review } from '@anticrm/recruit' @@ -32,6 +32,8 @@ export let preserveCandidate = false + const currentUser = getCurrentAccount() as EmployeeAccount + let status: Status = OK let title: string = '' @@ -56,7 +58,8 @@ description, company, verdict: '', - title + title, + participants: [currentUser.employee] } const dispatch = createEventDispatcher() diff --git a/plugins/recruit-resources/src/components/review/Reviews.svelte b/plugins/recruit-resources/src/components/review/Reviews.svelte index 9719883cfe..8c194cc58c 100644 --- a/plugins/recruit-resources/src/components/review/Reviews.svelte +++ b/plugins/recruit-resources/src/components/review/Reviews.svelte @@ -16,7 +16,7 @@ import type { Doc, Ref } from '@anticrm/core' import core from '@anticrm/core' import { IntlString } from '@anticrm/platform' - import task from '@anticrm/task' + import calendar from '@anticrm/calendar' import { CircleButton, IconAdd, Label, showPopup } from '@anticrm/ui' import { Table } from '@anticrm/view-resources' import recruit from '../../plugin' @@ -50,8 +50,7 @@ label: recruit.string.Opinions, sortingKey: 'opinions' }, - 'date', - 'dueDate' + { key: '', presenter: calendar.component.DateTimePresenter, label: calendar.string.Date, sortingKey: 'date' }, ]} options={{ lookup: {