mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-30 02:37:46 +03:00
Vacancies sorting (#1143)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
728216c936
commit
36ddf8477a
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Doc, DocumentQuery, Ref } from '@anticrm/core'
|
import core, { Doc, DocumentQuery, Ref } from '@anticrm/core'
|
||||||
import { createQuery } from '@anticrm/presentation'
|
import { createQuery } from '@anticrm/presentation'
|
||||||
import { Applicant, Vacancy } from '@anticrm/recruit'
|
import { Applicant, Vacancy } from '@anticrm/recruit'
|
||||||
import { Button, getCurrentLocation, Icon, Label, navigate, Scroller, showPopup, IconAdd } from '@anticrm/ui'
|
import { Button, getCurrentLocation, Icon, Label, navigate, Scroller, showPopup, IconAdd } from '@anticrm/ui'
|
||||||
@ -42,7 +42,7 @@
|
|||||||
vacancies = res
|
vacancies = res
|
||||||
})
|
})
|
||||||
|
|
||||||
function lowerIncludes (a?: string, b: string): boolean {
|
function lowerIncludes (a: string | undefined, b: string): boolean {
|
||||||
return (a ?? '').toLowerCase().includes(b)
|
return (a ?? '').toLowerCase().includes(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +63,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: resultQuery = vquery === '' ? {} : { $search: vquery }
|
$: resultQuery = vquery === '' ? {} : { $search: vquery }
|
||||||
|
type ApplicationInfo = { count: number, modifiedOn: number }
|
||||||
let applications: Map<Ref<Vacancy>, number> | undefined
|
let applications: Map<Ref<Vacancy>, ApplicationInfo> | undefined
|
||||||
|
|
||||||
const applicantQuery = createQuery()
|
const applicantQuery = createQuery()
|
||||||
$: if (vacancies.length > 0) {
|
$: if (vacancies.length > 0) {
|
||||||
@ -73,10 +73,13 @@
|
|||||||
recruit.class.Applicant,
|
recruit.class.Applicant,
|
||||||
{ ...(resultQuery as DocumentQuery<Applicant>), space: { $in: vacancies.map((it) => it._id) } },
|
{ ...(resultQuery as DocumentQuery<Applicant>), space: { $in: vacancies.map((it) => it._id) } },
|
||||||
(res) => {
|
(res) => {
|
||||||
const result = new Map<Ref<Vacancy>, number>()
|
const result = new Map<Ref<Vacancy>, ApplicationInfo>()
|
||||||
|
|
||||||
for (const d of res) {
|
for (const d of res) {
|
||||||
result.set(d.space, (result.get(d.space) ?? 0) + 1)
|
const v = result.get(d.space) ?? { count: 0, modifiedOn: 0 }
|
||||||
|
v.count++
|
||||||
|
v.modifiedOn = Math.max(v.modifiedOn, d.modifiedOn)
|
||||||
|
result.set(d.space, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
applications = result
|
applications = result
|
||||||
@ -88,6 +91,8 @@
|
|||||||
function showCreateDialog (ev: Event) {
|
function showCreateDialog (ev: Event) {
|
||||||
showPopup(CreateVacancy, { space: recruit.space.CandidatesPublic }, ev.target as HTMLElement)
|
showPopup(CreateVacancy, { space: recruit.space.CandidatesPublic }, ev.target as HTMLElement)
|
||||||
}
|
}
|
||||||
|
const applicationSorting = (a:Doc, b:Doc) => ((applications?.get(b._id as Ref<Vacancy>)?.count ?? 0) - (applications?.get(a._id as Ref<Vacancy>)?.count ?? 0)) ?? 0
|
||||||
|
const modifiedSorting = (a:Doc, b:Doc) => ((applications?.get(b._id as Ref<Vacancy>)?.modifiedOn ?? 0) - (applications?.get(a._id as Ref<Vacancy>)?.modifiedOn ?? 0)) ?? 0
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="ac-header full">
|
<div class="ac-header full">
|
||||||
@ -118,12 +123,21 @@
|
|||||||
key: '',
|
key: '',
|
||||||
presenter: recruit.component.VacancyCountPresenter,
|
presenter: recruit.component.VacancyCountPresenter,
|
||||||
label: recruit.string.Applications,
|
label: recruit.string.Applications,
|
||||||
props: { applications, resultQuery }
|
props: { applications, resultQuery },
|
||||||
|
sortingKey: '@applications',
|
||||||
|
sortingFunction: applicationSorting
|
||||||
},
|
},
|
||||||
'company',
|
'company',
|
||||||
'location',
|
'location',
|
||||||
'description',
|
'description',
|
||||||
'modifiedOn'
|
{
|
||||||
|
key: '',
|
||||||
|
presenter: recruit.component.VacancyModifiedPresenter,
|
||||||
|
label: core.string.Modified,
|
||||||
|
props: { applications },
|
||||||
|
sortingKey: 'modifiedOn',
|
||||||
|
sortingFunction: modifiedSorting
|
||||||
|
}
|
||||||
]}
|
]}
|
||||||
options={{}}
|
options={{}}
|
||||||
query={{
|
query={{
|
||||||
|
@ -21,14 +21,14 @@ import recruit from '../plugin'
|
|||||||
import VacancyApplicationsPopup from './VacancyApplicationsPopup.svelte'
|
import VacancyApplicationsPopup from './VacancyApplicationsPopup.svelte'
|
||||||
|
|
||||||
export let value: Vacancy
|
export let value: Vacancy
|
||||||
export let applications: Map<Ref<Vacancy>, number> | undefined
|
export let applications: Map<Ref<Vacancy>, {count: number, modifiedOn: number}> | undefined
|
||||||
export let resultQuery: DocumentQuery<Doc>
|
export let resultQuery: DocumentQuery<Doc>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if (applications?.get(value._id) ?? 0) > 0}
|
{#if (applications?.get(value._id)?.count ?? 0) > 0}
|
||||||
<Tooltip label={recruit.string.Applications} component={VacancyApplicationsPopup} props={{ value: value._id, resultQuery }}>
|
<Tooltip label={recruit.string.Applications} component={VacancyApplicationsPopup} props={{ value: value._id, resultQuery }}>
|
||||||
<div class="sm-tool-icon">
|
<div class="sm-tool-icon">
|
||||||
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span> {(applications?.get(value._id) ?? 0)}
|
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span> {(applications?.get(value._id)?.count ?? 0)}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
@ -0,0 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
// 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 { Ref } from '@anticrm/core'
|
||||||
|
import { Vacancy } from '@anticrm/recruit'
|
||||||
|
import { TimeSince } from '@anticrm/ui'
|
||||||
|
|
||||||
|
export let value: Vacancy
|
||||||
|
export let applications: Map<Ref<Vacancy>, {count: number, modifiedOn: number}> | undefined
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<TimeSince value={Math.max(applications?.get(value._id)?.modifiedOn ?? 0, value.modifiedOn)}/>
|
@ -47,6 +47,7 @@ import Vacancies from './components/Vacancies.svelte'
|
|||||||
import VacancyItemPresenter from './components/VacancyItemPresenter.svelte'
|
import VacancyItemPresenter from './components/VacancyItemPresenter.svelte'
|
||||||
import VacancyPresenter from './components/VacancyPresenter.svelte'
|
import VacancyPresenter from './components/VacancyPresenter.svelte'
|
||||||
import VacancyCountPresenter from './components/VacancyCountPresenter.svelte'
|
import VacancyCountPresenter from './components/VacancyCountPresenter.svelte'
|
||||||
|
import VacancyModifiedPresenter from './components/VacancyModifiedPresenter.svelte'
|
||||||
import recruit from './plugin'
|
import recruit from './plugin'
|
||||||
import PersonsPresenter from './components/review/PersonsPresenter.svelte'
|
import PersonsPresenter from './components/review/PersonsPresenter.svelte'
|
||||||
|
|
||||||
@ -155,6 +156,7 @@ export default async (): Promise<Resources> => ({
|
|||||||
Vacancies,
|
Vacancies,
|
||||||
VacancyItemPresenter,
|
VacancyItemPresenter,
|
||||||
VacancyCountPresenter,
|
VacancyCountPresenter,
|
||||||
|
VacancyModifiedPresenter,
|
||||||
|
|
||||||
CreateReviewCategory,
|
CreateReviewCategory,
|
||||||
EditReviewCategory,
|
EditReviewCategory,
|
||||||
|
@ -116,6 +116,7 @@ export default mergeIds(recruitId, recruit, {
|
|||||||
VacancyItemPresenter: '' as AnyComponent,
|
VacancyItemPresenter: '' as AnyComponent,
|
||||||
VacancyCountPresenter: '' as AnyComponent,
|
VacancyCountPresenter: '' as AnyComponent,
|
||||||
OpinionsPresenter: '' as AnyComponent,
|
OpinionsPresenter: '' as AnyComponent,
|
||||||
PersonsPresenter: '' as AnyComponent
|
PersonsPresenter: '' as AnyComponent,
|
||||||
|
VacancyModifiedPresenter: '' as AnyComponent
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
|
|
||||||
const q = createQuery()
|
const q = createQuery()
|
||||||
|
|
||||||
|
$: sortingFunction = (config.find(it => (typeof it !== 'string') && it.sortingKey === sortKey) as BuildModelKey)?.sortingFunction
|
||||||
|
|
||||||
async function update (
|
async function update (
|
||||||
_class: Ref<Class<Doc>>,
|
_class: Ref<Class<Doc>>,
|
||||||
query: DocumentQuery<Doc>,
|
query: DocumentQuery<Doc>,
|
||||||
@ -58,6 +60,10 @@
|
|||||||
query,
|
query,
|
||||||
(result) => {
|
(result) => {
|
||||||
objects = result
|
objects = result
|
||||||
|
if (sortingFunction !== undefined) {
|
||||||
|
const sf = sortingFunction
|
||||||
|
objects.sort((a, b) => -1 * sortOrder * sf(a, b))
|
||||||
|
}
|
||||||
loading = false
|
loading = false
|
||||||
},
|
},
|
||||||
{ sort: { [sortKey]: sortOrder }, ...options, limit: 200 }
|
{ sort: { [sortKey]: sortOrder }, ...options, limit: 200 }
|
||||||
|
@ -124,6 +124,9 @@ export interface BuildModelKey {
|
|||||||
|
|
||||||
label?: IntlString
|
label?: IntlString
|
||||||
sortingKey?: string
|
sortingKey?: string
|
||||||
|
|
||||||
|
// On client sorting function
|
||||||
|
sortingFunction?: (a: Doc, b: Doc) => number
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user