Skip to content

Svetlov testwork recruit plugin refactor #8425

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
643 changes: 116 additions & 527 deletions plugins/recruit-resources/src/components/CreateCandidate.svelte

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
// Copyright © 2020 Anticrm Platform Contributors.
//
// 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 { ChannelsDropdown } from '@hcengineering/contact-resources'
import { AttachedData, Channel } from '@hcengineering/contact'

export let object: any
export let loading = false
export let matchedChannels: AttachedData<Channel>[] = []
</script>

<ChannelsDropdown
editable={!loading}
focusIndex={10}
bind:value={object.channels}
highlighted={matchedChannels.map((it) => it.provider)}
kind={'regular'}
size={'large'}
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!--
// Copyright © 2020 Anticrm Platform Contributors.
//
// 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 { AvatarType } from '@hcengineering/contact'
import { combineName } from '@hcengineering/contact'
import { EditableAvatar } from '@hcengineering/contact-resources'
import { EditBox, Button, ActionIcon } from '@hcengineering/ui'
import recruit from '../../plugin'
import IconShuffle from '../icons/Shuffle.svelte'

export let object: any
export let loading = false
export let avatarEditor: EditableAvatar

function swapNames(): void {
const first = object.firstName
object.firstName = object.lastName
object.lastName = first
}
</script>

