diff --git a/models/core/src/core.ts b/models/core/src/core.ts index 532d4c7366..1de84914cd 100644 --- a/models/core/src/core.ts +++ b/models/core/src/core.ts @@ -62,8 +62,8 @@ export class TAttribute extends TDoc implements AnyAttribute { label!: IntlString } -@Model(core.class.Type, core.class.Doc) -export class TType extends TDoc implements Type { +@Model(core.class.Type, core.class.Obj) +export class TType extends TObj implements Type { label!: IntlString } diff --git a/models/core/src/security.ts b/models/core/src/security.ts index 16772ee23d..2ff043681a 100644 --- a/models/core/src/security.ts +++ b/models/core/src/security.ts @@ -15,7 +15,7 @@ import type { Account, Arr, Domain, Ref, Space, State } from '@anticrm/core' import { DOMAIN_MODEL } from '@anticrm/core' -import { Implements, Model, Prop, TypeBoolean, TypeState, TypeString } from '@anticrm/model' +import { Implements, Model, Prop, TypeBoolean, TypeRef, TypeString } from '@anticrm/model' import type { IntlString } from '@anticrm/platform' import core from './component' import { TDoc } from './core' @@ -53,7 +53,7 @@ export class TState extends TDoc implements State { @Implements(core.interface.DocWithState) export class TDocWithState extends TDoc { - @Prop(TypeState(), 'State' as IntlString) + @Prop(TypeRef(core.class.State), 'State' as IntlString) state!: Ref @Prop(TypeString(), 'No.' as IntlString) diff --git a/models/recruit/package.json b/models/recruit/package.json index 8222f0ce42..12c3445a6d 100644 --- a/models/recruit/package.json +++ b/models/recruit/package.json @@ -38,7 +38,6 @@ "@anticrm/recruit-resources": "~0.6.0", "@anticrm/chunter": "~0.6.0", "@anticrm/model-chunter": "~0.6.0", - "@anticrm/view": "~0.6.0", - "@anticrm/activity": "~0.6.0" + "@anticrm/view": "~0.6.0" } } diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 26c61fd47a..48dc81d937 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -13,10 +13,9 @@ // limitations under the License. // -import activity from '@anticrm/activity' import type { Employee } from '@anticrm/contact' import type { Doc, Domain, FindOptions, Ref, Timestamp } from '@anticrm/core' -import { Builder, Model, Prop, TypeBoolean, TypeDate, TypeString, UX } from '@anticrm/model' +import { Builder, Model, Prop, TypeBoolean, TypeDate, TypeRef, TypeString, UX } from '@anticrm/model' import chunter from '@anticrm/model-chunter' import contact, { TPerson } from '@anticrm/model-contact' import core, { TAttachedDoc, TDocWithState, TSpace, TSpaceWithStates } from '@anticrm/model-core' @@ -80,7 +79,7 @@ export class TCandidate extends TPerson implements Candidate { @UX('Application' as IntlString, recruit.icon.RecruitApplication, 'APP' as IntlString) export class TApplicant extends TAttachedDoc implements Applicant { // We need to declare, to provide property with label - @Prop(TypeString(), 'Candidate' as IntlString) + @Prop(TypeRef(recruit.class.Candidate), 'Candidate' as IntlString) declare attachedTo: Ref @Prop(TypeString(), 'Attachments' as IntlString) @@ -89,8 +88,8 @@ export class TApplicant extends TAttachedDoc implements Applicant { @Prop(TypeString(), 'Comments' as IntlString) comments?: number - @Prop(TypeString(), 'Assigned recruiter' as IntlString) - employee!: Ref + @Prop(TypeRef(contact.class.Employee), 'Assigned recruiter' as IntlString) + employee!: Ref | null // We need this two to make typescript happy. declare state: TDocWithState['state'] @@ -228,14 +227,6 @@ export function createModel (builder: Builder): void { attachedTo: recruit.class.Applicant, sequence: 0 }) - - builder.createDoc(activity.class.TxViewlet, core.space.Model, { - objectClass: recruit.class.Applicant, - icon: recruit.icon.RecruitApplication, - txClass: core.class.TxUpdateDoc, - component: recruit.activity.TxApplicantUpdate, - display: 'inline' - }, recruit.ids.TxApplicantUpdate) } export { default } from './plugin' diff --git a/models/recruit/src/plugin.ts b/models/recruit/src/plugin.ts index be7e39d7e2..081d61b318 100644 --- a/models/recruit/src/plugin.ts +++ b/models/recruit/src/plugin.ts @@ -13,14 +13,13 @@ // limitations under the License. // -import { mergeIds } from '@anticrm/platform' +import type { Doc, Ref, Space } from '@anticrm/core' import type { IntlString, Resource } from '@anticrm/platform' -import type { Ref, Space, Doc } from '@anticrm/core' -import type { AnyComponent } from '@anticrm/ui' -import type { Action } from '@anticrm/view' +import { mergeIds } from '@anticrm/platform' import { recruitId } from '@anticrm/recruit' import recruit from '@anticrm/recruit-resources/src/plugin' -import { TxViewlet } from '@anticrm/activity' +import type { AnyComponent } from '@anticrm/ui' +import type { Action } from '@anticrm/view' export default mergeIds(recruitId, recruit, { action: { @@ -48,11 +47,5 @@ export default mergeIds(recruitId, recruit, { }, space: { CandidatesPublic: '' as Ref - }, - ids: { - TxApplicantUpdate: '' as Ref - }, - activity: { - TxApplicantUpdate: '' as AnyComponent } }) diff --git a/models/task/src/index.ts b/models/task/src/index.ts index 3701a6b4fb..335f20e684 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -16,7 +16,7 @@ import type { Employee } from '@anticrm/contact' import contact from '@anticrm/contact' import type { Doc, DocWithState, Domain, FindOptions, Ref } from '@anticrm/core' -import { Builder, Model, Prop, TypeString, UX } from '@anticrm/model' +import { Builder, Model, Prop, TypeRef, TypeString, UX } from '@anticrm/model' import chunter from '@anticrm/model-chunter' import core, { TDoc, TSpaceWithStates } from '@anticrm/model-core' import view from '@anticrm/model-view' @@ -42,8 +42,8 @@ export class TTask extends TDoc implements Task { @Prop(TypeString(), 'Description' as IntlString) description!: string - @Prop(TypeString(), 'Assignee' as IntlString) - assignee!: Ref + @Prop(TypeRef(contact.class.Employee), 'Assignee' as IntlString) + assignee!: Ref | null @Prop(TypeString(), 'Comments' as IntlString) comments!: number diff --git a/packages/core/src/memdb.ts b/packages/core/src/memdb.ts index 046114a26c..19bfcbb51d 100644 --- a/packages/core/src/memdb.ts +++ b/packages/core/src/memdb.ts @@ -84,7 +84,7 @@ export abstract class MemDb extends TxProcessor { const result: LookupData = {} for (const key in lookup) { const id = (doc as any)[key] as Ref - if (id !== undefined) { + if (id != null) { (result as any)[key] = this.getObject(id) } } diff --git a/packages/model/src/dsl.ts b/packages/model/src/dsl.ts index c09e9fcd3a..214e0e0da5 100644 --- a/packages/model/src/dsl.ts +++ b/packages/model/src/dsl.ts @@ -308,8 +308,8 @@ export function TypeDate (): Type { /** * @public */ -export function TypeState (): Type { - return { _class: core.class.State, label: 'TypeState' as IntlString } +export function TypeRef (_class: Ref>): Type { + return { _class: _class, label: 'TypeRef' as IntlString } } /** diff --git a/packages/presentation/src/components/AttributeBarEditor.svelte b/packages/presentation/src/components/AttributeBarEditor.svelte index e31f99d9e9..0261e7bd62 100644 --- a/packages/presentation/src/components/AttributeBarEditor.svelte +++ b/packages/presentation/src/components/AttributeBarEditor.svelte @@ -15,12 +15,13 @@ --> diff --git a/packages/presentation/src/components/UserBox.svelte b/packages/presentation/src/components/UserBox.svelte index fafbb54dae..33db11e08e 100644 --- a/packages/presentation/src/components/UserBox.svelte +++ b/packages/presentation/src/components/UserBox.svelte @@ -29,8 +29,11 @@ export let _class: Ref> export let title: IntlString export let caption: IntlString - export let value: Ref + export let value: Ref | null | undefined export let show: boolean = false + export let allowDeselect = false + export let titleDeselect: IntlString | undefined = undefined + const dispatch = createEventDispatcher() let selected: Person | undefined @@ -40,11 +43,13 @@ const client = getClient() - async function updateSelected(value: Ref) { + async function updateSelected (value: Ref) { selected = await client.findOne(_class, { _id: value }) } - $: updateSelected(value) + $: if (value != null) { + updateSelected(value) + } onMount(() => { if (btn && show) { @@ -59,10 +64,19 @@ btn.focus() if (!opened) { opened = true - showPopup(UsersPopup, { _class, title, caption }, container, (result) => { - if (result) { + showPopup(UsersPopup, { _class, title, caption, allowDeselect, selected: value, titleDeselect }, container, (result) => { + if (result === undefined) { + // Value is not changed. + opened = false + return + } + if (result != null) { value = result._id dispatch('change', value) + } else { + value = null + selected = undefined + dispatch('change', null) } opened = false }) diff --git a/packages/presentation/src/components/UsersPopup.svelte b/packages/presentation/src/components/UsersPopup.svelte index 9f5613e801..944ad28ae1 100644 --- a/packages/presentation/src/components/UsersPopup.svelte +++ b/packages/presentation/src/components/UsersPopup.svelte @@ -22,17 +22,23 @@ import type { Ref, Class } from '@anticrm/core' import type { Person } from '@anticrm/contact' import { createQuery } from '../utils' + import { ActionIcon } from '@anticrm/ui' + import BlueCheck from './icons/BlueCheck.svelte' export let _class: Ref> export let title: IntlString export let caption: IntlString + export let selected: Ref | undefined + + export let allowDeselect: boolean = false + export let titleDeselect: IntlString | undefined = undefined let search: string = '' let objects: Person[] = [] const dispatch = createEventDispatcher() const query = createQuery() - $: query.query(_class, { name: { $like: '%'+search+'%' } }, result => { objects = result }) + $: query.query(_class, { name: { $like: '%' + search + '%' } }, result => { objects = result }) afterUpdate(() => { dispatch('update', Date.now()) }) @@ -46,7 +52,12 @@
{#each objects as person} {/each}
diff --git a/packages/presentation/src/components/icons/BlueCheck.svelte b/packages/presentation/src/components/icons/BlueCheck.svelte new file mode 100644 index 0000000000..d6e27d4d9c --- /dev/null +++ b/packages/presentation/src/components/icons/BlueCheck.svelte @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/plugins/activity-resources/src/components/TxView.svelte b/plugins/activity-resources/src/components/TxView.svelte index f2c82baa66..d036f1c544 100644 --- a/plugins/activity-resources/src/components/TxView.svelte +++ b/plugins/activity-resources/src/components/TxView.svelte @@ -129,8 +129,15 @@ actions = result }) - function getValue (utx: TxUpdateDoc, key: string): any { - return (utx.operations as any)[key] + async function getValue (m: AttributeModel, utx: TxUpdateDoc): Promise { + const val = (utx.operations as any)[m.key] + console.log(m._class, m.key, val, typeof val) + + if (client.getHierarchy().isDerived(m._class, core.class.Doc) && typeof val === 'string') { + // We have an reference, we need to find a real object to pass for presenter + return await client.findOne(m._class, { _id: val as Ref }) + } + return val } const showMenu = async (ev: MouseEvent): Promise => { showPopup( @@ -207,8 +214,14 @@ {/if} {#if viewlet === undefined && model.length > 0 && tx.updateTx} {#each model as m} - changed {m.label} to -
+ {#await getValue(m, tx.updateTx) then value} + {#if value === null} + unset {m.label} + {:else} + changed {m.label} to +
+ {/if} + {/await} {/each} {:else if viewlet && viewlet.display === 'inline' && viewlet.component}
diff --git a/plugins/recruit-resources/src/components/ApplicantHeader.svelte b/plugins/recruit-resources/src/components/ApplicantHeader.svelte index 6f5380162a..f33979fe3f 100644 --- a/plugins/recruit-resources/src/components/ApplicantHeader.svelte +++ b/plugins/recruit-resources/src/components/ApplicantHeader.svelte @@ -13,28 +13,43 @@ // See the License for the specific language governing permissions and // limitations under the License. --> -
- +
\ No newline at end of file + diff --git a/plugins/recruit-resources/src/components/CreateApplication.svelte b/plugins/recruit-resources/src/components/CreateApplication.svelte index 4310cfda29..ed803c54a2 100644 --- a/plugins/recruit-resources/src/components/CreateApplication.svelte +++ b/plugins/recruit-resources/src/components/CreateApplication.svelte @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. --> - - { dispatch('close') }}> + { + dispatch('close') + }} +> {#if !preserveCandidate} - + {/if} - + diff --git a/plugins/recruit-resources/src/components/activity/TxApplicantUpdate.svelte b/plugins/recruit-resources/src/components/activity/TxApplicantUpdate.svelte deleted file mode 100644 index 59b7c4fa75..0000000000 --- a/plugins/recruit-resources/src/components/activity/TxApplicantUpdate.svelte +++ /dev/null @@ -1,48 +0,0 @@ - - - - -{#if tx.operations.state} -
- updated State to - {#if statePresenter?.presenter} - {#await client.findOne(core.class.State, { _id: tx.operations.state }) then st} - {#if st} - - {/if} - {/await} - {/if} -
-{/if} - - diff --git a/plugins/recruit-resources/src/index.ts b/plugins/recruit-resources/src/index.ts index b8007d81a0..253a48abab 100644 --- a/plugins/recruit-resources/src/index.ts +++ b/plugins/recruit-resources/src/index.ts @@ -25,7 +25,6 @@ import KanbanCard from './components/KanbanCard.svelte' import EditVacancy from './components/EditVacancy.svelte' import ApplicationPresenter from './components/ApplicationPresenter.svelte' import ApplicationsPresenter from './components/ApplicationsPresenter.svelte' -import TxApplicantUpdate from './components/activity/TxApplicantUpdate.svelte' import { showPopup } from '@anticrm/ui' import { Resources } from '@anticrm/platform' @@ -49,8 +48,5 @@ export default async (): Promise => ({ ApplicationPresenter, ApplicationsPresenter, EditVacancy - }, - activity: { - TxApplicantUpdate } }) diff --git a/plugins/recruit/src/index.ts b/plugins/recruit/src/index.ts index 71097c5bb7..7b85fc8d5e 100644 --- a/plugins/recruit/src/index.ts +++ b/plugins/recruit/src/index.ts @@ -53,7 +53,7 @@ export interface Candidate extends Person { export interface Applicant extends DocWithState, AttachedDoc { attachments?: number comments?: number - employee: Ref + employee: Ref | null } /** diff --git a/plugins/task-assets/lang/en.json b/plugins/task-assets/lang/en.json index ae5098566e..46c91c2a36 100644 --- a/plugins/task-assets/lang/en.json +++ b/plugins/task-assets/lang/en.json @@ -16,6 +16,7 @@ "UploadDropFilesHere": "Upload or drop files here", "NoAttachmentsForTask": "There are no attachments for this task.", "AssigneeRequired": "Assignee is required", - "More": "Options" + "More": "Options", + "TaskUnAssign": "Unassign" } } \ No newline at end of file diff --git a/plugins/task-resources/src/components/CreateTask.svelte b/plugins/task-resources/src/components/CreateTask.svelte index 9cddc13f25..cc04edda63 100644 --- a/plugins/task-resources/src/components/CreateTask.svelte +++ b/plugins/task-resources/src/components/CreateTask.svelte @@ -13,7 +13,7 @@ // limitations under the License. -->