mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 03:22:19 +03:00
Fix creating suubissues from template (#4610)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
7794771694
commit
19da703193
@ -66,6 +66,7 @@ import {
|
||||
type TimeSpendReport
|
||||
} from '@hcengineering/tracker'
|
||||
import tracker from './plugin'
|
||||
import { type TaskType } from '@hcengineering/task'
|
||||
|
||||
export const DOMAIN_TRACKER = 'tracker' as Domain
|
||||
|
||||
@ -271,6 +272,9 @@ export class TIssueTemplate extends TDoc implements IssueTemplate {
|
||||
@Prop(ArrOf(TypeRef(tags.class.TagElement)), tracker.string.Labels)
|
||||
labels?: Ref<TagElement>[]
|
||||
|
||||
@Prop(TypeRef(task.class.TaskType), task.string.TaskType)
|
||||
kind?: Ref<TaskType>
|
||||
|
||||
declare space: Ref<Project>
|
||||
|
||||
@Prop(TypeDate(DateRangeMode.DATETIME), tracker.string.DueDate)
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { Class, Doc, Ref, toIdMap } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import task, { ProjectType, TaskType } from '@hcengineering/task'
|
||||
import { DropdownLabels } from '@hcengineering/ui'
|
||||
import { ButtonKind, DropdownLabels } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import { selectedTaskTypeStore, taskTypeStore } from '../..'
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
export let projectType: Ref<ProjectType> | undefined
|
||||
export let focusIndex: number = -1
|
||||
export let baseClass: Ref<Class<Doc>> | undefined = undefined
|
||||
export let kind: ButtonKind = 'regular'
|
||||
export let allTypes = false
|
||||
const client = getClient()
|
||||
|
||||
@ -44,12 +45,5 @@
|
||||
</script>
|
||||
|
||||
{#if projectType !== undefined && items.length > 1}
|
||||
<DropdownLabels
|
||||
{focusIndex}
|
||||
kind={'regular'}
|
||||
{items}
|
||||
bind:selected={value}
|
||||
enableSearch={false}
|
||||
on:selected={change}
|
||||
/>
|
||||
<DropdownLabels {focusIndex} {kind} {items} bind:selected={value} enableSearch={false} on:selected={change} />
|
||||
{/if}
|
||||
|
@ -17,7 +17,17 @@
|
||||
import { AttachmentPresenter, AttachmentStyledBox } from '@hcengineering/attachment-resources'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import core, { Account, Class, Doc, DocData, Ref, SortingOrder, fillDefaults, generateId } from '@hcengineering/core'
|
||||
import core, {
|
||||
Account,
|
||||
Class,
|
||||
Doc,
|
||||
DocData,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
fillDefaults,
|
||||
generateId,
|
||||
toIdMap
|
||||
} from '@hcengineering/core'
|
||||
import { getResource, translate } from '@hcengineering/platform'
|
||||
import preference, { SpacePreference } from '@hcengineering/preference'
|
||||
import {
|
||||
@ -64,6 +74,7 @@
|
||||
import { activeComponent, activeMilestone, generateIssueShortLink, updateIssueRelation } from '../issues'
|
||||
import tracker from '../plugin'
|
||||
import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte'
|
||||
import SubIssues from './SubIssues.svelte'
|
||||
import ComponentSelector from './components/ComponentSelector.svelte'
|
||||
import AssigneeEditor from './issues/AssigneeEditor.svelte'
|
||||
import IssueNotification from './issues/IssueNotification.svelte'
|
||||
@ -107,7 +118,7 @@
|
||||
let project: Project | undefined
|
||||
let object = getDefaultObjectFromDraft() ?? getDefaultObject(id)
|
||||
let isAssigneeTouched = false
|
||||
let kind: Ref<TaskType> | undefined
|
||||
let kind: Ref<TaskType> | undefined = undefined
|
||||
|
||||
let templateId: Ref<IssueTemplate> | undefined = draft?.template?.template
|
||||
let appliedTemplateId: Ref<IssueTemplate> | undefined = draft?.template?.template
|
||||
@ -156,6 +167,7 @@
|
||||
_id: id ?? generateId(),
|
||||
title: '',
|
||||
description: '',
|
||||
kind: '' as Ref<TaskType>,
|
||||
priority: priority ?? IssuePriority.NoPriority,
|
||||
space: _space as Ref<Project>,
|
||||
component: component ?? $activeComponent ?? null,
|
||||
@ -258,14 +270,34 @@
|
||||
}
|
||||
const { _class, _id, space, children, comments, attachments, labels, description, ...templBase } = template
|
||||
|
||||
const allLabels = new Set<Ref<TagElement>>()
|
||||
for (const label of labels ?? []) {
|
||||
allLabels.add(label)
|
||||
}
|
||||
for (const child of children) {
|
||||
for (const label of child.labels ?? []) {
|
||||
allLabels.add(label)
|
||||
}
|
||||
}
|
||||
const tagElements = toIdMap(await client.findAll(tags.class.TagElement, { _id: { $in: Array.from(allLabels) } }))
|
||||
|
||||
object.subIssues = template.children.map((p) => {
|
||||
return {
|
||||
...p,
|
||||
_id: p.id,
|
||||
kind: p.kind ?? kind ?? ('' as Ref<TaskType>),
|
||||
_id: generateId(),
|
||||
space: _space as Ref<Project>,
|
||||
subIssues: [],
|
||||
dueDate: null,
|
||||
labels: [],
|
||||
labels:
|
||||
p.labels !== undefined
|
||||
? (p.labels
|
||||
.map((p) => {
|
||||
const val = tagElements.get(p)
|
||||
return val !== undefined ? tagAsRef(val) : undefined
|
||||
})
|
||||
.filter((p) => p !== undefined) as TagReference[])
|
||||
: [],
|
||||
status: currentProject?.defaultIssueStatus
|
||||
}
|
||||
})
|
||||
@ -279,8 +311,19 @@
|
||||
}
|
||||
}
|
||||
appliedTemplateId = templateId
|
||||
const tagElements = await client.findAll(tags.class.TagElement, { _id: { $in: labels } })
|
||||
object.labels = tagElements.map(tagAsRef)
|
||||
object.labels =
|
||||
labels !== undefined
|
||||
? (labels
|
||||
.map((p) => {
|
||||
const val = tagElements.get(p)
|
||||
return val !== undefined ? tagAsRef(val) : undefined
|
||||
})
|
||||
.filter((p) => p !== undefined) as TagReference[])
|
||||
: []
|
||||
|
||||
if (object.kind !== undefined) {
|
||||
kind = object.kind
|
||||
}
|
||||
fillDefaults(hierarchy, object, tracker.class.Issue)
|
||||
}
|
||||
|
||||
@ -336,6 +379,8 @@
|
||||
return value.trim()
|
||||
}
|
||||
|
||||
let subIssuesComponent: SubIssues
|
||||
|
||||
export function canClose (): boolean {
|
||||
return true
|
||||
}
|
||||
@ -439,6 +484,15 @@
|
||||
|
||||
await operations.commit()
|
||||
await descriptionBox.createAttachments(_id)
|
||||
|
||||
const parents = parentIssue
|
||||
? [
|
||||
{ parentId: _id, parentTitle: value.title, space: parentIssue.space },
|
||||
{ parentId: parentIssue._id, parentTitle: parentIssue.title, space: parentIssue.space },
|
||||
...parentIssue.parents
|
||||
]
|
||||
: [{ parentId: _id, parentTitle: value.title, space: _space }]
|
||||
await subIssuesComponent.save(parents, _id)
|
||||
addNotification(
|
||||
await translate(tracker.string.IssueCreated, {}, $themeStore.language),
|
||||
getTitle(object.title),
|
||||
@ -727,6 +781,16 @@
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
{#if _space}
|
||||
<SubIssues
|
||||
bind:this={subIssuesComponent}
|
||||
projectId={_space}
|
||||
project={currentProject}
|
||||
milestone={object.milestone}
|
||||
component={object.component}
|
||||
bind:subIssues={object.subIssues}
|
||||
/>
|
||||
{/if}
|
||||
<DocCreateExtComponent manager={docCreateManager} kind={'body'} space={currentProject} props={extraProps} />
|
||||
<svelte:fragment slot="pool">
|
||||
<div id="status-editor">
|
||||
|
199
plugins/tracker-resources/src/components/SubIssues.svelte
Normal file
199
plugins/tracker-resources/src/components/SubIssues.svelte
Normal file
@ -0,0 +1,199 @@
|
||||
<!--
|
||||
// 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 attachment, { Attachment } from '@hcengineering/attachment'
|
||||
import { deleteFile } from '@hcengineering/attachment-resources/src/utils'
|
||||
import core, { AttachedData, Doc, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { DraftController, draftsStore, getClient } from '@hcengineering/presentation'
|
||||
import tags from '@hcengineering/tags'
|
||||
import { calcRank } from '@hcengineering/task'
|
||||
import { Component, Issue, IssueDraft, IssueParentInfo, Milestone, Project } from '@hcengineering/tracker'
|
||||
import { Button, ExpandCollapse, Scroller } from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import tracker from '../plugin'
|
||||
import Collapsed from './icons/Collapsed.svelte'
|
||||
import Expanded from './icons/Expanded.svelte'
|
||||
import DraftIssueChildList from './templates/DraftIssueChildList.svelte'
|
||||
export let projectId: Ref<Project>
|
||||
export let project: Project | undefined
|
||||
export let milestone: Ref<Milestone> | null = null
|
||||
export let component: Ref<Component> | null = null
|
||||
export let subIssues: IssueDraft[] = []
|
||||
let lastProject = project
|
||||
let isCollapsed = false
|
||||
async function handleIssueSwap (ev: CustomEvent<{ fromIndex: number, toIndex: number }>) {
|
||||
if (subIssues) {
|
||||
const { fromIndex, toIndex } = ev.detail
|
||||
const [fromIssue] = subIssues.splice(fromIndex, 1)
|
||||
const leftPart = subIssues.slice(0, toIndex)
|
||||
const rightPart = subIssues.slice(toIndex)
|
||||
subIssues = [...leftPart, fromIssue, ...rightPart]
|
||||
}
|
||||
}
|
||||
$: onProjectChange(project)
|
||||
function onProjectChange (project: Project | undefined) {
|
||||
if (lastProject?._id === project?._id) return
|
||||
lastProject = project
|
||||
if (project === undefined) return
|
||||
subIssues.forEach((p) => {
|
||||
p.status = project.defaultIssueStatus
|
||||
p.space = project._id
|
||||
})
|
||||
}
|
||||
const client = getClient()
|
||||
// TODO: move to utils
|
||||
export async function save (parents: IssueParentInfo[], _id: Ref<Doc>) {
|
||||
if (project === undefined) return
|
||||
saved = true
|
||||
for (const subIssue of subIssues) {
|
||||
const lastOne = await client.findOne<Issue>(tracker.class.Issue, {}, { sort: { rank: SortingOrder.Descending } })
|
||||
const incResult = await client.updateDoc(
|
||||
tracker.class.Project,
|
||||
core.space.Space,
|
||||
project._id,
|
||||
{
|
||||
$inc: { sequence: 1 }
|
||||
},
|
||||
true
|
||||
)
|
||||
const number = (incResult as any).object.sequence
|
||||
const childId = subIssue._id
|
||||
const cvalue: AttachedData<Issue> = {
|
||||
title: subIssue.title.trim(),
|
||||
description: subIssue.description,
|
||||
assignee: subIssue.assignee,
|
||||
component: subIssue.component,
|
||||
milestone: subIssue.milestone,
|
||||
number,
|
||||
status: subIssue.status ?? project.defaultIssueStatus,
|
||||
priority: subIssue.priority,
|
||||
rank: calcRank(lastOne, undefined),
|
||||
comments: 0,
|
||||
subIssues: 0,
|
||||
dueDate: null,
|
||||
parents,
|
||||
reportedTime: 0,
|
||||
remainingTime: 0,
|
||||
estimation: subIssue.estimation,
|
||||
reports: 0,
|
||||
relations: [],
|
||||
childInfo: [],
|
||||
kind: subIssue.kind,
|
||||
identifier: `${project.identifier}-${number}`
|
||||
}
|
||||
await client.addCollection(
|
||||
tracker.class.Issue,
|
||||
project._id,
|
||||
_id,
|
||||
tracker.class.Issue,
|
||||
'subIssues',
|
||||
cvalue,
|
||||
childId
|
||||
)
|
||||
if ((subIssue.labels?.length ?? 0) > 0) {
|
||||
for (const label of subIssue.labels) {
|
||||
await client.addCollection(tags.class.TagReference, project._id, childId, tracker.class.Issue, 'labels', {
|
||||
title: label.title,
|
||||
color: label.color,
|
||||
tag: label.tag
|
||||
})
|
||||
}
|
||||
}
|
||||
saveAttachments(childId)
|
||||
}
|
||||
}
|
||||
async function saveAttachments (issue: Ref<Issue>) {
|
||||
const draftAttachments = $draftsStore[`${issue}_attachments`]
|
||||
if (draftAttachments) {
|
||||
for (const key in draftAttachments) {
|
||||
await saveAttachment(draftAttachments[key as Ref<Attachment>], issue)
|
||||
}
|
||||
}
|
||||
removeDraft(issue)
|
||||
}
|
||||
async function saveAttachment (doc: Attachment, issue: Ref<Issue>): Promise<void> {
|
||||
await client.addCollection(
|
||||
attachment.class.Attachment,
|
||||
projectId,
|
||||
issue,
|
||||
tracker.class.Issue,
|
||||
'attachments',
|
||||
doc,
|
||||
doc._id
|
||||
)
|
||||
}
|
||||
export function load (value: IssueDraft[]) {
|
||||
subIssues = value
|
||||
}
|
||||
let saved = false
|
||||
onDestroy(() => {
|
||||
if (!saved) {
|
||||
subIssues.forEach((st) => {
|
||||
removeDraft(st._id, true)
|
||||
})
|
||||
}
|
||||
})
|
||||
// TODO: move to utils
|
||||
export async function removeDraft (_id: string, removeFiles: boolean = false): Promise<void> {
|
||||
const draftAttachments = $draftsStore[`${_id}_attachments`]
|
||||
DraftController.remove(`${_id}_attachments`)
|
||||
if (removeFiles && draftAttachments) {
|
||||
for (const key in draftAttachments) {
|
||||
const attachment = draftAttachments[key as Ref<Attachment>]
|
||||
await deleteFile(attachment.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- TODO: check if sub issues list is empty in a parent component -->
|
||||
{#if subIssues.length > 0}
|
||||
<div class="flex-between clear-mins">
|
||||
<Button
|
||||
width="min-content"
|
||||
icon={isCollapsed ? Collapsed : Expanded}
|
||||
size="small"
|
||||
kind="ghost"
|
||||
label={tracker.string.SubIssuesList}
|
||||
labelParams={{ subIssues: subIssues.length }}
|
||||
on:click={() => (isCollapsed = !isCollapsed)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ExpandCollapse isExpanded={!isCollapsed} on:changeContent>
|
||||
<div class="flex-col flex-no-shrink max-h-30 list clear-mins" class:collapsed={isCollapsed}>
|
||||
<Scroller>
|
||||
<DraftIssueChildList
|
||||
{component}
|
||||
{milestone}
|
||||
bind:issues={subIssues}
|
||||
project={projectId}
|
||||
on:move={handleIssueSwap}
|
||||
on:update-issue
|
||||
/>
|
||||
</Scroller>
|
||||
</div>
|
||||
</ExpandCollapse>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.list {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
&.collapsed {
|
||||
padding-top: 1px;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -17,13 +17,15 @@
|
||||
import { Account, Doc, generateId, Ref } from '@hcengineering/core'
|
||||
import presentation, { DraftController, getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
import tags, { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { TaskType } from '@hcengineering/task'
|
||||
import { TaskKindSelector } from '@hcengineering/task-resources'
|
||||
import {
|
||||
Component as ComponentType,
|
||||
Issue,
|
||||
IssueDraft,
|
||||
IssuePriority,
|
||||
Project,
|
||||
Milestone
|
||||
Milestone,
|
||||
Project
|
||||
} from '@hcengineering/tracker'
|
||||
import { Button, Component, EditBox } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
@ -65,6 +67,7 @@
|
||||
_id: generateId(),
|
||||
title: '',
|
||||
description: '',
|
||||
kind: '' as Ref<TaskType>,
|
||||
assignee: project.defaultAssignee ?? null,
|
||||
status: project.defaultIssueStatus,
|
||||
space: project._id,
|
||||
@ -208,6 +211,12 @@
|
||||
on:change={({ detail }) => (object.priority = detail)}
|
||||
/>
|
||||
</div>
|
||||
<TaskKindSelector
|
||||
projectType={project.type}
|
||||
kind="no-border"
|
||||
bind:value={object.kind}
|
||||
baseClass={tracker.class.Issue}
|
||||
/>
|
||||
<div id="sub-issue-assignee-editor">
|
||||
{#key object.assignee}
|
||||
<AssigneeEditor
|
||||
|
@ -14,9 +14,10 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createQuery, ActionContext } from '@hcengineering/presentation'
|
||||
import tracker, { Component, IssueDraft, Project, Milestone } from '@hcengineering/tracker'
|
||||
import { eventToHTMLElement, IconCircles, showPopup } from '@hcengineering/ui'
|
||||
import { ActionContext, createQuery } from '@hcengineering/presentation'
|
||||
import { TaskKindSelector } from '@hcengineering/task-resources'
|
||||
import tracker, { Component, IssueDraft, Milestone, Project } from '@hcengineering/tracker'
|
||||
import { IconCircles, eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
import { FixedColumn } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { flip } from 'svelte/animate'
|
||||
@ -137,7 +138,6 @@
|
||||
value={{ ...issue, space: project }}
|
||||
kind="list"
|
||||
size="small"
|
||||
shouldShowLabel={true}
|
||||
on:change={({ detail }) => (issue.status = detail)}
|
||||
/>
|
||||
<PriorityEditor
|
||||
@ -173,6 +173,12 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-center flex-no-shrink">
|
||||
<TaskKindSelector
|
||||
projectType={currentProject?.type}
|
||||
kind={'link'}
|
||||
bind:value={issue.kind}
|
||||
baseClass={tracker.class.Issue}
|
||||
/>
|
||||
<EstimationEditor
|
||||
kind={'link'}
|
||||
size={'large'}
|
||||
|
@ -16,11 +16,12 @@
|
||||
import { generateId, Ref } from '@hcengineering/core'
|
||||
import presentation, { createQuery, getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
import tags, { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { TaskKindSelector } from '@hcengineering/task-resources'
|
||||
import { StyledTextArea } from '@hcengineering/text-editor'
|
||||
import {
|
||||
Component as ComponentType,
|
||||
IssuePriority,
|
||||
IssueTemplateChild,
|
||||
Component as ComponentType,
|
||||
Milestone,
|
||||
Project
|
||||
} from '@hcengineering/tracker'
|
||||
@ -108,6 +109,18 @@
|
||||
labels = [...labels, tag]
|
||||
}
|
||||
|
||||
const projectQuery = createQuery()
|
||||
$: projectQuery.query(
|
||||
tracker.class.Project,
|
||||
{
|
||||
_id: projectId
|
||||
},
|
||||
(res) => {
|
||||
;[currentProject] = res
|
||||
}
|
||||
)
|
||||
let currentProject: Project | undefined = undefined
|
||||
|
||||
$: thisRef && thisRef.scrollIntoView({ behavior: 'smooth' })
|
||||
$: canSave = getTitle(newIssue.title ?? '').length > 0
|
||||
|
||||
@ -138,6 +151,12 @@
|
||||
</div>
|
||||
<div class="mt-4 flex-between items-end">
|
||||
<div class="inline-flex flex-wrap xsmall-gap">
|
||||
<TaskKindSelector
|
||||
projectType={currentProject?.type}
|
||||
kind="no-border"
|
||||
bind:value={newIssue.kind}
|
||||
baseClass={tracker.class.Issue}
|
||||
/>
|
||||
<PriorityEditor
|
||||
value={newIssue}
|
||||
shouldShowLabel
|
||||
|
@ -14,8 +14,9 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createQuery, ActionContext } from '@hcengineering/presentation'
|
||||
import tracker, { Component, Issue, IssueTemplateChild, Project, Milestone } from '@hcengineering/tracker'
|
||||
import { ActionContext, createQuery } from '@hcengineering/presentation'
|
||||
import { TaskKindSelector } from '@hcengineering/task-resources'
|
||||
import tracker, { Component, Issue, IssueTemplateChild, Milestone, Project } from '@hcengineering/tracker'
|
||||
import { IconCircles, eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
import { FixedColumn } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@ -41,6 +42,7 @@
|
||||
IssueTemplateChildEditor,
|
||||
{
|
||||
showBorder: true,
|
||||
projectId: project,
|
||||
milestone,
|
||||
component,
|
||||
childIssue: target
|
||||
@ -168,6 +170,12 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-center flex-no-shrink">
|
||||
<TaskKindSelector
|
||||
projectType={currentProject?.type}
|
||||
kind={'link'}
|
||||
bind:value={issue.kind}
|
||||
baseClass={tracker.class.Issue}
|
||||
/>
|
||||
<EstimationEditor
|
||||
kind={'link'}
|
||||
size={'large'}
|
||||
|
@ -210,7 +210,7 @@ export interface Issue extends Task {
|
||||
* @public
|
||||
*/
|
||||
export interface IssueDraft {
|
||||
kind?: Ref<TaskType>
|
||||
kind: Ref<TaskType>
|
||||
_id: Ref<Issue>
|
||||
title: string
|
||||
description: Markup
|
||||
@ -253,6 +253,8 @@ export interface IssueTemplateData {
|
||||
estimation: number
|
||||
|
||||
labels?: Ref<TagElement>[]
|
||||
|
||||
kind?: Ref<TaskType>
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user