From ceac67f3a3c7a2dcae4c7c09de4abb40dfca8520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pete=20An=C3=B8ther?= Date: Fri, 5 Apr 2024 07:59:35 -0300 Subject: [PATCH] TSK-1682: Slightly reorganized recruit files for future changes (#5196) Signed-off-by: Petr Vyazovetskiy --- models/recruit/src/index.ts | 184 +++-------------------- models/recruit/src/review-model.ts | 59 -------- models/recruit/src/types.ts | 228 +++++++++++++++++++++++++++++ plugins/recruit/src/index.ts | 129 +--------------- plugins/recruit/src/types.ts | 107 ++++++++++++++ 5 files changed, 360 insertions(+), 347 deletions(-) delete mode 100644 models/recruit/src/review-model.ts create mode 100644 models/recruit/src/types.ts create mode 100644 plugins/recruit/src/types.ts diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index df99aab78e..91cdf152fc 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -13,188 +13,44 @@ // limitations under the License. // -import type { Employee, Organization } from '@hcengineering/contact' -import { IndexKind, type Lookup, type Ref, SortingOrder, type Status, type Timestamp } from '@hcengineering/core' -import { - type Builder, - Collection, - Hidden, - Index, - Mixin, - Model, - Prop, - ReadOnly, - TypeBoolean, - TypeCollaborativeMarkup, - TypeDate, - TypeMarkup, - TypeRef, - TypeString, - UX -} from '@hcengineering/model' +import activity from '@hcengineering/activity' +import { type Lookup, type Ref, SortingOrder } from '@hcengineering/core' +import { type Builder } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' import calendar from '@hcengineering/model-calendar' import chunter from '@hcengineering/model-chunter' -import contact, { TOrganization, TPerson } from '@hcengineering/model-contact' -import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core' +import contact from '@hcengineering/model-contact' +import core from '@hcengineering/model-core' import { generateClassNotificationTypes } from '@hcengineering/model-notification' import presentation from '@hcengineering/model-presentation' import tags from '@hcengineering/model-tags' -import task, { DOMAIN_TASK, TProject, TTask, actionTemplates } from '@hcengineering/model-task' +import task, { actionTemplates } from '@hcengineering/model-task' import tracker from '@hcengineering/model-tracker' -import view, { createAction, showColorsViewOption, actionTemplates as viewTemplates } from '@hcengineering/model-view' +import view, { actionTemplates as viewTemplates, createAction, showColorsViewOption } from '@hcengineering/model-view' import workbench, { type Application, createNavigateAction } from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' -import { type IntlString, getEmbeddedLabel } from '@hcengineering/platform' -import { - type Applicant, - type ApplicantMatch, - type Candidate, - type Candidates, - type Vacancy, - type VacancyList, - recruitId -} from '@hcengineering/recruit' +import { type IntlString } from '@hcengineering/platform' +import { type Applicant, recruitId } from '@hcengineering/recruit' import setting from '@hcengineering/setting' import { type KeyBinding, type ViewOptionModel, type ViewOptionsModel } from '@hcengineering/view' -import activity from '@hcengineering/activity' import recruit from './plugin' import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review' -import { TOpinion, TReview } from './review-model' +import { + TApplicant, + TApplicantMatch, + TCandidate, + TCandidates, + TOpinion, + TReview, + TVacancy, + TVacancyList +} from './types' export { recruitId } from '@hcengineering/recruit' export { recruitOperation } from './migration' export { default } from './plugin' - -@Model(recruit.class.Vacancy, task.class.Project) -@UX(recruit.string.Vacancy, recruit.icon.Vacancy, 'VCN', 'name', undefined, recruit.string.Vacancies) -export class TVacancy extends TProject implements Vacancy { - @Prop(TypeCollaborativeMarkup(), recruit.string.FullDescription) - @Index(IndexKind.FullText) - fullDescription?: string - - @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) - attachments?: number - - @Prop(TypeDate(), recruit.string.Due, recruit.icon.Calendar) - dueTo?: Timestamp - - @Prop(TypeString(), recruit.string.Location, recruit.icon.Location) - @Index(IndexKind.FullText) - location?: string - - @Prop(TypeRef(contact.class.Organization), recruit.string.Company, { icon: contact.icon.Company }) - company?: Ref - - @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) - comments?: number - - @Prop(TypeString(), recruit.string.Vacancy) - @Index(IndexKind.FullText) - @Hidden() - number!: number -} - -@Model(recruit.class.Candidates, core.class.Space) -@UX(recruit.string.TalentPools, recruit.icon.RecruitApplication) -export class TCandidates extends TSpace implements Candidates {} - -@Mixin(recruit.mixin.Candidate, contact.class.Person) -@UX(recruit.string.Talent, recruit.icon.RecruitApplication, 'TLNT', 'name', undefined, recruit.string.Talents) -export class TCandidate extends TPerson implements Candidate { - @Prop(TypeString(), recruit.string.Title) - @Index(IndexKind.FullText) - title?: string - - @Prop(Collection(recruit.class.Applicant), recruit.string.Applications, { - shortLabel: recruit.string.ApplicationsShort - }) - applications?: number - - @Prop(TypeBoolean(), recruit.string.Onsite) - onsite?: boolean - - @Prop(TypeBoolean(), recruit.string.Remote) - remote?: boolean - - @Prop(TypeString(), recruit.string.Source) - @Index(IndexKind.FullText) - source?: string - - @Prop(Collection(tags.class.TagReference, recruit.string.SkillLabel), recruit.string.SkillsLabel, { - icon: recruit.icon.Skills, - schema: '3' - }) - skills?: number - - @Prop(Collection(recruit.class.Review, recruit.string.Review), recruit.string.Reviews) - reviews?: number - - @Prop( - Collection(recruit.class.ApplicantMatch, getEmbeddedLabel('Vacancy match')), - getEmbeddedLabel('Vacancy Matches') - ) - vacancyMatch?: number -} - -@Mixin(recruit.mixin.VacancyList, contact.class.Organization) -@UX(recruit.string.VacancyList, recruit.icon.RecruitApplication, 'CM', 'name') -export class TVacancyList extends TOrganization implements VacancyList { - @Prop(Collection(recruit.class.Vacancy), recruit.string.Vacancies) - vacancies!: number -} - -@Model(recruit.class.Applicant, task.class.Task) -@UX(recruit.string.Application, recruit.icon.Application, 'APP', 'number', undefined, recruit.string.Applications) -export class TApplicant extends TTask implements Applicant { - // We need to declare, to provide property with label - @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) - @Index(IndexKind.Indexed) - @ReadOnly() - declare attachedTo: Ref - - // We need to declare, to provide property with label - @Prop(TypeRef(recruit.class.Vacancy), recruit.string.Vacancy) - @Index(IndexKind.Indexed) - declare space: Ref - - @Prop(TypeDate(), task.string.StartDate) - startDate!: Timestamp | null - - @Prop(TypeRef(contact.mixin.Employee), recruit.string.AssignedRecruiter) - @Index(IndexKind.Indexed) - declare assignee: Ref | null - - @Prop(TypeRef(core.class.Status), task.string.TaskState, { _id: recruit.attribute.State }) - @Index(IndexKind.Indexed) - declare status: Ref -} - -@Model(recruit.class.ApplicantMatch, core.class.AttachedDoc, DOMAIN_TASK) -@UX(recruit.string.Application, recruit.icon.Application, 'APP', 'number') -export class TApplicantMatch extends TAttachedDoc implements ApplicantMatch { - // We need to declare, to provide property with label - @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) - @Index(IndexKind.Indexed) - declare attachedTo: Ref - - @Prop(TypeBoolean(), getEmbeddedLabel('Complete')) - @ReadOnly() - complete!: boolean - - @Prop(TypeString(), getEmbeddedLabel('Vacancy')) - @ReadOnly() - vacancy!: string - - @Prop(TypeString(), getEmbeddedLabel('Summary')) - @ReadOnly() - summary!: string - - @Prop(TypeMarkup(), getEmbeddedLabel('Response')) - @ReadOnly() - response!: string -} +export * from './types' export function createModel (builder: Builder): void { builder.createModel(TVacancy, TCandidates, TCandidate, TApplicant, TReview, TOpinion, TVacancyList, TApplicantMatch) diff --git a/models/recruit/src/review-model.ts b/models/recruit/src/review-model.ts deleted file mode 100644 index 8187c88187..0000000000 --- a/models/recruit/src/review-model.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { type Organization } from '@hcengineering/contact' -import { type Domain, IndexKind, type Ref } from '@hcengineering/core' -import { Collection, Index, Model, Prop, TypeMarkup, TypeRef, TypeString, UX } from '@hcengineering/model' -import attachment from '@hcengineering/model-attachment' -import calendar, { TEvent } from '@hcengineering/model-calendar' -import contact from '@hcengineering/model-contact' -import core, { TAttachedDoc } from '@hcengineering/model-core' -import task from '@hcengineering/model-task' -import { type Applicant, type Candidate, type Opinion, type Review } from '@hcengineering/recruit' -import chunter from '@hcengineering/model-chunter' - -import recruit from './plugin' - -@Model(recruit.class.Review, calendar.class.Event) -@UX(recruit.string.Review, recruit.icon.Review, 'RVE', 'number', undefined, recruit.string.Reviews) -export class TReview extends TEvent implements Review { - // We need to declare, to provide property with label - @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) - declare attachedTo: Ref - - @Prop(TypeString(), recruit.string.Review) - number!: number - - @Prop(TypeString(), recruit.string.Verdict) - @Index(IndexKind.FullText) - verdict!: string - - @Prop(TypeRef(recruit.class.Applicant), recruit.string.Application, { icon: recruit.icon.Application }) - application?: Ref - - @Prop(TypeRef(contact.class.Organization), recruit.string.Company, { icon: contact.icon.Company }) - company?: Ref - - @Prop(Collection(recruit.class.Opinion), recruit.string.Opinions) - opinions?: number -} - -@Model(recruit.class.Opinion, core.class.AttachedDoc, 'recruit' as Domain) -@UX(recruit.string.Opinion, recruit.icon.Opinion, 'OPE') -export class TOpinion extends TAttachedDoc implements Opinion { - @Prop(TypeString(), task.string.TaskNumber) - number!: number - - // We need to declare, to provide property with label - @Prop(TypeRef(recruit.class.Review), recruit.string.Review) - declare attachedTo: Ref - - @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) - attachments?: number - - @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) - comments?: number - - @Prop(TypeMarkup(), recruit.string.Description) - description!: string - - @Prop(TypeString(), recruit.string.OpinionValue) - value!: string -} diff --git a/models/recruit/src/types.ts b/models/recruit/src/types.ts new file mode 100644 index 0000000000..29070a2390 --- /dev/null +++ b/models/recruit/src/types.ts @@ -0,0 +1,228 @@ +// +// Copyright © 2024 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. +// + +import type { Employee, Organization } from '@hcengineering/contact' +import { type Domain, IndexKind, type Ref, type Status, type Timestamp } from '@hcengineering/core' +import { + Collection, + Hidden, + Index, + Mixin, + Model, + Prop, + ReadOnly, + TypeBoolean, + TypeCollaborativeMarkup, + TypeDate, + TypeMarkup, + TypeRef, + TypeString, + UX +} from '@hcengineering/model' +import attachment from '@hcengineering/model-attachment' +import calendar, { TEvent } from '@hcengineering/model-calendar' +import chunter from '@hcengineering/model-chunter' +import contact, { TOrganization, TPerson } from '@hcengineering/model-contact' +import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core' +import tags from '@hcengineering/model-tags' +import task, { DOMAIN_TASK, TProject, TTask } from '@hcengineering/model-task' +import { getEmbeddedLabel } from '@hcengineering/platform' +import type { + Applicant, + ApplicantMatch, + Candidate, + Candidates, + Opinion, + Review, + Vacancy, + VacancyList +} from '@hcengineering/recruit' +import recruit from './plugin' + +@Model(recruit.class.Vacancy, task.class.Project) +@UX(recruit.string.Vacancy, recruit.icon.Vacancy, 'VCN', 'name', undefined, recruit.string.Vacancies) +export class TVacancy extends TProject implements Vacancy { + @Prop(TypeCollaborativeMarkup(), recruit.string.FullDescription) + @Index(IndexKind.FullText) + fullDescription?: string + + @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) + attachments?: number + + @Prop(TypeDate(), recruit.string.Due, recruit.icon.Calendar) + dueTo?: Timestamp + + @Prop(TypeString(), recruit.string.Location, recruit.icon.Location) + @Index(IndexKind.FullText) + location?: string + + @Prop(TypeRef(contact.class.Organization), recruit.string.Company, { icon: contact.icon.Company }) + company?: Ref + + @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) + comments?: number + + @Prop(TypeString(), recruit.string.Vacancy) + @Index(IndexKind.FullText) + @Hidden() + number!: number +} + +@Model(recruit.class.Candidates, core.class.Space) +@UX(recruit.string.TalentPools, recruit.icon.RecruitApplication) +export class TCandidates extends TSpace implements Candidates {} + +@Mixin(recruit.mixin.Candidate, contact.class.Person) +@UX(recruit.string.Talent, recruit.icon.RecruitApplication, 'TLNT', 'name', undefined, recruit.string.Talents) +export class TCandidate extends TPerson implements Candidate { + @Prop(TypeString(), recruit.string.Title) + @Index(IndexKind.FullText) + title?: string + + @Prop(Collection(recruit.class.Applicant), recruit.string.Applications, { + shortLabel: recruit.string.ApplicationsShort + }) + applications?: number + + @Prop(TypeBoolean(), recruit.string.Onsite) + onsite?: boolean + + @Prop(TypeBoolean(), recruit.string.Remote) + remote?: boolean + + @Prop(TypeString(), recruit.string.Source) + @Index(IndexKind.FullText) + source?: string + + @Prop(Collection(tags.class.TagReference, recruit.string.SkillLabel), recruit.string.SkillsLabel, { + icon: recruit.icon.Skills, + schema: '3' + }) + skills?: number + + @Prop(Collection(recruit.class.Review, recruit.string.Review), recruit.string.Reviews) + reviews?: number + + @Prop( + Collection(recruit.class.ApplicantMatch, getEmbeddedLabel('Vacancy match')), + getEmbeddedLabel('Vacancy Matches') + ) + vacancyMatch?: number +} + +@Mixin(recruit.mixin.VacancyList, contact.class.Organization) +@UX(recruit.string.VacancyList, recruit.icon.RecruitApplication, 'CM', 'name') +export class TVacancyList extends TOrganization implements VacancyList { + @Prop(Collection(recruit.class.Vacancy), recruit.string.Vacancies) + vacancies!: number +} + +@Model(recruit.class.Applicant, task.class.Task) +@UX(recruit.string.Application, recruit.icon.Application, 'APP', 'number', undefined, recruit.string.Applications) +export class TApplicant extends TTask implements Applicant { + // We need to declare, to provide property with label + @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) + @Index(IndexKind.Indexed) + @ReadOnly() + declare attachedTo: Ref + + // We need to declare, to provide property with label + @Prop(TypeRef(recruit.class.Vacancy), recruit.string.Vacancy) + @Index(IndexKind.Indexed) + declare space: Ref + + @Prop(TypeDate(), task.string.StartDate) + startDate!: Timestamp | null + + @Prop(TypeRef(contact.mixin.Employee), recruit.string.AssignedRecruiter) + @Index(IndexKind.Indexed) + declare assignee: Ref | null + + @Prop(TypeRef(core.class.Status), task.string.TaskState, { _id: recruit.attribute.State }) + @Index(IndexKind.Indexed) + declare status: Ref +} + +@Model(recruit.class.ApplicantMatch, core.class.AttachedDoc, DOMAIN_TASK) +@UX(recruit.string.Application, recruit.icon.Application, 'APP', 'number') +export class TApplicantMatch extends TAttachedDoc implements ApplicantMatch { + // We need to declare, to provide property with label + @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) + @Index(IndexKind.Indexed) + declare attachedTo: Ref + + @Prop(TypeBoolean(), getEmbeddedLabel('Complete')) + @ReadOnly() + complete!: boolean + + @Prop(TypeString(), getEmbeddedLabel('Vacancy')) + @ReadOnly() + vacancy!: string + + @Prop(TypeString(), getEmbeddedLabel('Summary')) + @ReadOnly() + summary!: string + + @Prop(TypeMarkup(), getEmbeddedLabel('Response')) + @ReadOnly() + response!: string +} + +@Model(recruit.class.Review, calendar.class.Event) +@UX(recruit.string.Review, recruit.icon.Review, 'RVE', 'number', undefined, recruit.string.Reviews) +export class TReview extends TEvent implements Review { + // We need to declare, to provide property with label + @Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Talent) + declare attachedTo: Ref + + @Prop(TypeString(), recruit.string.Review) + number!: number + + @Prop(TypeString(), recruit.string.Verdict) + @Index(IndexKind.FullText) + verdict!: string + + @Prop(TypeRef(recruit.class.Applicant), recruit.string.Application, { icon: recruit.icon.Application }) + application?: Ref + + @Prop(TypeRef(contact.class.Organization), recruit.string.Company, { icon: contact.icon.Company }) + company?: Ref + + @Prop(Collection(recruit.class.Opinion), recruit.string.Opinions) + opinions?: number +} + +@Model(recruit.class.Opinion, core.class.AttachedDoc, 'recruit' as Domain) +@UX(recruit.string.Opinion, recruit.icon.Opinion, 'OPE') +export class TOpinion extends TAttachedDoc implements Opinion { + @Prop(TypeString(), task.string.TaskNumber) + number!: number + + // We need to declare, to provide property with label + @Prop(TypeRef(recruit.class.Review), recruit.string.Review) + declare attachedTo: Ref + + @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) + attachments?: number + + @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) + comments?: number + + @Prop(TypeMarkup(), recruit.string.Description) + description!: string + + @Prop(TypeString(), recruit.string.OpinionValue) + value!: string +} diff --git a/plugins/recruit/src/index.ts b/plugins/recruit/src/index.ts index 1428d58285..c197659912 100644 --- a/plugins/recruit/src/index.ts +++ b/plugins/recruit/src/index.ts @@ -13,134 +13,15 @@ // limitations under the License. // -import { Calendar, Event } from '@hcengineering/calendar' -import type { Channel, Organization, Person } from '@hcengineering/contact' -import type { - AttachedData, - AttachedDoc, - Attribute, - Class, - Doc, - Mixin, - Ref, - Space, - Status, - Timestamp -} from '@hcengineering/core' +import { Calendar } from '@hcengineering/calendar' +import type { Attribute, Class, Doc, Mixin, Ref, Status } from '@hcengineering/core' import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import { TagReference } from '@hcengineering/tags' -import type { Project, ProjectTypeDescriptor, Task, TaskType } from '@hcengineering/task' +import type { ProjectTypeDescriptor, TaskType } from '@hcengineering/task' import { AnyComponent, ResolvedLocation } from '@hcengineering/ui' +import type { Applicant, ApplicantMatch, Candidate, Candidates, Opinion, Review, Vacancy, VacancyList } from './types' -/** - * @public - */ -export interface Vacancy extends Project { - fullDescription?: string - attachments?: number - dueTo?: Timestamp - location?: string - company?: Ref - comments?: number - number: number -} - -/** - * @public - */ -export interface VacancyList extends Organization { - vacancies: number -} - -/** - * @public - */ -export interface Candidates extends Space {} - -/** - * @public - */ -export interface Candidate extends Person { - title?: string - applications?: number - onsite?: boolean - remote?: boolean - source?: string - skills?: number - reviews?: number -} - -/** - * @public - */ -export interface CandidateDraft { - _id: Ref - firstName?: string - lastName?: string - title?: string - city: string - resumeUuid?: string - resumeName?: string - resumeSize?: number - resumeType?: string - resumeLastModified?: number - avatar?: File | undefined - channels: AttachedData[] - onsite?: boolean - remote?: boolean - skills: TagReference[] -} - -/** - * @public - */ -export interface Applicant extends Task { - space: Ref - attachedTo: Ref - status: Ref - startDate: Timestamp | null -} - -/** - * @public - */ -export interface ApplicantMatch extends AttachedDoc { - attachedTo: Ref - - complete: boolean - vacancy: string - summary: string - response: string -} - -/** - * @public - */ -export interface Review extends Event { - attachedTo: Ref - number: number - - verdict: string - - application?: Ref - - company?: Ref - - opinions?: number -} - -/** - * @public - */ -export interface Opinion extends AttachedDoc { - number: number - attachedTo: Ref - comments?: number - attachments?: number - description: string - value: string -} +export * from './types' /** * @public diff --git a/plugins/recruit/src/types.ts b/plugins/recruit/src/types.ts new file mode 100644 index 0000000000..50e39cdff3 --- /dev/null +++ b/plugins/recruit/src/types.ts @@ -0,0 +1,107 @@ +// +// Copyright © 2024 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. +// + +import { Event } from '@hcengineering/calendar' +import type { Channel, Organization, Person } from '@hcengineering/contact' +import type { AttachedData, AttachedDoc, Ref, Space, Status, Timestamp } from '@hcengineering/core' +import { TagReference } from '@hcengineering/tags' +import type { Project, Task } from '@hcengineering/task' + +/** @public */ +export interface Candidates extends Space {} + +/** @public */ +export interface Vacancy extends Project { + fullDescription?: string + attachments?: number + dueTo?: Timestamp + location?: string + company?: Ref + comments?: number + number: number +} + +/** @public */ +export interface VacancyList extends Organization { + vacancies: number +} + +/** @public */ +export interface Candidate extends Person { + title?: string + applications?: number + onsite?: boolean + remote?: boolean + source?: string + skills?: number + reviews?: number +} + +/** @public */ +export interface CandidateDraft { + _id: Ref + firstName?: string + lastName?: string + title?: string + city: string + resumeUuid?: string + resumeName?: string + resumeSize?: number + resumeType?: string + resumeLastModified?: number + avatar?: File | undefined + channels: AttachedData[] + onsite?: boolean + remote?: boolean + skills: TagReference[] +} + +/** @public */ +export interface Applicant extends Task { + space: Ref + attachedTo: Ref + status: Ref + startDate: Timestamp | null +} + +/** @public */ +export interface ApplicantMatch extends AttachedDoc { + attachedTo: Ref + + complete: boolean + vacancy: string + summary: string + response: string +} + +/** @public */ +export interface Review extends Event { + attachedTo: Ref + number: number + verdict: string + application?: Ref + company?: Ref + opinions?: number +} + +/** @public */ +export interface Opinion extends AttachedDoc { + number: number + attachedTo: Ref + comments?: number + attachments?: number + description: string + value: string +}