mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Various small issue fixes (#2556)
* Fix Issue title be selectable * TSK-582: Fix Vacancy subtitle be hyperlink * TSK-585: Add tasks to Applications Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
317e705b39
commit
d1fb81582d
@ -44,6 +44,7 @@
|
|||||||
"@hcengineering/setting": "^0.6.2",
|
"@hcengineering/setting": "^0.6.2",
|
||||||
"@hcengineering/model-task": "^0.6.0",
|
"@hcengineering/model-task": "^0.6.0",
|
||||||
"@hcengineering/workbench": "^0.6.2",
|
"@hcengineering/workbench": "^0.6.2",
|
||||||
|
"@hcengineering/model-tracker": "^0.6.0",
|
||||||
"@hcengineering/model-presentation": "^0.6.0",
|
"@hcengineering/model-presentation": "^0.6.0",
|
||||||
"@hcengineering/model-calendar": "^0.6.0",
|
"@hcengineering/model-calendar": "^0.6.0",
|
||||||
"@hcengineering/model-tags": "^0.6.0",
|
"@hcengineering/model-tags": "^0.6.0",
|
||||||
|
@ -39,6 +39,7 @@ import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core'
|
|||||||
import presentation from '@hcengineering/model-presentation'
|
import presentation from '@hcengineering/model-presentation'
|
||||||
import tags from '@hcengineering/model-tags'
|
import tags from '@hcengineering/model-tags'
|
||||||
import task, { actionTemplates, DOMAIN_TASK, TSpaceWithStates, TTask } from '@hcengineering/model-task'
|
import task, { actionTemplates, DOMAIN_TASK, TSpaceWithStates, TTask } from '@hcengineering/model-task'
|
||||||
|
import tracker from '@hcengineering/model-tracker'
|
||||||
import view, { actionTemplates as viewTemplates, createAction } from '@hcengineering/model-view'
|
import view, { actionTemplates as viewTemplates, createAction } from '@hcengineering/model-view'
|
||||||
import workbench, { Application, createNavigateAction } from '@hcengineering/model-workbench'
|
import workbench, { Application, createNavigateAction } from '@hcengineering/model-workbench'
|
||||||
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
||||||
@ -331,6 +332,11 @@ export function createModel (builder: Builder): void {
|
|||||||
'city',
|
'city',
|
||||||
'applications',
|
'applications',
|
||||||
'attachments',
|
'attachments',
|
||||||
|
{
|
||||||
|
key: '',
|
||||||
|
presenter: tracker.component.RelatedIssueSelector,
|
||||||
|
label: tracker.string.Relations
|
||||||
|
},
|
||||||
'comments',
|
'comments',
|
||||||
{
|
{
|
||||||
// key: '$lookup.skills', // Required, since presenter require list of tag references or '' and TagsPopupPresenter
|
// key: '$lookup.skills', // Required, since presenter require list of tag references or '' and TagsPopupPresenter
|
||||||
@ -351,7 +357,14 @@ export function createModel (builder: Builder): void {
|
|||||||
sortingKey: ['$lookup.channels.lastMessage', 'channels']
|
sortingKey: ['$lookup.channels.lastMessage', 'channels']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
hiddenKeys: ['name']
|
hiddenKeys: ['name'],
|
||||||
|
options: {
|
||||||
|
lookup: {
|
||||||
|
_id: {
|
||||||
|
related: [tracker.class.Issue, 'relations._id']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
recruit.viewlet.TableCandidate
|
recruit.viewlet.TableCandidate
|
||||||
)
|
)
|
||||||
@ -390,8 +403,21 @@ export function createModel (builder: Builder): void {
|
|||||||
descriptor: task.viewlet.StatusTable,
|
descriptor: task.viewlet.StatusTable,
|
||||||
config: [
|
config: [
|
||||||
'',
|
'',
|
||||||
'attachedTo',
|
{
|
||||||
|
key: 'attachedTo',
|
||||||
|
presenter: contact.component.PersonRefPresenter,
|
||||||
|
sortingKey: 'attachedTo',
|
||||||
|
label: recruit.string.Talent,
|
||||||
|
props: {
|
||||||
|
_class: recruit.mixin.Candidate
|
||||||
|
}
|
||||||
|
},
|
||||||
'assignee',
|
'assignee',
|
||||||
|
{
|
||||||
|
key: '',
|
||||||
|
presenter: tracker.component.RelatedIssueSelector,
|
||||||
|
label: tracker.string.Issues
|
||||||
|
},
|
||||||
'state',
|
'state',
|
||||||
'doneState',
|
'doneState',
|
||||||
'attachments',
|
'attachments',
|
||||||
@ -399,9 +425,18 @@ export function createModel (builder: Builder): void {
|
|||||||
'modifiedOn',
|
'modifiedOn',
|
||||||
{
|
{
|
||||||
key: '$lookup.attachedTo.$lookup.channels',
|
key: '$lookup.attachedTo.$lookup.channels',
|
||||||
|
label: contact.string.ContactInfo,
|
||||||
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels']
|
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels']
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
hiddenKeys: ['name', 'attachedTo'],
|
||||||
|
options: {
|
||||||
|
lookup: {
|
||||||
|
_id: {
|
||||||
|
related: [tracker.class.Issue, 'relations._id']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
recruit.viewlet.TableApplicant
|
recruit.viewlet.TableApplicant
|
||||||
)
|
)
|
||||||
@ -413,18 +448,40 @@ export function createModel (builder: Builder): void {
|
|||||||
descriptor: view.viewlet.Table,
|
descriptor: view.viewlet.Table,
|
||||||
config: [
|
config: [
|
||||||
'',
|
'',
|
||||||
'attachedTo',
|
{
|
||||||
|
key: 'attachedTo',
|
||||||
|
presenter: contact.component.PersonRefPresenter,
|
||||||
|
label: recruit.string.Talent,
|
||||||
|
sortingKey: 'attachedTo',
|
||||||
|
props: {
|
||||||
|
_class: recruit.mixin.Candidate
|
||||||
|
}
|
||||||
|
},
|
||||||
'assignee',
|
'assignee',
|
||||||
|
{
|
||||||
|
key: '',
|
||||||
|
presenter: tracker.component.RelatedIssueSelector,
|
||||||
|
label: tracker.string.Issues
|
||||||
|
},
|
||||||
'state',
|
'state',
|
||||||
'comments',
|
'comments',
|
||||||
'attachments',
|
'attachments',
|
||||||
'modifiedOn',
|
'modifiedOn',
|
||||||
|
'$lookup.space.company',
|
||||||
{
|
{
|
||||||
key: '$lookup.attachedTo.$lookup.channels',
|
key: '$lookup.attachedTo.$lookup.channels',
|
||||||
|
label: contact.string.ContactInfo,
|
||||||
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels']
|
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
hiddenKeys: ['name']
|
options: {
|
||||||
|
lookup: {
|
||||||
|
_id: {
|
||||||
|
related: [tracker.class.Issue, 'relations._id']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hiddenKeys: ['name', 'attachedTo']
|
||||||
},
|
},
|
||||||
recruit.viewlet.ApplicantTable
|
recruit.viewlet.ApplicantTable
|
||||||
)
|
)
|
||||||
@ -452,7 +509,7 @@ export function createModel (builder: Builder): void {
|
|||||||
],
|
],
|
||||||
assignee: contact.class.Employee,
|
assignee: contact.class.Employee,
|
||||||
_id: {
|
_id: {
|
||||||
todoItems: task.class.TodoItem
|
related: [tracker.class.Issue, 'relations._id']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,7 +729,7 @@ export function createModel (builder: Builder): void {
|
|||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ClassFilters, {
|
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ClassFilters, {
|
||||||
filters: ['attachedTo', 'assignee', 'state', 'doneState', 'modifiedOn']
|
filters: ['attachedTo', 'space', 'assignee', 'state', 'doneState', 'modifiedOn']
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ClassFilters, {
|
builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ClassFilters, {
|
||||||
@ -917,6 +974,25 @@ export function createModel (builder: Builder): void {
|
|||||||
group: 'create'
|
group: 'create'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(recruit.mixin.Candidate, core.class.Class, view.mixin.ObjectEditorFooter, {
|
||||||
|
editor: tracker.component.RelatedIssuesSection,
|
||||||
|
props: {
|
||||||
|
label: recruit.string.RelatedIssues
|
||||||
|
}
|
||||||
|
})
|
||||||
|
builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ObjectEditorFooter, {
|
||||||
|
editor: tracker.component.RelatedIssuesSection,
|
||||||
|
props: {
|
||||||
|
label: recruit.string.RelatedIssues
|
||||||
|
}
|
||||||
|
})
|
||||||
|
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ObjectEditorFooter, {
|
||||||
|
editor: tracker.component.RelatedIssuesSection,
|
||||||
|
props: {
|
||||||
|
label: recruit.string.RelatedIssues
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { recruitOperation } from './migration'
|
export { recruitOperation } from './migration'
|
||||||
|
@ -134,8 +134,8 @@ export class TTask extends TAttachedDoc implements Task {
|
|||||||
|
|
||||||
declare rank: string
|
declare rank: string
|
||||||
|
|
||||||
@Prop(Collection(task.class.TodoItem), task.string.Todos)
|
// @Prop(Collection(task.class.TodoItem), task.string.Todos)
|
||||||
todoItems!: number
|
// todoItems!: number
|
||||||
|
|
||||||
@Prop(Collection(tags.class.TagReference, task.string.TaskLabels), task.string.TaskLabels)
|
@Prop(Collection(tags.class.TagReference, task.string.TaskLabels), task.string.TaskLabels)
|
||||||
labels!: number
|
labels!: number
|
||||||
|
@ -46,6 +46,7 @@ import type {
|
|||||||
ListItemPresenter,
|
ListItemPresenter,
|
||||||
ObjectEditor,
|
ObjectEditor,
|
||||||
ObjectEditorHeader,
|
ObjectEditorHeader,
|
||||||
|
ObjectEditorFooter,
|
||||||
ObjectFactory,
|
ObjectFactory,
|
||||||
ObjectPresenter,
|
ObjectPresenter,
|
||||||
ObjectTitle,
|
ObjectTitle,
|
||||||
@ -173,6 +174,11 @@ export class TObjectEditorHeader extends TClass implements ObjectEditorHeader {
|
|||||||
editor!: AnyComponent
|
editor!: AnyComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mixin(view.mixin.ObjectEditorFooter, core.class.Class)
|
||||||
|
export class TObjectEditorFooter extends TClass implements ObjectEditorFooter {
|
||||||
|
editor!: AnyComponent
|
||||||
|
}
|
||||||
|
|
||||||
@Mixin(view.mixin.SpaceHeader, core.class.Class)
|
@Mixin(view.mixin.SpaceHeader, core.class.Class)
|
||||||
export class TSpaceHeader extends TClass implements SpaceHeader {
|
export class TSpaceHeader extends TClass implements SpaceHeader {
|
||||||
header!: AnyComponent
|
header!: AnyComponent
|
||||||
@ -325,6 +331,7 @@ export function createModel (builder: Builder): void {
|
|||||||
TObjectFactory,
|
TObjectFactory,
|
||||||
TObjectTitle,
|
TObjectTitle,
|
||||||
TObjectEditorHeader,
|
TObjectEditorHeader,
|
||||||
|
TObjectEditorFooter,
|
||||||
TSpaceHeader,
|
TSpaceHeader,
|
||||||
TSpaceName,
|
TSpaceName,
|
||||||
TIgnoreActions,
|
TIgnoreActions,
|
||||||
|
@ -71,7 +71,14 @@
|
|||||||
{#if icon}<div class="wrapped-icon"><Icon {icon} size={'medium'} /></div>{/if}
|
{#if icon}<div class="wrapped-icon"><Icon {icon} size={'medium'} /></div>{/if}
|
||||||
<div class="title-wrapper">
|
<div class="title-wrapper">
|
||||||
{#if title}<span class="wrapped-title">{title}</span>{/if}
|
{#if title}<span class="wrapped-title">{title}</span>{/if}
|
||||||
{#if subtitle}<span class="wrapped-subtitle">{subtitle}</span>{/if}
|
{#if subtitle || $$slots.subtitle}
|
||||||
|
<span class="wrapped-subtitle">
|
||||||
|
{#if subtitle}
|
||||||
|
{subtitle}
|
||||||
|
{/if}
|
||||||
|
<slot name="subtitle" />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import contact, { Contact, Employee, formatName } from '@hcengineering/contact'
|
import contact, { Contact, Employee, formatName } from '@hcengineering/contact'
|
||||||
import { Class, DocumentQuery, FindOptions, Ref } from '@hcengineering/core'
|
import { Class, DocumentQuery, FindOptions, Hierarchy, Ref } from '@hcengineering/core'
|
||||||
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
@ -166,7 +166,7 @@
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
action={() => {
|
action={() => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
showPanel(view.component.EditDoc, selected._id, selected._class, 'content')
|
showPanel(view.component.EditDoc, selected._id, Hierarchy.mixinOrClass(selected), 'content')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import contact, { Contact, formatName } from '@hcengineering/contact'
|
import contact, { Contact, formatName } from '@hcengineering/contact'
|
||||||
import type { Class, DocumentQuery, FindOptions, Ref } from '@hcengineering/core'
|
import { Class, DocumentQuery, FindOptions, Hierarchy, Ref } from '@hcengineering/core'
|
||||||
import { Asset, getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
import { Asset, getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
@ -180,7 +180,7 @@
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
action={() => {
|
action={() => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
showPanel(view.component.EditDoc, selected._id, selected._class, 'content')
|
showPanel(view.component.EditDoc, selected._id, Hierarchy.mixinOrClass(selected), 'content')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -644,6 +644,7 @@ a.no-line {
|
|||||||
|
|
||||||
.pointer-events-none { pointer-events: none; }
|
.pointer-events-none { pointer-events: none; }
|
||||||
.select-text { user-select: text; }
|
.select-text { user-select: text; }
|
||||||
|
.select-text-i { user-select: text !important; }
|
||||||
|
|
||||||
/* Text */
|
/* Text */
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import attachment from '@hcengineering/attachment'
|
import attachment from '@hcengineering/attachment'
|
||||||
import contact, { Channel, Contact, formatName } from '@hcengineering/contact'
|
import contact, { Channel, Contact, formatName } from '@hcengineering/contact'
|
||||||
|
import { Hierarchy } from '@hcengineering/core'
|
||||||
import { Avatar, createQuery } from '@hcengineering/presentation'
|
import { Avatar, createQuery } from '@hcengineering/presentation'
|
||||||
import { Component, Label, showPanel } from '@hcengineering/ui'
|
import { Component, Label, showPanel } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
@ -42,11 +43,12 @@
|
|||||||
<Avatar avatar={object.avatar} size={'large'} icon={contact.icon.Company} />
|
<Avatar avatar={object.avatar} size={'large'} icon={contact.icon.Company} />
|
||||||
</div>
|
</div>
|
||||||
{#if object}
|
{#if object}
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
class="name lines-limit-2"
|
class="name lines-limit-2"
|
||||||
class:over-underline={!disabled}
|
class:over-underline={!disabled}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (!disabled) showPanel(view.component.EditDoc, object._id, object._class, 'content')
|
if (!disabled) showPanel(view.component.EditDoc, object._id, Hierarchy.mixinOrClass(object), 'content')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{formatName(object.name)}
|
{formatName(object.name)}
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import contact, { Person } from '@hcengineering/contact'
|
import contact, { Person } from '@hcengineering/contact'
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Class, Ref } from '@hcengineering/core'
|
||||||
import { IntlString } from '@hcengineering/platform'
|
import { IntlString } from '@hcengineering/platform'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import { PersonLabelTooltip } from '..'
|
import { PersonLabelTooltip } from '..'
|
||||||
import PersonPresenter from './PersonPresenter.svelte'
|
import PersonPresenter from './PersonPresenter.svelte'
|
||||||
|
|
||||||
export let value: Ref<Person> | null | undefined
|
export let value: Ref<Person> | null | undefined
|
||||||
|
export let _class: Ref<Class<Person>> = contact.class.Person
|
||||||
export let inline = false
|
export let inline = false
|
||||||
export let enlargedText = false
|
export let enlargedText = false
|
||||||
export let isInteractive = true
|
export let isInteractive = true
|
||||||
@ -34,7 +35,7 @@
|
|||||||
|
|
||||||
let person: Person | undefined
|
let person: Person | undefined
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
$: value && query.query(contact.class.Person, { _id: value }, (res) => ([person] = res), { limit: 1 })
|
$: value && query.query(_class, { _id: value }, (res) => ([person] = res), { limit: 1 })
|
||||||
|
|
||||||
function getValue (person: Person | undefined, value: Ref<Person> | null | undefined): Person | null | undefined {
|
function getValue (person: Person | undefined, value: Ref<Person> | null | undefined): Person | null | undefined {
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
|
@ -67,7 +67,8 @@ export {
|
|||||||
EmployeeBrowser,
|
EmployeeBrowser,
|
||||||
MemberPresenter,
|
MemberPresenter,
|
||||||
EmployeeEditor,
|
EmployeeEditor,
|
||||||
EmployeeAccountRefPresenter
|
EmployeeAccountRefPresenter,
|
||||||
|
EditPerson
|
||||||
}
|
}
|
||||||
|
|
||||||
const toObjectSearchResult = (e: WithLookup<Contact>): ObjectSearchResult => ({
|
const toObjectSearchResult = (e: WithLookup<Contact>): ObjectSearchResult => ({
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"HaveWorkspace": "Уже есть рабочее пространство?",
|
"HaveWorkspace": "Уже есть рабочее пространство?",
|
||||||
"LastName": "Фамилия",
|
"LastName": "Фамилия",
|
||||||
"FirstName": "Имя",
|
"FirstName": "Имя",
|
||||||
"Join": "Присоедениться",
|
"Join": "Присоединиться",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Password": "Пароль",
|
"Password": "Пароль",
|
||||||
"Workspace": "Рабочее пространство",
|
"Workspace": "Рабочее пространство",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import chunter from '@hcengineering/chunter'
|
import chunter from '@hcengineering/chunter'
|
||||||
import contact, { Channel, formatName, Person } from '@hcengineering/contact'
|
import contact, { Channel, formatName, Person } from '@hcengineering/contact'
|
||||||
import { ChannelsEditor } from '@hcengineering/contact-resources'
|
import { ChannelsEditor } from '@hcengineering/contact-resources'
|
||||||
|
import { Hierarchy } from '@hcengineering/core'
|
||||||
import { Avatar, createQuery, getClient } from '@hcengineering/presentation'
|
import { Avatar, createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Component, Label, showPanel } from '@hcengineering/ui'
|
import { Component, Label, showPanel } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
@ -47,12 +48,13 @@
|
|||||||
<div class="label uppercase"><Label label={recruit.string.Talent} /></div>
|
<div class="label uppercase"><Label label={recruit.string.Talent} /></div>
|
||||||
<Avatar avatar={candidate?.avatar} size={'large'} />
|
<Avatar avatar={candidate?.avatar} size={'large'} />
|
||||||
{#if candidate}
|
{#if candidate}
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
class="name lines-limit-2"
|
class="name lines-limit-2"
|
||||||
class:over-underline={!disabled}
|
class:over-underline={!disabled}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (!disabled && candidate) {
|
if (!disabled && candidate) {
|
||||||
showPanel(view.component.EditDoc, candidate._id, candidate._class, 'content')
|
showPanel(view.component.EditDoc, candidate._id, Hierarchy.mixinOrClass(candidate), 'content')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -14,16 +14,16 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import type { Candidate, Applicant, Vacancy } from '@hcengineering/recruit'
|
import type { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
|
||||||
import { Scroller } from '@hcengineering/ui'
|
import { Scroller } from '@hcengineering/ui'
|
||||||
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import CandidateCard from './CandidateCard.svelte'
|
import CandidateCard from './CandidateCard.svelte'
|
||||||
import VacancyCard from './VacancyCard.svelte'
|
|
||||||
import ExpandRightDouble from './icons/ExpandRightDouble.svelte'
|
import ExpandRightDouble from './icons/ExpandRightDouble.svelte'
|
||||||
|
import VacancyCard from './VacancyCard.svelte'
|
||||||
|
|
||||||
import recruit from '../plugin'
|
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Ref } from '@hcengineering/core'
|
||||||
|
import recruit from '../plugin'
|
||||||
import Reviews from './review/Reviews.svelte'
|
import Reviews from './review/Reviews.svelte'
|
||||||
|
|
||||||
export let object: Applicant
|
export let object: Applicant
|
||||||
|
@ -21,8 +21,7 @@
|
|||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Vacancy } from '@hcengineering/recruit'
|
import { Vacancy } from '@hcengineering/recruit'
|
||||||
import { FullDescriptionBox } from '@hcengineering/text-editor'
|
import { FullDescriptionBox } from '@hcengineering/text-editor'
|
||||||
import tracker from '@hcengineering/tracker'
|
import { Button, EditBox, Grid, IconMoreH, showPopup } from '@hcengineering/ui'
|
||||||
import { Button, Component, EditBox, Grid, IconMoreH, showPopup } from '@hcengineering/ui'
|
|
||||||
import { ClassAttributeBar, ContextMenu } from '@hcengineering/view-resources'
|
import { ClassAttributeBar, ContextMenu } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import recruit from '../plugin'
|
import recruit from '../plugin'
|
||||||
@ -65,7 +64,6 @@
|
|||||||
<Panel
|
<Panel
|
||||||
icon={clazz.icon}
|
icon={clazz.icon}
|
||||||
title={object.name}
|
title={object.name}
|
||||||
subtitle={object.description}
|
|
||||||
isHeader={true}
|
isHeader={true}
|
||||||
isAside={true}
|
isAside={true}
|
||||||
{object}
|
{object}
|
||||||
@ -73,6 +71,11 @@
|
|||||||
dispatch('close')
|
dispatch('close')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<svelte:fragment slot="subtitle">
|
||||||
|
<a href={object.description} target="_blank" rel="noreferrer noopener">
|
||||||
|
{object.description}
|
||||||
|
</a>
|
||||||
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="attributes" let:direction={dir}>
|
<svelte:fragment slot="attributes" let:direction={dir}>
|
||||||
{#if dir === 'column'}
|
{#if dir === 'column'}
|
||||||
<div class="ac-subtitle">
|
<div class="ac-subtitle">
|
||||||
@ -129,9 +132,6 @@
|
|||||||
space={object.space}
|
space={object.space}
|
||||||
attachments={object.attachments ?? 0}
|
attachments={object.attachments ?? 0}
|
||||||
/>
|
/>
|
||||||
<!-- <MembersBox label={recruit.string.Members} space={object} /> -->
|
|
||||||
|
|
||||||
<Component is={tracker.component.RelatedIssuesSection} props={{ object, label: recruit.string.RelatedIssues }} />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Panel>
|
</Panel>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
import { AttachmentsPresenter } from '@hcengineering/attachment-resources'
|
import { AttachmentsPresenter } from '@hcengineering/attachment-resources'
|
||||||
import { CommentsPresenter } from '@hcengineering/chunter-resources'
|
import { CommentsPresenter } from '@hcengineering/chunter-resources'
|
||||||
import contact, { formatName } from '@hcengineering/contact'
|
import contact, { formatName } from '@hcengineering/contact'
|
||||||
import type { WithLookup } from '@hcengineering/core'
|
import { Hierarchy, WithLookup } from '@hcengineering/core'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import { Avatar } from '@hcengineering/presentation'
|
import { Avatar } from '@hcengineering/presentation'
|
||||||
import type { Applicant, Candidate } from '@hcengineering/recruit'
|
import type { Applicant, Candidate } from '@hcengineering/recruit'
|
||||||
import task, { TodoItem } from '@hcengineering/task'
|
|
||||||
import { AssigneePresenter } from '@hcengineering/task-resources'
|
import { AssigneePresenter } from '@hcengineering/task-resources'
|
||||||
import { Component, showPanel, tooltip } from '@hcengineering/ui'
|
import tracker from '@hcengineering/tracker'
|
||||||
|
import { Component, showPanel } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import ApplicationPresenter from './ApplicationPresenter.svelte'
|
import ApplicationPresenter from './ApplicationPresenter.svelte'
|
||||||
|
|
||||||
@ -30,15 +30,13 @@
|
|||||||
export let dragged: boolean
|
export let dragged: boolean
|
||||||
|
|
||||||
function showCandidate () {
|
function showCandidate () {
|
||||||
showPanel(view.component.EditDoc, object._id, object._class, 'content')
|
showPanel(view.component.EditDoc, object._id, Hierarchy.mixinOrClass(object), 'content')
|
||||||
}
|
}
|
||||||
|
|
||||||
$: todoItems = (object.$lookup?.todoItems as TodoItem[]) ?? []
|
|
||||||
$: doneTasks = todoItems.filter((it) => it.done)
|
|
||||||
|
|
||||||
$: channels = (object.$lookup?.attachedTo as WithLookup<Candidate>)?.$lookup?.channels
|
$: channels = (object.$lookup?.attachedTo as WithLookup<Candidate>)?.$lookup?.channels
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div class="flex-col pt-2 pb-2 pr-4 pl-4 cursor-pointer" on:click={showCandidate}>
|
<div class="flex-col pt-2 pb-2 pr-4 pl-4 cursor-pointer" on:click={showCandidate}>
|
||||||
<div class="flex-between mb-3">
|
<div class="flex-between mb-3">
|
||||||
<div class="flex-row-center">
|
<div class="flex-row-center">
|
||||||
@ -72,18 +70,7 @@
|
|||||||
<div class="flex-row-center">
|
<div class="flex-row-center">
|
||||||
<div class="sm-tool-icon step-lr75">
|
<div class="sm-tool-icon step-lr75">
|
||||||
<ApplicationPresenter value={object} />
|
<ApplicationPresenter value={object} />
|
||||||
{#if todoItems.length > 0}
|
<Component is={tracker.component.RelatedIssueSelector} props={{ object }} />
|
||||||
<div
|
|
||||||
class="ml-2"
|
|
||||||
use:tooltip={{
|
|
||||||
label: task.string.TodoItems,
|
|
||||||
component: task.component.TodoItemsPopup,
|
|
||||||
props: { value: object }
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
({doneTasks?.length}/{todoItems.length})
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{#if (object.attachments ?? 0) > 0}
|
{#if (object.attachments ?? 0) > 0}
|
||||||
<div class="step-lr75">
|
<div class="step-lr75">
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import calendar from '@hcengineering/calendar'
|
import calendar from '@hcengineering/calendar'
|
||||||
import contact, { Contact } from '@hcengineering/contact'
|
import contact, { Contact } from '@hcengineering/contact'
|
||||||
|
import { Hierarchy } from '@hcengineering/core'
|
||||||
import { getClient, UserBox } from '@hcengineering/presentation'
|
import { getClient, UserBox } from '@hcengineering/presentation'
|
||||||
import type { Review } from '@hcengineering/recruit'
|
import type { Review } from '@hcengineering/recruit'
|
||||||
import { FullDescriptionBox } from '@hcengineering/text-editor'
|
import { FullDescriptionBox } from '@hcengineering/text-editor'
|
||||||
@ -70,7 +71,7 @@
|
|||||||
class="clear-mins"
|
class="clear-mins"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (candidate !== undefined) {
|
if (candidate !== undefined) {
|
||||||
showPanel(view.component.EditDoc, candidate._id, candidate._class, 'content')
|
showPanel(view.component.EditDoc, candidate._id, Hierarchy.mixinOrClass(candidate), 'content')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -185,7 +185,7 @@
|
|||||||
<UpDownNavigator element={issue} />
|
<UpDownNavigator element={issue} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="header">
|
<svelte:fragment slot="header">
|
||||||
<span class="fs-title">
|
<span class="fs-title select-text-i">
|
||||||
{#if issueId}{issueId}{/if}
|
{#if issueId}{issueId}{/if}
|
||||||
</span>
|
</span>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
@ -265,7 +265,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<span slot="actions-label">
|
<span slot="actions-label" class="select-text">
|
||||||
{#if issueId}{issueId}{/if}
|
{#if issueId}{issueId}{/if}
|
||||||
</span>
|
</span>
|
||||||
<svelte:fragment slot="actions">
|
<svelte:fragment slot="actions">
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
<!--
|
||||||
|
// 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 { Doc, Ref, SortingOrder, WithLookup } from '@hcengineering/core'
|
||||||
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
|
import { Issue, IssueStatus, Team } from '@hcengineering/tracker'
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonKind,
|
||||||
|
ButtonSize,
|
||||||
|
closeTooltip,
|
||||||
|
getPlatformColor,
|
||||||
|
ProgressCircle,
|
||||||
|
SelectPopup,
|
||||||
|
showPanel,
|
||||||
|
showPopup
|
||||||
|
} from '@hcengineering/ui'
|
||||||
|
import { getIssueId } from '../../../issues'
|
||||||
|
import tracker from '../../../plugin'
|
||||||
|
import { subIssueListProvider } from '../../../utils'
|
||||||
|
|
||||||
|
export let object: WithLookup<Doc & { related: number }> | undefined
|
||||||
|
export let value: WithLookup<Doc & { related: number }> | undefined
|
||||||
|
export let currentTeam: Team | undefined
|
||||||
|
|
||||||
|
export let kind: ButtonKind = 'link-bordered'
|
||||||
|
export let size: ButtonSize = 'inline'
|
||||||
|
export let justify: 'left' | 'center' = 'left'
|
||||||
|
export let width: string | undefined = 'min-contet'
|
||||||
|
|
||||||
|
let btn: HTMLElement
|
||||||
|
|
||||||
|
let subIssues: Issue[] = []
|
||||||
|
let countComplate: number = 0
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
const statusesQuery = createQuery()
|
||||||
|
|
||||||
|
$: _object = object ?? value
|
||||||
|
|
||||||
|
$: _object && update(_object)
|
||||||
|
|
||||||
|
function update (value: WithLookup<Doc & { related: number }>): void {
|
||||||
|
if (value.$lookup?.related !== undefined) {
|
||||||
|
query.unsubscribe()
|
||||||
|
subIssues = value.$lookup.related as Issue[]
|
||||||
|
subIssues.sort((a, b) => (a.rank ?? '').localeCompare(b.rank ?? ''))
|
||||||
|
} else {
|
||||||
|
query.query(
|
||||||
|
tracker.class.Issue,
|
||||||
|
{ 'relations._id': value._id, 'relations._class': value._class },
|
||||||
|
(res) => (subIssues = res),
|
||||||
|
{
|
||||||
|
sort: { rank: SortingOrder.Ascending }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
statusesQuery.query(tracker.class.IssueStatus, {}, (res) => (statuses = res), {
|
||||||
|
lookup: { category: tracker.class.IssueStatusCategory }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let statuses: WithLookup<IssueStatus>[] = []
|
||||||
|
|
||||||
|
$: if (statuses && subIssues) {
|
||||||
|
const doneStatuses = statuses.filter((s) => s.category === tracker.issueStatusCategory.Completed).map((p) => p._id)
|
||||||
|
countComplate = subIssues.filter((si) => doneStatuses.includes(si.status)).length
|
||||||
|
}
|
||||||
|
$: hasSubIssues = (subIssues?.length ?? 0) > 0
|
||||||
|
|
||||||
|
function getIssueStatusIcon (issue: Issue, statuses: WithLookup<IssueStatus>[] | undefined) {
|
||||||
|
const status = statuses?.find((s) => issue.status === s._id)
|
||||||
|
const category = status?.$lookup?.category
|
||||||
|
const color = status?.color ?? category?.color
|
||||||
|
|
||||||
|
return {
|
||||||
|
...(category?.icon !== undefined ? { icon: category.icon } : {}),
|
||||||
|
...(color !== undefined ? { iconColor: getPlatformColor(color) } : {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openIssue (target: Ref<Issue>) {
|
||||||
|
subIssueListProvider(subIssues, target)
|
||||||
|
showPanel(tracker.component.EditIssue, target, tracker.class.Issue, 'content')
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSubIssues () {
|
||||||
|
if (subIssues) {
|
||||||
|
closeTooltip()
|
||||||
|
showPopup(
|
||||||
|
SelectPopup,
|
||||||
|
{
|
||||||
|
value: subIssues.map((iss) => {
|
||||||
|
const text = currentTeam ? `${getIssueId(currentTeam, iss)} ${iss.title}` : iss.title
|
||||||
|
|
||||||
|
return { id: iss._id, text, isSelected: false, ...getIssueStatusIcon(iss, statuses) }
|
||||||
|
}),
|
||||||
|
width: 'large'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getBoundingClientRect: () => {
|
||||||
|
const rect = btn.getBoundingClientRect()
|
||||||
|
const offsetX = 0
|
||||||
|
const offsetY = 0
|
||||||
|
|
||||||
|
return DOMRect.fromRect({ width: 1, height: 1, x: rect.left + offsetX, y: rect.bottom + offsetY })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(selectedIssue) => {
|
||||||
|
selectedIssue !== undefined && openIssue(selectedIssue)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if hasSubIssues}
|
||||||
|
<div class="flex-center flex-no-shrink" bind:this={btn}>
|
||||||
|
<Button
|
||||||
|
{width}
|
||||||
|
{kind}
|
||||||
|
{size}
|
||||||
|
{justify}
|
||||||
|
on:click={(ev) => {
|
||||||
|
ev.stopPropagation()
|
||||||
|
if (subIssues) showSubIssues()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="content">
|
||||||
|
{#if subIssues}
|
||||||
|
<div class="flex-row-center content-color text-sm pointer-events-none">
|
||||||
|
<div class="mr-1">
|
||||||
|
<ProgressCircle bind:value={countComplate} bind:max={subIssues.length} size={'inline'} primary />
|
||||||
|
</div>
|
||||||
|
{countComplate}/{subIssues.length}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
@ -61,6 +61,7 @@ import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.sv
|
|||||||
import Views from './components/views/Views.svelte'
|
import Views from './components/views/Views.svelte'
|
||||||
import Statuses from './components/workflow/Statuses.svelte'
|
import Statuses from './components/workflow/Statuses.svelte'
|
||||||
import RelatedIssuesSection from './components/issues/related/RelatedIssuesSection.svelte'
|
import RelatedIssuesSection from './components/issues/related/RelatedIssuesSection.svelte'
|
||||||
|
import RelatedIssueSelector from './components/issues/related/RelatedIssueSelector.svelte'
|
||||||
import {
|
import {
|
||||||
getIssueId,
|
getIssueId,
|
||||||
getIssueTitle,
|
getIssueTitle,
|
||||||
@ -280,7 +281,8 @@ export default async (): Promise<Resources> => ({
|
|||||||
TeamPresenter,
|
TeamPresenter,
|
||||||
IssueStatistics,
|
IssueStatistics,
|
||||||
StatusRefPresenter,
|
StatusRefPresenter,
|
||||||
RelatedIssuesSection
|
RelatedIssuesSection,
|
||||||
|
RelatedIssueSelector
|
||||||
},
|
},
|
||||||
completion: {
|
completion: {
|
||||||
IssueQuery: async (client: Client, query: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] }) =>
|
IssueQuery: async (client: Client, query: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] }) =>
|
||||||
|
@ -400,6 +400,7 @@ export default plugin(trackerId, {
|
|||||||
TrackerApp: '' as AnyComponent,
|
TrackerApp: '' as AnyComponent,
|
||||||
RelatedIssues: '' as AnyComponent,
|
RelatedIssues: '' as AnyComponent,
|
||||||
RelatedIssuesSection: '' as AnyComponent,
|
RelatedIssuesSection: '' as AnyComponent,
|
||||||
|
RelatedIssueSelector: '' as AnyComponent,
|
||||||
RelatedIssueTemplates: '' as AnyComponent,
|
RelatedIssueTemplates: '' as AnyComponent,
|
||||||
EditIssue: '' as AnyComponent,
|
EditIssue: '' as AnyComponent,
|
||||||
CreateIssue: '' as AnyComponent,
|
CreateIssue: '' as AnyComponent,
|
||||||
|
@ -35,8 +35,8 @@
|
|||||||
import { categorizeFields, getCollectionCounter, getFiltredKeys } from '../utils'
|
import { categorizeFields, getCollectionCounter, getFiltredKeys } from '../utils'
|
||||||
import ActionContext from './ActionContext.svelte'
|
import ActionContext from './ActionContext.svelte'
|
||||||
import DocAttributeBar from './DocAttributeBar.svelte'
|
import DocAttributeBar from './DocAttributeBar.svelte'
|
||||||
import UpDownNavigator from './UpDownNavigator.svelte'
|
|
||||||
import IconMixin from './icons/Mixin.svelte'
|
import IconMixin from './icons/Mixin.svelte'
|
||||||
|
import UpDownNavigator from './UpDownNavigator.svelte'
|
||||||
|
|
||||||
export let _id: Ref<Doc>
|
export let _id: Ref<Doc>
|
||||||
export let _class: Ref<Class<Doc>>
|
export let _class: Ref<Class<Doc>>
|
||||||
@ -147,19 +147,32 @@
|
|||||||
pinned?: boolean
|
pinned?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEditor (_class: Ref<Class<Doc>>): Promise<MixinEditor> {
|
function getEditor (_class: Ref<Class<Doc>>): MixinEditor {
|
||||||
const clazz = hierarchy.getClass(_class)
|
const clazz = hierarchy.getClass(_class)
|
||||||
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
|
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
|
||||||
if (editorMixin?.editor == null && clazz.extends != null) return getEditor(clazz.extends)
|
if (editorMixin?.editor == null && clazz.extends != null) return getEditor(clazz.extends)
|
||||||
return { editor: editorMixin.editor, pinned: editorMixin?.pinned }
|
return { editor: editorMixin.editor, pinned: editorMixin?.pinned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEditorFooter (_class: Ref<Class<Doc>>): { footer: AnyComponent; props?: Record<string, any> } | undefined {
|
||||||
|
const clazz = hierarchy.getClass(_class)
|
||||||
|
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditorFooter)
|
||||||
|
if (editorMixin?.editor == null && clazz.extends != null) return getEditorFooter(clazz.extends)
|
||||||
|
if (editorMixin.editor) {
|
||||||
|
return { footer: editorMixin.editor, props: editorMixin?.props }
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
let mainEditor: MixinEditor | undefined
|
let mainEditor: MixinEditor | undefined
|
||||||
|
|
||||||
|
$: editorFooter = getEditorFooter(_class)
|
||||||
|
|
||||||
$: getEditorOrDefault(realObjectClass, showAllMixins, _id)
|
$: getEditorOrDefault(realObjectClass, showAllMixins, _id)
|
||||||
|
|
||||||
async function getEditorOrDefault (_class: Ref<Class<Doc>>, showAllMixins: boolean, _id: Ref<Doc>): Promise<void> {
|
function getEditorOrDefault (_class: Ref<Class<Doc>>, showAllMixins: boolean, _id: Ref<Doc>): void {
|
||||||
parentClass = getParentClass(_class)
|
parentClass = getParentClass(_class)
|
||||||
mainEditor = await getEditor(_class)
|
mainEditor = getEditor(_class)
|
||||||
updateKeys(showAllMixins)
|
updateKeys(showAllMixins)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,5 +383,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if editorFooter}
|
||||||
|
<Component is={editorFooter.footer} props={{ object, _class, ...editorFooter.props }} />
|
||||||
|
{/if}
|
||||||
</Panel>
|
</Panel>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@hcengineering/core'
|
import { Class, Doc, DocumentQuery, FindOptions, Hierarchy, Ref } from '@hcengineering/core'
|
||||||
import { Asset, IntlString } from '@hcengineering/platform'
|
import { Asset, IntlString } from '@hcengineering/platform'
|
||||||
import presentation, { getClient, ObjectCreate } from '@hcengineering/presentation'
|
import presentation, { getClient, ObjectCreate } from '@hcengineering/presentation'
|
||||||
import {
|
import {
|
||||||
@ -151,7 +151,7 @@
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
action={() => {
|
action={() => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
showPanel(view.component.EditDoc, selected._id, selected._class, 'content')
|
showPanel(view.component.EditDoc, selected._id, Hierarchy.mixinOrClass(selected), 'content')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
|
|
||||||
$: lookup = options?.lookup ?? buildConfigLookup(hierarchy, _class, config)
|
$: lookup = buildConfigLookup(hierarchy, _class, config, options?.lookup)
|
||||||
|
|
||||||
let _sortKey = prefferedSorting
|
let _sortKey = prefferedSorting
|
||||||
$: if (!userSorting) {
|
$: if (!userSorting) {
|
||||||
@ -109,7 +109,7 @@
|
|||||||
dispatch('content', objects)
|
dispatch('content', objects)
|
||||||
loading = loading === 1 ? 0 : -1
|
loading = loading === 1 ? 0 : -1
|
||||||
},
|
},
|
||||||
{ sort, limit: 200, lookup, ...options }
|
{ sort, limit: 200, ...options, lookup }
|
||||||
)
|
)
|
||||||
if (update && ++loading > 0) {
|
if (update && ++loading > 0) {
|
||||||
objects = []
|
objects = []
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config)
|
const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config, viewlet.options?.lookup)
|
||||||
|
|
||||||
const groupBy = config.groupBy
|
const groupBy = config.groupBy
|
||||||
.map((p) => {
|
.map((p) => {
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBaseConfig (viewlet: Viewlet): AttributeConfig[] {
|
function getBaseConfig (viewlet: Viewlet): AttributeConfig[] {
|
||||||
const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config)
|
const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config, viewlet.options?.lookup)
|
||||||
const result: AttributeConfig[] = []
|
const result: AttributeConfig[] = []
|
||||||
for (const param of viewlet.config) {
|
for (const param of viewlet.config) {
|
||||||
if (typeof param === 'string') {
|
if (typeof param === 'string') {
|
||||||
|
@ -48,8 +48,8 @@
|
|||||||
$: orderBy = viewOptions.orderBy
|
$: orderBy = viewOptions.orderBy
|
||||||
|
|
||||||
const docsQuery = createQuery()
|
const docsQuery = createQuery()
|
||||||
$: lookup = options?.lookup ?? buildConfigLookup(client.getHierarchy(), _class, config)
|
$: lookup = buildConfigLookup(client.getHierarchy(), _class, config, options?.lookup)
|
||||||
$: resultOptions = { lookup, ...options, sort: { [orderBy[0]]: orderBy[1] } }
|
$: resultOptions = { ...options, lookup, sort: { [orderBy[0]]: orderBy[1] } }
|
||||||
|
|
||||||
let resultQuery: DocumentQuery<Doc> = query
|
let resultQuery: DocumentQuery<Doc> = query
|
||||||
$: getResultQuery(query, viewOptionsConfig, viewOptions).then((p) => {
|
$: getResultQuery(query, viewOptionsConfig, viewOptions).then((p) => {
|
||||||
|
@ -25,7 +25,9 @@ import core, {
|
|||||||
Obj,
|
Obj,
|
||||||
Ref,
|
Ref,
|
||||||
RefTo,
|
RefTo,
|
||||||
TxOperations
|
TxOperations,
|
||||||
|
ReverseLookup,
|
||||||
|
ReverseLookups
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import type { IntlString } from '@hcengineering/platform'
|
import type { IntlString } from '@hcengineering/platform'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
@ -234,7 +236,8 @@ function getKeyLookup<T extends Doc> (
|
|||||||
export function buildConfigLookup<T extends Doc> (
|
export function buildConfigLookup<T extends Doc> (
|
||||||
hierarchy: Hierarchy,
|
hierarchy: Hierarchy,
|
||||||
_class: Ref<Class<T>>,
|
_class: Ref<Class<T>>,
|
||||||
config: Array<BuildModelKey | string>
|
config: Array<BuildModelKey | string>,
|
||||||
|
existingLookup?: Lookup<T>
|
||||||
): Lookup<T> {
|
): Lookup<T> {
|
||||||
let res: Lookup<T> = {}
|
let res: Lookup<T> = {}
|
||||||
for (const key of config) {
|
for (const key of config) {
|
||||||
@ -244,6 +247,14 @@ export function buildConfigLookup<T extends Doc> (
|
|||||||
res = getKeyLookup(hierarchy, _class, key.key, res)
|
res = getKeyLookup(hierarchy, _class, key.key, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (existingLookup !== undefined) {
|
||||||
|
// Let's merg
|
||||||
|
const _id: ReverseLookup = {
|
||||||
|
...((existingLookup as ReverseLookups)._id ?? {}),
|
||||||
|
...((res as ReverseLookups)._id ?? {})
|
||||||
|
}
|
||||||
|
res = { ...existingLookup, ...res, _id }
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,14 @@ export interface ObjectEditor extends Class<Doc> {
|
|||||||
pinned?: boolean
|
pinned?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface ObjectEditorFooter extends Class<Doc> {
|
||||||
|
editor: AnyComponent
|
||||||
|
props?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -523,6 +531,7 @@ const view = plugin(viewId, {
|
|||||||
ObjectEditor: '' as Ref<Mixin<ObjectEditor>>,
|
ObjectEditor: '' as Ref<Mixin<ObjectEditor>>,
|
||||||
ObjectPresenter: '' as Ref<Mixin<ObjectPresenter>>,
|
ObjectPresenter: '' as Ref<Mixin<ObjectPresenter>>,
|
||||||
ObjectEditorHeader: '' as Ref<Mixin<ObjectEditorHeader>>,
|
ObjectEditorHeader: '' as Ref<Mixin<ObjectEditorHeader>>,
|
||||||
|
ObjectEditorFooter: '' as Ref<Mixin<ObjectEditorFooter>>,
|
||||||
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
|
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
|
||||||
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
|
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
|
||||||
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
|
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"View": "Посмотреть",
|
"View": "Посмотреть",
|
||||||
"Leave": "Покинуть",
|
"Leave": "Покинуть",
|
||||||
"Joined": "Вы присоеденились",
|
"Joined": "Вы присоеденились",
|
||||||
"Join": "Присоедениться",
|
"Join": "Присоединиться",
|
||||||
"BrowseSpaces": "Обзор пространств",
|
"BrowseSpaces": "Обзор пространств",
|
||||||
"AccountDisabled": "Аккаунт отключен",
|
"AccountDisabled": "Аккаунт отключен",
|
||||||
"AccountDisabledDescr": "Пожалуйста свяжитесь с администратором",
|
"AccountDisabledDescr": "Пожалуйста свяжитесь с администратором",
|
||||||
|
@ -267,7 +267,7 @@ class TServerStorage implements ServerStorage {
|
|||||||
): Promise<FindResult<T>> {
|
): Promise<FindResult<T>> {
|
||||||
return await ctx.with('find-all', {}, (ctx) => {
|
return await ctx.with('find-all', {}, (ctx) => {
|
||||||
const domain = this.hierarchy.getDomain(clazz)
|
const domain = this.hierarchy.getDomain(clazz)
|
||||||
if (query.$search !== undefined) {
|
if (query?.$search !== undefined) {
|
||||||
return ctx.with('full-text-find-all', {}, (ctx) => this.fulltext.findAll(ctx, clazz, query, options))
|
return ctx.with('full-text-find-all', {}, (ctx) => this.fulltext.findAll(ctx, clazz, query, options))
|
||||||
}
|
}
|
||||||
return ctx.with('db-find-all', { _class: clazz, domain }, () =>
|
return ctx.with('db-find-all', { _class: clazz, domain }, () =>
|
||||||
|
@ -181,6 +181,7 @@ describe('mongo operations', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('check add', async () => {
|
it('check add', async () => {
|
||||||
|
jest.setTimeout(50000)
|
||||||
for (let i = 0; i < 50; i++) {
|
for (let i = 0; i < 50; i++) {
|
||||||
await operations.createDoc(taskPlugin.class.Task, '' as Ref<Space>, {
|
await operations.createDoc(taskPlugin.class.Task, '' as Ref<Space>, {
|
||||||
name: `my-task-${i}`,
|
name: `my-task-${i}`,
|
||||||
|
Loading…
Reference in New Issue
Block a user