mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-23 05:53:09 +03:00
initial status reordering
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
parent
a29118ac5e
commit
64b5e14208
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,7 @@
|
||||
//
|
||||
|
||||
import type { Class, Doc, Mixin, Ref, Type } from '@anticrm/core'
|
||||
import { coreId } from '@anticrm/core'
|
||||
import core from '@anticrm/model'
|
||||
import core, { coreId } from '@anticrm/core'
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
|
||||
export default mergeIds(coreId, core, {
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { Builder } from '@anticrm/model'
|
||||
import core from './component'
|
||||
import { TAttribute, TClass, TDoc, TMixin, TObj, TType, TTypeString } from './core'
|
||||
import { TSpace, TAccount, TState } from './security'
|
||||
import { TSpace, TAccount, TState, TSpaceWithStates } from './security'
|
||||
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag } from './tx'
|
||||
|
||||
export * from './core'
|
||||
@ -37,6 +37,7 @@ export function createModel (builder: Builder): void {
|
||||
TTxMixin,
|
||||
TTxUpdateDoc,
|
||||
TSpace,
|
||||
TSpaceWithStates,
|
||||
TAccount,
|
||||
TAttribute,
|
||||
TType,
|
||||
|
@ -21,7 +21,7 @@ import { TDoc } from './core'
|
||||
|
||||
export const DOMAIN_STATE = 'state' as Domain
|
||||
|
||||
// S E C U R I T Y
|
||||
// S P A C E
|
||||
|
||||
@Model(core.class.Space, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TSpace extends TDoc implements Space {
|
||||
@ -38,7 +38,11 @@ export class TAccount extends TDoc implements Account {
|
||||
|
||||
@Model(core.class.State, core.class.Doc, DOMAIN_STATE)
|
||||
export class TState extends TDoc implements State {
|
||||
machine!: Ref<Space>
|
||||
title!: string
|
||||
color!: string
|
||||
}
|
||||
|
||||
@Model(core.class.SpaceWithStates, core.class.Space)
|
||||
export class TSpaceWithStates extends TSpace {
|
||||
states!: Arr<Ref<State>>
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { Builder, Model, UX, Prop, TypeString, Bag as TypeBag } from '@anticrm/model'
|
||||
import type { Ref, FindOptions, Doc, Domain, State, Bag } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc } from '@anticrm/model-core'
|
||||
import core, { TSpace, TSpaceWithStates, TDoc } from '@anticrm/model-core'
|
||||
import type { Vacancy, Candidates, Candidate, Applicant } from '@anticrm/recruit'
|
||||
import type { Attachment } from '@anticrm/chunter'
|
||||
|
||||
@ -29,9 +29,9 @@ import chunter from '@anticrm/model-chunter'
|
||||
|
||||
export const DOMAIN_RECRUIT = 'recruit' as Domain
|
||||
|
||||
@Model(recruit.class.Vacancy, core.class.Space)
|
||||
@Model(recruit.class.Vacancy, core.class.SpaceWithStates)
|
||||
@UX(recruit.string.Vacancy, recruit.icon.Vacancy)
|
||||
export class TVacancy extends TSpace implements Vacancy {}
|
||||
export class TVacancy extends TSpaceWithStates implements Vacancy {}
|
||||
|
||||
@Model(recruit.class.Candidates, core.class.Space)
|
||||
@UX(recruit.string.CandidatePools, recruit.icon.RecruitApplication)
|
||||
|
@ -175,7 +175,7 @@ export interface ArrOf<T extends PropertyType> extends Type<T[]> {
|
||||
*/
|
||||
export const DOMAIN_MODEL = 'model' as Domain
|
||||
|
||||
// S E C U R I T Y
|
||||
// S P A C E
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -200,7 +200,13 @@ export interface Account extends Doc {
|
||||
* @public
|
||||
*/
|
||||
export interface State extends Doc {
|
||||
machine: Ref<Space>
|
||||
title: string
|
||||
color: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SpaceWithStates extends Space {
|
||||
states: Arr<Ref<State>>
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
import type { Plugin, StatusCode } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Account, Class, Doc, Obj, Ref, Space, AnyAttribute, State, Type, PropertyType } from './classes'
|
||||
import type { Account, Class, Doc, Obj, Ref, Space, AnyAttribute, State, Type, PropertyType, SpaceWithStates } from './classes'
|
||||
import type { Tx, TxCreateDoc, TxCUD, TxMixin, TxPutBag, TxRemoveDoc, TxUpdateDoc } from './tx'
|
||||
|
||||
/**
|
||||
@ -36,6 +36,7 @@ export default plugin(coreId, {
|
||||
TxRemoveDoc: '' as Ref<Class<TxRemoveDoc<Doc>>>,
|
||||
TxPutBag: '' as Ref<Class<TxPutBag<PropertyType>>>,
|
||||
Space: '' as Ref<Class<Space>>,
|
||||
SpaceWithStates: '' as Ref<Class<SpaceWithStates>>,
|
||||
Account: '' as Ref<Class<Account>>,
|
||||
State: '' as Ref<Class<State>>,
|
||||
TypeString: '' as Ref<Class<Type<string>>>,
|
||||
|
@ -15,6 +15,7 @@
|
||||
//
|
||||
|
||||
import type { Doc, PropertyType } from './classes'
|
||||
import type { Position } from './tx'
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -24,12 +25,25 @@ export type _OperatorFunc = (doc: Doc, op: object) => void
|
||||
function $push (document: Doc, keyval: Record<string, PropertyType>): void {
|
||||
const doc = document as any
|
||||
for (const key in keyval) {
|
||||
const arr = doc[key]
|
||||
if (arr === undefined) {
|
||||
doc[key] = [keyval[key]]
|
||||
} else {
|
||||
arr.push(keyval[key])
|
||||
if (doc[key] === undefined) {
|
||||
doc[key] = []
|
||||
}
|
||||
const val = keyval[key]
|
||||
if (typeof val === 'object') {
|
||||
const arr = doc[key] as Array<any>
|
||||
const desc = val as Position<PropertyType>
|
||||
arr.splice(desc.$position, 0, ...desc.$each)
|
||||
} else {
|
||||
doc[key].push(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function $pull (document: Doc, keyval: Record<string, PropertyType>): void {
|
||||
const doc = document as any
|
||||
for (const key in keyval) {
|
||||
const arr = doc[key] as Array<any>
|
||||
doc[key] = arr.filter(val => val !== keyval[key])
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +65,7 @@ function $pushMixin (document: Doc, options: any): void {
|
||||
|
||||
const operators: Record<string, _OperatorFunc> = {
|
||||
$push,
|
||||
$pull,
|
||||
$pushMixin
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,21 @@ export type ArrayAsElement<T extends Doc> = {
|
||||
[P in keyof T]: T[P] extends Arr<infer X> ? X : never
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Position<X extends PropertyType> {
|
||||
$each: X[]
|
||||
$position: number
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ArrayAsElementPosition<T extends Doc> = {
|
||||
[P in keyof T]: T[P] extends Arr<infer X> ? X | Position<X> : never
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -79,7 +94,8 @@ export type OmitNever<T extends object> = Omit<T, KeysByType<T, never>>
|
||||
* @public
|
||||
*/
|
||||
export interface PushOptions<T extends Doc> {
|
||||
$push?: Partial<OmitNever<ArrayAsElement<T>>>
|
||||
$push?: Partial<OmitNever<ArrayAsElementPosition<T>>>
|
||||
$pull?: Partial<OmitNever<ArrayAsElement<T>>>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
import type { Class, Ref, Obj, Doc } from '@anticrm/core'
|
||||
import { Model, Prop, TypeString, Builder } from '../dsl'
|
||||
import core from '../component'
|
||||
import core from '@anticrm/core'
|
||||
|
||||
function removeIds (txes: Doc[]): void {
|
||||
txes.forEach((i) => {
|
||||
|
@ -1,22 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import core, { coreId } from '@anticrm/core'
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
|
||||
export default mergeIds(coreId, core, {
|
||||
class: {
|
||||
}
|
||||
})
|
@ -29,12 +29,10 @@ import type {
|
||||
Space,
|
||||
ExtendedAttributes
|
||||
} from '@anticrm/core'
|
||||
import { ClassifierKind, IndexKind, generateId, TxFactory } from '@anticrm/core'
|
||||
import core, { ClassifierKind, IndexKind, generateId, TxFactory } from '@anticrm/core'
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import toposort from 'toposort'
|
||||
|
||||
import core from './component'
|
||||
|
||||
type NoIDs<T extends Tx> = Omit<T, '_id' | 'objectId'>
|
||||
|
||||
const targets = new Map<any, Map<string, IndexKind>>()
|
||||
|
@ -14,4 +14,3 @@
|
||||
//
|
||||
|
||||
export * from './dsl'
|
||||
export { default } from './component'
|
||||
|
@ -55,7 +55,7 @@ class LiveQuery {
|
||||
private unsubscribe = () => {}
|
||||
|
||||
constructor() {
|
||||
onDestroy(this.unsubscribe)
|
||||
onDestroy(() => { console.log('onDestroy query'); this.unsubscribe() })
|
||||
}
|
||||
|
||||
query<T extends Doc>(_class: Ref<Class<T>>, query: DocumentQuery<T>, callback: (result: T[]) => void, options?: FindOptions<T>) {
|
||||
|
@ -83,7 +83,10 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
})
|
||||
|
||||
return () => {
|
||||
console.log('queries', this.queries.length)
|
||||
console.log('removing query:', this.queries.indexOf(q))
|
||||
this.queries.splice(this.queries.indexOf(q), 1)
|
||||
console.log('queries', this.queries.length)
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,6 +113,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
}
|
||||
|
||||
protected async txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<void> {
|
||||
console.log(`updating ${this.queries.length} queries`)
|
||||
for (const q of this.queries) {
|
||||
if (q.result instanceof Promise) {
|
||||
q.result = await q.result
|
||||
|
@ -43,23 +43,36 @@
|
||||
name,
|
||||
description,
|
||||
private: false,
|
||||
members: []
|
||||
members: [],
|
||||
states: []
|
||||
})
|
||||
await client.createDoc(core.class.State, id, {
|
||||
machine: id,
|
||||
const s1 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Initial',
|
||||
color: colors[0]
|
||||
})
|
||||
await client.createDoc(core.class.State, id, {
|
||||
machine: id,
|
||||
title: 'Interview',
|
||||
const s2 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Interview 1',
|
||||
color: colors[1]
|
||||
})
|
||||
await client.createDoc(core.class.State, id, {
|
||||
machine: id,
|
||||
title: 'Final',
|
||||
const s3 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Interview 2',
|
||||
color: colors[2]
|
||||
})
|
||||
const s4 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Interview 3',
|
||||
color: colors[3]
|
||||
})
|
||||
const s5 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Interview 4',
|
||||
color: colors[4]
|
||||
})
|
||||
const s6 = await client.createDoc(core.class.State, id, {
|
||||
title: 'Final',
|
||||
color: colors[0]
|
||||
})
|
||||
await client.updateDoc(recruit.class.Vacancy, core.space.Model, id, {
|
||||
states: [s1, s2, s3, s4, s5, s6]
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -15,14 +15,14 @@
|
||||
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Plugin, Asset } from '@anticrm/platform'
|
||||
import type { Space, Doc, Ref, State, Bag } from '@anticrm/core'
|
||||
import type { Space, SpaceWithStates, Doc, Ref, State, Bag } from '@anticrm/core'
|
||||
import type { Person } from '@anticrm/contact'
|
||||
import type { Attachment } from '@anticrm/chunter'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Vacancy extends Space {}
|
||||
export interface Vacancy extends SpaceWithStates {}
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -15,43 +15,103 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Ref, Space, State } from '@anticrm/core'
|
||||
import type { Ref, SpaceWithStates, State } from '@anticrm/core'
|
||||
import { Dialog } from '@anticrm/ui'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
|
||||
import core from '@anticrm/core'
|
||||
|
||||
export let _id: Ref<Space>
|
||||
export let _id: Ref<SpaceWithStates>
|
||||
|
||||
let space: SpaceWithStates | undefined
|
||||
|
||||
let states: State[] = []
|
||||
let elements: HTMLElement[] = []
|
||||
|
||||
const client = getClient()
|
||||
|
||||
function sort(states: State[]): State[] {
|
||||
if (space === undefined || states.length === 0) { return [] }
|
||||
console.log(states)
|
||||
const map = states.reduce((map, state) => { map.set(state._id, state); return map }, new Map<Ref<State>, State>())
|
||||
console.log(space.states)
|
||||
const x = space.states.map(id => map.get(id) as State )
|
||||
// console.log(x)
|
||||
return x
|
||||
}
|
||||
|
||||
const spaceQuery = createQuery()
|
||||
$: spaceQuery.query(core.class.SpaceWithStates, { _id }, result => { space = result[0] })
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(core.class.State, { machine: _id }, result => { states = result })
|
||||
$: query.query(core.class.State, { _id: { $in: space?.states ?? [] } }, result => { states = sort(result) })
|
||||
|
||||
let selected: string | undefined = undefined
|
||||
let selected: number | undefined
|
||||
let dragState: Ref<State>
|
||||
let dragStateInitialPosition: number
|
||||
|
||||
function dragswap(ev: MouseEvent, i: number): boolean {
|
||||
let s = selected as number
|
||||
if (i < s) {
|
||||
return ev.offsetY < elements[i].offsetHeight / 2
|
||||
} else if (i > s) {
|
||||
return ev.offsetY > elements[i].offsetHeight / 2
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function dragover(ev: MouseEvent, i: number) {
|
||||
let s = selected as number
|
||||
if (dragswap(ev, i)) {
|
||||
const dragover = states[i]
|
||||
const dragging = states[s]
|
||||
states[i] = dragging
|
||||
states[s] = dragover
|
||||
selected = i
|
||||
}
|
||||
}
|
||||
|
||||
async function move(to: number) {
|
||||
await client.updateDoc(core.class.SpaceWithStates, core.space.Model, _id, {
|
||||
$pull: {
|
||||
states: dragState
|
||||
}
|
||||
})
|
||||
await client.updateDoc(core.class.SpaceWithStates, core.space.Model, _id, {
|
||||
$push: {
|
||||
states: {
|
||||
$each: [dragState],
|
||||
$position: to < dragStateInitialPosition ? to : to
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<Dialog label="Edit Statuses">
|
||||
{#each states as state}
|
||||
<div class="flex-center states" style="background-color: {state.color}" draggable={true}
|
||||
on:dragover|preventDefault={() => {
|
||||
console.log(`Dragging ${selected} over ${state._id} (${state.title})`)
|
||||
{#each states as state, i}
|
||||
{#if state}
|
||||
<div bind:this={elements[i]} class="flex-center states" style="background-color: {state.color}; height: 60px" draggable={true}
|
||||
on:dragover|preventDefault={(ev) => {
|
||||
dragover(ev, i)
|
||||
}}
|
||||
on:drop|preventDefault={() => {
|
||||
console.log(`Drop ${selected} into ${state._id} (${state.title})`)
|
||||
console.log('DROP')
|
||||
move(i)
|
||||
}}
|
||||
on:dragstart={() => {
|
||||
selected = state._id
|
||||
console.log('Start dragging: ' + selected)
|
||||
dragStateInitialPosition = selected = i
|
||||
dragState = states[i]._id
|
||||
}}
|
||||
on:dragend={() => {
|
||||
console.log('End dragging: ' + selected)
|
||||
console.log('DRAGEND')
|
||||
selected = undefined
|
||||
}}
|
||||
>
|
||||
{state.title}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</Dialog>
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user