From ec738daf75af6b9497a9da9b5105bbec8d9976e1 Mon Sep 17 00:00:00 2001 From: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> Date: Mon, 20 Dec 2021 15:37:15 +0600 Subject: [PATCH] Move with state and validate (#680) Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> --- models/recruit/src/index.ts | 4 + models/recruit/src/migration.ts | 37 +++++--- models/recruit/src/plugin.ts | 7 +- models/view/src/index.ts | 13 ++- .../src/components/CreateApplication.svelte | 73 ++++++++++------ plugins/recruit-resources/src/index.ts | 26 +++++- plugins/view-resources/package.json | 1 + .../view-resources/src/components/Move.svelte | 84 +++++++++++++------ plugins/view/src/index.ts | 12 ++- 9 files changed, 182 insertions(+), 75 deletions(-) diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 8c354c99cb..4ddafaf06c 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -224,6 +224,10 @@ export function createModel (builder: Builder): void { presenter: recruit.component.ApplicationPresenter }) + builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ObjectValidator, { + validator: recruit.validator.ApplicantValidator + }) + builder.createDoc( view.class.Action, core.space.Model, diff --git a/models/recruit/src/migration.ts b/models/recruit/src/migration.ts index 575bad5f0b..bd4e52f6b2 100644 --- a/models/recruit/src/migration.ts +++ b/models/recruit/src/migration.ts @@ -25,22 +25,35 @@ function logInfo (msg: string, result: MigrationResult): void { } export const recruitOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise { - logInfo('done for Applicants', await client.update(DOMAIN_TASK, { _class: recruit.class.Applicant, doneState: { $exists: false } }, { doneState: null })) + logInfo( + 'done for Applicants', + await client.update( + DOMAIN_TASK, + { _class: recruit.class.Applicant, doneState: { $exists: false } }, + { doneState: null } + ) + ) - logInfo('$move employee => assignee', await client.update( - DOMAIN_TASK, - { _class: recruit.class.Applicant, employee: { $exists: true } }, - { $rename: { employee: 'assignee' } } - )) + logInfo( + '$move employee => assignee', + await client.update( + DOMAIN_TASK, + { _class: recruit.class.Applicant, employee: { $exists: true } }, + { $rename: { employee: 'assignee' } } + ) + ) - const employees = (await client.find(DOMAIN_CONTACT, { _class: contact.class.Employee })).map(emp => emp._id) + const employees = (await client.find(DOMAIN_CONTACT, { _class: contact.class.Employee })).map((emp) => emp._id) // update assignee to unassigned if there is no employee exists. - logInfo('applicants wrong assignee', await client.update( - DOMAIN_TASK, - { _class: recruit.class.Applicant, assignee: { $not: { $in: employees } } }, - { assignee: null } - )) + logInfo( + 'applicants wrong assignee', + await client.update( + DOMAIN_TASK, + { _class: recruit.class.Applicant, assignee: { $not: { $in: employees } } }, + { assignee: null } + ) + ) }, async upgrade (client: MigrationUpgradeClient): Promise { console.log('Recruit: Performing model upgrades') diff --git a/models/recruit/src/plugin.ts b/models/recruit/src/plugin.ts index 7394e25fb9..31293ae2cb 100644 --- a/models/recruit/src/plugin.ts +++ b/models/recruit/src/plugin.ts @@ -13,8 +13,8 @@ // limitations under the License. // -import type { Doc, Ref, Space } from '@anticrm/core' -import type { IntlString, Resource } from '@anticrm/platform' +import type { Client, Doc, Ref, Space } from '@anticrm/core' +import type { IntlString, Resource, Status } from '@anticrm/platform' import { mergeIds } from '@anticrm/platform' import { recruitId } from '@anticrm/recruit' import recruit from '@anticrm/recruit-resources/src/plugin' @@ -40,6 +40,9 @@ export default mergeIds(recruitId, recruit, { Candidates: '' as IntlString, Vacancy: '' as IntlString }, + validator: { + ApplicantValidator: '' as Resource<(doc: T, client: Client) => Promise> + }, component: { CreateVacancy: '' as AnyComponent, CreateCandidates: '' as AnyComponent, diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 769c715b4c..c68d9338d5 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -13,13 +13,13 @@ // limitations under the License. // -import type { Class, Doc, Ref, Space } from '@anticrm/core' +import type { Class, Client, Doc, Ref, Space } from '@anticrm/core' import { DOMAIN_MODEL } from '@anticrm/core' import { Builder, Mixin, Model } from '@anticrm/model' import core, { TClass, TDoc } from '@anticrm/model-core' -import type { Asset, IntlString, Resource } from '@anticrm/platform' +import type { Asset, IntlString, Resource, Status } from '@anticrm/platform' import type { AnyComponent } from '@anticrm/ui' -import type { Action, ActionTarget, AttributeEditor, AttributePresenter, ObjectEditor, Viewlet, ViewletDescriptor } from '@anticrm/view' +import type { Action, ActionTarget, AttributeEditor, AttributePresenter, ObjectEditor, ObjectValidator, Viewlet, ViewletDescriptor } from '@anticrm/view' import view from './plugin' @Mixin(view.mixin.AttributeEditor, core.class.Class) @@ -37,6 +37,11 @@ export class TObjectEditor extends TClass implements ObjectEditor { editor!: AnyComponent } +@Mixin(view.mixin.ObjectValidator, core.class.Class) +export class TObjectValidator extends TClass implements ObjectValidator { + validator!: Resource<((doc: T, client: Client) => Promise>)> +} + @Model(view.class.ViewletDescriptor, core.class.Doc, DOMAIN_MODEL) export class TViewletDescriptor extends TDoc implements ViewletDescriptor { component!: AnyComponent @@ -65,7 +70,7 @@ export class TActionTarget extends TDoc implements ActionTarget { } export function createModel (builder: Builder): void { - builder.createModel(TAttributeEditor, TAttributePresenter, TObjectEditor, TViewletDescriptor, TViewlet, TAction, TActionTarget) + builder.createModel(TAttributeEditor, TAttributePresenter, TObjectEditor, TViewletDescriptor, TViewlet, TAction, TActionTarget, TObjectValidator) builder.mixin(core.class.TypeString, core.class.Class, view.mixin.AttributeEditor, { editor: view.component.StringEditor diff --git a/plugins/recruit-resources/src/components/CreateApplication.svelte b/plugins/recruit-resources/src/components/CreateApplication.svelte index bb4380710c..cdbc7b4a73 100644 --- a/plugins/recruit-resources/src/components/CreateApplication.svelte +++ b/plugins/recruit-resources/src/components/CreateApplication.svelte @@ -15,16 +15,17 @@ { dispatch('close') }} @@ -117,13 +136,13 @@ {#if !preserveCandidate} - + {/if} diff --git a/plugins/recruit-resources/src/index.ts b/plugins/recruit-resources/src/index.ts index 253fdc84c6..d889255729 100644 --- a/plugins/recruit-resources/src/index.ts +++ b/plugins/recruit-resources/src/index.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import type { Doc } from '@anticrm/core' +import type { Client, Doc } from '@anticrm/core' import CreateVacancy from './components/CreateVacancy.svelte' import CreateCandidates from './components/CreateCandidates.svelte' @@ -29,16 +29,38 @@ import Applications from './components/Applications.svelte' import EditApplication from './components/EditApplication.svelte' import { showPopup } from '@anticrm/ui' -import { Resources } from '@anticrm/platform' +import { OK, Resources, Severity, Status } from '@anticrm/platform' +import { Applicant } from '@anticrm/recruit' +import recruit from './plugin' async function createApplication (object: Doc): Promise { showPopup(CreateApplication, { candidate: object._id, preserveCandidate: true }) } +export async function applicantValidator (applicant: Applicant, client: Client): Promise { + if (applicant.attachedTo === undefined) { + return new Status(Severity.INFO, recruit.status.CandidateRequired, {}) + } + if (applicant.space === undefined) { + return new Status(Severity.INFO, recruit.status.VacancyRequired, {}) + } + const applicants = await client.findAll(recruit.class.Applicant, { + space: applicant.space, + attachedTo: applicant.attachedTo + }) + if (applicants.filter((p) => p._id !== applicant._id).length > 0) { + return new Status(Severity.ERROR, recruit.status.ApplicationExists, {}) + } + return OK +} + export default async (): Promise => ({ actionImpl: { CreateApplication: createApplication }, + validator: { + ApplicantValidator: applicantValidator + }, component: { CreateVacancy, CreateCandidates, diff --git a/plugins/view-resources/package.json b/plugins/view-resources/package.json index e8f9740f0b..377ecf5de9 100644 --- a/plugins/view-resources/package.json +++ b/plugins/view-resources/package.json @@ -35,6 +35,7 @@ "@anticrm/core": "~0.6.11", "@anticrm/view": "~0.6.0", "@anticrm/ui": "~0.6.0", + "@anticrm/task": "~0.6.0", "@anticrm/presentation": "~0.6.2" } } diff --git a/plugins/view-resources/src/components/Move.svelte b/plugins/view-resources/src/components/Move.svelte index 005b2f2b49..28c933dc82 100644 --- a/plugins/view-resources/src/components/Move.svelte +++ b/plugins/view-resources/src/components/Move.svelte @@ -14,19 +14,20 @@ // limitations under the License. -->
-
+
-
+ +
- {#if currentSpace} - - {/if} + {#await getSpace() then} + {#if currentSpace} + + {/if} + {/await}