2021-12-02 09:09:37 +00:00
|
|
|
<!--
|
|
|
|
// 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">
|
2022-09-21 08:08:25 +00:00
|
|
|
import { Attachments } from '@hcengineering/attachment-resources'
|
2023-03-29 09:18:59 +00:00
|
|
|
import core, { ClassifierKind, Doc, Mixin, Ref } from '@hcengineering/core'
|
2022-09-21 08:08:25 +00:00
|
|
|
import { Panel } from '@hcengineering/panel'
|
|
|
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
|
|
|
import { Vacancy } from '@hcengineering/recruit'
|
|
|
|
import { FullDescriptionBox } from '@hcengineering/text-editor'
|
2023-03-15 14:06:03 +00:00
|
|
|
import tracker from '@hcengineering/tracker'
|
2023-04-27 12:28:12 +00:00
|
|
|
import { Button, Component, EditBox, Grid, IconMixin, IconMoreH, LinkWrapper, showPopup } from '@hcengineering/ui'
|
2023-03-29 09:18:59 +00:00
|
|
|
import { ContextMenu, DocAttributeBar } from '@hcengineering/view-resources'
|
2021-12-02 09:09:37 +00:00
|
|
|
import { createEventDispatcher } from 'svelte'
|
|
|
|
import recruit from '../plugin'
|
2023-03-15 14:06:03 +00:00
|
|
|
import VacancyApplications from './VacancyApplications.svelte'
|
2023-04-21 10:30:27 +00:00
|
|
|
import { getResource } from '@hcengineering/platform'
|
|
|
|
import notification from '@hcengineering/notification'
|
|
|
|
import { onDestroy } from 'svelte'
|
2021-12-02 09:09:37 +00:00
|
|
|
|
|
|
|
export let _id: Ref<Vacancy>
|
2023-04-05 07:12:06 +00:00
|
|
|
export let embedded = false
|
2021-12-02 09:09:37 +00:00
|
|
|
|
2022-04-06 10:20:35 +00:00
|
|
|
let object: Required<Vacancy>
|
2022-06-29 05:53:57 +00:00
|
|
|
let rawName: string = ''
|
|
|
|
let rawDesc: string = ''
|
2023-04-21 10:30:27 +00:00
|
|
|
let lastId: Ref<Vacancy> | undefined = undefined
|
2021-12-02 09:09:37 +00:00
|
|
|
|
2023-04-12 16:10:03 +00:00
|
|
|
let showAllMixins = false
|
|
|
|
|
2021-12-02 09:09:37 +00:00
|
|
|
const dispatch = createEventDispatcher()
|
2023-04-21 10:30:27 +00:00
|
|
|
const notificationClient = getResource(notification.function.GetNotificationClient).then((res) => res())
|
|
|
|
|
|
|
|
onDestroy(async () => {
|
|
|
|
notificationClient.then((client) => client.updateLastView(_id, recruit.class.Vacancy))
|
|
|
|
})
|
2021-12-02 09:09:37 +00:00
|
|
|
|
|
|
|
const client = getClient()
|
|
|
|
|
|
|
|
const query = createQuery()
|
|
|
|
const clazz = client.getHierarchy().getClass(recruit.class.Vacancy)
|
2022-02-07 09:21:32 +00:00
|
|
|
|
2022-04-06 10:20:35 +00:00
|
|
|
function updateObject (_id: Ref<Vacancy>): void {
|
2023-04-21 10:30:27 +00:00
|
|
|
if (lastId !== _id) {
|
|
|
|
const prev = lastId
|
|
|
|
lastId = _id
|
|
|
|
if (prev) {
|
|
|
|
notificationClient.then((client) => client.updateLastView(prev, recruit.class.Vacancy))
|
|
|
|
}
|
|
|
|
query.query(recruit.class.Vacancy, { _id }, (result) => {
|
|
|
|
object = result[0] as Required<Vacancy>
|
|
|
|
rawName = object.name
|
|
|
|
rawDesc = object.description
|
|
|
|
})
|
|
|
|
}
|
2022-02-07 09:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$: updateObject(_id)
|
2021-12-02 09:09:37 +00:00
|
|
|
|
2022-04-29 05:27:17 +00:00
|
|
|
function onChange (key: string, value: any): void {
|
2021-12-02 09:09:37 +00:00
|
|
|
client.updateDoc(object._class, object.space, object._id, { [key]: value })
|
|
|
|
}
|
2022-09-09 03:44:33 +00:00
|
|
|
|
|
|
|
function showMenu (ev?: Event): void {
|
|
|
|
if (object !== undefined) {
|
|
|
|
showPopup(ContextMenu, { object }, (ev as MouseEvent).target as HTMLElement)
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 09:18:59 +00:00
|
|
|
|
|
|
|
const ignoreMixins: Set<Ref<Mixin<Doc>>> = new Set<Ref<Mixin<Doc>>>()
|
|
|
|
const hierarchy = client.getHierarchy()
|
|
|
|
let mixins: Mixin<Doc>[] = []
|
|
|
|
|
2023-04-12 16:10:03 +00:00
|
|
|
function getMixins (object: Doc, showAllMixins: boolean): void {
|
2023-03-29 09:18:59 +00:00
|
|
|
if (object === undefined) return
|
|
|
|
const descendants = hierarchy.getDescendants(core.class.Doc).map((p) => hierarchy.getClass(p))
|
|
|
|
|
|
|
|
mixins = descendants.filter(
|
2023-04-12 16:10:03 +00:00
|
|
|
(m) =>
|
|
|
|
m.kind === ClassifierKind.MIXIN &&
|
|
|
|
!ignoreMixins.has(m._id) &&
|
|
|
|
(hierarchy.hasMixin(object, m._id) ||
|
|
|
|
(showAllMixins && hierarchy.isDerived(object._class, hierarchy.getBaseClass(m._id))))
|
2023-03-29 09:18:59 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-04-12 16:10:03 +00:00
|
|
|
$: getMixins(object, showAllMixins)
|
2021-12-02 09:09:37 +00:00
|
|
|
</script>
|
|
|
|
|
2022-05-12 11:29:49 +00:00
|
|
|
{#if object}
|
|
|
|
<Panel
|
2022-06-28 06:50:39 +00:00
|
|
|
icon={clazz.icon}
|
2022-05-12 11:29:49 +00:00
|
|
|
title={object.name}
|
2022-11-30 05:53:49 +00:00
|
|
|
isHeader={true}
|
2022-05-12 11:29:49 +00:00
|
|
|
isAside={true}
|
2023-04-05 07:12:06 +00:00
|
|
|
{embedded}
|
2022-05-12 11:29:49 +00:00
|
|
|
{object}
|
|
|
|
on:close={() => {
|
|
|
|
dispatch('close')
|
|
|
|
}}
|
|
|
|
>
|
2023-01-29 05:44:12 +00:00
|
|
|
<svelte:fragment slot="subtitle">
|
2023-02-16 09:19:48 +00:00
|
|
|
{#if object.description}
|
2023-04-27 12:28:12 +00:00
|
|
|
<div class="flex">
|
|
|
|
<span class="overflow-label" title={object.description}>
|
|
|
|
<LinkWrapper text={object.description} />
|
|
|
|
</span>
|
|
|
|
</div>
|
2023-02-16 09:19:48 +00:00
|
|
|
{/if}
|
2023-01-29 05:44:12 +00:00
|
|
|
</svelte:fragment>
|
2022-05-12 11:29:49 +00:00
|
|
|
<svelte:fragment slot="attributes" let:direction={dir}>
|
2023-04-12 16:10:03 +00:00
|
|
|
<div class="flex flex-reverse flex-no-shrink clear-mins">
|
|
|
|
<Button
|
|
|
|
kind={'transparent'}
|
|
|
|
shape={'round'}
|
|
|
|
selected={showAllMixins}
|
|
|
|
on:click={() => {
|
|
|
|
showAllMixins = !showAllMixins
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<svelte:fragment slot="content">
|
|
|
|
<IconMixin size={'small'} />
|
|
|
|
</svelte:fragment>
|
|
|
|
</Button>
|
|
|
|
</div>
|
2022-05-12 11:29:49 +00:00
|
|
|
{#if dir === 'column'}
|
2023-04-05 07:12:06 +00:00
|
|
|
<DocAttributeBar
|
|
|
|
{object}
|
|
|
|
{mixins}
|
|
|
|
ignoreKeys={['name', 'description', 'fullDescription', 'private', 'archived']}
|
|
|
|
/>
|
2022-05-12 11:29:49 +00:00
|
|
|
{/if}
|
|
|
|
</svelte:fragment>
|
|
|
|
|
2022-11-30 05:53:49 +00:00
|
|
|
<svelte:fragment slot="subheader">
|
2022-09-09 03:44:33 +00:00
|
|
|
<span class="fs-title flex-grow">
|
|
|
|
<EditBox
|
|
|
|
bind:value={object.name}
|
|
|
|
placeholder={recruit.string.VacancyPlaceholder}
|
|
|
|
kind={'large-style'}
|
|
|
|
focusable
|
|
|
|
on:blur={() => {
|
|
|
|
if (rawName !== object.name) onChange('name', object.name)
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</span>
|
|
|
|
</svelte:fragment>
|
2022-11-30 05:53:49 +00:00
|
|
|
<svelte:fragment slot="utils">
|
2022-09-09 03:44:33 +00:00
|
|
|
<div class="p-1">
|
|
|
|
<Button icon={IconMoreH} kind={'transparent'} size={'medium'} on:click={showMenu} />
|
|
|
|
</div>
|
|
|
|
</svelte:fragment>
|
|
|
|
|
2022-05-13 06:41:30 +00:00
|
|
|
<Grid column={1} rowGap={1.5}>
|
|
|
|
<EditBox
|
|
|
|
bind:value={object.description}
|
|
|
|
placeholder={recruit.string.VacancyDescription}
|
2022-06-28 06:50:39 +00:00
|
|
|
focusable
|
2022-06-29 05:53:57 +00:00
|
|
|
on:blur={() => {
|
|
|
|
if (rawDesc !== object.description) onChange('description', object.description)
|
2022-05-13 06:41:30 +00:00
|
|
|
}}
|
|
|
|
/>
|
2022-06-28 06:50:39 +00:00
|
|
|
<FullDescriptionBox
|
|
|
|
content={object.fullDescription}
|
2022-06-29 05:53:57 +00:00
|
|
|
on:save={(res) => {
|
|
|
|
onChange('fullDescription', res.detail)
|
2022-06-28 06:50:39 +00:00
|
|
|
}}
|
|
|
|
/>
|
2022-05-25 05:56:06 +00:00
|
|
|
<Attachments
|
|
|
|
objectId={object._id}
|
|
|
|
_class={object._class}
|
|
|
|
space={object.space}
|
|
|
|
attachments={object.attachments ?? 0}
|
|
|
|
/>
|
2023-03-15 14:06:03 +00:00
|
|
|
<VacancyApplications objectId={object._id} />
|
2023-02-07 11:15:59 +00:00
|
|
|
<Component is={tracker.component.RelatedIssuesSection} props={{ object, label: recruit.string.RelatedIssues }} />
|
2023-01-18 05:14:59 +00:00
|
|
|
</Grid>
|
2022-05-12 11:29:49 +00:00
|
|
|
</Panel>
|
|
|
|
{/if}
|