Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2023-09-04 23:06:34 +06:00
committed by GitHub
parent a2388cd1d4
commit 2422baa108
97 changed files with 1678 additions and 1268 deletions
@@ -1,12 +1,13 @@
<script lang="ts">
import { Ref } from '@hcengineering/core'
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
import { getStates } from '@hcengineering/task'
import { Issue, IssueStatus, Project } from '@hcengineering/tracker'
import { Button, Label, SelectPopup, eventToHTMLElement, showPopup } from '@hcengineering/ui'
import presentation, { getClient } from '@hcengineering/presentation'
import tracker from '../../plugin'
import { createEventDispatcher } from 'svelte'
import IssueStatusIcon from '../issues/IssueStatusIcon.svelte'
import { StatusPresenter, statusStore } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin'
import IssueStatusIcon from '../issues/IssueStatusIcon.svelte'
export let projectId: Ref<Project>
export let issues: Issue[]
@@ -14,13 +15,18 @@
let processing = false
let _space: Project | undefined = undefined
const query = createQuery()
$: query.query(tracker.class.Project, { space: projectId }, (result) => {
_space = result[0]
})
const client = getClient()
let newStatus: IssueStatus =
$statusStore
.getDocs()
.find((s) => s._id !== status._id && s.category === status.category && s.space === projectId) ??
$statusStore.getDocs().find((s) => s._id !== status._id && s.space === projectId) ??
$: newStatus =
statuses.find((s) => s._id !== status._id && s.category === status.category && s.space === projectId) ??
statuses.find((s) => s._id !== status._id && s.space === projectId) ??
status
async function remove () {
@@ -32,12 +38,14 @@
})
})
)
await client.remove(status)
if (_space) {
await client.update(_space, { $pull: { states: status._id } })
}
processing = false
dispatch('close')
}
$: statuses = $statusStore.filter((it) => it.space === projectId && it._id !== status._id)
$: statuses = getStates(_space, $statusStore).filter((p) => p._id !== status._id)
$: statusesInfo = statuses?.map((s) => {
return {
id: s._id,
@@ -55,7 +63,7 @@
{ value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
eventToHTMLElement(event),
(val) => {
newStatus = $statusStore.getIdMap().get(val) ?? newStatus
newStatus = $statusStore.get(val) ?? newStatus
}
)
}
@@ -74,9 +82,7 @@
<Button kind={'link'} justify={'left'} width={'10rem'} on:click={handleStatusEditorOpened}>
<span slot="content" class="flex-row-center pointer-events-none">
{#if newStatus}
<IssueStatusIcon value={newStatus} size="inline" />
{/if}
{#if newStatus}
<IssueStatusIcon value={newStatus} space={projectId} size="inline" />
<span class="overflow-label disabled ml-1">
{newStatus.name}
</span>
@@ -13,13 +13,15 @@
// limitations under the License.
-->
<script lang="ts">
import { IssueStatus } from '@hcengineering/tracker'
import { Ref } from '@hcengineering/core'
import { IssueStatus, Project } from '@hcengineering/tracker'
import { Icon, IconCircles, IconDelete, IconEdit, Label, tooltip } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin'
import IssueStatusIcon from '../issues/IssueStatusIcon.svelte'
export let value: IssueStatus
export let space: Ref<Project>
export let isDefault = false
export let isSingle = true
@@ -36,7 +38,7 @@
<IconCircles size={'small'} />
</div>
<div class="flex-no-shrink">
<IssueStatusIcon {value} size="small" />
<IssueStatusIcon {value} size="small" {space} />
</div>
<span class="caption-color ml-2">{value.name}</span>
{#if value.description}
@@ -14,16 +14,17 @@
-->
<script lang="ts">
import core, { Class, Data, Ref, SortingOrder, StatusCategory } from '@hcengineering/core'
import { createQuery, getClient, MessageBox, Card } from '@hcengineering/presentation'
import { calcRank, IssueStatus, Project } from '@hcengineering/tracker'
import { Button, closeTooltip, ExpandCollapse, IconAdd, Label, Loading, Scroller, showPopup } from '@hcengineering/ui'
import { Card, MessageBox, createQuery, getClient } from '@hcengineering/presentation'
import { createState, getStates } from '@hcengineering/task'
import { IssueStatus, Project } from '@hcengineering/tracker'
import { Button, ExpandCollapse, IconAdd, Label, Loading, Scroller, closeTooltip, showPopup } from '@hcengineering/ui'
import { statusStore } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import { flip } from 'svelte/animate'
import tracker from '../../plugin'
import RemoveStatus from './RemoveStatus.svelte'
import StatusEditor from './StatusEditor.svelte'
import StatusPresenter from './StatusPresenter.svelte'
import RemoveStatus from './RemoveStatus.svelte'
import { statusStore } from '@hcengineering/view-resources'
export let projectId: Ref<Project>
export let projectClass: Ref<Class<Project>>
@@ -56,18 +57,16 @@
}
async function addStatus () {
if (editingStatus?.name && editingStatus?.category) {
const [prevStatus, nextStatus] = getSiblingsForNewStatus(editingStatus.category)
if (editingStatus?.name && editingStatus?.category && project) {
isSaving = true
await client.createDoc(tracker.class.IssueStatus, projectId, {
const id = await createState(client, tracker.class.IssueStatus, {
ofAttribute: tracker.attribute.IssueStatus,
name: editingStatus.name,
description: editingStatus.description,
color: editingStatus.color,
category: editingStatus.category,
rank: calcRank(prevStatus, nextStatus)
category: editingStatus.category
})
await client.update(project, { $push: { states: id } })
isSaving = false
}
@@ -77,16 +76,13 @@
async function editStatus () {
if (statusCategories && editingStatus?.name && editingStatus?.category && '_id' in editingStatus) {
const statusId = '_id' in editingStatus ? editingStatus._id : undefined
const status = statusId && $statusStore.getIdMap().get(statusId)
const status = statusId && $statusStore.get(statusId)
if (!status) {
return
}
const updates: Partial<Data<IssueStatus>> = {}
if (status.name !== editingStatus.name) {
updates.name = editingStatus.name
}
if (status.description !== editingStatus.description) {
updates.description = editingStatus.description
}
@@ -101,8 +97,29 @@
updates.color = editingStatus.color
}
}
if (Object.keys(updates).length > 0) {
if (status.name !== editingStatus.name) {
isSaving = true
const newId = await createState(client, tracker.class.IssueStatus, {
ofAttribute: tracker.attribute.IssueStatus,
name: editingStatus.name,
description: editingStatus.description,
color: editingStatus.color,
category: editingStatus.category
})
projectStatuses = projectStatuses.map((s) => (s._id === statusId ? { ...s, _id: newId } : s))
if (project) {
const issues = await client.findAll(tracker.class.Issue, { status: status._id, space: projectId })
await Promise.all(
issues.map(async (p) => {
await client.update(p, {
status: newId
})
})
)
await client.update(project, { states: projectStatuses.map((s) => s._id) })
}
isSaving = false
} else if (Object.keys(updates).length > 0) {
isSaving = true
await client.update(status, updates)
isSaving = false
@@ -136,7 +153,7 @@
async (result) => {
if (result && project) {
isSaving = true
await client.removeDoc(status._class, status.space, status._id)
await client.update(project, { $pull: { states: status._id } })
if (project.defaultIssueStatus === status._id) {
const newDefaultStatus = projectStatuses.find(
@@ -166,23 +183,22 @@
}
function handleDragOver (ev: DragEvent, status: IssueStatus) {
hoveringStatus = status
ev.preventDefault()
if (status.category === draggingStatus?.category) {
hoveringStatus = status
ev.preventDefault()
}
}
async function handleDrop (toItem: IssueStatus) {
if (draggingStatus != null && draggingStatus?._id !== toItem._id) {
const fromIndex = getStatusIndex(draggingStatus)
const toIndex = getStatusIndex(toItem)
const [prev, next] = [
projectStatuses[fromIndex < toIndex ? toIndex : toIndex - 1],
projectStatuses[fromIndex < toIndex ? toIndex + 1 : toIndex]
]
const item = projectStatuses.splice(fromIndex, 1)
isSaving = true
let newCategory = {}
if (draggingStatus?.category !== toItem.category) newCategory = { category: toItem.category }
await client.update(draggingStatus, { rank: calcRank(prev, next), ...newCategory })
projectStatuses = [...projectStatuses.slice(0, toIndex), ...item, ...projectStatuses.slice(toIndex)]
if (project) {
await client.update(project, { states: projectStatuses.map((s) => s._id) })
}
isSaving = false
}
@@ -193,33 +209,6 @@
return projectStatuses.findIndex(({ _id }) => _id === status._id) ?? -1
}
function getSiblingsForNewStatus (
categoryId: StatusCategory['_id']
): readonly [] | readonly [IssueStatus | undefined, IssueStatus | undefined] {
const categoryStatuses = projectStatuses.filter((s) => s.category === categoryId)
if (categoryStatuses.length > 0) {
const prev = categoryStatuses[categoryStatuses.length - 1]
const next = projectStatuses[getStatusIndex(prev) + 1]
return [prev, next]
}
const category = statusCategories?.find(({ _id }) => _id === categoryId)
if (!category) {
return []
}
const { order } = category
const prev = projectStatuses.findLast(
(s) => s.$lookup?.category?.order !== undefined && s.$lookup.category.order < order
)
const next = projectStatuses.find(
(s) => s.$lookup?.category?.order !== undefined && s.$lookup.category.order > order
)
return [prev, next]
}
function resetDrag () {
draggingStatus = null
hoveringStatus = null
@@ -227,7 +216,7 @@
$: projectQuery.query(projectClass, { _id: projectId }, (result) => ([project] = result), { limit: 1 })
$: updateStatusCategories()
$: projectStatuses = $statusStore.getDocs().filter((status) => status.space === projectId)
$: projectStatuses = getStates(project, $statusStore)
</script>
<Card
@@ -266,15 +255,17 @@
/>
</div>
<div class="flex-col">
{#each statuses as status, _ (status._id)}
{#each statuses as status (status._id)}
<div
class="row"
class:is-dragged-over-up={draggingStatus &&
status._id === hoveringStatus?._id &&
status.rank < draggingStatus.rank}
draggingStatus.category === status.category &&
getStatusIndex(status) < getStatusIndex(draggingStatus)}
class:is-dragged-over-down={draggingStatus &&
status._id === hoveringStatus?._id &&
status.rank > draggingStatus.rank}
draggingStatus.category === status.category &&
getStatusIndex(status) > getStatusIndex(draggingStatus)}
draggable={!isSingle}
animate:flip={{ duration: 200 }}
on:dragstart={(ev) => handleDragStart(ev, status)}
@@ -292,6 +283,7 @@
/>
{:else}
<StatusPresenter
space={projectId}
value={status}
isDefault={status._id === project.defaultIssueStatus}
{isSingle}