mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Inactive employee (#2157)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
61216392e9
commit
168ae1cd54
@ -2,6 +2,11 @@
|
||||
|
||||
## 0.6.30 (upcoming)
|
||||
|
||||
Core:
|
||||
|
||||
- Allow to leave workspace
|
||||
- Allow to kick employee
|
||||
|
||||
HR:
|
||||
|
||||
- Allow to change assignee in Kanban
|
||||
|
@ -37,6 +37,7 @@
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/platform": "~0.6.6",
|
||||
"@anticrm/contact": "~0.6.5",
|
||||
"@anticrm/contact-resources": "~0.6.0"
|
||||
"@anticrm/contact-resources": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,8 @@ export class TStatus extends TAttachedDoc implements Status {
|
||||
@Model(contact.class.Employee, contact.class.Person)
|
||||
@UX(contact.string.Employee, contact.icon.Person, undefined, 'name')
|
||||
export class TEmployee extends TPerson implements Employee {
|
||||
active!: boolean
|
||||
|
||||
@Prop(Collection(contact.class.Status), contact.string.Status)
|
||||
statuses?: number
|
||||
}
|
||||
@ -243,7 +245,7 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Employee, core.class.Class, view.mixin.AttributeEditor, {
|
||||
inlineEditor: contact.component.PersonEditor
|
||||
inlineEditor: contact.component.EmployeeEditor
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Channel, core.class.Class, view.mixin.AttributePresenter, {
|
||||
@ -393,6 +395,22 @@ export function createModel (builder: Builder): void {
|
||||
group: 'create'
|
||||
}
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
action: contact.actionImpl.KickEmployee,
|
||||
label: contact.string.KickEmployee,
|
||||
category: contact.category.Contact,
|
||||
target: contact.class.Employee,
|
||||
input: 'focus',
|
||||
context: {
|
||||
mode: ['context'],
|
||||
group: 'other'
|
||||
}
|
||||
},
|
||||
contact.action.KickEmployee
|
||||
)
|
||||
}
|
||||
|
||||
export { contactOperation } from './migration'
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { TxOperations } from '@anticrm/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
||||
import core from '@anticrm/model-core'
|
||||
import contact from './index'
|
||||
import contact, { DOMAIN_CONTACT } from './index'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
@ -56,8 +56,22 @@ async function createSpace (tx: TxOperations): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function setActiveEmployee (client: MigrationClient): Promise<void> {
|
||||
await client.update(
|
||||
DOMAIN_CONTACT,
|
||||
{
|
||||
_class: contact.class.Employee
|
||||
},
|
||||
{
|
||||
active: true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const contactOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await setActiveEmployee(client)
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
|
@ -20,6 +20,7 @@ import {} from '@anticrm/core'
|
||||
import { ObjectSearchCategory, ObjectSearchFactory } from '@anticrm/model-presentation'
|
||||
import { IntlString, mergeIds, Resource } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import { Action, ActionCategory, ViewAction } from '@anticrm/view'
|
||||
|
||||
export default mergeIds(contactId, contact, {
|
||||
component: {
|
||||
@ -38,7 +39,8 @@ export default mergeIds(contactId, contact, {
|
||||
Members: '' as AnyComponent,
|
||||
MemberPresenter: '' as AnyComponent,
|
||||
EditMember: '' as AnyComponent,
|
||||
EmployeeArrayEditor: '' as AnyComponent
|
||||
EmployeeArrayEditor: '' as AnyComponent,
|
||||
EmployeeEditor: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
Persons: '' as IntlString,
|
||||
@ -71,5 +73,14 @@ export default mergeIds(contactId, contact, {
|
||||
EmployeeCategory: '' as Ref<ObjectSearchCategory>,
|
||||
PersonCategory: '' as Ref<ObjectSearchCategory>,
|
||||
OrganizationCategory: '' as Ref<ObjectSearchCategory>
|
||||
},
|
||||
category: {
|
||||
Contact: '' as Ref<ActionCategory>
|
||||
},
|
||||
action: {
|
||||
KickEmployee: '' as Ref<Action>
|
||||
},
|
||||
actionImpl: {
|
||||
KickEmployee: '' as ViewAction
|
||||
}
|
||||
})
|
||||
|
@ -54,7 +54,8 @@ export const demoOperation: MigrateOperation = {
|
||||
if (current === undefined) {
|
||||
const employee = await tx.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name: 'Chen,Rosamund',
|
||||
city: 'Mountain View'
|
||||
city: 'Mountain View',
|
||||
active: true
|
||||
})
|
||||
|
||||
await tx.createDoc<EmployeeAccount>(contact.class.EmployeeAccount, core.space.Model, {
|
||||
|
60
packages/presentation/src/components/EmployeeBox.svelte
Normal file
60
packages/presentation/src/components/EmployeeBox.svelte
Normal file
@ -0,0 +1,60 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 contact, { Employee } from '@anticrm/contact'
|
||||
import type { Class, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { ButtonKind, ButtonSize, LabelAndProps } from '@anticrm/ui'
|
||||
import presentation from '..'
|
||||
import IconPerson from './icons/Person.svelte'
|
||||
import UserBox from './UserBox.svelte'
|
||||
|
||||
export let _class: Ref<Class<Employee>> = contact.class.Employee
|
||||
export let options: FindOptions<Employee> | undefined = undefined
|
||||
export let docQuery: DocumentQuery<Employee> | undefined = {
|
||||
active: true
|
||||
}
|
||||
export let label: IntlString
|
||||
export let placeholder: IntlString = presentation.string.Search
|
||||
export let value: Ref<Employee> | null | undefined
|
||||
export let allowDeselect = false
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let focusIndex = -1
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
</script>
|
||||
|
||||
<UserBox
|
||||
{_class}
|
||||
{options}
|
||||
{docQuery}
|
||||
{label}
|
||||
icon={IconPerson}
|
||||
{placeholder}
|
||||
bind:value
|
||||
{allowDeselect}
|
||||
{titleDeselect}
|
||||
{kind}
|
||||
{size}
|
||||
{justify}
|
||||
{width}
|
||||
{focusIndex}
|
||||
{showTooltip}
|
||||
on:change
|
||||
/>
|
@ -16,7 +16,6 @@
|
||||
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import {
|
||||
AnyComponent,
|
||||
Button,
|
||||
CheckBox,
|
||||
createFocusManager,
|
||||
@ -32,6 +31,7 @@
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import presentation from '..'
|
||||
import { createQuery, getClient } from '../utils'
|
||||
import { ObjectCreate } from '../types'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let options: FindOptions<Doc> | undefined = undefined
|
||||
@ -53,13 +53,7 @@
|
||||
|
||||
export let groupBy = '_class'
|
||||
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
update: (doc: Doc) => string
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
|
||||
let search: string = ''
|
||||
let objects: Doc[] = []
|
||||
@ -151,7 +145,7 @@
|
||||
// We expect reference to new object.
|
||||
const newPerson = await client.findOne(_class, { _id: res })
|
||||
if (newPerson !== undefined) {
|
||||
search = c.update(newPerson)
|
||||
search = c.update?.(newPerson) ?? ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -23,7 +23,6 @@
|
||||
Button,
|
||||
eventToHTMLElement,
|
||||
getFocusManager,
|
||||
AnyComponent,
|
||||
Tooltip,
|
||||
TooltipAlignment,
|
||||
ButtonKind,
|
||||
@ -33,6 +32,7 @@
|
||||
|
||||
import type { Ref, Class, Space, DocumentQuery } from '@anticrm/core'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { ObjectCreate } from '../types'
|
||||
|
||||
export let _class: Ref<Class<Space>>
|
||||
export let spaceQuery: DocumentQuery<Space> | undefined = { archived: false }
|
||||
@ -40,17 +40,13 @@
|
||||
export let value: Ref<Space> | undefined
|
||||
export let focusIndex = -1
|
||||
export let focus = false
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let allowDeselect = false
|
||||
|
||||
let selected: Space | undefined
|
||||
|
||||
@ -70,6 +66,7 @@
|
||||
{
|
||||
_class,
|
||||
label,
|
||||
allowDeselect,
|
||||
options: { sort: { modifiedOn: -1 } },
|
||||
selected,
|
||||
spaceQuery,
|
||||
|
@ -15,7 +15,8 @@
|
||||
<script lang="ts">
|
||||
import type { Class, DocumentQuery, Ref, Space } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { AnyComponent, ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||
import { ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||
import { ObjectCreate } from '../types'
|
||||
import SpaceSelect from './SpaceSelect.svelte'
|
||||
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
@ -26,13 +27,9 @@
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let allowDeselect = false
|
||||
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
</script>
|
||||
|
||||
<SpaceSelect
|
||||
@ -41,6 +38,7 @@
|
||||
focusIndex={-10}
|
||||
{_class}
|
||||
spaceQuery={query}
|
||||
{allowDeselect}
|
||||
{label}
|
||||
{size}
|
||||
{kind}
|
||||
|
@ -14,20 +14,15 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, DocumentQuery, Ref, Space } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { AnyComponent } from '@anticrm/ui'
|
||||
import { ObjectCreate } from '../types'
|
||||
import ObjectPopup from './ObjectPopup.svelte'
|
||||
import SpaceInfo from './SpaceInfo.svelte'
|
||||
|
||||
export let _class: Ref<Class<Space>>
|
||||
export let selected: Ref<Space> | undefined
|
||||
export let spaceQuery: DocumentQuery<Space> | undefined
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
export let allowDeselect = false
|
||||
|
||||
$: _create =
|
||||
create !== undefined
|
||||
@ -43,7 +38,7 @@
|
||||
{selected}
|
||||
bind:docQuery={spaceQuery}
|
||||
multiSelect={false}
|
||||
allowDeselect={false}
|
||||
{allowDeselect}
|
||||
shadows={true}
|
||||
create={_create}
|
||||
on:update
|
||||
|
@ -15,10 +15,9 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Contact, formatName } from '@anticrm/contact'
|
||||
import type { Class, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { Class, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
import {
|
||||
AnyComponent,
|
||||
AnySvelteComponent,
|
||||
Button,
|
||||
ButtonKind,
|
||||
@ -30,6 +29,7 @@
|
||||
} from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation from '..'
|
||||
import { ObjectCreate } from '../types'
|
||||
import { getClient } from '../utils'
|
||||
import IconPerson from './icons/Person.svelte'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
@ -38,6 +38,7 @@
|
||||
export let _class: Ref<Class<Contact>>
|
||||
export let excluded: Ref<Contact>[] | undefined = undefined
|
||||
export let options: FindOptions<Contact> | undefined = undefined
|
||||
export let docQuery: DocumentQuery<Contact> | undefined = undefined
|
||||
export let label: IntlString
|
||||
export let icon: Asset | AnySvelteComponent | undefined = IconPerson
|
||||
export let placeholder: IntlString = presentation.string.Search
|
||||
@ -52,12 +53,7 @@
|
||||
export let focusIndex = -1
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -85,6 +81,7 @@
|
||||
{
|
||||
_class,
|
||||
options,
|
||||
docQuery,
|
||||
ignoreUsers: excluded ?? [],
|
||||
icon,
|
||||
allowDeselect,
|
||||
@ -108,54 +105,31 @@
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
$: hideIcon = size === 'x-large' || (size === 'large' && kind !== 'link')
|
||||
</script>
|
||||
|
||||
<div bind:this={container} class="min-w-0" class:w-full={width === '100%'}>
|
||||
{#if kind !== 'link'}
|
||||
<Button
|
||||
{focusIndex}
|
||||
icon={size === 'x-large' && selected ? undefined : icon}
|
||||
width={width ?? 'min-content'}
|
||||
{size}
|
||||
{kind}
|
||||
{justify}
|
||||
{showTooltip}
|
||||
on:click={_click}
|
||||
>
|
||||
<span slot="content" class="overflow-label disabled">
|
||||
{#if selected}
|
||||
{#if size === 'x-large'}
|
||||
<UserInfo value={selected} size={'medium'} {icon} />
|
||||
{:else}
|
||||
{getName(selected)}
|
||||
{/if}
|
||||
<Button
|
||||
{focusIndex}
|
||||
icon={hideIcon && selected ? undefined : icon}
|
||||
width={width ?? 'min-content'}
|
||||
{size}
|
||||
{kind}
|
||||
{justify}
|
||||
{showTooltip}
|
||||
on:click={_click}
|
||||
>
|
||||
<span slot="content" class="overflow-label disabled">
|
||||
{#if selected}
|
||||
{#if hideIcon}
|
||||
<UserInfo value={selected} size={kind === 'link' ? 'x-small' : 'medium'} {icon} />
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{getName(selected)}
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
{focusIndex}
|
||||
icon={(size === 'x-large' || size === 'large') && selected ? undefined : icon}
|
||||
width={width ?? 'min-content'}
|
||||
{size}
|
||||
{kind}
|
||||
{justify}
|
||||
{showTooltip}
|
||||
on:click={_click}
|
||||
>
|
||||
<span slot="content" class="overflow-label disabled">
|
||||
{#if selected}
|
||||
{#if size === 'x-large' || size === 'large'}
|
||||
<UserInfo value={selected} size={'x-small'} {icon} />
|
||||
{:else}
|
||||
{getName(selected)}
|
||||
{/if}
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
{/if}
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -13,20 +13,22 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Person } from '@anticrm/contact'
|
||||
import type { Class, Doc, Ref } from '@anticrm/core'
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import type { Class, DocumentQuery, Ref } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { translate } from '@anticrm/platform'
|
||||
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@anticrm/ui'
|
||||
import { ButtonKind, ButtonSize, Label, TooltipAlignment } from '@anticrm/ui'
|
||||
import { Tooltip, showPopup, Button } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation, { CombineAvatars, UsersPopup } from '..'
|
||||
import { createQuery } from '../utils'
|
||||
import Members from './icons/Members.svelte'
|
||||
|
||||
export let items: Ref<Person>[] = []
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let items: Ref<Employee>[] = []
|
||||
export let _class: Ref<Class<Employee>> = contact.class.Employee
|
||||
export let label: IntlString
|
||||
export let docQuery: DocumentQuery<Employee> | undefined = {
|
||||
active: true
|
||||
}
|
||||
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
@ -34,11 +36,11 @@
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
|
||||
let persons: Person[] = []
|
||||
let persons: Employee[] = []
|
||||
|
||||
const query = createQuery()
|
||||
|
||||
$: query.query<Person>(_class, { _id: { $in: items } }, (result) => {
|
||||
$: query.query<Employee>(_class, { _id: { $in: items } }, (result) => {
|
||||
persons = result
|
||||
})
|
||||
|
||||
@ -50,6 +52,7 @@
|
||||
{
|
||||
_class,
|
||||
label,
|
||||
docQuery,
|
||||
multiSelect: true,
|
||||
allowDeselect: false,
|
||||
selectedUsers: items
|
||||
@ -80,9 +83,9 @@
|
||||
{#if persons.length > 0}
|
||||
<div class="flex-row-center flex-nowrap pointer-events-none">
|
||||
<CombineAvatars {_class} bind:items size={'inline'} />
|
||||
{#await translate(presentation.string.NumberMembers, { count: persons.length }) then text}
|
||||
<span class="overflow-label ml-1-5">{text}</span>
|
||||
{/await}
|
||||
<span class="overflow-label ml-1-5">
|
||||
<Label label={presentation.string.NumberMembers} params={{ count: persons.length }} />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
@ -15,17 +15,19 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import { Contact, getFirstName, Person } from '@anticrm/contact'
|
||||
import type { Class, Doc, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
import { AnyComponent, AnySvelteComponent, Icon, Label } from '@anticrm/ui'
|
||||
import { AnySvelteComponent, Icon, Label } from '@anticrm/ui'
|
||||
import presentation from '..'
|
||||
import { getClient } from '../utils'
|
||||
import ObjectPopup from './ObjectPopup.svelte'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
import { ObjectCreate } from '../types'
|
||||
|
||||
export let _class: Ref<Class<Contact>>
|
||||
export let options: FindOptions<Contact> | undefined = undefined
|
||||
export let selected: Ref<Person> | undefined
|
||||
export let docQuery: DocumentQuery<Contact> | undefined = undefined
|
||||
|
||||
export let multiSelect: boolean = false
|
||||
export let allowDeselect: boolean = false
|
||||
@ -35,14 +37,9 @@
|
||||
export let ignoreUsers: Ref<Person>[] = []
|
||||
export let shadows: boolean = true
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
|
||||
const hierarchy = getClient().getHierarchy()
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
|
||||
$: _create =
|
||||
create !== undefined
|
||||
@ -68,6 +65,7 @@
|
||||
{allowDeselect}
|
||||
{titleDeselect}
|
||||
{placeholder}
|
||||
{docQuery}
|
||||
groupBy={'_class'}
|
||||
bind:selectedObjects={selectedUsers}
|
||||
bind:ignoreObjects={ignoreUsers}
|
||||
|
@ -37,6 +37,7 @@ export { default as SpacesMultiPopup } from './components/SpacesMultiPopup.svelt
|
||||
export { default as UserBox } from './components/UserBox.svelte'
|
||||
export { default as UserBoxList } from './components/UserBoxList.svelte'
|
||||
export { default as UserInfo } from './components/UserInfo.svelte'
|
||||
export { default as EmployeeBox } from './components/EmployeeBox.svelte'
|
||||
export { default as UsersPopup } from './components/UsersPopup.svelte'
|
||||
export { default as MembersBox } from './components/MembersBox.svelte'
|
||||
export { default as IconMembers } from './components/icons/Members.svelte'
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Client, Doc } from '@anticrm/core'
|
||||
import { Asset, IntlString, Resource } from '@anticrm/platform'
|
||||
import { AnySvelteComponent } from '@anticrm/ui'
|
||||
import { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -14,6 +14,15 @@ export interface ObjectSearchResult {
|
||||
iconProps?: any
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ObjectCreate {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
update?: (doc: Doc) => string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import { Class, Ref, Space } from '@anticrm/core'
|
||||
import { SpaceMultiBoxList, UserBoxList } from '@anticrm/presentation'
|
||||
import { DropdownLabelsIntl } from '@anticrm/ui'
|
||||
@ -31,7 +31,6 @@
|
||||
<div class="filterBlockContainer">
|
||||
<div class="simpleFilterButton">
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={selectedParticipants}
|
||||
label={attachment.string.FileBrowserFilterFrom}
|
||||
on:update={(evt) => {
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { AttachmentDroppable, AttachmentsPresenter } from '@anticrm/attachment-resources'
|
||||
import type { Card } from '@anticrm/board'
|
||||
import { CommentsPresenter } from '@anticrm/chunter-resources'
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import type { Ref, WithLookup } from '@anticrm/core'
|
||||
import notification from '@anticrm/notification'
|
||||
import view from '@anticrm/view'
|
||||
@ -217,12 +217,7 @@
|
||||
</div>
|
||||
{#if (object.members?.length ?? 0) > 0}
|
||||
<div class="flex justify-end mt-1 mb-2" style:pointer-events={dragoverAttachment ? 'none' : 'all'}>
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={object.members}
|
||||
label={board.string.Members}
|
||||
on:update={updateMembers}
|
||||
/>
|
||||
<UserBoxList items={object.members} label={board.string.Members} on:update={updateMembers} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import { Ref } from '@anticrm/core'
|
||||
|
||||
import { UserBoxList } from '@anticrm/presentation'
|
||||
@ -8,4 +8,4 @@
|
||||
export let value: Ref<Employee>[]
|
||||
</script>
|
||||
|
||||
<UserBoxList items={value} _class={contact.class.Employee} label={board.string.Members} on:update />
|
||||
<UserBoxList items={value} label={board.string.Members} on:update />
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@anticrm/core'
|
||||
import { createQuery, getClient, UserBox, MessageBox } from '@anticrm/presentation'
|
||||
import { createQuery, getClient, EmployeeBox, MessageBox } from '@anticrm/presentation'
|
||||
import type { TodoItem } from '@anticrm/task'
|
||||
import task, { calcRank } from '@anticrm/task'
|
||||
import {
|
||||
@ -30,7 +30,7 @@
|
||||
DateRangePresenter
|
||||
} from '@anticrm/ui'
|
||||
import { ContextMenu, HTMLPresenter } from '@anticrm/view-resources'
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
|
||||
import board from '../../plugin'
|
||||
import { getDateIcon } from '../../utils/BoardUtils'
|
||||
@ -273,8 +273,7 @@
|
||||
on:change={(e) => updateDueDate(item, e.detail)}
|
||||
noShift
|
||||
/>
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
<EmployeeBox
|
||||
label={board.string.Assignee}
|
||||
bind:value={item.assignee}
|
||||
allowDeselect={true}
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import { Class, Doc, getCurrentAccount, Ref } from '@anticrm/core'
|
||||
import { Card, getClient, UserBoxList } from '@anticrm/presentation'
|
||||
import ui, { EditBox, DateRangePresenter } from '@anticrm/ui'
|
||||
@ -71,6 +71,6 @@
|
||||
<svelte:fragment slot="pool">
|
||||
<DateRangePresenter bind:value withTime editable labelNull={ui.string.SelectDate} />
|
||||
<DateRangePresenter bind:value={dueDate} labelNull={calendar.string.DueTo} withTime editable />
|
||||
<UserBoxList _class={contact.class.Employee} bind:items={participants} label={calendar.string.Participants} />
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import { Class, Doc, getCurrentAccount, Ref } from '@anticrm/core'
|
||||
import { Card, getClient, UserBoxList } from '@anticrm/presentation'
|
||||
import ui, { EditBox, DateRangePresenter } from '@anticrm/ui'
|
||||
@ -74,6 +74,6 @@
|
||||
<svelte:fragment slot="pool">
|
||||
<!-- <TimeShiftPicker title={calendar.string.Date} bind:value direction="after" /> -->
|
||||
<DateRangePresenter bind:value withTime={true} editable={true} labelNull={ui.string.SelectDate} />
|
||||
<UserBoxList _class={contact.class.Employee} bind:items={participants} label={calendar.string.Participants} />
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -73,6 +73,9 @@
|
||||
<UsersPopup
|
||||
selected={undefined}
|
||||
_class={contact.class.Employee}
|
||||
docQuery={{
|
||||
active: true
|
||||
}}
|
||||
multiSelect={true}
|
||||
allowDeselect={true}
|
||||
selectedUsers={selectedEmployees}
|
||||
|
@ -70,9 +70,5 @@
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
label={chunter.string.Members}
|
||||
on:update={(evt) => (employeeIds = evt.detail)}
|
||||
/>
|
||||
<UserBoxList label={chunter.string.Members} on:update={(evt) => (employeeIds = evt.detail)} />
|
||||
</SpaceCreateCard>
|
||||
|
@ -63,6 +63,8 @@
|
||||
"Member": "Member",
|
||||
"Members": "Members",
|
||||
"NoMembers": "No members added",
|
||||
"AddMember": "Add member"
|
||||
"AddMember": "Add member",
|
||||
"KickEmployee": "Kick an employee",
|
||||
"KickEmployeeDescr": "Are you sure you want to kick the employee out of the workspace? This action cannot be undone"
|
||||
}
|
||||
}
|
@ -63,6 +63,8 @@
|
||||
"Member": "Сотрудник",
|
||||
"Members": "Сотрудники",
|
||||
"NoMembers": "Нет добавленных сотрудников",
|
||||
"AddMember": "Добавить сотрудника"
|
||||
"AddMember": "Добавить сотрудника",
|
||||
"KickEmployee": "Исключить сотрудника",
|
||||
"KickEmployeeDescr": "Вы действительно хотите выгнать сотрудника из рабочего пространства? Это действие нельзя отменить"
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@
|
||||
"@anticrm/notification-resources": "~0.6.0",
|
||||
"@anticrm/panel": "~0.6.0",
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"@anticrm/attachment": "~0.6.1"
|
||||
"@anticrm/attachment": "~0.6.1",
|
||||
"@anticrm/login-resources": "~0.6.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { Person } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import { Ref } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { UserBoxList } from '@anticrm/presentation'
|
||||
import contact from '../plugin'
|
||||
|
||||
export let label: IntlString
|
||||
export let value: Ref<Person>[]
|
||||
export let onChange: (refs: Ref<Person>[]) => void
|
||||
export let value: Ref<Employee>[]
|
||||
export let onChange: (refs: Ref<Employee>[]) => void
|
||||
|
||||
let timer: any
|
||||
|
||||
function onUpdate (evt: CustomEvent<Ref<Person>[]>): void {
|
||||
function onUpdate (evt: CustomEvent<Ref<Employee>[]>): void {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
onChange(evt.detail)
|
||||
@ -19,13 +18,4 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={value}
|
||||
{label}
|
||||
on:update={onUpdate}
|
||||
kind={'link'}
|
||||
size={'medium'}
|
||||
justify={'left'}
|
||||
width={'100%'}
|
||||
/>
|
||||
<UserBoxList items={value} {label} on:update={onUpdate} kind={'link'} size={'medium'} justify={'left'} width={'100%'} />
|
||||
|
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
// 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 { Employee } from '@anticrm/contact'
|
||||
import { DocumentQuery, Ref, RefTo } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { EmployeeBox } from '@anticrm/presentation'
|
||||
import contact from '../plugin'
|
||||
import { ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||
|
||||
export let value: Ref<Employee> | undefined
|
||||
export let label: IntlString = contact.string.Employee
|
||||
export let onChange: (value: any) => void
|
||||
export let type: RefTo<Employee> | undefined
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
|
||||
$: _class = type?.to ?? contact.class.Employee
|
||||
|
||||
const query: DocumentQuery<Employee> = {
|
||||
active: true
|
||||
}
|
||||
</script>
|
||||
|
||||
<EmployeeBox
|
||||
{_class}
|
||||
docQuery={query}
|
||||
{label}
|
||||
{kind}
|
||||
{size}
|
||||
{justify}
|
||||
{width}
|
||||
bind:value
|
||||
on:change={(e) => onChange(e.detail)}
|
||||
/>
|
@ -14,10 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Contact, formatName } from '@anticrm/contact'
|
||||
import { Contact, Employee, formatName } from '@anticrm/contact'
|
||||
import { Class, Client, Ref } from '@anticrm/core'
|
||||
import { Resources } from '@anticrm/platform'
|
||||
import { Avatar, ObjectSearchResult, UserInfo } from '@anticrm/presentation'
|
||||
import { Avatar, getClient, MessageBox, ObjectSearchResult, UserInfo } from '@anticrm/presentation'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import Channels from './components/Channels.svelte'
|
||||
import ChannelsEditor from './components/ChannelsEditor.svelte'
|
||||
import ChannelsPresenter from './components/ChannelsPresenter.svelte'
|
||||
@ -45,6 +46,8 @@ import Members from './components/Members.svelte'
|
||||
import MemberPresenter from './components/MemberPresenter.svelte'
|
||||
import EditMember from './components/EditMember.svelte'
|
||||
import EmployeeArrayEditor from './components/EmployeeArrayEditor.svelte'
|
||||
import EmployeeEditor from './components/EmployeeEditor.svelte'
|
||||
import { leaveWorkspace } from '@anticrm/login-resources'
|
||||
|
||||
export {
|
||||
Channels,
|
||||
@ -55,7 +58,8 @@ export {
|
||||
ChannelsDropdown,
|
||||
EmployeePresenter,
|
||||
EmployeeBrowser,
|
||||
MemberPresenter
|
||||
MemberPresenter,
|
||||
EmployeeEditor
|
||||
}
|
||||
|
||||
async function queryContact (
|
||||
@ -73,7 +77,30 @@ async function queryContact (
|
||||
}))
|
||||
}
|
||||
|
||||
async function kickEmployee (doc: Employee): Promise<void> {
|
||||
const client = getClient()
|
||||
const email = await client.findOne(contact.class.EmployeeAccount, { employee: doc._id })
|
||||
if (email === undefined) return
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: contact.string.KickEmployee,
|
||||
message: contact.string.KickEmployeeDescr
|
||||
},
|
||||
undefined,
|
||||
(res?: boolean) => {
|
||||
if (res === true) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
leaveWorkspace(email.email)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
actionImpl: {
|
||||
KickEmployee: kickEmployee
|
||||
},
|
||||
component: {
|
||||
PersonEditor,
|
||||
OrganizationEditor,
|
||||
@ -94,7 +121,8 @@ export default async (): Promise<Resources> => ({
|
||||
Members,
|
||||
MemberPresenter,
|
||||
EditMember,
|
||||
EmployeeArrayEditor
|
||||
EmployeeArrayEditor,
|
||||
EmployeeEditor
|
||||
},
|
||||
completion: {
|
||||
EmployeeQuery: async (client: Client, query: string) => await queryContact(contact.class.Employee, client, query),
|
||||
|
@ -56,6 +56,8 @@ export default mergeIds(contactId, contact, {
|
||||
Member: '' as IntlString,
|
||||
Members: '' as IntlString,
|
||||
NoMembers: '' as IntlString,
|
||||
AddMember: '' as IntlString
|
||||
AddMember: '' as IntlString,
|
||||
KickEmployee: '' as IntlString,
|
||||
KickEmployeeDescr: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -105,6 +105,7 @@ export interface Status extends AttachedDoc {
|
||||
* @public
|
||||
*/
|
||||
export interface Employee extends Person {
|
||||
active: boolean
|
||||
statuses?: number
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import { Ref } from '@anticrm/core'
|
||||
import { Card, getClient, SpaceSelector, UserBox } from '@anticrm/presentation'
|
||||
import { Card, getClient, SpaceSelector, EmployeeBox } from '@anticrm/presentation'
|
||||
import { Button, createFocusManager, EditBox, FocusHandler } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import hr from '../plugin'
|
||||
@ -74,16 +74,13 @@
|
||||
<SpaceSelector _class={hr.class.Department} label={hr.string.ParentDepartmentLabel} bind:space />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="pool">
|
||||
<UserBox
|
||||
<EmployeeBox
|
||||
focusIndex={3}
|
||||
_class={contact.class.Employee}
|
||||
label={hr.string.TeamLead}
|
||||
placeholder={hr.string.TeamLead}
|
||||
bind:value={lead}
|
||||
allowDeselect
|
||||
titleDeselect={hr.string.UnAssignLead}
|
||||
kind={'no-border'}
|
||||
size={'small'}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -52,7 +52,10 @@
|
||||
_class: contact.class.Employee,
|
||||
selected: value.$lookup?.teamLead,
|
||||
allowDeselect: true,
|
||||
placeholder: hr.string.TeamLead
|
||||
placeholder: hr.string.TeamLead,
|
||||
docQuery: {
|
||||
active: true
|
||||
}
|
||||
},
|
||||
eventToHTMLElement(event),
|
||||
changeLead
|
||||
|
@ -35,6 +35,7 @@
|
||||
{size}
|
||||
{kind}
|
||||
{justify}
|
||||
allowDeselect
|
||||
{width}
|
||||
bind:space={value}
|
||||
on:change={(e) => onChange(e.detail)}
|
||||
|
@ -77,6 +77,9 @@
|
||||
UsersPopup,
|
||||
{
|
||||
_class: contact.class.Employee,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
ignoreUsers: employees.filter((p) => p.department === objectId).map((p) => p._id)
|
||||
},
|
||||
eventToHTMLElement(e),
|
||||
|
@ -434,3 +434,34 @@ export async function changePassword (oldPassword: string, password: string): Pr
|
||||
body: serialize(request)
|
||||
})
|
||||
}
|
||||
|
||||
export async function leaveWorkspace (email: string): Promise<void> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
|
||||
if (accountsUrl === undefined) {
|
||||
throw new Error('accounts url not specified')
|
||||
}
|
||||
|
||||
const overrideToken = getMetadata(login.metadata.OverrideLoginToken)
|
||||
if (overrideToken !== undefined) {
|
||||
const endpoint = getMetadata(login.metadata.OverrideEndpoint)
|
||||
if (endpoint !== undefined) {
|
||||
return
|
||||
}
|
||||
}
|
||||
const token = fetchMetadataLocalStorage(login.metadata.LoginToken) as string
|
||||
|
||||
const request: Request<[string]> = {
|
||||
method: 'leaveWorkspace',
|
||||
params: [email]
|
||||
}
|
||||
|
||||
await fetch(accountsUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: serialize(request)
|
||||
})
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
import contact from '@anticrm/contact'
|
||||
import { Account, Class, Client, Doc, generateId, Ref, SortingOrder, Space } from '@anticrm/core'
|
||||
import { getResource, OK, Resource, Severity, Status } from '@anticrm/platform'
|
||||
import { Card, createQuery, getClient, SpaceSelector, UserBox } from '@anticrm/presentation'
|
||||
import { Card, createQuery, EmployeeBox, getClient, SpaceSelector, UserBox } from '@anticrm/presentation'
|
||||
import type { Applicant, Candidate } from '@anticrm/recruit'
|
||||
import task, { calcRank, SpaceWithStates, State } from '@anticrm/task'
|
||||
import ui, {
|
||||
@ -269,16 +269,13 @@
|
||||
create={{ component: recruit.component.CreateCandidate, label: recruit.string.CreateTalent }}
|
||||
/>
|
||||
{/if}
|
||||
<UserBox
|
||||
<EmployeeBox
|
||||
focusIndex={2}
|
||||
_class={contact.class.Employee}
|
||||
label={recruit.string.AssignRecruiter}
|
||||
placeholder={recruit.string.Recruiters}
|
||||
bind:value={doc.assignee}
|
||||
allowDeselect
|
||||
titleDeselect={recruit.string.UnAssignRecruiter}
|
||||
kind={'no-border'}
|
||||
size={'small'}
|
||||
/>
|
||||
{#if states.length > 0}
|
||||
<Button
|
||||
|
@ -180,6 +180,6 @@
|
||||
on:change={updateStart}
|
||||
/>
|
||||
<DateRangePresenter bind:value={dueDate} labelNull={recruit.string.DueDate} withTime editable />
|
||||
<UserBoxList _class={contact.class.Employee} bind:items={doc.participants} label={calendar.string.Participants} />
|
||||
<UserBoxList bind:items={doc.participants} label={calendar.string.Participants} />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -43,6 +43,8 @@
|
||||
"EditAttribute": "Edit attribute",
|
||||
"CreateEnum": "Create enum",
|
||||
"Enums": "Enums",
|
||||
"NewValue": "New value"
|
||||
"NewValue": "New value",
|
||||
"Leave": "Leave workspace",
|
||||
"LeaveDescr": "Are you sure you want to leave the workspace? This action cannot be undone."
|
||||
}
|
||||
}
|
@ -43,6 +43,8 @@
|
||||
"EditAttribute": "Редактирование атрибута",
|
||||
"CreateEnum": "Создать справочник",
|
||||
"Enums": "Справочники",
|
||||
"NewValue": "Новое значение"
|
||||
"NewValue": "Новое значение",
|
||||
"Leave": "Покинуть рабочее пространство",
|
||||
"LeaveDescr": "Вы действительно хотите покинуть рабочее пространство? Отменить это действие невозможно"
|
||||
}
|
||||
}
|
@ -15,15 +15,16 @@
|
||||
<script lang="ts">
|
||||
import { AttributeEditor, createQuery, EditableAvatar, getClient } from '@anticrm/presentation'
|
||||
|
||||
import setting from '@anticrm/setting'
|
||||
import { EditBox, Icon, Label, createFocusManager, FocusHandler } from '@anticrm/ui'
|
||||
import setting from '../plugin'
|
||||
import { EditBox, Icon, Label, createFocusManager, FocusHandler, Button, showPopup } from '@anticrm/ui'
|
||||
import contact, { Employee, EmployeeAccount, getFirstName, getLastName } from '@anticrm/contact'
|
||||
import contactRes from '@anticrm/contact-resources/src/plugin'
|
||||
import { getCurrentAccount } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import attachment from '@anticrm/attachment'
|
||||
import { changeName } from '@anticrm/login-resources'
|
||||
import { changeName, leaveWorkspace } from '@anticrm/login-resources'
|
||||
import { ChannelsEditor } from '@anticrm/contact-resources'
|
||||
import MessageBox from '@anticrm/presentation/src/components/MessageBox.svelte'
|
||||
const client = getClient()
|
||||
|
||||
let employee: Employee | undefined
|
||||
@ -71,6 +72,22 @@
|
||||
}
|
||||
|
||||
const manager = createFocusManager()
|
||||
|
||||
async function leave (): Promise<void> {
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: setting.string.Leave,
|
||||
message: setting.string.LeaveDescr
|
||||
},
|
||||
undefined,
|
||||
async (res?: boolean) => {
|
||||
if (res === true) {
|
||||
await leaveWorkspace(getCurrentAccount().email)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<FocusHandler {manager} />
|
||||
@ -80,51 +97,62 @@
|
||||
<div class="ac-header__icon"><Icon icon={setting.icon.EditProfile} size={'medium'} /></div>
|
||||
<div class="ac-header__title"><Label label={setting.string.EditProfile} /></div>
|
||||
</div>
|
||||
{#if employee}
|
||||
<div class="ac-body columns p-10">
|
||||
<div class="mr-8">
|
||||
<EditableAvatar avatar={employee.avatar} size={'x-large'} on:done={onAvatarDone} on:remove={removeAvatar} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="flex-col">
|
||||
<div class="name">
|
||||
<EditBox
|
||||
placeholder={contactRes.string.PersonFirstNamePlaceholder}
|
||||
maxWidth="20rem"
|
||||
bind:value={firstName}
|
||||
focus
|
||||
focusIndex={1}
|
||||
on:change={() => {
|
||||
changeName(firstName, lastName)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="name">
|
||||
<EditBox
|
||||
placeholder={contactRes.string.PersonLastNamePlaceholder}
|
||||
maxWidth="20rem"
|
||||
bind:value={lastName}
|
||||
focusIndex={2}
|
||||
on:change={() => {
|
||||
changeName(firstName, lastName)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="location">
|
||||
<AttributeEditor
|
||||
maxWidth="20rem"
|
||||
_class={contact.class.Person}
|
||||
object={employee}
|
||||
focusIndex={3}
|
||||
key="city"
|
||||
/>
|
||||
</div>
|
||||
<div class="ac-body p-10">
|
||||
{#if employee}
|
||||
<div class="flex flex-grow">
|
||||
<div class="mr-8">
|
||||
<EditableAvatar avatar={employee.avatar} size={'x-large'} on:done={onAvatarDone} on:remove={removeAvatar} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="flex-col">
|
||||
<div class="name">
|
||||
<EditBox
|
||||
placeholder={contactRes.string.PersonFirstNamePlaceholder}
|
||||
maxWidth="20rem"
|
||||
bind:value={firstName}
|
||||
focus
|
||||
focusIndex={1}
|
||||
on:change={() => {
|
||||
changeName(firstName, lastName)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="name">
|
||||
<EditBox
|
||||
placeholder={contactRes.string.PersonLastNamePlaceholder}
|
||||
maxWidth="20rem"
|
||||
bind:value={lastName}
|
||||
focusIndex={2}
|
||||
on:change={() => {
|
||||
changeName(firstName, lastName)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="location">
|
||||
<AttributeEditor
|
||||
maxWidth="20rem"
|
||||
_class={contact.class.Person}
|
||||
object={employee}
|
||||
focusIndex={3}
|
||||
key="city"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator" />
|
||||
<ChannelsEditor attachedTo={employee._id} attachedClass={employee._class} focusIndex={10} allowOpen={false} />
|
||||
</div>
|
||||
<div class="separator" />
|
||||
<ChannelsEditor attachedTo={employee._id} attachedClass={employee._class} focusIndex={10} allowOpen={false} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="footer">
|
||||
<Button
|
||||
icon={setting.icon.Signout}
|
||||
label={setting.string.Leave}
|
||||
on:click={() => {
|
||||
leave()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@ -144,4 +172,8 @@
|
||||
height: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
|
||||
.footer {
|
||||
align-self: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
@ -14,19 +14,12 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, DocumentQuery, Enum, Ref } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { ObjectPopup } from '@anticrm/presentation'
|
||||
import { AnyComponent } from '@anticrm/ui'
|
||||
import { ObjectCreate, ObjectPopup } from '@anticrm/presentation'
|
||||
|
||||
export let _class: Ref<Class<Enum>>
|
||||
export let selected: Ref<Enum> | undefined
|
||||
export let query: DocumentQuery<Enum> | undefined
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
|
||||
$: _create =
|
||||
create !== undefined
|
||||
|
@ -21,24 +21,19 @@
|
||||
Button,
|
||||
eventToHTMLElement,
|
||||
getFocusManager,
|
||||
AnyComponent,
|
||||
Tooltip,
|
||||
TooltipAlignment
|
||||
} from '@anticrm/ui'
|
||||
import EnumPopup from './EnumPopup.svelte'
|
||||
|
||||
import core, { Ref, Class, DocumentQuery, Enum } from '@anticrm/core'
|
||||
import { ObjectCreate } from '@anticrm/presentation'
|
||||
|
||||
export let label: IntlString
|
||||
export let value: Enum | undefined
|
||||
export let focusIndex = -1
|
||||
export let focus = false
|
||||
export let create:
|
||||
| {
|
||||
component: AnyComponent
|
||||
label: IntlString
|
||||
}
|
||||
| undefined = undefined
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
|
||||
const _class: Ref<Class<Enum>> = core.class.Enum
|
||||
|
@ -39,6 +39,8 @@ export default mergeIds(settingId, setting, {
|
||||
EditAttribute: '' as IntlString,
|
||||
CreateEnum: '' as IntlString,
|
||||
Enums: '' as IntlString,
|
||||
NewValue: '' as IntlString
|
||||
NewValue: '' as IntlString,
|
||||
Leave: '' as IntlString,
|
||||
LeaveDescr: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -83,6 +83,9 @@
|
||||
{
|
||||
_class: contact.class.Employee,
|
||||
selected: value?._id,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
allowDeselect: true,
|
||||
placeholder: task.string.AssignThisTask
|
||||
},
|
||||
|
@ -16,10 +16,9 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import { AttachedData, Ref } from '@anticrm/core'
|
||||
import { getClient, UserBox } from '@anticrm/presentation'
|
||||
import { getClient, EmployeeBox } from '@anticrm/presentation'
|
||||
import { Issue } from '@anticrm/tracker'
|
||||
import { ButtonKind, ButtonSize, TooltipAlignment } from '@anticrm/ui'
|
||||
import contact from '@anticrm/contact'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: Issue | AttachedData<Issue>
|
||||
@ -45,8 +44,7 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
<EmployeeBox
|
||||
label={tracker.string.Assignee}
|
||||
placeholder={tracker.string.Assignee}
|
||||
value={value.assignee}
|
||||
|
@ -83,6 +83,9 @@
|
||||
{
|
||||
_class: contact.class.Employee,
|
||||
selected: value?._id,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
allowDeselect: true,
|
||||
placeholder: tracker.string.AssignTo
|
||||
},
|
||||
|
@ -72,6 +72,9 @@
|
||||
{
|
||||
_class: contact.class.Employee,
|
||||
selected: value?._id,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
allowDeselect: true,
|
||||
placeholder: tracker.string.ProjectLeadSearchPlaceholder
|
||||
},
|
||||
|
@ -13,10 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact from '@anticrm/contact'
|
||||
import { Data, Ref } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { Card, getClient, SpaceSelector, UserBox, UserBoxList } from '@anticrm/presentation'
|
||||
import { Card, getClient, SpaceSelector, EmployeeBox, UserBoxList } from '@anticrm/presentation'
|
||||
import { Project, ProjectStatus, Team } from '@anticrm/tracker'
|
||||
import { DatePresenter, EditBox } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@ -83,19 +82,14 @@
|
||||
</div>
|
||||
<div slot="pool" class="flex-row-center text-sm gap-1-5">
|
||||
<ProjectStatusSelector selectedProjectStatus={object.status} onProjectStatusChange={handleProjectStatusChanged} />
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
<EmployeeBox
|
||||
label={tracker.string.ProjectLead}
|
||||
placeholder={tracker.string.AssignTo}
|
||||
bind:value={object.lead}
|
||||
allowDeselect
|
||||
titleDeselect={tracker.string.Unassigned}
|
||||
/>
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
bind:items={object.members}
|
||||
label={tracker.string.ProjectStatusPlaceholder}
|
||||
/>
|
||||
<UserBoxList bind:items={object.members} label={tracker.string.ProjectStatusPlaceholder} />
|
||||
<!-- TODO: add labels after customize IssueNeedsToBeCompletedByThisDate -->
|
||||
<DatePresenter bind:value={object.startDate} labelNull={tracker.string.StartDate} editable />
|
||||
<DatePresenter bind:value={object.targetDate} labelNull={tracker.string.TargetDate} editable />
|
||||
|
@ -61,6 +61,9 @@
|
||||
selectedUsers: value.members,
|
||||
allowDeselect: true,
|
||||
multiSelect: true,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
placeholder: tracker.string.ProjectMembersSearchPlaceholder
|
||||
},
|
||||
eventToHTMLElement(event),
|
||||
|
@ -14,6 +14,8 @@
|
||||
"Leave": "Leave",
|
||||
"Joined": "Joined",
|
||||
"Join": "Join",
|
||||
"BrowseSpaces": "Browse spaces"
|
||||
"BrowseSpaces": "Browse spaces",
|
||||
"AccountDisabled": "Account is disabled",
|
||||
"AccountDisabledDescr": "Please contact the workspace administrator"
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
"Leave": "Покинуть",
|
||||
"Joined": "Вы присоеденились",
|
||||
"Join": "Присоедениться",
|
||||
"BrowseSpaces": "Обзор пространств"
|
||||
"BrowseSpaces": "Обзор пространств",
|
||||
"AccountDisabled": "Аккаунт отключен",
|
||||
"AccountDisabledDescr": "Пожалуйста свяжитесь с администратором"
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@
|
||||
DatePickerPopup,
|
||||
fetchMetadataLocalStorage,
|
||||
getCurrentLocation,
|
||||
Label,
|
||||
location,
|
||||
Location,
|
||||
navigate,
|
||||
@ -358,7 +359,7 @@
|
||||
</script>
|
||||
|
||||
<svelte:window on:resize={windowResize} />
|
||||
{#if client}
|
||||
{#if employee?.active === true}
|
||||
<ActionHandler />
|
||||
<svg class="svg-mask">
|
||||
<clipPath id="notify-normal">
|
||||
@ -426,9 +427,7 @@
|
||||
showPopup(AccountPopup, {}, 'account')
|
||||
}}
|
||||
>
|
||||
{#if employee}
|
||||
<Avatar avatar={employee.avatar} size={'medium'} />
|
||||
{/if}
|
||||
<Avatar avatar={employee.avatar} size={'medium'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -507,7 +506,10 @@
|
||||
</Popup>
|
||||
<DatePickerPopup />
|
||||
{:else}
|
||||
No client
|
||||
<div class="flex-col-center justify-center h-full flex-grow">
|
||||
<h1><Label label={workbench.string.AccountDisabled} /></h1>
|
||||
<Label label={workbench.string.AccountDisabledDescr} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -34,7 +34,9 @@ export default mergeIds(workbenchId, workbench, {
|
||||
Leave: '' as IntlString,
|
||||
Joined: '' as IntlString,
|
||||
Join: '' as IntlString,
|
||||
BrowseSpaces: '' as IntlString
|
||||
BrowseSpaces: '' as IntlString,
|
||||
AccountDisabled: '' as IntlString,
|
||||
AccountDisabledDescr: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
SpacePanel: '' as AnyComponent
|
||||
|
@ -14,12 +14,12 @@
|
||||
//
|
||||
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import core, { Ref, SortingOrder, Tx, TxFactory, TxMixin } from '@anticrm/core'
|
||||
import core, { Ref, SortingOrder, Tx, TxFactory, TxMixin, TxUpdateDoc } from '@anticrm/core'
|
||||
import hr, { Department, DepartmentMember, Staff } from '@anticrm/hr'
|
||||
import { extractTx, TriggerControl } from '@anticrm/server-core'
|
||||
|
||||
async function getOldDepartment (
|
||||
currentTx: TxMixin<Employee, Staff>,
|
||||
currentTx: TxMixin<Employee, Staff> | TxUpdateDoc<Employee>,
|
||||
control: TriggerControl
|
||||
): Promise<Ref<Department> | undefined> {
|
||||
const txes = await control.findAll<TxMixin<Employee, Staff>>(
|
||||
@ -109,6 +109,12 @@ export async function OnDepartmentStaff (tx: Tx, control: TriggerControl): Promi
|
||||
const lastDepartment = await getOldDepartment(ctx, control)
|
||||
|
||||
const departmentId = ctx.attributes.department
|
||||
if (departmentId === null) {
|
||||
if (lastDepartment !== undefined) {
|
||||
const removed = await buildHierarchy(lastDepartment, control)
|
||||
return getTxes(control.txFactory, targetAccount._id, [], removed)
|
||||
}
|
||||
}
|
||||
const push = await buildHierarchy(departmentId, control)
|
||||
|
||||
if (lastDepartment === undefined) {
|
||||
@ -124,9 +130,36 @@ export async function OnDepartmentStaff (tx: Tx, control: TriggerControl): Promi
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function OnEmployeeDeactivate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const actualTx = extractTx(tx)
|
||||
if (core.class.TxUpdateDoc !== actualTx._class) {
|
||||
return []
|
||||
}
|
||||
const ctx = actualTx as TxUpdateDoc<Employee>
|
||||
if (ctx.objectClass !== contact.class.Employee || ctx.operations.active !== false) {
|
||||
return []
|
||||
}
|
||||
|
||||
const targetAccount = (
|
||||
await control.modelDb.findAll(contact.class.EmployeeAccount, {
|
||||
employee: ctx.objectId
|
||||
})
|
||||
)[0]
|
||||
if (targetAccount === undefined) return []
|
||||
const lastDepartment = await getOldDepartment(ctx, control)
|
||||
if (lastDepartment === undefined) return []
|
||||
|
||||
const removed = await buildHierarchy(lastDepartment, control)
|
||||
return getTxes(control.txFactory, targetAccount._id, [], removed)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
OnDepartmentStaff
|
||||
OnDepartmentStaff,
|
||||
OnEmployeeDeactivate
|
||||
}
|
||||
})
|
||||
|
@ -13,8 +13,8 @@
|
||||
// limitations under the f.
|
||||
//
|
||||
|
||||
import contact, { combineName } from '@anticrm/contact'
|
||||
import core, { TxOperations } from '@anticrm/core'
|
||||
import contact, { combineName, Employee } from '@anticrm/contact'
|
||||
import core, { Ref, TxOperations } from '@anticrm/core'
|
||||
import platform, {
|
||||
getMetadata,
|
||||
PlatformError,
|
||||
@ -461,6 +461,14 @@ export async function assignWorkspace (db: Db, email: string, workspace: string)
|
||||
if (account !== null) await createEmployeeAccount(account, workspace)
|
||||
}
|
||||
|
||||
async function createEmployee (ops: TxOperations, name: string): Promise<Ref<Employee>> {
|
||||
return await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name,
|
||||
city: '',
|
||||
active: true
|
||||
})
|
||||
}
|
||||
|
||||
async function createEmployeeAccount (account: Account, workspace: string): Promise<void> {
|
||||
const connection = await connect(getTransactor(), workspace, account.email)
|
||||
try {
|
||||
@ -472,10 +480,7 @@ async function createEmployeeAccount (account: Account, workspace: string): Prom
|
||||
const existingAccount = await ops.findOne(contact.class.EmployeeAccount, { email: account.email })
|
||||
|
||||
if (existingAccount === undefined) {
|
||||
const employee = await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name,
|
||||
city: ''
|
||||
})
|
||||
const employee = await createEmployee(ops, name)
|
||||
|
||||
await ops.createDoc(contact.class.EmployeeAccount, core.space.Model, {
|
||||
email: account.email,
|
||||
@ -486,13 +491,15 @@ async function createEmployeeAccount (account: Account, workspace: string): Prom
|
||||
const employee = await ops.findOne(contact.class.Employee, { _id: existingAccount.employee })
|
||||
if (employee === undefined) {
|
||||
// Employee was deleted, let's restore it.
|
||||
const employeeId = await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name,
|
||||
city: ''
|
||||
})
|
||||
const employeeId = await createEmployee(ops, name)
|
||||
|
||||
await ops.updateDoc(contact.class.EmployeeAccount, existingAccount.space, existingAccount._id, {
|
||||
employee: employeeId
|
||||
})
|
||||
} else if (!employee.active) {
|
||||
await ops.update(employee, {
|
||||
active: true
|
||||
})
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -599,12 +606,81 @@ export async function dropAccount (db: Db, email: string): Promise<void> {
|
||||
if (account === null) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, accountPlugin.status.AccountNotFound, { account: email }))
|
||||
}
|
||||
|
||||
const workspaces = await db
|
||||
.collection<Workspace>(WORKSPACE_COLLECTION)
|
||||
.find({ _id: { $in: account.workspaces } })
|
||||
.toArray()
|
||||
|
||||
await Promise.all(
|
||||
workspaces.map(async (ws) => {
|
||||
return await deactivateEmployeeAccount(account, ws.workspace)
|
||||
})
|
||||
)
|
||||
|
||||
await db.collection(ACCOUNT_COLLECTION).deleteOne({ _id: account._id })
|
||||
await db
|
||||
.collection<Workspace>(WORKSPACE_COLLECTION)
|
||||
.updateMany({ _id: { $in: account.workspaces } }, { $pull: { accounts: account._id } })
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function leaveWorkspace (db: Db, token: string, email: string): Promise<void> {
|
||||
const tokenData = decodeToken(token)
|
||||
|
||||
const account = await getAccount(db, email)
|
||||
if (account === null) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, accountPlugin.status.AccountNotFound, { account: email }))
|
||||
}
|
||||
|
||||
if (tokenData.email !== email) {
|
||||
const currentAccount = await getAccount(db, tokenData.email)
|
||||
if (currentAccount === null) {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, accountPlugin.status.AccountNotFound, { account: tokenData.email })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const workspace = await getWorkspace(db, tokenData.workspace)
|
||||
if (workspace === null) {
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, accountPlugin.status.WorkspaceNotFound, { workspace: tokenData.workspace })
|
||||
)
|
||||
}
|
||||
|
||||
await deactivateEmployeeAccount(account, workspace.workspace)
|
||||
|
||||
await db
|
||||
.collection<Workspace>(WORKSPACE_COLLECTION)
|
||||
.updateOne({ _id: workspace._id }, { $pull: { accounts: account._id } })
|
||||
await db
|
||||
.collection<Account>(ACCOUNT_COLLECTION)
|
||||
.updateOne({ _id: account._id }, { $pull: { workspaces: workspace._id } })
|
||||
}
|
||||
|
||||
async function deactivateEmployeeAccount (account: Account, workspace: string): Promise<void> {
|
||||
const connection = await connect(getTransactor(), workspace, account.email)
|
||||
try {
|
||||
const ops = new TxOperations(connection, core.account.System)
|
||||
|
||||
const existingAccount = await ops.findOne(contact.class.EmployeeAccount, { email: account.email })
|
||||
|
||||
if (existingAccount !== undefined) {
|
||||
const employee = await ops.findOne(contact.class.Employee, { _id: existingAccount.employee })
|
||||
if (employee !== undefined) {
|
||||
await ops.update(employee, {
|
||||
active: false
|
||||
})
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await connection.close()
|
||||
}
|
||||
}
|
||||
|
||||
function wrap (f: (db: Db, ...args: any[]) => Promise<any>) {
|
||||
return async function (db: Db, request: Request<any[]>, token?: string): Promise<Response<any>> {
|
||||
if (token !== undefined) request.params.unshift(token)
|
||||
@ -634,6 +710,7 @@ export const methods = {
|
||||
createWorkspace: wrap(createUserWorkspace),
|
||||
assignWorkspace: wrap(assignWorkspace),
|
||||
removeWorkspace: wrap(removeWorkspace),
|
||||
leaveWorkspace: wrap(leaveWorkspace),
|
||||
listWorkspaces: wrap(listWorkspaces),
|
||||
changeName: wrap(changeName),
|
||||
changePassword: wrap(changePassword)
|
||||
|
Loading…
Reference in New Issue
Block a user