UBER-1137: prevent changes of spaces while kanban drag-and-drop (#3928)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2023-11-01 17:55:11 +04:00 committed by GitHub
parent d7089dae74
commit 6ee350103a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 2 deletions

View File

@ -36,6 +36,7 @@
export let dontUpdateRank: boolean = false export let dontUpdateRank: boolean = false
export let getUpdateProps: (doc: Doc, state: CategoryType) => DocumentUpdate<Item> | undefined export let getUpdateProps: (doc: Doc, state: CategoryType) => DocumentUpdate<Item> | undefined
export let getAvailableCategories: ((doc: Doc) => Promise<CategoryType[]>) | undefined = undefined
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -43,6 +44,13 @@
if (dragCard === undefined) { if (dragCard === undefined) {
return return
} }
const canDrop = !dragCardAvailableCategories || dragCardAvailableCategories.includes(state)
if (!canDrop) {
return
}
let updates = getUpdateProps(dragCard, state) let updates = getUpdateProps(dragCard, state)
if (updates === undefined) { if (updates === undefined) {
@ -61,6 +69,7 @@
await client.diffUpdate(dragCard, updates) await client.diffUpdate(dragCard, updates)
} }
dragCard = undefined dragCard = undefined
dragCardAvailableCategories = undefined
} }
const client = getClient() const client = getClient()
@ -70,6 +79,7 @@
let dragCardInitialState: CategoryType let dragCardInitialState: CategoryType
let dragCardInitialPosition: number | undefined let dragCardInitialPosition: number | undefined
let dragCardState: CategoryType | undefined let dragCardState: CategoryType | undefined
let dragCardAvailableCategories: CategoryType[] | undefined
let isDragging = false let isDragging = false
@ -84,6 +94,12 @@
function panelDragOver (event: Event | undefined, state: CategoryType): void { function panelDragOver (event: Event | undefined, state: CategoryType): void {
event?.preventDefault() event?.preventDefault()
if (dragCard !== undefined && dragCardState !== state) { if (dragCard !== undefined && dragCardState !== state) {
const canDrop = !dragCardAvailableCategories || dragCardAvailableCategories.includes(state)
if (!canDrop) {
return
}
const updates = getUpdateProps(dragCard, state) const updates = getUpdateProps(dragCard, state)
if (updates === undefined) { if (updates === undefined) {
return return
@ -169,7 +185,7 @@
} }
isDragging = false isDragging = false
} }
function onDragStart (object: Item, state: CategoryType): void { async function onDragStart (object: Item, state: CategoryType) {
dragCardInitialState = state dragCardInitialState = state
dragCardState = state dragCardState = state
dragCardInitialRank = object.rank dragCardInitialRank = object.rank
@ -177,6 +193,7 @@
dragCardInitialPosition = items.findIndex((p) => p._id === object._id) dragCardInitialPosition = items.findIndex((p) => p._id === object._id)
dragCard = object dragCard = object
isDragging = true isDragging = true
dragCardAvailableCategories = await getAvailableCategories?.(object)
dispatch('obj-focus', object) dispatch('obj-focus', object)
} }
// eslint-disable-next-line // eslint-disable-next-line

View File

@ -66,7 +66,8 @@
noCategory, noCategory,
openDoc, openDoc,
SelectDirection, SelectDirection,
setGroupByValues setGroupByValues,
statusStore
} from '@hcengineering/view-resources' } from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin' import view from '@hcengineering/view-resources/src/plugin'
import { onMount } from 'svelte' import { onMount } from 'svelte'
@ -82,6 +83,8 @@
import PriorityEditor from './PriorityEditor.svelte' import PriorityEditor from './PriorityEditor.svelte'
import StatusEditor from './StatusEditor.svelte' import StatusEditor from './StatusEditor.svelte'
import EstimationEditor from './timereport/EstimationEditor.svelte' import EstimationEditor from './timereport/EstimationEditor.svelte'
import { getStates } from '@hcengineering/task'
import { typeStore } from '@hcengineering/task-resources'
export let space: Ref<Project> | undefined = undefined export let space: Ref<Project> | undefined = undefined
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
@ -264,6 +267,39 @@
if (enabledConfig(config, 'attachments') && (issue.attachments ?? 0) > 0) return true if (enabledConfig(config, 'attachments') && (issue.attachments ?? 0) > 0) return true
return false return false
} }
const getAvailableCategories = async (doc: Doc): Promise<CategoryType[]> => {
const issue = toIssue(doc)
if ([IssuesGrouping.Component, IssuesGrouping.Milestone].includes(groupByKey)) {
const availableCategories = []
const clazz = hierarchy.getAttribute(tracker.class.Issue, groupByKey)
for (const category of categories) {
if (!category || (issue as any)[groupByKey] === category) {
availableCategories.push(category)
} else if (clazz !== undefined && 'to' in clazz.type) {
const categoryDoc = await client.findOne(clazz.type.to as Ref<Class<Doc>>, {
_id: category as Ref<Doc>,
space: issue.space
})
if (categoryDoc) {
availableCategories.push(category)
}
}
}
return availableCategories
}
if (groupByKey === IssuesGrouping.Status) {
const space = await client.findOne(tracker.class.Project, { _id: issue.space })
return getStates(space, $typeStore, $statusStore.byId).map(({ _id }) => _id)
}
return categories
}
</script> </script>
{#if categories.length === 0} {#if categories.length === 0}
@ -288,6 +324,7 @@
on:obj-focus={(evt) => { on:obj-focus={(evt) => {
listProvider.updateFocus(evt.detail) listProvider.updateFocus(evt.detail)
}} }}
{getAvailableCategories}
selection={listProvider.current($focusStore)} selection={listProvider.current($focusStore)}
checked={$selection ?? []} checked={$selection ?? []}
on:check={(evt) => { on:check={(evt) => {