<div class="flex-between">
<div class="flex-col">
<EditBox
disabled={loading}
placeholder={recruit.string.PersonFirstNamePlaceholder}
bind:value={object.firstName}
kind={'large-style'}
autoFocus
maxWidth={'30rem'}
focusIndex={1}
/>
<EditBox
disabled={loading}
placeholder={recruit.string.PersonLastNamePlaceholder}
bind:value={object.lastName}
maxWidth={'30rem'}
kind={'large-style'}
focusIndex={2}
/>
<div class="mt-1">
<EditBox
disabled={loading}
placeholder={recruit.string.Title}
bind:value={object.title}
kind={'small-style'}
focusIndex={3}
maxWidth={'30rem'}
/>
</div>
<EditBox
disabled={loading}
placeholder={recruit.string.Location}
bind:value={object.city}
kind={'small-style'}
focusIndex={4}
maxWidth={'30rem'}
/>
</div>
<div class="flex-col items-center flex-gap-2 ml-4">
<EditableAvatar
disabled={loading}
bind:this={avatarEditor}
bind:direct={object.avatar}
person={{
avatarType: AvatarType.COLOR
}}
size={'large'}
name={combineName(object?.firstName?.trim() ?? '', object?.lastName?.trim() ?? '')}
/>
<ActionIcon
icon={IconShuffle}
label={recruit.string.SwapFirstAndLastNames}
size={'medium'}
action={swapNames}
/>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<!--
// Copyright © 2020 Anticrm Platform Contributors.
//
// 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 { Button, MiniToggle } from '@hcengineering/ui'
import { IconFile as FileIcon, IconAttachment, Spinner } from '@hcengineering/ui'
import { FilePreviewPopup } from '@hcengineering/presentation'
import { showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import recruit from '../../plugin'

export let object: any
export let loading = false
export let dragover = false
export let shouldCreateNewSkills = false
export let inputFile: HTMLInputElement

function drop(event: DragEvent): void {
dragover = false
const droppedFile = event.dataTransfer?.files[0]
if (droppedFile !== undefined) {
dispatch('createAttachment', droppedFile)
}
}

function fileSelected(): void {
const file = inputFile.files?.[0]
if (file !== undefined) {
dispatch('createAttachment', file)
}
}

const dispatch = createEventDispatcher()
</script>

<div
class="flex-center resume"
class:solid={dragover || object.resumeUuid}
on:dragover|preventDefault={() => {
dragover = true
}}
on:dragleave={() => {
dragover = false
}}
on:drop|preventDefault|stopPropagation={drop}
>
{#if loading && object.resumeUuid}
<Button label={recruit.string.Parsing} icon={Spinner} disabled />
{:else}
{#if loading}
<Button label={recruit.string.Uploading} icon={Spinner} disabled />
{:else if object.resumeUuid}
<Button
disabled={loading}
focusIndex={103}
icon={FileIcon}
on:click={() => {
showPopup(
FilePreviewPopup,
{
file: object.resumeUuid,
contentType: object.resumeType,
name: object.resumeName
},
object.resumeType?.startsWith('image/') ? 'centered' : 'float'
)
}}
>
<svelte:fragment slot="content">
<span class="overflow-label disabled">{object.resumeName}</span>
</svelte:fragment>
</Button>
{:else}
<Button
focusIndex={103}
label={recruit.string.AddDropHere}
icon={IconAttachment}
notSelected
on:click={() => {
inputFile.click()
}}
/>
{/if}
<input bind:this={inputFile} type="file" name="file" id="file" style="display: none" on:change={fileSelected} />
{/if}
<div class="ml-1">
<MiniToggle bind:on={shouldCreateNewSkills} label={recruit.string.CreateNewSkills} />
</div>
</div>

<style lang="scss">
.resume {
box-shadow: 0 0 0 0 var(--primary-button-outline);
border-radius: 0.25rem;
transition: box-shadow 0.15s ease-in-out;

&.solid {
box-shadow: 0 0 0 2px var(--primary-button-outline);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!--
Copyright © 2020 Anticrm Platform Contributors.

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 { Component } from '@hcengineering/ui'
import tags, { TagElement, TagReference } from '@hcengineering/tags'
import core, { Ref, Doc, PersonId } from '@hcengineering/core'
import { generateId } from '@hcengineering/core'
import recruit from '../../plugin'

export let object: any
export let loading = false
export let elements: Map<Ref<TagElement>, TagElement>
export let newElements: TagElement[]
export let key: any

function addTagRef(tag: TagElement): void {
object.skills = [
...object.skills,
{
_class: tags.class.TagReference,
_id: generateId(),
attachedTo: '' as Ref<Doc>,
attachedToClass: recruit.mixin.Candidate,
collection: 'skills',
space: core.space.Workspace,
modifiedOn: 0,
modifiedBy: '' as PersonId,
title: tag.title,
tag: tag._id,
color: tag.color
}
]
}
</script>

<Component
is={tags.component.TagsDropdownEditor}
props={{
disabled: loading,
focusIndex: 102,
items: object.skills,
key,
targetClass: recruit.mixin.Candidate,
showTitle: false,
elements,
newElements,
countLabel: recruit.string.NumberSkills,
kind: 'regular',
size: 'large'
}}
on:open={({ detail }) => {
addTagRef(detail)
}}
on:delete={({ detail }) => {
object.skills = object.skills.filter((it) => it.tag !== detail._id)
}}
/>
{#if object.skills.length > 0}
<div class="antiComponent antiEmphasized w-full flex-grow mt-2">
<Component
is={tags.component.TagsEditor}
props={{
disabled: loading,
focusIndex: 102,
items: object.skills,
key,
targetClass: recruit.mixin.Candidate,
showTitle: false,
elements,
newElements,
countLabel: recruit.string.NumberSkills
}}
on:open={({ detail }) => {
addTagRef(detail)
}}
on:delete={({ detail }) => {
object.skills = object.skills.filter((it) => it._id !== detail)
}}
on:change={({ detail }) => {
detail.tag.weight = detail.tag.weight
object.skills = object.skills
}}
/>
</div>
{:else}
<div class="flex-grow w-full" style="margin: 0" />
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
// Copyright © 2020 Anticrm Platform Contributors.
//
// 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 YesNo from '../YesNo.svelte'
import recruit from '../../plugin'

export let object: any
export let loading = false
</script>

<YesNo
disabled={loading}
focusIndex={100}
label={recruit.string.Onsite}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.onsite}
kind={'regular'}
size={'large'}
/>
<YesNo
disabled={loading}
focusIndex={101}
label={recruit.string.Remote}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.remote}
kind={'regular'}
size={'large'}
/>
Loading