mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 04:08:19 +00:00
Fix process issues (#2287)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
b2b6b6de90
commit
4ed2f7ede2
@ -940,7 +940,7 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.ClassFilters, {
|
||||
filters: ['priority', 'assignee', 'project', 'sprint', 'estimation', 'modifiedOn']
|
||||
filters: ['priority', 'assignee', 'project', 'sprint', 'modifiedOn']
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
|
@ -50,7 +50,7 @@ function $pull (document: Doc, keyval: Record<string, PropertyType>): void {
|
||||
doc[key] = []
|
||||
}
|
||||
const arr = doc[key] as Array<any>
|
||||
if (typeof keyval[key] === 'object') {
|
||||
if (typeof keyval[key] === 'object' && keyval[key] !== null) {
|
||||
const { $in } = keyval[key] as PullArray<PropertyType>
|
||||
|
||||
doc[key] = arr.filter((val) => {
|
||||
|
@ -45,10 +45,23 @@ let client: TxOperations
|
||||
|
||||
const txListeners: Array<(tx: Tx) => void> = []
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function addTxListener (l: (tx: Tx) => void): void {
|
||||
txListeners.push(l)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function removeTxListener (l: (tx: Tx) => void): void {
|
||||
const pos = txListeners.findIndex((it) => it === l)
|
||||
if (pos !== -1) {
|
||||
txListeners.splice(pos, 1)
|
||||
}
|
||||
}
|
||||
|
||||
class UIClient extends TxOperations implements Client {
|
||||
constructor (client: Client, private readonly liveQuery: LQ) {
|
||||
super(client, getCurrentAccount()._id)
|
||||
@ -59,10 +72,16 @@ class UIClient extends TxOperations implements Client {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getClient (): TxOperations {
|
||||
return client
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function setClient (_client: Client): void {
|
||||
liveQuery = new LQ(_client)
|
||||
client = new UIClient(_client, liveQuery)
|
||||
@ -73,6 +92,9 @@ export function setClient (_client: Client): void {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export class LiveQuery {
|
||||
private oldClass: Ref<Class<Doc>> | undefined
|
||||
private oldQuery: DocumentQuery<Doc> | undefined
|
||||
@ -128,10 +150,16 @@ export class LiveQuery {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createQuery (dontDestroy?: boolean): LiveQuery {
|
||||
return new LiveQuery(dontDestroy)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getFileUrl (file: string, size: IconSize = 'full'): string {
|
||||
const uploadUrl = getMetadata(login.metadata.UploadUrl)
|
||||
const token = getMetadata(login.metadata.LoginToken)
|
||||
@ -139,6 +167,9 @@ export function getFileUrl (file: string, size: IconSize = 'full'): string {
|
||||
return url
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function getBlobURL (blob: Blob): Promise<string> {
|
||||
return await new Promise((resolve) => {
|
||||
const reader = new FileReader()
|
||||
@ -148,6 +179,9 @@ export async function getBlobURL (blob: Blob): Promise<string> {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function copyTextToClipboard (text: string): Promise<void> {
|
||||
try {
|
||||
// Safari specific behavior
|
||||
@ -162,9 +196,16 @@ export async function copyTextToClipboard (text: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AttributeCategory = 'attribute' | 'inplace' | 'collection' | 'array'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const AttributeCategoryOrder = { attribute: 0, inplace: 1, collection: 2, array: 2 }
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -132,12 +132,27 @@
|
||||
templateQuery.unsubscribe()
|
||||
}
|
||||
|
||||
function updateObject (template: IssueTemplate): void {
|
||||
function tagAsRef (tag: TagElement): TagReference {
|
||||
return {
|
||||
_class: tags.class.TagReference,
|
||||
_id: generateId() as Ref<TagReference>,
|
||||
attachedTo: '' as Ref<Doc>,
|
||||
attachedToClass: tracker.class.Issue,
|
||||
collection: 'labels',
|
||||
space: tags.space.Tags,
|
||||
modifiedOn: 0,
|
||||
modifiedBy: '' as Ref<Account>,
|
||||
title: tag.title,
|
||||
tag: tag._id,
|
||||
color: tag.color
|
||||
}
|
||||
}
|
||||
async function updateObject (template: IssueTemplate): Promise<void> {
|
||||
if (object.template?.template === template._id) {
|
||||
return
|
||||
}
|
||||
|
||||
const { _class, _id, space, children, comments, attachments, labels, dueDate, ...templBase } = template
|
||||
const { _class, _id, space, children, comments, attachments, labels: labels_, ...templBase } = template
|
||||
|
||||
subIssues = template.children
|
||||
|
||||
@ -148,6 +163,8 @@
|
||||
template: template._id
|
||||
}
|
||||
}
|
||||
const tagElements = await client.findAll(tags.class.TagElement, { _id: { $in: labels_ } })
|
||||
labels = tagElements.map(tagAsRef)
|
||||
}
|
||||
function updateTemplate (template?: IssueTemplate): void {
|
||||
if (template !== undefined) {
|
||||
@ -304,7 +321,7 @@
|
||||
rank: calcRank(lastOne, undefined),
|
||||
comments: 0,
|
||||
subIssues: 0,
|
||||
dueDate: subIssue.dueDate,
|
||||
dueDate: null,
|
||||
parents: parentIssue
|
||||
? [
|
||||
{ parentId: objectId, parentTitle: value.title },
|
||||
@ -313,7 +330,7 @@
|
||||
]
|
||||
: [{ parentId: objectId, parentTitle: value.title }],
|
||||
reportedTime: 0,
|
||||
estimation: object.estimation,
|
||||
estimation: subIssue.estimation,
|
||||
reports: 0,
|
||||
relations: [],
|
||||
childInfo: []
|
||||
@ -405,22 +422,7 @@
|
||||
}
|
||||
|
||||
function addTagRef (tag: TagElement): void {
|
||||
labels = [
|
||||
...labels,
|
||||
{
|
||||
_class: tags.class.TagReference,
|
||||
_id: generateId() as Ref<TagReference>,
|
||||
attachedTo: '' as Ref<Doc>,
|
||||
attachedToClass: tracker.class.Issue,
|
||||
collection: 'labels',
|
||||
space: tags.space.Tags,
|
||||
modifiedOn: 0,
|
||||
modifiedBy: '' as Ref<Account>,
|
||||
title: tag.title,
|
||||
tag: tag._id,
|
||||
color: tag.color
|
||||
}
|
||||
]
|
||||
labels = [...labels, tagAsRef(tag)]
|
||||
}
|
||||
function handleTemplateChange (evt: CustomEvent<Ref<IssueTemplate>>): void {
|
||||
if (templateId == null) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
import PriorityEditor from '../issues/PriorityEditor.svelte'
|
||||
import ProjectSelector from '../ProjectSelector.svelte'
|
||||
import SprintSelector from '../sprints/SprintSelector.svelte'
|
||||
import EstimationEditor from './EstimationEditor.svelte'
|
||||
import SubIssueTemplates from './IssueTemplateChilds.svelte'
|
||||
|
||||
export let space: Ref<Team>
|
||||
@ -35,7 +36,6 @@
|
||||
export let project: Ref<Project> | null = $activeProject ?? null
|
||||
export let sprint: Ref<Sprint> | null = $activeSprint ?? null
|
||||
|
||||
const dueDate: number | undefined = undefined
|
||||
let labels: TagElement[] = []
|
||||
|
||||
let objectId: Ref<IssueTemplate> = generateId()
|
||||
@ -46,7 +46,6 @@
|
||||
project: project,
|
||||
sprint: sprint,
|
||||
priority: priority,
|
||||
dueDate: dueDate ?? null,
|
||||
estimation: 0,
|
||||
children: [],
|
||||
labels: [],
|
||||
@ -89,7 +88,6 @@
|
||||
project: object.project,
|
||||
sprint: object.sprint,
|
||||
priority: object.priority,
|
||||
dueDate: dueDate ?? null,
|
||||
estimation: object.estimation,
|
||||
children: object.children,
|
||||
comments: 0,
|
||||
@ -211,9 +209,7 @@
|
||||
labels = labels.filter((it) => it._id !== evt.detail)
|
||||
}}
|
||||
/>
|
||||
<!-- <EstimationEditor kind={'no-border'} size={'small'} value={object} /> -->
|
||||
<!-- <NumberEditor kind={'no-border'} bind:value={dueDate} placeholder={tracker.string.DueDate}
|
||||
focus={false} onChange={({ detail }) => (dueDate = detail) }/> -->
|
||||
<EstimationEditor kind={'no-border'} size={'small'} value={object} />
|
||||
<ProjectSelector value={object.project} onChange={handleProjectIdChanged} />
|
||||
<SprintSelector value={object.sprint} onChange={handleSprintIdChanged} useProject={object.project ?? undefined} />
|
||||
</div>
|
||||
|
@ -21,6 +21,7 @@
|
||||
import presentation, { createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import setting, { settingId } from '@hcengineering/setting'
|
||||
import type { IssueTemplate, IssueTemplateChild, Team } from '@hcengineering/tracker'
|
||||
import tags from '@hcengineering/tags'
|
||||
import {
|
||||
Button,
|
||||
EditBox,
|
||||
@ -85,7 +86,7 @@
|
||||
description = template.description
|
||||
currentTeam = template.$lookup?.space
|
||||
},
|
||||
{ lookup: { space: tracker.class.Team } }
|
||||
{ lookup: { space: tracker.class.Team, labels: tags.class.TagElement } }
|
||||
)
|
||||
|
||||
$: canSave = title.trim().length > 0
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Data } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { IssueTemplate, IssueTemplateChild } from '@hcengineering/tracker'
|
||||
import { Button, ButtonKind, ButtonSize, eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
@ -20,7 +21,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: IssueTemplateChild | IssueTemplate
|
||||
export let value: IssueTemplateChild | IssueTemplate | Data<IssueTemplate>
|
||||
export let isEditable: boolean = true
|
||||
|
||||
export let kind: ButtonKind = 'link'
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { generateId, Ref } from '@hcengineering/core'
|
||||
import presentation, { getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
import presentation, { createQuery, getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
import tags, { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { StyledTextArea } from '@hcengineering/text-editor'
|
||||
import { IssuePriority, IssueTemplateChild, Project, Sprint } from '@hcengineering/tracker'
|
||||
@ -38,6 +38,12 @@
|
||||
let focusIssueTitle: () => void
|
||||
let labels: TagElement[] = []
|
||||
|
||||
const labelsQuery = createQuery()
|
||||
|
||||
$: labelsQuery.query(tags.class.TagElement, { _id: { $in: childIssue?.labels ?? [] } }, (res) => {
|
||||
labels = res
|
||||
})
|
||||
|
||||
const key: KeyedAttribute = {
|
||||
key: 'labels',
|
||||
attr: client.getHierarchy().getAttribute(tracker.class.IssueTemplate, 'labels')
|
||||
@ -51,7 +57,6 @@
|
||||
assignee: null,
|
||||
project: null,
|
||||
priority: IssuePriority.NoPriority,
|
||||
dueDate: null,
|
||||
sprint: sprint,
|
||||
estimation: 0
|
||||
}
|
||||
|
@ -13,10 +13,11 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Doc } from '@hcengineering/core'
|
||||
import { Doc, generateId, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { AttributeBarEditor, createQuery, getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
import tags, { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import type { IssueTemplate } from '@hcengineering/tracker'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import { Component, Label } from '@hcengineering/ui'
|
||||
import { getFiltredKeys, isCollectionAttr } from '@hcengineering/view-resources/src/utils'
|
||||
import tracker from '../../plugin'
|
||||
import AssigneeEditor from '../issues/AssigneeEditor.svelte'
|
||||
@ -24,7 +25,7 @@
|
||||
import ProjectEditor from '../projects/ProjectEditor.svelte'
|
||||
import SprintEditor from '../sprints/SprintEditor.svelte'
|
||||
|
||||
export let issue: IssueTemplate
|
||||
export let issue: WithLookup<IssueTemplate>
|
||||
|
||||
const query = createQuery()
|
||||
let showIsBlocking = false
|
||||
@ -45,6 +46,30 @@
|
||||
}
|
||||
|
||||
$: updateKeys(['title', 'description', 'priority', 'number', 'assignee', 'project', 'sprint'])
|
||||
|
||||
const key: KeyedAttribute = {
|
||||
key: 'labels',
|
||||
attr: client.getHierarchy().getAttribute(tracker.class.IssueTemplate, 'labels')
|
||||
}
|
||||
|
||||
let labelRefs: TagReference[] = []
|
||||
|
||||
$: labelIds = issue?.$lookup?.labels ?? []
|
||||
|
||||
$: if (labelIds !== undefined) {
|
||||
labelRefs = (Array.isArray(labelIds) ? labelIds : [labelIds]).map(
|
||||
(it) => ({ ...(it as unknown as TagReference), _id: generateId(), tag: it._id } as unknown as TagReference)
|
||||
)
|
||||
}
|
||||
|
||||
const onTagDelete = async (evt: CustomEvent<Ref<TagReference>>): Promise<void> => {
|
||||
const itm = labelRefs.find((it) => it._id === evt.detail)
|
||||
if (itm !== undefined) {
|
||||
await client.update(issue, {
|
||||
$pull: { labels: itm.tag as unknown as Ref<TagElement> }
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="content">
|
||||
@ -58,10 +83,24 @@
|
||||
</span>
|
||||
<AssigneeEditor value={issue} />
|
||||
|
||||
<!-- <span class="labelTop">
|
||||
<span class="labelTop">
|
||||
<Label label={tracker.string.Labels} />
|
||||
</span> -->
|
||||
<!-- <Component is={tags.component.TagsAttributeEditor} props={{ object: issue, label: tracker.string.AddLabel }} /> -->
|
||||
</span>
|
||||
|
||||
<Component
|
||||
is={tags.component.TagsDropdownEditor}
|
||||
props={{
|
||||
kind: 'no-border',
|
||||
items: labelRefs,
|
||||
key,
|
||||
targetClass: tracker.class.Issue,
|
||||
countLabel: tracker.string.NumberLabels
|
||||
}}
|
||||
on:open={async (evt) => {
|
||||
await client.update(issue, { $push: { labels: evt.detail._id } })
|
||||
}}
|
||||
on:delete={onTagDelete}
|
||||
/>
|
||||
|
||||
<div class="divider" />
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user