mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-07 18:27:44 +02:00
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@anticrm/contact'
|
||||
import type { AttachedData, Data, Doc, Ref, Space } from '@anticrm/core'
|
||||
import { AttachedData, calcRank, Data, Doc, Ref, Space } from '@anticrm/core'
|
||||
import { generateId } from '@anticrm/core'
|
||||
import { OK, Status } from '@anticrm/platform'
|
||||
import { Card, getClient, UserBox } from '@anticrm/presentation'
|
||||
@@ -63,6 +63,11 @@
|
||||
throw new Error('sequence object not found')
|
||||
}
|
||||
|
||||
const lastOne = await client.findOne(
|
||||
task.class.Task,
|
||||
{ state: state._id },
|
||||
{ sort: { rank: SortingOrder.Descending } }
|
||||
)
|
||||
const incResult = await client.updateDoc(
|
||||
task.class.Sequence,
|
||||
task.space.Sequence,
|
||||
@@ -79,7 +84,8 @@
|
||||
assignee,
|
||||
number: (incResult as any).object.sequence,
|
||||
doneState: null,
|
||||
state: state._id
|
||||
state: state._id,
|
||||
rank: calcRank(lastOne, undefined)
|
||||
}
|
||||
|
||||
await client.addCollection(task.class.Issue, _space, parent?._id ?? task.global.Task, parent?._class ?? task.class.Issue, 'tasks', value, taskId)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Ref, Doc } from '@anticrm/core'
|
||||
import { Ref, Doc, SortingOrder, calcRank } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import type { Kanban, State, DoneState } from '@anticrm/task'
|
||||
import task from '@anticrm/task'
|
||||
@@ -33,45 +33,49 @@
|
||||
|
||||
const client = getClient()
|
||||
|
||||
function sort <T extends Doc> (order: Ref<T>[], items: T[]): T[] {
|
||||
if (items.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const itemMap = new Map(items.map(x => [x._id, x]))
|
||||
const x = order
|
||||
.map(id => itemMap.get(id))
|
||||
.filter((x): x is T => x !== undefined)
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
const statesQ = createQuery()
|
||||
$: statesQ.query(task.class.State, { _id: { $in: kanban.states ?? [] } }, result => { states = sort(kanban.states, result) })
|
||||
$: statesQ.query(task.class.State, { space: kanban.space }, result => { states = result}, {
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
})
|
||||
|
||||
const doneStatesQ = createQuery()
|
||||
$: doneStatesQ.query(task.class.DoneState, { _id: { $in: kanban.doneStates } }, (result) => { doneStates = sort(kanban.doneStates, result) })
|
||||
$: doneStatesQ.query(task.class.DoneState, { space: kanban.space }, (result) => { doneStates = result }, {
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
})
|
||||
|
||||
async function onMove ({ detail: { stateID, position } }: { detail: { stateID: Ref<State>, position: number } }) {
|
||||
client.updateDoc(kanban._class, kanban.space, kanban._id, {
|
||||
$move: {
|
||||
states: {
|
||||
$value: stateID,
|
||||
$position: position
|
||||
}
|
||||
const [prev, next] = [states[position - 1], states[position + 1]]
|
||||
const state = states.find((x) => x._id === stateID)
|
||||
|
||||
if (state === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
await client.updateDoc(
|
||||
state._class,
|
||||
state.space,
|
||||
state._id,
|
||||
{
|
||||
rank: calcRank(prev, next)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async function onAdd () {
|
||||
const state = await client.createDoc(task.class.State, kanban.space, {
|
||||
const lastOne = await client.findOne(
|
||||
task.class.State,
|
||||
{ space: kanban.space },
|
||||
{ sort: { rank: SortingOrder.Descending } }
|
||||
)
|
||||
|
||||
await client.createDoc(task.class.State, kanban.space, {
|
||||
title: 'New State',
|
||||
color: '#7C6FCD'
|
||||
})
|
||||
await client.updateDoc(kanban._class, kanban.space, kanban._id, {
|
||||
$push: {
|
||||
states: state
|
||||
}
|
||||
color: '#7C6FCD',
|
||||
rank: calcRank(lastOne, undefined)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Ref, Space, Doc, generateId } from '@anticrm/core'
|
||||
import { Ref, Space, SortingOrder, calcRank } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import type { State, DoneStateTemplate, KanbanTemplate, StateTemplate } from '@anticrm/task'
|
||||
@@ -35,42 +35,49 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
function sort <T extends Doc>(order: Ref<T>[], items: T[]): T[] {
|
||||
if (items.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const itemMap = new Map(items.map(x => [x._id, x]))
|
||||
const x = order
|
||||
.map(id => itemMap.get(id))
|
||||
.filter((x): x is T => x !== undefined)
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
const statesQ = createQuery()
|
||||
$: statesQ.query(task.class.StateTemplate, { attachedTo: kanban._id }, result => { states = sort(kanban.states, result) })
|
||||
$: statesQ.query(task.class.StateTemplate, { attachedTo: kanban._id }, result => { states = result }, {
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
})
|
||||
|
||||
const doneStatesQ = createQuery()
|
||||
$: doneStatesQ.query(task.class.DoneStateTemplate, { attachedTo: kanban._id }, (result) => { doneStates = sort(kanban.doneStates, result) })
|
||||
$: doneStatesQ.query(task.class.DoneStateTemplate, { attachedTo: kanban._id }, (result) => { doneStates = result }, {
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
})
|
||||
|
||||
let space: Space | undefined
|
||||
const spaceQ = createQuery()
|
||||
$: spaceQ.query(core.class.Space, { _id: kanban.space }, (result) => { space = result[0] })
|
||||
|
||||
async function onMove ({ detail: { stateID, position } }: { detail: { stateID: Ref<StateTemplate>, position: number } }) {
|
||||
client.updateDoc(kanban._class, kanban.space, kanban._id, {
|
||||
$move: {
|
||||
states: {
|
||||
$value: stateID,
|
||||
$position: position
|
||||
}
|
||||
const [prev, next] = [states[position - 1], states[position + 1]]
|
||||
const state = states.find((x) => x._id === stateID)
|
||||
|
||||
if (state === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
await client.updateDoc(
|
||||
state._class,
|
||||
state.space,
|
||||
state._id,
|
||||
{
|
||||
rank: calcRank(prev, next)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async function onAdd () {
|
||||
const stateID = generateId<StateTemplate>()
|
||||
const lastOne = await client.findOne(
|
||||
task.class.StateTemplate,
|
||||
{ attachedTo: kanban._id },
|
||||
{ sort: { rank: SortingOrder.Descending } }
|
||||
)
|
||||
|
||||
await client.addCollection(
|
||||
task.class.StateTemplate,
|
||||
kanban.space,
|
||||
@@ -79,16 +86,10 @@
|
||||
'statesC',
|
||||
{
|
||||
title: 'New State',
|
||||
color: '#7C6FCD'
|
||||
},
|
||||
stateID
|
||||
)
|
||||
|
||||
await client.updateDoc(kanban._class, kanban.space, kanban._id, {
|
||||
$push: {
|
||||
states: stateID
|
||||
color: '#7C6FCD',
|
||||
rank: calcRank(lastOne, undefined)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function onDelete ({ detail: { state } }: { detail: { state: State }}) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { AttachedDoc, Class, Doc, FindOptions, Ref } from '@anticrm/core'
|
||||
import { AttachedDoc, calcRank, Class, Doc, DocumentUpdate, DocWithRank, FindOptions, Ref, SortingOrder } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
@@ -26,7 +26,7 @@
|
||||
import KanbanPanel from './KanbanPanel.svelte'
|
||||
// import KanbanPanelEmpty from './KanbanPanelEmpty.svelte'
|
||||
|
||||
type Item = Doc & { state: Ref<State>, doneState: Ref<DoneState> | null }
|
||||
type Item = DocWithRank & { state: Ref<State>, doneState: Ref<DoneState> | null }
|
||||
|
||||
export let _class: Ref<Class<Item>>
|
||||
export let space: Ref<SpaceWithStates>
|
||||
@@ -36,50 +36,38 @@
|
||||
|
||||
let kanban: Kanban
|
||||
let states: State[] = []
|
||||
let rawStates: State[] = []
|
||||
|
||||
let objects: (Item | undefined)[] = []
|
||||
let rawObjects: Item[] = []
|
||||
let kanbanStates: Ref<State>[] = []
|
||||
let kanbanDoneStates: Ref<DoneState>[] = []
|
||||
let objects: Item[] = []
|
||||
let wonState: WonState | undefined
|
||||
let lostState: LostState | undefined
|
||||
|
||||
const kanbanQuery = createQuery()
|
||||
$: kanbanQuery.query(task.class.Kanban, { attachedTo: space }, result => { kanban = result[0] })
|
||||
|
||||
$: kanbanStates = kanban?.states ?? []
|
||||
$: kanbanDoneStates = kanban?.doneStates ?? []
|
||||
|
||||
function sort (kanban: Kanban, states: State[]): State[] {
|
||||
if (kanban === undefined || states.length === 0) { return [] }
|
||||
const map = states.reduce((map, state) => { map.set(state._id, state); return map }, new Map<Ref<State>, State>())
|
||||
return kanban.states.map(id => map.get(id) as State)
|
||||
}
|
||||
|
||||
function sortObjects<T extends Doc> (kanban: Kanban, objects: T[]): (T | undefined)[] {
|
||||
if (kanban === undefined || objects.length === 0) { return [] }
|
||||
const map = objects.reduce((map, doc) => { map.set(doc._id, doc); return map }, new Map<Ref<T>, T>())
|
||||
return kanban.order
|
||||
.map(id => map.get(id as Ref<T>))
|
||||
}
|
||||
|
||||
const statesQuery = createQuery()
|
||||
$: if (kanbanStates.length > 0) statesQuery.query(task.class.State, { _id: { $in: kanbanStates } }, result => { rawStates = result })
|
||||
$: states = sort(kanban, rawStates)
|
||||
$: if (kanban !== undefined) {
|
||||
statesQuery.query(task.class.State, { space: kanban.space }, result => { states = result }, {
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const doneStatesQ = createQuery()
|
||||
$: if (kanbanDoneStates.length > 0) {
|
||||
doneStatesQ.query(task.class.DoneState, { _id: { $in: kanbanDoneStates } }, (result) => {
|
||||
$: if (kanban !== undefined) {
|
||||
doneStatesQ.query(task.class.DoneState, { space: kanban.space }, (result) => {
|
||||
wonState = result.find((x) => x._class === task.class.WonState)
|
||||
lostState = result.find((x) => x._class === task.class.LostState)
|
||||
})
|
||||
}
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(_class, { space, doneState: null }, result => { rawObjects = result }, options)
|
||||
|
||||
$: objects = sortObjects(kanban, rawObjects)
|
||||
$: query.query(_class, { space, doneState: null }, result => { objects = result }, {
|
||||
...options,
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
},
|
||||
})
|
||||
|
||||
function dragover (ev: MouseEvent, object: Item) {
|
||||
if (dragCard !== object) {
|
||||
@@ -89,28 +77,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function updateItem (item: Item, update: DocumentUpdate<Item>) {
|
||||
if (client.getHierarchy().isDerived(_class, core.class.AttachedDoc)) {
|
||||
const adoc: AttachedDoc = item as Doc as AttachedDoc
|
||||
await client.updateCollection(
|
||||
_class,
|
||||
space,
|
||||
adoc._id as Ref<Doc> as Ref<AttachedDoc>,
|
||||
adoc.attachedTo,
|
||||
adoc.attachedToClass,
|
||||
adoc.collection,
|
||||
update
|
||||
)
|
||||
} else {
|
||||
await client.updateDoc(item._class, item.space, item._id, update)
|
||||
}
|
||||
}
|
||||
|
||||
async function move (state: Ref<State>) {
|
||||
const id = dragCard._id
|
||||
let updates: DocumentUpdate<Item> = {}
|
||||
|
||||
if (dragCardInitialState !== state) {
|
||||
if (client.getHierarchy().isDerived(_class, core.class.AttachedDoc)) {
|
||||
const adoc: AttachedDoc = dragCard as Doc as AttachedDoc
|
||||
// We need to update using updateCollection
|
||||
client.updateCollection(_class, space, id as Ref<Doc> as Ref<AttachedDoc>, adoc.attachedTo, adoc.attachedToClass, adoc.collection, { state })
|
||||
} else {
|
||||
client.updateDoc<Task>(_class, space, id as Ref<Task>, { state })
|
||||
updates = {
|
||||
...updates,
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
if (dragCardInitialPosition !== dragCardEndPosition) {
|
||||
client.updateDoc(task.class.Kanban, space, kanban._id, {
|
||||
$move: {
|
||||
order: {
|
||||
$value: id,
|
||||
$position: dragCardEndPosition
|
||||
}
|
||||
}
|
||||
})
|
||||
const [prev, next] = [objects[dragCardEndPosition - 1], objects[dragCardEndPosition + 1]]
|
||||
|
||||
updates = {
|
||||
...updates,
|
||||
rank: calcRank(prev, next)
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await updateItem(dragCard, updates)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,25 +132,9 @@
|
||||
}
|
||||
|
||||
const onDone = (state: DoneState) => async () => {
|
||||
if (client.getHierarchy().isDerived(_class, core.class.AttachedDoc)) {
|
||||
const adoc: AttachedDoc = dragCard as Doc as AttachedDoc
|
||||
await client.updateCollection<Doc, Task>(
|
||||
_class,
|
||||
space,
|
||||
adoc._id as Ref<Task>,
|
||||
adoc.attachedTo,
|
||||
adoc.attachedToClass,
|
||||
adoc.collection,
|
||||
{ doneState: state._id }
|
||||
)
|
||||
} else {
|
||||
await client.updateDoc(dragCard._class, dragCard.space, dragCard._id, {
|
||||
doneState: state._id
|
||||
})
|
||||
}
|
||||
|
||||
isDragging = false
|
||||
hoveredDoneState = undefined
|
||||
await updateItem(dragCard, { doneState: state._id })
|
||||
}
|
||||
|
||||
let isDragging = false
|
||||
@@ -174,7 +162,7 @@
|
||||
}}>
|
||||
<!-- <KanbanCardEmpty label={'Create new application'} /> -->
|
||||
{#each objects as object, j (object)}
|
||||
{#if object !== undefined && object.state === state._id}
|
||||
{#if object.state === state._id}
|
||||
<div
|
||||
class="step-tb75"
|
||||
on:dragover|preventDefault={(ev) => {
|
||||
@@ -226,11 +214,9 @@
|
||||
class="flex-grow flex-center done-item"
|
||||
class:hovered={hoveredDoneState === lostState._id}
|
||||
on:dragenter={() => {
|
||||
console.log('enter')
|
||||
hoveredDoneState = lostState?._id
|
||||
}}
|
||||
on:dragleave={() => {
|
||||
console.log('leave')
|
||||
hoveredDoneState = undefined
|
||||
}}
|
||||
on:dragover|preventDefault={() => {}}
|
||||
|
||||
Reference in New Issue
Block a user