Send emails to applicants action (#5615)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2024-05-17 16:56:00 +05:00 committed by GitHub
parent 1041755e29
commit 7128585f05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 65 additions and 37 deletions

View File

@ -433,7 +433,6 @@ export function createModel (builder: Builder): void {
},
label: chunter.string.CopyLink,
icon: chunter.icon.Copy,
keyBinding: [],
input: 'none',
category: chunter.category.Chunter,
target: activity.class.ActivityMessage,

View File

@ -361,7 +361,6 @@ function defineDocument (builder: Builder): void {
},
label: document.string.CopyDocumentUrl,
icon: view.icon.CopyLink,
keyBinding: [],
input: 'focus',
category: document.category.Document,
target: document.class.Document,

View File

@ -233,7 +233,6 @@ export function createModel (builder: Builder): void {
label: gmail.string.WriteEmail,
icon: contact.icon.Email,
visibilityTester: gmail.function.HasEmail,
keyBinding: [],
input: 'any',
category: contact.category.Contact,
target: contact.class.Contact,

View File

@ -18,7 +18,6 @@ export function createPublicLinkAction (builder: Builder, _class: Ref<Class<Doc>
},
label: guest.string.PublicLink,
icon: guest.icon.Link,
keyBinding: [],
input: 'any',
category: guest.category.Guest,
target: _class,

View File

@ -448,7 +448,6 @@ export function createModel (builder: Builder): void {
},
label: hr.string.Department,
icon: hr.icon.Department,
keyBinding: [],
input: 'none',
category: hr.category.HR,
target: hr.mixin.Staff,

View File

@ -589,7 +589,6 @@ export function createModel (builder: Builder): void {
},
label: lead.string.CreateLead,
icon: lead.icon.Lead,
keyBinding: [],
input: 'none',
category: lead.category.Lead,
target: core.class.Doc,

View File

@ -624,7 +624,6 @@ export function createModel (builder: Builder): void {
action: notification.actionImpl.ArchiveAll,
label: notification.string.ArchiveAll,
icon: view.icon.CheckCircle,
keyBinding: [],
input: 'none',
category: notification.category.Notification,
target: core.class.Doc,
@ -642,7 +641,6 @@ export function createModel (builder: Builder): void {
action: notification.actionImpl.ReadAll,
label: notification.string.MarkReadAll,
icon: view.icon.Eye,
keyBinding: [],
input: 'none',
category: notification.category.Notification,
target: core.class.Doc,
@ -660,7 +658,6 @@ export function createModel (builder: Builder): void {
action: notification.actionImpl.UnreadAll,
label: notification.string.MarkUnreadAll,
icon: view.icon.EyeCrossed,
keyBinding: [],
input: 'none',
category: notification.category.Notification,
target: core.class.Doc,

View File

@ -42,6 +42,7 @@
"@hcengineering/model-notification": "^0.6.0",
"@hcengineering/model-presentation": "^0.6.0",
"@hcengineering/model-tags": "^0.6.0",
"@hcengineering/model-gmail": "^0.6.0",
"@hcengineering/model-task": "^0.6.0",
"@hcengineering/model-tracker": "^0.6.0",
"@hcengineering/model-view": "^0.6.0",

View File

@ -33,6 +33,7 @@ import { type IntlString } from '@hcengineering/platform'
import { recruitId, type Applicant } from '@hcengineering/recruit'
import setting from '@hcengineering/setting'
import { type KeyBinding, type ViewOptionModel, type ViewOptionsModel } from '@hcengineering/view'
import gmail from '@hcengineering/model-gmail'
import recruit from './plugin'
import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review'
@ -988,7 +989,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.CreateVacancy,
icon: recruit.icon.Create,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: core.class.Doc,
@ -1009,7 +1009,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.CreateApplication,
icon: recruit.icon.Create,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: core.class.Doc,
@ -1164,7 +1163,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.AssignRecruiter,
icon: contact.icon.Person,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: recruit.class.Applicant,
@ -1205,7 +1203,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.CopyId,
icon: view.icon.CopyId,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: recruit.class.Applicant,
@ -1226,7 +1223,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.CopyLink,
icon: view.icon.CopyLink,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: recruit.class.Applicant,
@ -1247,7 +1243,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.CopyLink,
icon: view.icon.CopyLink,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: recruit.class.Vacancy,
@ -1469,7 +1464,6 @@ export function createModel (builder: Builder): void {
},
input: 'any',
category: recruit.category.Recruit,
keyBinding: [],
target: recruit.mixin.Candidate,
context: {
mode: ['context', 'browser'],
@ -1538,7 +1532,6 @@ export function createModel (builder: Builder): void {
},
label: recruit.string.GetTalentIds,
icon: view.icon.CopyId,
keyBinding: [],
input: 'any',
category: recruit.category.Recruit,
target: recruit.mixin.Candidate,
@ -1551,5 +1544,29 @@ export function createModel (builder: Builder): void {
recruit.action.GetTalentIds
)
createAction(
builder,
{
action: view.actionImpl.ShowPopup,
actionProps: {
component: gmail.component.NewMessages,
element: 'float',
fillProps: {
attachedTo: 'value'
}
},
label: gmail.string.WriteEmail,
icon: contact.icon.Email,
visibilityTester: recruit.function.ApplicantHasEmail,
input: 'any',
category: recruit.category.Recruit,
target: recruit.class.Applicant,
context: {
mode: ['context', 'browser']
}
},
recruit.action.WriteEmail
)
defineSpaceType(builder)
}

View File

@ -21,7 +21,14 @@ import { recruitId } from '@hcengineering/recruit'
import recruit from '@hcengineering/recruit-resources/src/plugin'
import { type TaskTypeDescriptor, type ProjectType } from '@hcengineering/task'
import type { AnyComponent, Location } from '@hcengineering/ui/src/types'
import type { Action, ActionCategory, ViewAction, ViewQueryAction, Viewlet } from '@hcengineering/view'
import type {
Action,
ActionCategory,
ViewAction,
ViewActionAvailabilityFunction,
ViewQueryAction,
Viewlet
} from '@hcengineering/view'
import { type DocUpdateMessageViewlet } from '@hcengineering/activity'
import { type ChatMessageViewlet } from '@hcengineering/chunter'
@ -34,6 +41,7 @@ export default mergeIds(recruitId, recruit, {
CopyCandidateLink: '' as Ref<Action<Doc, any>>,
MoveApplicant: '' as Ref<Action>,
GetTalentIds: '' as Ref<Action<Doc, any>>,
WriteEmail: '' as Ref<Action<Doc, any>>,
EditStatuses: '' as Ref<Action>
},
actionImpl: {
@ -49,7 +57,8 @@ export default mergeIds(recruitId, recruit, {
GetObjectLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
GetTalentId: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
HideDoneState: '' as ViewQueryAction,
HideArchivedVacancies: '' as ViewQueryAction
HideArchivedVacancies: '' as ViewQueryAction,
ApplicantHasEmail: '' as Resource<ViewActionAvailabilityFunction>
},
string: {
ApplicationsShort: '' as IntlString,

View File

@ -255,7 +255,6 @@ export function createModel (builder: Builder): void {
},
label: time.string.CreateToDo,
icon: time.icon.Calendar,
keyBinding: [],
input: 'none',
category: time.category.Time,
target: core.class.Doc,
@ -281,7 +280,6 @@ export function createModel (builder: Builder): void {
},
label: time.string.CreateToDo,
icon: time.icon.Calendar,
keyBinding: [],
input: 'none',
category: time.category.Time,
target: core.class.Doc,
@ -303,7 +301,6 @@ export function createModel (builder: Builder): void {
},
label: time.string.EditToDo,
icon: view.icon.Edit,
keyBinding: [],
input: 'focus',
category: time.category.Time,
target: time.class.ToDo,

View File

@ -233,7 +233,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.NewIssue,
icon: tracker.icon.NewIssue,
keyBinding: [],
input: 'none',
category: tracker.category.Tracker,
target: core.class.Doc,
@ -259,7 +258,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.NewSubIssue,
icon: tracker.icon.Subissue,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -285,7 +283,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.SetParent,
icon: tracker.icon.Parent,
keyBinding: [],
input: 'none',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -312,7 +309,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.NewRelatedIssue,
icon: tracker.icon.NewIssue,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: core.class.Doc,
@ -336,7 +332,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.SetParent,
icon: tracker.icon.Parent,
keyBinding: [],
input: 'none',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -582,7 +577,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.CopyIssueId,
icon: view.icon.CopyId,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -603,7 +597,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.CopyIssueTitle,
icon: tracker.icon.CopyBranch,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -624,7 +617,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.CopyIssueUrl,
icon: view.icon.CopyLink,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -642,7 +634,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
action: tracker.actionImpl.Move,
label: tracker.string.MoveToProject,
icon: view.icon.Move,
keyBinding: [],
input: 'any',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -665,7 +656,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.Relations,
icon: tracker.icon.Relations,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -691,7 +681,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.Duplicate,
icon: tracker.icon.Duplicate,
keyBinding: [],
input: 'focus',
category: tracker.category.Tracker,
target: tracker.class.Issue,
@ -736,7 +725,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
},
label: tracker.string.MapRelatedIssues,
icon: tracker.icon.Relations,
keyBinding: [],
input: 'none',
category: tracker.category.Tracker,
target: core.class.Space,

View File

@ -79,7 +79,6 @@ export function createModel (builder: Builder): void {
},
label: getEmbeddedLabel('Server statistics'),
icon: view.icon.Configure,
keyBinding: [],
input: 'none',
category: view.category.General,
target: core.class.Doc,

View File

@ -24,8 +24,9 @@ import {
type RelatedDocument
} from '@hcengineering/core'
import { OK, Severity, Status, type Resources } from '@hcengineering/platform'
import { createQuery, type ObjectSearchResult } from '@hcengineering/presentation'
import { createQuery, getClient, type ObjectSearchResult } from '@hcengineering/presentation'
import { type Applicant, type Candidate, type Vacancy } from '@hcengineering/recruit'
import contact from '@hcengineering/contact'
import task from '@hcengineering/task'
import { showPopup } from '@hcengineering/ui'
import { type Filter } from '@hcengineering/view'
@ -316,6 +317,30 @@ export async function hideArchivedVacancies (value: any, query: DocumentQuery<Do
return query
}
export async function applicantHasEmail (doc: Doc | Doc[] | undefined): Promise<boolean> {
if (doc === undefined) return false
const client = getClient()
const applicants = Array.isArray(doc) ? (doc as Applicant[]) : ([doc] as Applicant[])
const hierarchy = client.getHierarchy()
for (const app of applicants) {
if (!hierarchy.isDerived(app._class, recruit.class.Applicant)) return false
}
const ids = applicants.map((p) => p.attachedTo)
const res = await client.findAll(
contact.class.Channel,
{
provider: contact.channelProvider.Email,
attachedTo: { $in: ids }
},
{ projection: { _id: 1, attachedTo: 1 } }
)
const set = new Set(res.map((p) => p.attachedTo))
for (const val of ids) {
if (!set.has(val)) return false
}
return true
}
export default async (): Promise<Resources> => ({
actionImpl: {
CreateOpinion: createOpinion,
@ -385,7 +410,8 @@ export default async (): Promise<Resources> => ({
GetObjectLinkFragment: getSequenceLink,
GetIdObjectLinkFragment: getObjectLink,
HideDoneState: hideDoneState,
HideArchivedVacancies: hideArchivedVacancies
HideArchivedVacancies: hideArchivedVacancies,
ApplicantHasEmail: applicantHasEmail
},
resolver: {
Location: resolveLocation