mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-21 00:57:56 +02:00
Merge remote-tracking branch 'origin/develop' into staging-new
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
VERSION=${VERSION:-"latest"}
|
||||
|
||||
docker build -t hardcoreeng/base:${VERSION} -f base.Dockerfile ${DOCKER_EXTRA} .
|
||||
docker build -t hardcoreeng/base-slim:${VERSION} -f slim.Dockerfile ${DOCKER_EXTRA} .
|
||||
docker build -t hardcoreeng/rekoni-base:${VERSION} -f rekoni.Dockerfile ${DOCKER_EXTRA} .
|
||||
docker build -t hardcoreeng/print-base:${VERSION} -f print.Dockerfile ${DOCKER_EXTRA} .
|
||||
docker build -t hardcoreeng/front-base:${VERSION} -f front.Dockerfile ${DOCKER_EXTRA} .
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
VERSION=${VERSION:-"latest"}
|
||||
|
||||
docker push hardcoreeng/base:${VERSION}
|
||||
docker push hardcoreeng/base-slim:${VERSION}
|
||||
docker push hardcoreeng/rekoni-base:${VERSION}
|
||||
docker push hardcoreeng/print-base:${VERSION}
|
||||
docker push hardcoreeng/front-base:${VERSION}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM node:22-slim
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install libjemalloc2 dumb-init
|
||||
RUN apt-get clean
|
||||
|
||||
ENV LD_PRELOAD=libjemalloc.so.2
|
||||
ENV MALLOC_CONF=dirty_decay_ms:1000,narenas:2,background_thread:true
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
ENV NODE_ENV=production
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"@hcengineering/time": "^0.6.0",
|
||||
"@hcengineering/setting": "^0.6.17",
|
||||
"@hcengineering/model-time": "^0.6.0",
|
||||
"@hcengineering/rank": "^0.6.4",
|
||||
"@hcengineering/process": "^0.6.0",
|
||||
"@hcengineering/process-resources": "^0.6.0",
|
||||
"@hcengineering/model-presentation": "^0.6.0",
|
||||
|
||||
@@ -19,6 +19,7 @@ import core, {
|
||||
DOMAIN_MODEL,
|
||||
type Doc,
|
||||
type Domain,
|
||||
type Rank,
|
||||
type Ref,
|
||||
SortingOrder,
|
||||
type Space,
|
||||
@@ -26,11 +27,13 @@ import core, {
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
type Builder,
|
||||
Hidden,
|
||||
Model,
|
||||
Prop,
|
||||
ReadOnly,
|
||||
TypeAny,
|
||||
TypeBoolean,
|
||||
TypeRank,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
UX
|
||||
@@ -134,6 +137,10 @@ export class TTransition extends TDoc implements Transition {
|
||||
triggerParams!: Record<string, any>
|
||||
|
||||
result?: TriggerResult | null
|
||||
|
||||
@Prop(TypeRank(), core.string.Rank)
|
||||
@Hidden()
|
||||
rank!: Rank
|
||||
}
|
||||
|
||||
@Model(process.class.ExecutionLog, core.class.Doc, DOMAIN_PROCESS_LOG)
|
||||
@@ -213,8 +220,16 @@ export class TMethod extends TDoc implements Method<Doc> {
|
||||
|
||||
@Model(process.class.State, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TState extends TDoc implements State {
|
||||
process!: Ref<Process>
|
||||
title!: string
|
||||
@Prop(TypeRef(process.class.Process), process.string.Process)
|
||||
@ReadOnly()
|
||||
process!: Ref<Process>
|
||||
|
||||
@Prop(TypeString(), core.string.Name)
|
||||
title!: string
|
||||
|
||||
@Prop(TypeRank(), core.string.Rank)
|
||||
@Hidden()
|
||||
rank!: Rank
|
||||
}
|
||||
|
||||
@Model(process.class.ProcessFunction, core.class.Doc, DOMAIN_MODEL)
|
||||
@@ -1086,7 +1101,8 @@ export function createModel (builder: Builder): void {
|
||||
presenter: process.component.ToDoSettingPresenter,
|
||||
requiredParams: ['_id'],
|
||||
checkFunction: process.triggerCheck.ToDo,
|
||||
init: false
|
||||
init: false,
|
||||
auto: true
|
||||
},
|
||||
process.trigger.OnToDoClose
|
||||
)
|
||||
@@ -1101,7 +1117,8 @@ export function createModel (builder: Builder): void {
|
||||
presenter: process.component.ToDoSettingPresenter,
|
||||
requiredParams: ['_id'],
|
||||
checkFunction: process.triggerCheck.ToDo,
|
||||
init: false
|
||||
init: false,
|
||||
auto: true
|
||||
},
|
||||
process.trigger.OnToDoRemove
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { type Client, type Doc, TxOperations } from '@hcengineering/core'
|
||||
import core, { type Client, type Doc, type Rank, TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
tryUpgrade
|
||||
} from '@hcengineering/model'
|
||||
import process, { type State, type Step } from '@hcengineering/process'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
import { processId } from '.'
|
||||
|
||||
export const processOperation: MigrateOperation = {
|
||||
@@ -31,6 +32,11 @@ export const processOperation: MigrateOperation = {
|
||||
state: 'migrateActionsFromStates',
|
||||
mode: 'upgrade',
|
||||
func: migrateActionsFromStates
|
||||
},
|
||||
{
|
||||
state: 'fillStatesRanks',
|
||||
mode: 'upgrade',
|
||||
func: fillStatesRanks
|
||||
}
|
||||
])
|
||||
}
|
||||
@@ -40,6 +46,23 @@ interface OldState extends State {
|
||||
actions: Step<Doc>[]
|
||||
}
|
||||
|
||||
async function fillStatesRanks (client: Client): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const states = await client.findAll(process.class.State, { rank: { $exists: false } })
|
||||
let prevRank: Rank | undefined
|
||||
for (const state of states) {
|
||||
prevRank = makeRank(prevRank, undefined)
|
||||
await txOp.update(state, { rank: prevRank })
|
||||
}
|
||||
|
||||
const transitions = await client.findAll(process.class.Transition, { rank: { $exists: false } })
|
||||
prevRank = undefined
|
||||
for (const transition of transitions) {
|
||||
prevRank = makeRank(prevRank, undefined)
|
||||
await txOp.update(transition, { rank: prevRank })
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateActionsFromStates (client: Client): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const rollbackTransitions = await client.findAll(process.class.Transition, { to: null as any })
|
||||
@@ -54,10 +77,12 @@ async function migrateActionsFromStates (client: Client): Promise<void> {
|
||||
arr.push(transition)
|
||||
transitionsMap.set(transition.to, arr)
|
||||
}
|
||||
let prevRank: Rank | undefined
|
||||
for (const state of states) {
|
||||
if (state.actions?.length > 0) {
|
||||
const transitions = transitionsMap.get(state._id) ?? []
|
||||
if (transitions.length === 0) {
|
||||
prevRank = makeRank(prevRank, undefined)
|
||||
await txOp.createDoc(
|
||||
process.class.Transition,
|
||||
core.space.Model,
|
||||
@@ -65,6 +90,7 @@ async function migrateActionsFromStates (client: Client): Promise<void> {
|
||||
from: null,
|
||||
to: state._id,
|
||||
actions: state.actions,
|
||||
rank: prevRank,
|
||||
trigger: process.trigger.OnExecutionStart,
|
||||
triggerParams: {},
|
||||
process: state.process
|
||||
|
||||
@@ -51,12 +51,12 @@ export function createModel (builder: Builder): void {
|
||||
builder.createModel(TMethodImpl, TFuncImpl, TTriggerImpl)
|
||||
|
||||
builder.mixin(process.trigger.OnToDoClose, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
serverCheckFunc: serverProcess.func.CheckToDo,
|
||||
serverCheckFunc: serverProcess.func.CheckToDoDone,
|
||||
rollbackFunc: serverProcess.rollbacks.ToDoCloseRollback
|
||||
})
|
||||
|
||||
builder.mixin(process.trigger.OnToDoRemove, process.class.Trigger, serverProcess.mixin.TriggerImpl, {
|
||||
serverCheckFunc: serverProcess.func.CheckToDo,
|
||||
serverCheckFunc: serverProcess.func.CheckToDoCancelled,
|
||||
rollbackFunc: serverProcess.rollbacks.ToDoCancellRollback
|
||||
})
|
||||
|
||||
|
||||
@@ -261,6 +261,10 @@ export class HulypulseClient implements Disposable {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.data === 'pong') {
|
||||
return
|
||||
}
|
||||
|
||||
const msg: PulseIncomingMessage = JSON.parse(event.data.toString())
|
||||
|
||||
// Handle incoming messages (Set, Expired, Del)
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
kind={'regular'}
|
||||
size={'small'}
|
||||
label={document.string.NoParentDocument}
|
||||
searchField={'name'}
|
||||
searchField={'title'}
|
||||
allowDeselect={true}
|
||||
showNavigate={false}
|
||||
docProps={{ disabled: true, noUnderline: true }}
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
docQuery={{ space }}
|
||||
kind={'regular'}
|
||||
size={'small'}
|
||||
searchField={'name'}
|
||||
searchField={'title'}
|
||||
allowDeselect={true}
|
||||
showNavigate={false}
|
||||
docProps={{ disabled: true, noUnderline: true }}
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
kind={'regular'}
|
||||
size={'small'}
|
||||
label={drive.string.Root}
|
||||
searchField={'name'}
|
||||
searchField={'title'}
|
||||
allowDeselect
|
||||
showNavigate={false}
|
||||
docProps={{ disabled: true, noUnderline: true }}
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
docQuery={{ space }}
|
||||
kind={'regular'}
|
||||
size={'small'}
|
||||
searchField={'name'}
|
||||
searchField={'title'}
|
||||
allowDeselect={true}
|
||||
showNavigate={false}
|
||||
docProps={{ disabled: true, noUnderline: true }}
|
||||
|
||||
@@ -717,10 +717,12 @@ async function checkRecordAvailable (): Promise<void> {
|
||||
setTimeout(() => {
|
||||
void checkRecordAvailable()
|
||||
}, 500)
|
||||
} else {
|
||||
} else if (endpoint !== '') {
|
||||
const res = await fetch(concatLink(endpoint, '/checkRecordAvailable'))
|
||||
const result = await res.json()
|
||||
isRecordingAvailable.set(result)
|
||||
} else {
|
||||
console.info('office recording is not configured')
|
||||
}
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import { Process, State } from '@hcengineering/process'
|
||||
import { ButtonIcon, getCurrentLocation, Icon, IconAdd, Label, navigate } from '@hcengineering/ui'
|
||||
import process from '../plugin'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
|
||||
export let masterTag: MasterTag
|
||||
|
||||
@@ -38,6 +39,7 @@
|
||||
core.space.Model,
|
||||
{
|
||||
process: id,
|
||||
rank: makeRank(undefined, undefined),
|
||||
title: await translate(process.string.NewState, {})
|
||||
},
|
||||
initState
|
||||
@@ -47,6 +49,7 @@
|
||||
from: null,
|
||||
to: initState,
|
||||
trigger: process.trigger.OnExecutionStart,
|
||||
rank: makeRank(undefined, undefined),
|
||||
actions: [],
|
||||
triggerParams: {}
|
||||
})
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Ref } from '@hcengineering/core'
|
||||
import core, { Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Process, State, Trigger, TriggerResult } from '@hcengineering/process'
|
||||
import { Process, State, Transition, Trigger, TriggerResult } from '@hcengineering/process'
|
||||
import { Component, Dropdown, DropdownIntlItem, DropdownLabelsIntl, Label, ListItem } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
|
||||
export let process: Process
|
||||
|
||||
@@ -28,9 +29,16 @@
|
||||
let result: TriggerResult | null = null
|
||||
|
||||
const query = createQuery()
|
||||
query.query(plugin.class.State, { process: process._id }, (res) => {
|
||||
states = res
|
||||
})
|
||||
query.query(
|
||||
plugin.class.State,
|
||||
{ process: process._id },
|
||||
(res) => {
|
||||
states = res
|
||||
},
|
||||
{
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
|
||||
let statesItems: ListItem[] = []
|
||||
|
||||
@@ -55,18 +63,39 @@
|
||||
|
||||
let params: Record<string, any> = {}
|
||||
|
||||
const transitionsQ = createQuery()
|
||||
|
||||
let transitions: Transition[] = []
|
||||
|
||||
transitionsQ.query(
|
||||
plugin.class.Transition,
|
||||
{ process: process._id },
|
||||
(res) => {
|
||||
transitions = res
|
||||
},
|
||||
{
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
|
||||
const triggersItems: DropdownIntlItem[] = triggers.map((p) => ({ label: p.label, id: p._id, icon: p.icon }))
|
||||
|
||||
async function save (): Promise<void> {
|
||||
if (to === undefined || trigger === undefined) {
|
||||
return
|
||||
}
|
||||
const prevTransitions =
|
||||
transitions.findLast((p) => p.from === from) ?? transitions.length > 0
|
||||
? transitions[transitions.length - 1]
|
||||
: undefined
|
||||
const rank = makeRank(prevTransitions?.rank, undefined)
|
||||
await client.createDoc(plugin.class.Transition, core.space.Model, {
|
||||
from,
|
||||
to,
|
||||
trigger,
|
||||
triggerParams: params,
|
||||
process: process._id,
|
||||
rank,
|
||||
result,
|
||||
actions: []
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { Process, State, Transition } from '@hcengineering/process'
|
||||
import { clearSettingsStore, settingsStore } from '@hcengineering/setting-resources'
|
||||
@@ -68,13 +68,27 @@
|
||||
}
|
||||
})
|
||||
|
||||
$: statesQuery.query(process.class.State, { process: _id }, (res) => {
|
||||
states = res
|
||||
})
|
||||
$: statesQuery.query(
|
||||
process.class.State,
|
||||
{ process: _id },
|
||||
(res) => {
|
||||
states = res
|
||||
},
|
||||
{
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
|
||||
$: transitionsQ.query(process.class.Transition, { process: _id }, (res) => {
|
||||
transitions = res
|
||||
})
|
||||
$: transitionsQ.query(
|
||||
process.class.Transition,
|
||||
{ process: _id },
|
||||
(res) => {
|
||||
transitions = res
|
||||
},
|
||||
{
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
|
||||
async function saveName (): Promise<void> {
|
||||
if (value !== undefined) {
|
||||
@@ -151,7 +165,7 @@
|
||||
</div>
|
||||
<div class="hulyComponent-content flex-col-center flex-gap-4">
|
||||
<StatesInlineEditor {states} {readonly} process={value} />
|
||||
<TransitionsInlineEditor {transitions} {readonly} process={value} />
|
||||
<TransitionsInlineEditor {readonly} process={value} />
|
||||
</div>
|
||||
</div>
|
||||
</Scroller>
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core from '@hcengineering/core'
|
||||
import core, { Doc } from '@hcengineering/core'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Process, State } from '@hcengineering/process'
|
||||
import { Button, IconAdd, Label } from '@hcengineering/ui'
|
||||
import plugin from '../../plugin'
|
||||
import StateInlineEditor from './StateInlineEditor.svelte'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
import { SortableList } from '@hcengineering/view-resources'
|
||||
|
||||
export let process: Process
|
||||
export let states: State[]
|
||||
@@ -28,11 +30,17 @@
|
||||
const client = getClient()
|
||||
|
||||
async function addState (): Promise<void> {
|
||||
const rank = makeRank(states.length > 0 ? states[states.length - 1].rank : undefined, undefined)
|
||||
await client.createDoc(plugin.class.State, core.space.Model, {
|
||||
process: process._id,
|
||||
title: await translate(plugin.string.NewState, {})
|
||||
title: await translate(plugin.string.NewState, {}),
|
||||
rank
|
||||
})
|
||||
}
|
||||
|
||||
function toState (doc: Doc): State {
|
||||
return doc as State
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
@@ -41,9 +49,11 @@
|
||||
<div class="header w-full p-4">
|
||||
<Label label={plugin.string.States} />
|
||||
</div>
|
||||
{#each states as state (state._id)}
|
||||
<StateInlineEditor value={state} />
|
||||
{/each}
|
||||
<SortableList _class={plugin.class.State} query={{ process: process._id }} isAddButtonHidden>
|
||||
<svelte:fragment slot="object" let:value>
|
||||
<StateInlineEditor value={toState(value)} />
|
||||
</svelte:fragment>
|
||||
</SortableList>
|
||||
{#if !readonly}
|
||||
<Button kind={'ghost'} width={'100%'} icon={IconAdd} label={plugin.string.AddState} on:click={addState} />
|
||||
{/if}
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import { Process, Transition } from '@hcengineering/process'
|
||||
import { Button, getCurrentLocation, IconAdd, Label, navigate, showPopup } from '@hcengineering/ui'
|
||||
import plugin from '../../plugin'
|
||||
import AddTransitionPopup from './AddTransitionPopup.svelte'
|
||||
import TransitionPresenter from './TransitionPresenter.svelte'
|
||||
import TriggerPresenter from './TriggerPresenter.svelte'
|
||||
import { SortableList } from '@hcengineering/view-resources'
|
||||
|
||||
export let process: Process
|
||||
export let transitions: Transition[]
|
||||
export let readonly: boolean
|
||||
|
||||
function addTransition (): void {
|
||||
@@ -35,6 +35,10 @@
|
||||
loc.path[6] = id
|
||||
navigate(loc, true)
|
||||
}
|
||||
|
||||
function toTransition (doc: Doc): Transition {
|
||||
return doc as Transition
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
@@ -43,23 +47,26 @@
|
||||
<div class="header w-full p-4">
|
||||
<Label label={plugin.string.Transitions} />
|
||||
</div>
|
||||
{#each transitions as transition (transition._id)}
|
||||
<Button
|
||||
width={'100%'}
|
||||
kind={'ghost'}
|
||||
justify={'left'}
|
||||
on:click={() => {
|
||||
handleSelect(transition._id)
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="flex-row-center flex-gap-4">
|
||||
<TransitionPresenter {transition} />
|
||||
<TriggerPresenter value={transition.trigger} {process} params={transition.triggerParams} withLabel={true} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
{/each}
|
||||
<SortableList _class={plugin.class.Transition} query={{ process: process._id }} isAddButtonHidden>
|
||||
<svelte:fragment slot="object" let:value>
|
||||
{@const transition = toTransition(value)}
|
||||
<Button
|
||||
width={'100%'}
|
||||
kind={'ghost'}
|
||||
justify={'left'}
|
||||
on:click={() => {
|
||||
handleSelect(transition._id)
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="flex-row-center flex-gap-4">
|
||||
<TransitionPresenter {transition} />
|
||||
<TriggerPresenter value={transition.trigger} {process} params={transition.triggerParams} withLabel={true} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
</SortableList>
|
||||
{#if !readonly}
|
||||
<Button kind={'ghost'} width={'100%'} icon={IconAdd} label={plugin.string.AddTransition} on:click={addTransition} />
|
||||
{/if}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Card, MasterTag, Tag } from '@hcengineering/card'
|
||||
import { Association, Class, Client, Doc, DocumentUpdate, ObjQueryType, Ref, Tx, Type } from '@hcengineering/core'
|
||||
import { Association, Class, Client, Doc, DocumentUpdate, ObjQueryType, Rank, Ref, Tx, Type } from '@hcengineering/core'
|
||||
import { Asset, IntlString, Plugin, plugin, Resource } from '@hcengineering/platform'
|
||||
import { ToDo } from '@hcengineering/time'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
@@ -67,6 +67,7 @@ export interface Transition extends Doc {
|
||||
trigger: Ref<Trigger>
|
||||
triggerParams: Record<string, any>
|
||||
result?: TriggerResult | null
|
||||
rank: Rank
|
||||
}
|
||||
|
||||
export interface ExecutionLog extends Doc {
|
||||
@@ -131,6 +132,7 @@ Record<string, any>
|
||||
export interface State extends Doc {
|
||||
process: Ref<Process>
|
||||
title: string
|
||||
rank: Rank
|
||||
}
|
||||
|
||||
export type StepId = string & { __stepId: true }
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<script lang="ts">
|
||||
import contact, { Employee, formatName } from '@hcengineering/contact'
|
||||
import { EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { Account, AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Breadcrumb, DropdownIntlItem, DropdownLabelsIntl, SearchInput, Header, Scroller } from '@hcengineering/ui'
|
||||
import { Breadcrumb, DropdownIntlItem, DropdownLabelsIntl, Header, Scroller, SearchInput } from '@hcengineering/ui'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
import { getAccountClient } from '../utils'
|
||||
import setting from '../plugin'
|
||||
import { getAccountClient } from '../utils'
|
||||
|
||||
const query = createQuery()
|
||||
const currentAccount = getCurrentAccount()
|
||||
@@ -70,6 +70,10 @@
|
||||
$: ownersCount = employees.filter(
|
||||
(e) => e.personUuid != null && workspaceMembers[e.personUuid] === AccountRole.Owner
|
||||
).length
|
||||
|
||||
function getItems (role: AccountRole, currentAccount: Account): DropdownIntlItem[] {
|
||||
return items.filter((i) => i.id === role || hasAccountRole(currentAccount, i.id as AccountRole))
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyComponent">
|
||||
@@ -92,10 +96,12 @@
|
||||
</div>
|
||||
<DropdownLabelsIntl
|
||||
label={setting.string.Role}
|
||||
disabled={!hasAccountRole(currentAccount, role) || (role === AccountRole.Owner && ownersCount === 1)}
|
||||
disabled={!hasAccountRole(currentAccount, role) ||
|
||||
(role === AccountRole.Owner && ownersCount === 1) ||
|
||||
currentAccount.uuid === personUuid}
|
||||
kind={'primary'}
|
||||
size={'medium'}
|
||||
{items}
|
||||
items={getItems(role, currentAccount)}
|
||||
selected={role}
|
||||
on:selected={(e) => {
|
||||
void change(personUuid, e.detail)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { AttachedData, FindOptions, type Rank, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import core, { AttachedData, Doc, FindOptions, type Rank, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { ObjectPopup, getClient } from '@hcengineering/presentation'
|
||||
import { makeRank } from '@hcengineering/task'
|
||||
import { Issue, IssueDraft } from '@hcengineering/tracker'
|
||||
@@ -65,7 +65,32 @@
|
||||
}
|
||||
|
||||
$: selected = !Array.isArray(value) ? ('attachedTo' in value ? value.attachedTo : undefined) : undefined
|
||||
$: ignoreObjects = !Array.isArray(value) ? ('_id' in value ? [value._id] : []) : undefined
|
||||
$: ignoreObjects = getIgnoreObjects(value)
|
||||
|
||||
function getIgnoreObjects (issues: Issue | AttachedData<Issue> | Issue[] | IssueDraft): Ref<Issue>[] {
|
||||
if (!Array.isArray(issues)) {
|
||||
const own = '_id' in issues ? issues._id : undefined
|
||||
const childs = 'childInfo' in issues ? issues.childInfo.map((c) => c.childId) : []
|
||||
return own !== undefined ? [own, ...childs] : childs
|
||||
} else {
|
||||
const res = new Set<Ref<Issue>>()
|
||||
for (const issue of issues) {
|
||||
const own = '_id' in issue ? issue._id : undefined
|
||||
const childs = 'childInfo' in issue ? issue.childInfo.map((c) => c.childId) : []
|
||||
if (own !== undefined) {
|
||||
res.add(own)
|
||||
for (const child of childs) {
|
||||
res.add(child)
|
||||
}
|
||||
} else {
|
||||
for (const child of childs) {
|
||||
res.add(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...res]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<ObjectPopup
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
let presenter: typeof SvelteComponent | undefined
|
||||
let objectFactory: ObjectFactory | undefined
|
||||
let items: FindResult<Doc> | undefined
|
||||
let items: Doc[] = []
|
||||
|
||||
let draggingIndex: number | null = null
|
||||
let hoveringIndex: number | null = null
|
||||
@@ -163,9 +163,13 @@
|
||||
$: isLoading = isPresenterLoading || areItemsloading
|
||||
$: isSortable = hierarchy.getAllAttributes(_class).has('rank')
|
||||
$: itemsCount = items?.length ?? 0
|
||||
|
||||
$: isVertical = direction === 'column'
|
||||
|
||||
$: isDraggable = isSortable && items.length > 1 && !areItemsSorting
|
||||
</script>
|
||||
|
||||
<div class="flex-col">
|
||||
<div class="flex-col" class:w-full={isVertical}>
|
||||
{#if label || !isAddButtonHidden}
|
||||
<div class="flex mb-4">
|
||||
{#if icon}
|
||||
@@ -199,10 +203,8 @@
|
||||
{#if isLoading}
|
||||
<Loading />
|
||||
{:else if ($$slots.object ?? presenter) && items}
|
||||
{@const isVertical = direction === 'column'}
|
||||
<div class="flex-gap-1" class:flex-col={isVertical} class:flex={!isVertical} class:flex-wrap={!isVertical}>
|
||||
{#each items as item, index (item._id)}
|
||||
{@const isDraggable = isSortable && items.length > 1 && !areItemsSorting}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="item"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/front-base:v20250310
|
||||
FROM hardcoreeng/front-base:v20250902
|
||||
WORKDIR /app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/model.json ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -27,15 +27,36 @@ import process, {
|
||||
import { ExecuteResult, ProcessControl } from '@hcengineering/server-process'
|
||||
import time, { ToDoPriority } from '@hcengineering/time'
|
||||
|
||||
export function CheckToDo (
|
||||
export async function CheckToDoDone (
|
||||
control: ProcessControl,
|
||||
execution: Execution,
|
||||
params: Record<string, any>,
|
||||
context: Record<string, any>
|
||||
): boolean {
|
||||
): Promise<boolean> {
|
||||
if (params._id === undefined) return false
|
||||
if (context.todo === undefined) return false
|
||||
return context.todo._id === params._id
|
||||
if (context.todo !== undefined) {
|
||||
return context.todo._id === params._id
|
||||
} else {
|
||||
const todo = await control.client.findOne(process.class.ProcessToDo, { _id: params._id })
|
||||
if (todo === undefined) return false
|
||||
return todo.doneOn !== null
|
||||
}
|
||||
}
|
||||
|
||||
export async function CheckToDoCancelled (
|
||||
control: ProcessControl,
|
||||
execution: Execution,
|
||||
params: Record<string, any>,
|
||||
context: Record<string, any>
|
||||
): Promise<boolean> {
|
||||
if (params._id === undefined) return false
|
||||
if (context.todo !== undefined) {
|
||||
return context.todo._id === params._id
|
||||
} else {
|
||||
const todo = await control.client.findOne(process.class.ProcessToDo, { _id: params._id })
|
||||
if (todo === undefined) return false
|
||||
return todo.doneOn === null
|
||||
}
|
||||
}
|
||||
|
||||
export async function CheckSubProcessesDone (control: ProcessControl, execution: Execution): Promise<boolean> {
|
||||
|
||||
@@ -78,7 +78,8 @@ import {
|
||||
CreateCard,
|
||||
AddRelation,
|
||||
AddTag,
|
||||
CheckToDo,
|
||||
CheckToDoDone,
|
||||
CheckToDoCancelled,
|
||||
OnCardUpdateCheck,
|
||||
CheckSubProcessesDone,
|
||||
CheckTime
|
||||
@@ -355,7 +356,8 @@ export default async () => ({
|
||||
CreateCard,
|
||||
AddRelation,
|
||||
AddTag,
|
||||
CheckToDo,
|
||||
CheckToDoDone,
|
||||
CheckToDoCancelled,
|
||||
OnCardUpdateCheck,
|
||||
CheckSubProcessesDone,
|
||||
CheckTime
|
||||
|
||||
@@ -54,7 +54,8 @@ export default plugin(serverProcessId, {
|
||||
AddRelation: '' as Resource<ExecuteFunc>,
|
||||
WaitSubProcess: '' as Resource<ExecuteFunc>,
|
||||
AddTag: '' as Resource<ExecuteFunc>,
|
||||
CheckToDo: '' as Resource<CheckFunc>,
|
||||
CheckToDoDone: '' as Resource<CheckFunc>,
|
||||
CheckToDoCancelled: '' as Resource<CheckFunc>,
|
||||
OnCardUpdateCheck: '' as Resource<CheckFunc>,
|
||||
CheckSubProcessesDone: '' as Resource<CheckFunc>,
|
||||
CheckTime: '' as Resource<CheckFunc>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
EXPOSE 3078
|
||||
CMD [ "node", "bundle.js" ]
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN npm install -g pnpm
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/front-base:v20250310
|
||||
FROM hardcoreeng/front-base:v20250902
|
||||
WORKDIR /app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/front-base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/front-base:v20250310
|
||||
FROM hardcoreeng/front-base:v20250902
|
||||
WORKDIR /app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/print-base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -20,6 +20,7 @@ import core, {
|
||||
getDiffUpdate,
|
||||
MeasureContext,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
Tx,
|
||||
TxProcessor,
|
||||
TxUpdateDoc,
|
||||
@@ -134,10 +135,14 @@ async function findTransitions (
|
||||
execution: Execution
|
||||
): Promise<Transition | undefined> {
|
||||
if (record.event === process.trigger.OnExecutionStart) {
|
||||
const transitions = control.client.getModel().findAllSync(process.class.Transition, {
|
||||
process: execution.process,
|
||||
trigger: record.event
|
||||
})
|
||||
const transitions = control.client.getModel().findAllSync(
|
||||
process.class.Transition,
|
||||
{
|
||||
process: execution.process,
|
||||
trigger: record.event
|
||||
},
|
||||
{ sort: { rank: SortingOrder.Ascending } }
|
||||
)
|
||||
return await pickTransition(control, execution, transitions, record.context)
|
||||
}
|
||||
if (record.event === process.trigger.OnExecutionContinue) {
|
||||
@@ -487,11 +492,17 @@ async function checkParent (execution: Execution, control: ProcessControl): Prom
|
||||
const _process = control.client.getModel().findObject(parent.process)
|
||||
if (_process === undefined) return
|
||||
if (parent.status !== ExecutionStatus.Active) return
|
||||
const transitions = control.client.getModel().findAllSync(process.class.Transition, {
|
||||
from: parent.currentState,
|
||||
process: parent.process,
|
||||
trigger: process.trigger.OnSubProcessesDone
|
||||
})
|
||||
const transitions = control.client.getModel().findAllSync(
|
||||
process.class.Transition,
|
||||
{
|
||||
from: parent.currentState,
|
||||
process: parent.process,
|
||||
trigger: process.trigger.OnSubProcessesDone
|
||||
},
|
||||
{
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
const transition = await pickTransition(control, execution, transitions, {})
|
||||
if (transition === undefined) return
|
||||
await executeTransition(parent, transition, control)
|
||||
@@ -499,11 +510,15 @@ async function checkParent (execution: Execution, control: ProcessControl): Prom
|
||||
|
||||
async function checkNext (control: ProcessControl, execution: Execution): Promise<boolean> {
|
||||
const autoTriggers = control.client.getModel().findAllSync(process.class.Trigger, { auto: true })
|
||||
const transitions = control.client.getModel().findAllSync(process.class.Transition, {
|
||||
from: execution.currentState,
|
||||
process: execution.process,
|
||||
trigger: { $in: autoTriggers.map((it) => it._id) }
|
||||
})
|
||||
const transitions = control.client.getModel().findAllSync(
|
||||
process.class.Transition,
|
||||
{
|
||||
from: execution.currentState,
|
||||
process: execution.process,
|
||||
trigger: { $in: autoTriggers.map((it) => it._id) }
|
||||
},
|
||||
{ sort: { rank: SortingOrder.Ascending } }
|
||||
)
|
||||
if (transitions.length > 0) {
|
||||
const doc = await control.client.findOne(cardPlugin.class.Card, { _id: execution.card })
|
||||
if (doc !== undefined) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM hardcoreeng/base:v20250310
|
||||
FROM hardcoreeng/base:v20250902
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle/bundle.js ./
|
||||
|
||||
Reference in New Issue
Block a user