Candidate move (#604)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2021-12-13 15:05:46 +06:00 committed by GitHub
parent 63466eb4fa
commit 12f66bc433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 254 additions and 32 deletions

View File

@ -85,11 +85,11 @@ export class TEmployeeAccount extends TAccount implements EmployeeAccount {
}
@Model(contact.class.Organizations, core.class.Space)
@UX(contact.string.Organizations, contact.icon.Company)
@UX(contact.string.OrganizationsFolder, contact.icon.Company)
export class TOrganizations extends TSpace implements Organizations {}
@Model(contact.class.Persons, core.class.Space)
@UX(contact.string.Persons, contact.icon.Person)
@UX(contact.string.PersonsFolder, contact.icon.Person)
export class TPersons extends TSpace implements Persons {}
export function createModel (builder: Builder): void {

View File

@ -35,6 +35,8 @@ export const ids = mergeIds(contactId, contact, {
},
string: {
Organizations: '' as IntlString,
OrganizationsFolder: '' as IntlString,
PersonsFolder: '' as IntlString,
Persons: '' as IntlString,
Contacts: '' as IntlString,
CreatePersons: '' as IntlString,

View File

@ -128,7 +128,7 @@ export function createModel (builder: Builder): void {
component: recruit.component.EditVacancy
},
{
label: recruit.string.CandidatePools,
label: recruit.string.Candidates,
spaceClass: recruit.class.Candidates,
addSpaceLabel: recruit.string.CreateCandidates,
createComponent: recruit.component.CreateCandidates
@ -136,12 +136,17 @@ export function createModel (builder: Builder): void {
]
}
})
builder.createDoc(recruit.class.Candidates, core.space.Model, {
name: 'public',
description: 'Public Candidates',
private: false,
members: []
}, recruit.space.CandidatesPublic)
builder.createDoc(
recruit.class.Candidates,
core.space.Model,
{
name: 'public',
description: 'Public Candidates',
private: false,
members: []
},
recruit.space.CandidatesPublic
)
builder.createDoc(view.class.Viewlet, core.space.Model, {
attachTo: recruit.class.Candidate,
@ -184,7 +189,8 @@ export function createModel (builder: Builder): void {
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments' },
'modifiedOn',
'$lookup.attachedTo.channels']
'$lookup.attachedTo.channels'
]
})
builder.createDoc(view.class.Viewlet, core.space.Model, {
@ -213,11 +219,16 @@ export function createModel (builder: Builder): void {
presenter: recruit.component.ApplicationPresenter
})
builder.createDoc(view.class.Action, core.space.Model, {
label: 'Create application' as IntlString,
icon: recruit.icon.Create,
action: recruit.actionImpl.CreateApplication
}, recruit.action.CreateApplication)
builder.createDoc(
view.class.Action,
core.space.Model,
{
label: 'Create application' as IntlString,
icon: recruit.icon.Create,
action: recruit.actionImpl.CreateApplication
},
recruit.action.CreateApplication
)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: recruit.class.Candidate,

View File

@ -32,6 +32,7 @@ export default mergeIds(recruitId, recruit, {
RecruitApplication: '' as IntlString,
Vacancies: '' as IntlString,
CandidatePools: '' as IntlString,
Candidates: '' as IntlString,
Vacancy: '' as IntlString
},
component: {

View File

@ -148,6 +148,17 @@ export function createModel (builder: Builder): void {
action: view.action.Delete
})
builder.createDoc(view.class.Action, core.space.Model, {
label: 'Move' as IntlString,
icon: view.icon.Move,
action: view.actionImpl.Move
}, view.action.Move)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: core.class.Doc,
action: view.action.Move
})
builder.createDoc(core.class.Space, core.space.Model, {
name: 'Sequences',
description: 'Internal space to store sequence numbers',

View File

@ -21,10 +21,12 @@ import view, { viewId, Action } from '@anticrm/view'
export default mergeIds(viewId, view, {
action: {
Delete: '' as Ref<Action>
Delete: '' as Ref<Action>,
Move: '' as Ref<Action>
},
actionImpl: {
Delete: '' as Resource<(doc: Doc) => Promise<void>>
Delete: '' as Resource<(doc: Doc) => Promise<void>>,
Move: '' as Resource<(doc: Doc) => Promise<void>>
},
component: {
StringEditor: '' as AnyComponent,

View File

@ -160,7 +160,14 @@ export interface IncOptions<T extends Doc> {
/**
* @public
*/
export type DocumentUpdate<T extends Doc> = Partial<Data<T>> & PushOptions<T> & PushMixinOptions<T> & IncOptions<T>
export interface SpaceUpdate {
space?: Ref<Space>
}
/**
* @public
*/
export type DocumentUpdate<T extends Doc> = Partial<Data<T>> & PushOptions<T> & PushMixinOptions<T> & IncOptions<T> & SpaceUpdate
/**
* @public

View File

@ -28,3 +28,4 @@ export { default as Channels } from './components/Channels.svelte'
export { default as PDFViewer } from './components/PDFViewer.svelte'
export { default as MessageBox } from './components/MessageBox.svelte'
export { default as SpaceCreateCard } from './components/SpaceCreateCard.svelte'
export { default as SpaceSelect } from './components/SpaceSelect.svelte'

View File

@ -150,3 +150,5 @@ export const ticker = readable(Date.now(), set => {
addStringsLoader(uiId, async (lang: string) => {
return await import(`../lang/${lang}.json`)
})
export { default } from './plugin'

View File

@ -2,7 +2,8 @@
"string": {
"RecruitApplication": "Recruiting",
"Vacancies": "Vacancies",
"CandidatePools": "Candidates",
"CandidatePools": "Candidates pool",
"Candidates": "Candidates",
"VacancyName": "Vacancy Title *",
"VacancyDescription": "Vacancy Description",
"CreateVacancy": "Create Vacancy",

View File

@ -25,4 +25,7 @@
<symbol id="delete" viewBox="0 0 16 16">
<path d="M14.2,2.8h-2.4c-0.3,0-0.5-0.2-0.6-0.6l-0.2-1C10.9,0.5,10.3,0,9.6,0H6.4C5.7,0,5.1,0.5,4.9,1.3l-0.2,1 C4.7,2.6,4.4,2.8,4.2,2.8H1.8c-0.3,0-0.6,0.3-0.6,0.6S1.4,4,1.8,4h0.4c0.1,1.4,0.4,7.6,0.6,9.7c0.1,1.4,1,2.3,2.3,2.3 C6,16,7,16,8,16c0.9,0,1.9,0,2.9,0c1.3,0,2.2-0.9,2.3-2.3c0.2-2,0.5-8.3,0.6-9.7h0.4c0.3,0,0.6-0.3,0.6-0.6S14.6,2.8,14.2,2.8z M6,2.5l0.2-0.9c0-0.2,0.2-0.3,0.3-0.3h3.1c0.1,0,0.3,0.1,0.3,0.3l0.2,1c0,0.1,0.1,0.2,0.1,0.3H5.8C5.9,2.7,5.9,2.6,6,2.5z M12,13.6 c-0.1,1.2-0.9,1.2-1.1,1.2c-2,0-3.9,0-5.7,0c-0.6,0-1-0.4-1.1-1.2c-0.2-2-0.5-8-0.6-9.5h9.2C12.5,5.5,12.2,11.6,12,13.6z"/>
</symbol>
<symbol id="move" viewBox="0 0 16 16">
<polygon points="6.4,14.4 5.6,13.6 11.3,8 5.6,2.4 6.4,1.6 12.7,8 "/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,6 @@
{
"string": {
"MoveClass": "Move {class}",
"SelectToMove": "Select the {classLabel} you want to move {class} to."
}
}

View File

@ -13,12 +13,15 @@
// limitations under the License.
//
import { loadMetadata } from '@anticrm/platform'
import view from '@anticrm/view'
import { addStringsLoader, loadMetadata } from '@anticrm/platform'
import view, { viewId } from '@anticrm/view'
const icons = require('../assets/icons.svg')
loadMetadata(view.icon, {
Table: `${icons}#table`,
Kanban: `${icons}#kanban`,
Delete: `${icons}#delete`,
Move: `${icons}#move`
})
addStringsLoader(viewId, async (lang: string) => await import(`../lang/${lang}.json`))

View File

@ -0,0 +1,135 @@
<!--
// 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 { Label, Button } from '@anticrm/ui'
import { getClient } from '@anticrm/presentation'
import core, { AttachedDoc, Collection, Doc, Ref, Space } from '@anticrm/core'
import { SpaceSelect } from '@anticrm/presentation'
import { createEventDispatcher } from 'svelte'
import ui from '@anticrm/ui'
import view from '../plugin'
import { translate } from '@anticrm/platform'
export let object: Doc
let currentSpace: Space | undefined
let space: Ref<Space> = object.space
const client = getClient()
const dispatch = createEventDispatcher()
const hierarchy = client.getHierarchy()
let label = ''
$: _class = currentSpace ? hierarchy.getClass(currentSpace._class).label : undefined
let classLabel = ''
$: translate(hierarchy.getClass(object._class).label, {}).then((res) => (label = res.toLocaleLowerCase()))
$: _class && translate(_class, {}).then((res) => (classLabel = res.toLocaleLowerCase()))
async function move (doc: Doc): Promise<void> {
console.log('start move')
console.log(doc)
const attributes = hierarchy.getAllAttributes(doc._class)
for (const [name, attribute] of attributes) {
if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) {
const collection = attribute.type as Collection<AttachedDoc>
console.log('find collection')
console.log(collection)
const allAttached = await client.findAll(collection.of, { attachedTo: doc._id })
console.log(allAttached)
for (const attached of allAttached) {
move(attached).catch((err) => console.log('failed to move', name, err))
}
}
}
if (doc.space === object.space) {
console.log('move doc')
console.log(doc)
client.updateDoc(doc._class, doc.space, doc._id, {
space: space
})
}
console.log('close')
dispatch('close')
}
$: client.findOne(core.class.Space, { _id: object.space }).then((res) => (currentSpace = res))
</script>
<div class="container">
<div class="header fs-title">
<Label label={view.string.MoveClass} params={{ class: label }} />
</div>
<div class="description">
<Label label={view.string.SelectToMove} params={{ class: label, classLabel: classLabel }} />
</div>
<div class="spaceSelect">
{#if currentSpace}
<SpaceSelect _class={currentSpace._class} label={_class ?? ''} bind:value={space} />
{/if}
</div>
<div class="footer">
<Button
label="Move"
size="small"
width="100px"
disabled={space === object?.space}
primary
on:click={() => {
move(object)
}}
/>
<Button
size="small"
width="100px"
label={ui.string.Cancel}
on:click={() => {
dispatch('close')
}}
/>
</div>
</div>
<style lang="scss">
.container {
display: flex;
flex-direction: column;
background-color: var(--theme-button-bg-hovered);
border-radius: 1.25rem;
padding: 2rem 1.75rem 1.75rem 1.75rem;
.description {
margin: 1rem 0;
}
.spaceSelect {
background-color: var(--theme-button-bg-enabled);
border-radius: 0.75rem;
padding: 1.25rem 1rem;
border: 0.5px solid var(--theme-bg-accent-color);
}
.footer {
flex-shrink: 0;
display: grid;
grid-auto-flow: column;
direction: rtl;
justify-content: start;
align-items: center;
margin-top: 1rem;
column-gap: 0.75rem;
mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 1.25rem, rgba(0, 0, 0, 1) 2.5rem);
overflow: hidden;
}
}
</style>

View File

@ -13,8 +13,7 @@
// limitations under the License.
//
import type { AttachedDoc, Doc } from '@anticrm/core'
import core from '@anticrm/core'
import type { Doc } from '@anticrm/core'
import { Resources } from '@anticrm/platform'
import { getClient, MessageBox } from '@anticrm/presentation'
import { showPopup } from '@anticrm/ui'
@ -31,25 +30,36 @@ import Table from './components/Table.svelte'
import TableView from './components/TableView.svelte'
import TimestampPresenter from './components/TimestampPresenter.svelte'
import { deleteObject } from './utils'
import MoveView from './components/Move.svelte'
export { default as ContextMenu } from './components/Menu.svelte'
export { buildModel, getActions, getObjectPresenter } from './utils'
export { Table }
function Delete (object: Doc): void {
showPopup(MessageBox, {
label: 'Delete object',
message: 'Do you want to delete this object?'
}, undefined, (result) => {
if (result) {
deleteObject(getClient(), object)
showPopup(
MessageBox,
{
label: 'Delete object',
message: 'Do you want to delete this object?'
},
undefined,
(result) => {
if (result) {
deleteObject(getClient(), object)
}
}
})
)
}
async function Move (object: Doc): Promise<void> {
showPopup(MoveView, { object })
}
export default async (): Promise<Resources> => ({
actionImpl: {
Delete
Delete,
Move
},
component: {
StringEditor,

View File

@ -0,0 +1,26 @@
//
// 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.
//
import { IntlString, mergeIds } from '@anticrm/platform'
import view, { viewId } from '@anticrm/view'
export default mergeIds(viewId, view, {
string: {
MoveClass: '' as IntlString,
SelectToMove: '' as IntlString
}
})

View File

@ -159,6 +159,7 @@ export default plugin(viewId, {
icon: {
Table: '' as Asset,
Kanban: '' as Asset,
Delete: '' as Asset
Delete: '' as Asset,
Move: '' as Asset
}
})