mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 04:08:19 +00:00
UBER-268: List views (#3270)
This commit is contained in:
parent
01a1a3fe6c
commit
b46b65fe5d
@ -44,6 +44,7 @@
|
||||
"@hcengineering/model-notification": "^0.6.0",
|
||||
"@hcengineering/notification": "^0.6.12",
|
||||
"@hcengineering/model-task": "^0.6.0",
|
||||
"@hcengineering/workbench": "^0.6.6"
|
||||
"@hcengineering/workbench": "^0.6.6",
|
||||
"@hcengineering/model-tracker": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import { ViewOptionsModel } from '@hcengineering/view'
|
||||
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
||||
import notification from '@hcengineering/notification'
|
||||
import lead from './plugin'
|
||||
import tracker from '@hcengineering/model-tracker'
|
||||
|
||||
export { leadId } from '@hcengineering/lead'
|
||||
export { leadOperation } from './migration'
|
||||
@ -193,6 +194,13 @@ export function createModel (builder: Builder): void {
|
||||
'',
|
||||
'_class',
|
||||
'leads',
|
||||
'attachments',
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Relations
|
||||
},
|
||||
'comments',
|
||||
'modifiedOn',
|
||||
{
|
||||
key: '$lookup.channels',
|
||||
@ -200,7 +208,14 @@ export function createModel (builder: Builder): void {
|
||||
sortingKey: ['$lookup.channels.lastMessage', 'channels']
|
||||
}
|
||||
],
|
||||
hiddenKeys: ['name']
|
||||
hiddenKeys: ['name'],
|
||||
options: {
|
||||
lookup: {
|
||||
_id: {
|
||||
related: [tracker.class.Issue, 'relations._id']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
lead.viewlet.TableCustomer
|
||||
)
|
||||
@ -215,49 +230,38 @@ export function createModel (builder: Builder): void {
|
||||
'',
|
||||
'title',
|
||||
'attachedTo',
|
||||
'assignee',
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Issues
|
||||
},
|
||||
'state',
|
||||
'doneState',
|
||||
'attachments',
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Relations
|
||||
},
|
||||
'comments',
|
||||
'modifiedOn',
|
||||
{
|
||||
key: '$lookup.attachedTo.$lookup.channels',
|
||||
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels']
|
||||
}
|
||||
]
|
||||
],
|
||||
options: {
|
||||
lookup: {
|
||||
_id: {
|
||||
related: [tracker.class.Issue, 'relations._id']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
lead.viewlet.TableLead
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: lead.class.Lead,
|
||||
descriptor: view.viewlet.List,
|
||||
config: [
|
||||
{ key: '', props: { listProps: { fixed: 'left' } } },
|
||||
{ key: 'title', props: { listProps: { fixed: 'left' } } },
|
||||
{ key: 'state', props: { listProps: { fixed: 'left' } } },
|
||||
{ key: 'doneState', props: { listProps: { fixed: 'left' } } },
|
||||
{ key: '', presenter: view.component.GrowPresenter },
|
||||
'attachments',
|
||||
'comments',
|
||||
'assignee'
|
||||
],
|
||||
viewOptions: {
|
||||
groupBy: ['assignee', 'state', 'attachedTo'],
|
||||
orderBy: [
|
||||
['assignee', -1],
|
||||
['state', 1],
|
||||
['attachedTo', 1],
|
||||
['modifiedOn', -1]
|
||||
],
|
||||
other: []
|
||||
}
|
||||
},
|
||||
lead.viewlet.ListLead
|
||||
)
|
||||
const leadViewOptions: ViewOptionsModel = {
|
||||
groupBy: ['state', 'assignee'],
|
||||
orderBy: [
|
||||
@ -278,6 +282,61 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
]
|
||||
}
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: lead.class.Lead,
|
||||
descriptor: view.viewlet.List,
|
||||
config: [
|
||||
{ key: '', props: { listProps: { fixed: 'left', key: 'lead' } } },
|
||||
{
|
||||
key: '',
|
||||
presenter: lead.component.TitlePresenter,
|
||||
props: { listProps: { fixed: 'left', key: 'title' }, maxWidth: '10rem' }
|
||||
},
|
||||
{
|
||||
key: '$lookup.attachedTo',
|
||||
presenter: contact.component.PersonPresenter,
|
||||
label: lead.string.Customer,
|
||||
sortingKey: '$lookup.attachedTo.name',
|
||||
props: {
|
||||
_class: lead.mixin.Customer,
|
||||
listProps: { fixed: 'left', key: 'talent' },
|
||||
inline: true,
|
||||
maxWidth: '10rem'
|
||||
}
|
||||
},
|
||||
{ key: 'state', props: { listProps: { fixed: 'left', key: 'state' } } },
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Relations,
|
||||
props: { listProps: { fixed: 'left', key: 'issues' } }
|
||||
},
|
||||
{ key: 'attachments', props: { listProps: { fixed: 'left', key: 'attachments' } } },
|
||||
{ key: 'comments', props: { listProps: { fixed: 'left' }, key: 'comments' } },
|
||||
{ key: '', presenter: view.component.GrowPresenter, props: { type: 'grow' } },
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{
|
||||
key: '$lookup.attachedTo.$lookup.channels',
|
||||
label: contact.string.ContactInfo,
|
||||
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels'],
|
||||
props: {
|
||||
listProps: {
|
||||
fixed: 'left',
|
||||
key: 'channels'
|
||||
}
|
||||
}
|
||||
},
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{ key: 'modifiedOn', props: { listProps: { key: 'modified', fixed: 'left' } } },
|
||||
{ key: 'assignee', props: { listProps: { key: 'assignee', fixed: 'right' }, shouldShowLabel: false } }
|
||||
],
|
||||
viewOptions: leadViewOptions
|
||||
},
|
||||
lead.viewlet.ListLead
|
||||
)
|
||||
|
||||
const lookupLeadOptions: FindOptions<Lead> = {
|
||||
lookup: {
|
||||
|
@ -284,7 +284,12 @@ export function createModel (builder: Builder): void {
|
||||
label: recruit.string.Applications,
|
||||
createLabel: recruit.string.ApplicationCreateLabel,
|
||||
createComponent: recruit.component.CreateApplication,
|
||||
descriptors: [view.viewlet.Table, task.viewlet.Kanban, recruit.viewlet.ApplicantDashboard]
|
||||
descriptors: [
|
||||
view.viewlet.Table,
|
||||
view.viewlet.List,
|
||||
task.viewlet.Kanban,
|
||||
recruit.viewlet.ApplicantDashboard
|
||||
]
|
||||
},
|
||||
position: 'vacancy'
|
||||
},
|
||||
@ -556,8 +561,8 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.Issues
|
||||
},
|
||||
'state',
|
||||
'comments',
|
||||
'attachments',
|
||||
'comments',
|
||||
'modifiedOn',
|
||||
'$lookup.space.company',
|
||||
{
|
||||
@ -639,6 +644,76 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
]
|
||||
}
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: recruit.class.Applicant,
|
||||
descriptor: view.viewlet.List,
|
||||
config: [
|
||||
{ key: '', props: { listProps: { fixed: 'left', key: 'app' } } },
|
||||
{
|
||||
key: '$lookup.attachedTo',
|
||||
presenter: contact.component.PersonPresenter,
|
||||
label: recruit.string.Talent,
|
||||
sortingKey: '$lookup.attachedTo.name',
|
||||
props: {
|
||||
_class: recruit.mixin.Candidate,
|
||||
listProps: { fixed: 'left', key: 'talent' },
|
||||
inline: true
|
||||
}
|
||||
},
|
||||
{ key: 'state', props: { listProps: { fixed: 'left', key: 'state' }, inline: true, showLabel: false } },
|
||||
{
|
||||
key: '$lookup.space.company',
|
||||
props: {
|
||||
listProps: { fixed: 'left', key: 'company' },
|
||||
inline: true,
|
||||
maxWidth: '10rem'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Issues,
|
||||
props: { listProps: { fixed: 'left', key: 'issues' } }
|
||||
},
|
||||
{ key: 'attachments', props: { listProps: { fixed: 'left', key: 'attachments' } } },
|
||||
{ key: 'comments', props: { listProps: { fixed: 'left' }, key: 'comments' } },
|
||||
{ key: '', presenter: view.component.GrowPresenter, props: { type: 'grow' } },
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{
|
||||
key: '$lookup.attachedTo.$lookup.channels',
|
||||
label: contact.string.ContactInfo,
|
||||
sortingKey: ['$lookup.attachedTo.$lookup.channels.lastMessage', '$lookup.attachedTo.channels'],
|
||||
props: {
|
||||
listProps: {
|
||||
fixed: 'left',
|
||||
key: 'channels'
|
||||
}
|
||||
}
|
||||
},
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{ key: 'modifiedOn', props: { listProps: { key: 'modified', fixed: 'left' } } },
|
||||
{ key: 'assignee', props: { listProps: { key: 'assignee', fixed: 'right' }, shouldShowLabel: false } }
|
||||
],
|
||||
options: {
|
||||
lookup: {
|
||||
_id: {
|
||||
related: [tracker.class.Issue, 'relations._id']
|
||||
},
|
||||
space: recruit.class.Vacancy
|
||||
}
|
||||
},
|
||||
hiddenKeys: ['name', 'attachedTo'],
|
||||
baseQuery: {
|
||||
doneState: null,
|
||||
'$lookup.space.archived': false
|
||||
},
|
||||
viewOptions: applicantViewOptions
|
||||
},
|
||||
recruit.viewlet.ListApplicant
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
|
@ -113,6 +113,7 @@ export default mergeIds(recruitId, recruit, {
|
||||
TableVacancy: '' as Ref<Viewlet>,
|
||||
ApplicantTable: '' as Ref<Viewlet>,
|
||||
ApplicantKanban: '' as Ref<Viewlet>,
|
||||
ListApplicant: '' as Ref<Viewlet>,
|
||||
TableApplicant: '' as Ref<Viewlet>,
|
||||
TableApplicantMatch: '' as Ref<Viewlet>,
|
||||
CalendarReview: '' as Ref<Viewlet>,
|
||||
|
@ -573,7 +573,12 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
key: 'assignee',
|
||||
presenter: tracker.component.AssigneePresenter,
|
||||
props: { defaultClass: contact.class.Employee, shouldShowLabel: false }
|
||||
props: {
|
||||
listProps: { key: 'assigee', fixed: 'right' },
|
||||
key: 'assignee',
|
||||
defaultClass: contact.class.Employee,
|
||||
shouldShowLabel: false
|
||||
}
|
||||
}
|
||||
],
|
||||
options: {
|
||||
|
@ -25,6 +25,7 @@
|
||||
export let value: Contact
|
||||
export let inline: boolean = false
|
||||
export let disabled = false
|
||||
export let maxWidth = ''
|
||||
|
||||
function isPerson (value: Contact): boolean {
|
||||
const client = getClient()
|
||||
@ -45,5 +46,5 @@
|
||||
{:else if isPerson(value)}
|
||||
<PersonPresenter {disabled} {value} {inline} />
|
||||
{:else}
|
||||
<OrganizationPresenter value={toOrg(value)} {inline} />
|
||||
<OrganizationPresenter value={toOrg(value)} {inline} {maxWidth} />
|
||||
{/if}
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
export let value: Ref<Contact>
|
||||
export let disabled = false
|
||||
export let maxWidth = ''
|
||||
export let inline = false
|
||||
|
||||
let doc: Contact | undefined
|
||||
const query = createQuery()
|
||||
@ -29,5 +31,5 @@
|
||||
</script>
|
||||
|
||||
{#if doc}
|
||||
<ContactPresenter value={doc} {disabled} />
|
||||
<ContactPresenter value={doc} {disabled} {maxWidth} {inline} />
|
||||
{/if}
|
||||
|
@ -22,11 +22,17 @@
|
||||
|
||||
export let value: Organization
|
||||
export let inline: boolean = false
|
||||
export let maxWidth = ''
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<DocNavLink {inline} object={value}>
|
||||
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||
<div
|
||||
class="flex-presenter overflow-label"
|
||||
style:max-width={maxWidth}
|
||||
class:inline-presenter={inline}
|
||||
use:tooltip={{ label: getEmbeddedLabel(value.name) }}
|
||||
>
|
||||
{#if !inline}
|
||||
<div class="icon circle"><Company size={'small'} /></div>
|
||||
{/if}
|
||||
|
@ -43,6 +43,7 @@
|
||||
export let enlargedText = false
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let maxWidth = ''
|
||||
|
||||
const onEditClick = (evt: MouseEvent) => {
|
||||
if (!disabled) {
|
||||
@ -70,6 +71,7 @@
|
||||
class="contentPresenter"
|
||||
class:text-base={enlargedText}
|
||||
class:inline-presenter={inline}
|
||||
style:max-width={maxWidth}
|
||||
>
|
||||
{#if !inline && shouldShowAvatar}
|
||||
<span
|
||||
|
@ -34,6 +34,7 @@
|
||||
export let element: HTMLElement | undefined = undefined
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let maxWidth = ''
|
||||
|
||||
function getTooltip (
|
||||
tooltipLabels: PersonLabelTooltip | undefined,
|
||||
@ -79,6 +80,7 @@
|
||||
{statusLabel}
|
||||
{colorInherit}
|
||||
{accent}
|
||||
{maxWidth}
|
||||
bind:element
|
||||
on:accent-color
|
||||
/>
|
||||
|
55
plugins/lead-resources/src/components/TitlePresenter.svelte
Normal file
55
plugins/lead-resources/src/components/TitlePresenter.svelte
Normal file
@ -0,0 +1,55 @@
|
||||
<!--
|
||||
// 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 { WithLookup } from '@hcengineering/core'
|
||||
import { Lead } from '@hcengineering/lead'
|
||||
|
||||
export let value: WithLookup<Lead>
|
||||
export let shouldUseMargin: boolean = false
|
||||
export let kind: 'list' | undefined = undefined
|
||||
export let maxWidth = '100%'
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<span
|
||||
class="name overflow-label select-text"
|
||||
class:with-margin={shouldUseMargin}
|
||||
class:list={kind === 'list'}
|
||||
style:max-width={'100%'}
|
||||
>
|
||||
{value.title}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.name {
|
||||
flex-shrink: 1;
|
||||
min-width: 1rem;
|
||||
|
||||
&.list {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&:active {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
|
||||
.with-margin {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
</style>
|
@ -28,6 +28,7 @@ import NewItemsHeader from './components/NewItemsHeader.svelte'
|
||||
import { getLeadTitle } from './utils'
|
||||
import EditFunnel from './components/EditFunnel.svelte'
|
||||
import MyLeads from './components/MyLeads.svelte'
|
||||
import TitlePresenter from './components/TitlePresenter.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
@ -42,7 +43,8 @@ export default async (): Promise<Resources> => ({
|
||||
CreateCustomer,
|
||||
NewItemsHeader,
|
||||
EditFunnel,
|
||||
MyLeads
|
||||
MyLeads,
|
||||
TitlePresenter
|
||||
},
|
||||
function: {
|
||||
LeadTitleProvider: getLeadTitle
|
||||
|
@ -49,7 +49,8 @@ export default mergeIds(leadId, lead, {
|
||||
LeadsPresenter: '' as AnyComponent,
|
||||
CreateFunnel: '' as AnyComponent,
|
||||
EditFunnel: '' as AnyComponent,
|
||||
MyLeads: '' as AnyComponent
|
||||
MyLeads: '' as AnyComponent,
|
||||
TitlePresenter: '' as AnyComponent
|
||||
},
|
||||
function: {
|
||||
LeadTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>) => Promise<string>>
|
||||
|
Loading…
Reference in New Issue
Block a user