mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 21:50:34 +03:00
Add sprint members (#2392)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
parent
a2af1802a2
commit
dcaa0ea9b0
@ -412,6 +412,9 @@ export class TSprint extends TDoc implements Sprint {
|
||||
@Prop(TypeRef(contact.class.Employee), tracker.string.ProjectLead)
|
||||
lead!: Ref<Employee> | null
|
||||
|
||||
@Prop(ArrOf(TypeRef(contact.class.Employee)), tracker.string.Members)
|
||||
members!: Ref<Employee>[]
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
|
||||
comments!: number
|
||||
|
||||
|
@ -205,6 +205,12 @@
|
||||
"ActiveSprints": "Active",
|
||||
"ClosedSprints": "Done",
|
||||
"AddToSprint": "Add to Sprint",
|
||||
"SprintNamePlaceholder": "Sprint name",
|
||||
"SprintLead": "Lead",
|
||||
"SprintLeadTitle": "Sprint lead",
|
||||
"SprintLeadSearchPlaceholder": "Set sprint lead\u2026",
|
||||
"SprintMembersTitle": "Sprint members",
|
||||
"SprintMembersSearchPlaceholder": "Change sprint members\u2026",
|
||||
|
||||
"NewSprint": "New Sprint",
|
||||
"CreateSprint": "Create",
|
||||
|
@ -205,6 +205,12 @@
|
||||
"ActiveSprints": "Активно",
|
||||
"ClosedSprints": "Завершено",
|
||||
"AddToSprint": "Добавить в Спринт",
|
||||
"SprintNamePlaceholder": "Название спринта",
|
||||
"SprintLead": "Руководитель",
|
||||
"SprintLeadTitle": "Руководитель спринта",
|
||||
"SprintLeadSearchPlaceholder": "Назначьте руководителя спринта\u2026",
|
||||
"SprintMembersTitle": "Участники спринта",
|
||||
"SprintMembersSearchPlaceholder": "Измененить участников спринта\u2026",
|
||||
|
||||
"NewSprint": "Новый Спринт",
|
||||
"CreateSprint": "Создать",
|
||||
|
@ -81,8 +81,9 @@
|
||||
bind:value={object.lead}
|
||||
allowDeselect
|
||||
titleDeselect={tracker.string.Unassigned}
|
||||
showNavigate={false}
|
||||
/>
|
||||
<UserBoxList bind:items={object.members} label={tracker.string.ProjectStatusPlaceholder} />
|
||||
<UserBoxList bind:items={object.members} label={tracker.string.ProjectMembersSearchPlaceholder} />
|
||||
<!-- TODO: add labels after customize IssueNeedsToBeCompletedByThisDate -->
|
||||
<DatePresenter bind:value={object.startDate} labelNull={tracker.string.StartDate} editable />
|
||||
<DatePresenter bind:value={object.targetDate} labelNull={tracker.string.TargetDate} editable />
|
||||
|
@ -148,7 +148,7 @@
|
||||
<svelte:component
|
||||
this={attributeModel.presenter}
|
||||
value={getObjectValue(attributeModel.key, docObject) ?? ''}
|
||||
projectId={docObject._id}
|
||||
parentId={docObject._id}
|
||||
{...attributeModel.props}
|
||||
/>
|
||||
</div>
|
||||
|
@ -15,11 +15,12 @@
|
||||
<script lang="ts">
|
||||
import { Data, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { Card, EmployeeBox, getClient, SpaceSelector } from '@hcengineering/presentation'
|
||||
import { Sprint, SprintStatus, Team } from '@hcengineering/tracker'
|
||||
import { Card, EmployeeBox, getClient, SpaceSelector, UserBoxList } from '@hcengineering/presentation'
|
||||
import { Project, Sprint, SprintStatus, Team } from '@hcengineering/tracker'
|
||||
import ui, { DatePresenter, EditBox } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import ProjectSelector from '../ProjectSelector.svelte'
|
||||
import SprintStatusSelector from './SprintStatusSelector.svelte'
|
||||
|
||||
export let space: Ref<Team>
|
||||
@ -31,8 +32,10 @@
|
||||
description: '',
|
||||
status: SprintStatus.Planned,
|
||||
lead: null,
|
||||
members: [],
|
||||
comments: 0,
|
||||
attachments: 0,
|
||||
capacity: 0,
|
||||
startDate: Date.now(),
|
||||
targetDate: Date.now() + 14 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
@ -48,6 +51,14 @@
|
||||
|
||||
object.status = newSprintStatus
|
||||
}
|
||||
|
||||
const handleProjectIdChanged = async (projectId: Ref<Project> | null | undefined) => {
|
||||
if (projectId === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
object.project = projectId ?? undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card
|
||||
@ -61,7 +72,7 @@
|
||||
<SpaceSelector _class={tracker.class.Team} label={tracker.string.Team} bind:space />
|
||||
</svelte:fragment>
|
||||
<div class="label">
|
||||
<EditBox bind:value={object.label} placeholder={tracker.string.ProjectNamePlaceholder} kind="large-style" focus />
|
||||
<EditBox bind:value={object.label} placeholder={tracker.string.SprintNamePlaceholder} kind="large-style" focus />
|
||||
</div>
|
||||
<div class="description">
|
||||
<EditBox
|
||||
@ -72,13 +83,16 @@
|
||||
</div>
|
||||
<div slot="pool" class="flex-row-center text-sm gap-1-5">
|
||||
<SprintStatusSelector selectedSprintStatus={object.status} onSprintStatusChange={handleProjectStatusChanged} />
|
||||
<ProjectSelector value={object.project} onChange={handleProjectIdChanged} />
|
||||
<EmployeeBox
|
||||
label={tracker.string.ProjectLead}
|
||||
label={tracker.string.SprintLead}
|
||||
placeholder={tracker.string.AssignTo}
|
||||
bind:value={object.lead}
|
||||
allowDeselect
|
||||
titleDeselect={tracker.string.Unassigned}
|
||||
showNavigate={false}
|
||||
/>
|
||||
<UserBoxList bind:items={object.members} label={tracker.string.SprintMembersSearchPlaceholder} />
|
||||
<DatePresenter
|
||||
bind:value={object.startDate}
|
||||
editable
|
||||
|
@ -171,6 +171,7 @@
|
||||
size: 'x-small'
|
||||
}
|
||||
},
|
||||
{ key: '', presenter: tracker.component.SprintMembersPresenter, props: { kind: 'link' } },
|
||||
{ key: '', presenter: SprintDatePresenter, props: { field: 'startDate' } },
|
||||
{ key: '', presenter: SprintDatePresenter, props: { field: 'targetDate' } },
|
||||
{ key: '', presenter: tracker.component.SprintStatusPresenter }
|
||||
|
@ -178,7 +178,8 @@
|
||||
<svelte:component
|
||||
this={attributeModel.presenter}
|
||||
value={getObjectValue(attributeModel.key, docObject) ?? ''}
|
||||
projectId={docObject._id}
|
||||
parentId={docObject._id}
|
||||
sprintId={docObject._id}
|
||||
{...attributeModel.props}
|
||||
/>
|
||||
</div>
|
||||
|
@ -0,0 +1,84 @@
|
||||
<!--
|
||||
// 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 '@hcengineering/core'
|
||||
import { Sprint } from '@hcengineering/tracker'
|
||||
import { Button, showPopup, eventToHTMLElement } from '@hcengineering/ui'
|
||||
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import { getClient, UsersPopup } from '@hcengineering/presentation'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: Sprint
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = 'min-content'
|
||||
|
||||
const client = getClient()
|
||||
|
||||
let buttonTitle = ''
|
||||
|
||||
$: translate(tracker.string.SprintMembersTitle, {}).then((res) => {
|
||||
buttonTitle = res
|
||||
})
|
||||
|
||||
const handleSprinttMembersChanged = async (result: Ref<Employee>[] | undefined) => {
|
||||
if (result === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const memberToPull = value.members.filter((x) => !result.includes(x))[0]
|
||||
const memberToPush = result.filter((x) => !value.members.includes(x))[0]
|
||||
|
||||
if (memberToPull) {
|
||||
await client.update(value, { $pull: { members: memberToPull } })
|
||||
}
|
||||
|
||||
if (memberToPush) {
|
||||
await client.update(value, { $push: { members: memberToPush } })
|
||||
}
|
||||
}
|
||||
|
||||
const handleSprintMembersEditorOpened = async (event: MouseEvent) => {
|
||||
showPopup(
|
||||
UsersPopup,
|
||||
{
|
||||
_class: contact.class.Employee,
|
||||
selectedUsers: value.members,
|
||||
allowDeselect: true,
|
||||
multiSelect: true,
|
||||
docQuery: {
|
||||
active: true
|
||||
},
|
||||
placeholder: tracker.string.SprintMembersSearchPlaceholder
|
||||
},
|
||||
eventToHTMLElement(event),
|
||||
undefined,
|
||||
handleSprinttMembersChanged
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button
|
||||
{kind}
|
||||
{size}
|
||||
{width}
|
||||
{justify}
|
||||
title={buttonTitle}
|
||||
icon={tracker.icon.ProjectMembers}
|
||||
on:click={handleSprintMembersEditorOpened}
|
||||
/>
|
@ -74,6 +74,7 @@ import SprintEditor from './components/sprints/SprintEditor.svelte'
|
||||
import SprintPresenter from './components/sprints/SprintPresenter.svelte'
|
||||
import Sprints from './components/sprints/Sprints.svelte'
|
||||
import SprintSelector from './components/sprints/SprintSelector.svelte'
|
||||
import SprintMembersPresenter from './components/sprints/SprintMembersPresenter.svelte'
|
||||
import SprintStatusPresenter from './components/sprints/SprintStatusPresenter.svelte'
|
||||
import SprintTitlePresenter from './components/sprints/SprintTitlePresenter.svelte'
|
||||
|
||||
@ -249,6 +250,7 @@ export default async (): Promise<Resources> => ({
|
||||
CreateIssueTemplate,
|
||||
Sprints,
|
||||
SprintPresenter,
|
||||
SprintMembersPresenter,
|
||||
SprintStatusPresenter,
|
||||
SprintTitlePresenter,
|
||||
SprintSelector,
|
||||
|
@ -221,6 +221,12 @@ export default mergeIds(trackerId, tracker, {
|
||||
PlannedSprints: '' as IntlString,
|
||||
ActiveSprints: '' as IntlString,
|
||||
ClosedSprints: '' as IntlString,
|
||||
SprintNamePlaceholder: '' as IntlString,
|
||||
SprintLead: '' as IntlString,
|
||||
SprintLeadTitle: '' as IntlString,
|
||||
SprintLeadSearchPlaceholder: '' as IntlString,
|
||||
SprintMembersTitle: '' as IntlString,
|
||||
SprintMembersSearchPlaceholder: '' as IntlString,
|
||||
|
||||
NewSprint: '' as IntlString,
|
||||
CreateSprint: '' as IntlString,
|
||||
@ -304,6 +310,7 @@ export default mergeIds(trackerId, tracker, {
|
||||
SprintPresenter: '' as AnyComponent,
|
||||
SprintStatusPresenter: '' as AnyComponent,
|
||||
SprintTitlePresenter: '' as AnyComponent,
|
||||
SprintMembersPresenter: '' as AnyComponent,
|
||||
ReportedTimeEditor: '' as AnyComponent,
|
||||
TimeSpendReport: '' as AnyComponent,
|
||||
EstimationEditor: '' as AnyComponent,
|
||||
|
@ -129,6 +129,7 @@ export interface Sprint extends Doc {
|
||||
status: SprintStatus
|
||||
|
||||
lead: Ref<Employee> | null
|
||||
members: Ref<Employee>[]
|
||||
|
||||
space: Ref<Team>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user