mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-30 13:35:04 +02:00
Process notifications (#9501)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -122,6 +122,12 @@ export class TExecutionLog extends TDoc implements ExecutionLog {
|
||||
@Prop(TypeRef(process.class.Execution), process.string.Execution)
|
||||
execution!: Ref<Execution>
|
||||
|
||||
@Prop(TypeRef(process.class.Process), process.string.Process)
|
||||
process!: Ref<Process>
|
||||
|
||||
@Prop(TypeRef(card.class.Card), card.string.Card)
|
||||
card!: Ref<Card>
|
||||
|
||||
@Prop(TypeRef(process.class.Transition), process.string.Transition)
|
||||
transition?: Ref<Transition>
|
||||
|
||||
@@ -925,6 +931,11 @@ export function createModel (builder: Builder): void {
|
||||
label: process.string.Processes,
|
||||
component: process.component.ProcessesSettingSection
|
||||
})
|
||||
|
||||
builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, {
|
||||
extension: workbench.extensions.WorkbenchExtensions,
|
||||
component: process.component.NotifierExtension
|
||||
})
|
||||
}
|
||||
|
||||
export { processId } from '@hcengineering/process'
|
||||
|
||||
@@ -71,6 +71,7 @@ export { default as CardSelector } from './components/CardSelector.svelte'
|
||||
export { default as CardIcon } from './components/CardIcon.svelte'
|
||||
export { default as Navigator } from './components/navigator-next/Navigator.svelte'
|
||||
export { default as Favorites } from './components/Favorites.svelte'
|
||||
export { default as CardPresenter } from './components/CardPresenter.svelte'
|
||||
|
||||
export * from './types'
|
||||
export { getCardIconInfo } from './utils'
|
||||
|
||||
@@ -21,4 +21,9 @@
|
||||
<path d="M16 2.00012C8.2 2.00012 2 8.20012 2 16.0001C2 23.8001 8.2 30.0001 16 30.0001C23.8 30.0001 30 23.8001 30 16.0001C30 8.20012 23.8 2.00012 16 2.00012ZM16 28.0001C9.4 28.0001 4 22.6001 4 16.0001C4 9.40012 9.4 4.00012 16 4.00012C22.6 4.00012 28 9.40012 28 16.0001C28 22.6001 22.6 28.0001 16 28.0001Z" />
|
||||
<path d="M9.29289 9.29326C8.90237 9.68378 8.90237 10.3169 9.29289 10.7075L14.5858 16.0004L9.29289 21.2933C8.90237 21.6838 8.90237 22.3169 9.29289 22.7075C9.68342 23.098 10.3166 23.098 10.7071 22.7075L16 17.4146L21.2929 22.7075C21.6834 23.098 22.3166 23.098 22.7071 22.7075C23.0976 22.3169 23.0976 21.6838 22.7071 21.2933L17.4142 16.0004L22.7071 10.7075C23.0976 10.3169 23.0976 9.68378 22.7071 9.29326C22.3166 8.90274 21.6834 8.90274 21.2929 9.29326L16 14.5862L10.7071 9.29326C10.3166 8.90274 9.68342 8.90274 9.29289 9.29326Z" />
|
||||
</symbol>
|
||||
<symbol id="start" viewBox="0 0 32 32">
|
||||
<path
|
||||
d="M27.71 4.29049C27.575 4.15616 27.4045 4.06316 27.2185 4.02241C27.0325 3.98167 26.8388 3.99488 26.66 4.06049L4.66 12.0605C4.47027 12.1325 4.30692 12.2604 4.19165 12.4274C4.07638 12.5944 4.01465 12.7926 4.01465 12.9955C4.01465 13.1984 4.07638 13.3965 4.19165 13.5635C4.30692 13.7305 4.47027 13.8585 4.66 13.9305L14.26 17.7705L18.1 27.3705C18.1721 27.5519 18.2958 27.7082 18.4557 27.8201C18.6157 27.9321 18.8049 27.9948 19 28.0005C19.2021 27.9963 19.3982 27.9311 19.5624 27.8132C19.7266 27.6954 19.8513 27.5306 19.92 27.3405L27.92 5.34049C27.9881 5.16356 28.0046 4.97092 27.9674 4.78501C27.9302 4.5991 27.8409 4.4276 27.71 4.29049ZM19 24.2005L16.21 17.2005L20.295 13.1155C20.6844 12.7261 20.6844 12.0948 20.295 11.7055C19.9056 11.3161 19.2744 11.3161 18.885 11.7055L14.76 15.8305L7.8 13.0005L25.33 6.67049L19 24.2005Z"
|
||||
/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 7.6 KiB |
@@ -87,7 +87,8 @@
|
||||
"Floor": "Zaokrouhlit dolů",
|
||||
"Ceil": "Zaokrouhlit nahoru",
|
||||
"Absolute": "Absolutní hodnota",
|
||||
"LogAction": "Událost"
|
||||
"LogAction": "Událost",
|
||||
"Started": "Spuštěno"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metoda nenalezena: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Abrunden",
|
||||
"Ceil": "Aufrunden",
|
||||
"Absolute": "Absolutwert",
|
||||
"LogAction": "Ereignis"
|
||||
"LogAction": "Ereignis",
|
||||
"Started": "Gestartet"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Methode nicht gefunden: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Absolute": "Absolute",
|
||||
"Ceil": "Ceil",
|
||||
"Floor": "Floor",
|
||||
"LogAction": "Event"
|
||||
"LogAction": "Event",
|
||||
"Started": "Started"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Method not found: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Redondear hacia abajo",
|
||||
"Ceil": "Redondear hacia arriba",
|
||||
"Absolute": "Valor absoluto",
|
||||
"LogAction": "Evento"
|
||||
"LogAction": "Evento",
|
||||
"Started": "Iniciado"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método no encontrado: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Arrondir vers le bas",
|
||||
"Ceil": "Arrondir vers le haut",
|
||||
"Absolute": "Valeur absolue",
|
||||
"LogAction": "Événement"
|
||||
"LogAction": "Événement",
|
||||
"Started": "Démarré"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Méthode introuvable : {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Arrotondare per difetto",
|
||||
"Ceil": "Arrotondare per eccesso",
|
||||
"Absolute": "Valore assoluto",
|
||||
"LogAction": "Evento"
|
||||
"LogAction": "Evento",
|
||||
"Started": "Avviato"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metodo non trovato: {methodId}",
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
"Floor": "切り捨て",
|
||||
"Ceil": "切り上げ",
|
||||
"Absolute": "絶対値",
|
||||
"LogAction": "イベント"
|
||||
"LogAction": "イベント",
|
||||
"Started": "開始"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "メソッドが見つかりません: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Arredondar para baixo",
|
||||
"Ceil": "Arredondar para cima",
|
||||
"Absolute": "Valor absoluto",
|
||||
"LogAction": "Evento"
|
||||
"LogAction": "Evento",
|
||||
"Started": "Iniciado"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método não encontrado: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "Округлить вниз",
|
||||
"Ceil": "Округлить вверх",
|
||||
"Absolute": "Абсолютное значение",
|
||||
"LogAction": "Событие"
|
||||
"LogAction": "Событие",
|
||||
"Started": "Начат"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Метод не найден: {methodId}",
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
"Floor": "向下取整",
|
||||
"Ceil": "向上取整",
|
||||
"Absolute": "绝对值",
|
||||
"LogAction": "事件"
|
||||
"LogAction": "事件",
|
||||
"Started": "已启动"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "找不到方法:{methodId}",
|
||||
|
||||
@@ -23,5 +23,6 @@ loadMetadata(process.icon, {
|
||||
Steps: `${icons}#steps`,
|
||||
ToDo: `${icons}#todo`,
|
||||
ToDoRemove: `${icons}#todo-remove`,
|
||||
WaitSubprocesses: `${icons}#subprocesses`
|
||||
WaitSubprocesses: `${icons}#subprocesses`,
|
||||
Start: `${icons}#start`
|
||||
})
|
||||
|
||||
@@ -118,12 +118,6 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- <Card
|
||||
label={process.string.Execution}
|
||||
okAction={() => { dispatch('close') }}
|
||||
width={'large'}
|
||||
on:close
|
||||
> -->
|
||||
<Modal
|
||||
type={'type-popup'}
|
||||
width={'large'}
|
||||
@@ -168,4 +162,3 @@
|
||||
/>
|
||||
{/if}
|
||||
</Modal>
|
||||
<!-- </Card> -->
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// 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.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ExecutionLog } from '@hcengineering/process'
|
||||
import { Notification, NotificationToast } from '@hcengineering/ui'
|
||||
import LogActionPresenter from './LogActionPresenter.svelte'
|
||||
import TransitionRefPresenter from './settings/TransitionRefPresenter.svelte'
|
||||
import { CardPresenter } from '@hcengineering/card-resources'
|
||||
|
||||
export let notification: Notification
|
||||
export let onRemove: () => void
|
||||
|
||||
$: val = notification?.params?.event as ExecutionLog
|
||||
</script>
|
||||
|
||||
{#if val}
|
||||
<NotificationToast title={notification.title} severity={notification.severity} onClose={onRemove}>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="fs-title">
|
||||
<CardPresenter value={val.card} shouldShowAvatar />
|
||||
</div>
|
||||
<div class="flex-row-center flex-wrap gap-2 reverse">
|
||||
<LogActionPresenter value={val.action} />
|
||||
{#if val.transition}
|
||||
<TransitionRefPresenter value={val.transition} />
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</NotificationToast>
|
||||
{/if}
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ExecutionLogAction } from '@hcengineering/process'
|
||||
import process, { ExecutionLogAction } from '@hcengineering/process'
|
||||
import { Icon } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</script>
|
||||
|
||||
{#if value === ExecutionLogAction.Started}
|
||||
<Icon icon={view.icon.Circle} size={'small'} />
|
||||
<Icon icon={process.icon.Start} size={'small'} />
|
||||
{:else if value === ExecutionLogAction.Transition}
|
||||
<Icon icon={view.icon.ArrowRight} size={'small'} />
|
||||
{:else}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// 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.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ExecutionLog, ExecutionLogAction } from '@hcengineering/process'
|
||||
import { addNotification, NotificationSeverity, themeStore } from '@hcengineering/ui'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import process from '../plugin'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import ExecutionNotification from './ExecutionNotification.svelte'
|
||||
|
||||
const processed = new Set<Ref<ExecutionLog>>()
|
||||
const client = getClient()
|
||||
let init = false
|
||||
|
||||
const query = createQuery()
|
||||
query.query(process.class.ExecutionLog, { createdOn: { $gt: Date.now() } }, (res) => {
|
||||
if (!init) {
|
||||
res.forEach((event) => {
|
||||
processed.add(event._id)
|
||||
})
|
||||
init = true
|
||||
} else {
|
||||
notifyAll(res)
|
||||
}
|
||||
})
|
||||
|
||||
async function notifyAll (events: ExecutionLog[]): Promise<void> {
|
||||
for (const event of events) {
|
||||
if (processed.has(event._id)) continue
|
||||
await notify(event)
|
||||
}
|
||||
}
|
||||
|
||||
async function notify (event: ExecutionLog): Promise<void> {
|
||||
processed.add(event._id)
|
||||
const _process = client.getModel().findObject(event.process)
|
||||
addNotification(
|
||||
await translate(
|
||||
event.action === ExecutionLogAction.Started
|
||||
? process.string.Started
|
||||
: event.action === ExecutionLogAction.Transition
|
||||
? process.string.Transition
|
||||
: process.string.Rollback,
|
||||
{},
|
||||
$themeStore.language
|
||||
),
|
||||
_process?.name ?? (await translate(process.string.Process, {}, $themeStore.language)),
|
||||
ExecutionNotification,
|
||||
{
|
||||
event
|
||||
},
|
||||
event.action === ExecutionLogAction.Rollback ? NotificationSeverity.Warning : NotificationSeverity.Info
|
||||
)
|
||||
}
|
||||
</script>
|
||||
@@ -52,6 +52,7 @@ import { ProcessMiddleware } from './middleware'
|
||||
import { continueExecution, showDoneQuery, todoTranstionCheck } from './utils'
|
||||
import LogActionPresenter from './components/LogActionPresenter.svelte'
|
||||
import TransitionRefPresenter from './components/settings/TransitionRefPresenter.svelte'
|
||||
import NotifierExtension from './components/NotifierExtension.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
actionImpl: {
|
||||
@@ -88,7 +89,8 @@ export default async (): Promise<Resources> => ({
|
||||
ProcessesCardSection,
|
||||
TransitionEditor,
|
||||
TransitionRefPresenter,
|
||||
LogActionPresenter
|
||||
LogActionPresenter,
|
||||
NotifierExtension
|
||||
},
|
||||
transformEditor: {
|
||||
DateOffsetEditor,
|
||||
|
||||
@@ -55,7 +55,8 @@ export default mergeIds(processId, process, {
|
||||
TransitionEditor: '' as AnyComponent,
|
||||
StateEditor: '' as AnyComponent,
|
||||
TransitionRefPresenter: '' as AnyComponent,
|
||||
LogActionPresenter: '' as AnyComponent
|
||||
LogActionPresenter: '' as AnyComponent,
|
||||
NotifierExtension: '' as AnyComponent
|
||||
},
|
||||
transformEditor: {
|
||||
DateOffsetEditor: '' as AnyComponent,
|
||||
@@ -148,6 +149,7 @@ export default mergeIds(processId, process, {
|
||||
Search: '' as IntlString,
|
||||
Separator: '' as IntlString,
|
||||
Start: '' as IntlString,
|
||||
End: '' as IntlString
|
||||
End: '' as IntlString,
|
||||
Started: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -67,6 +67,8 @@ export interface Transition extends Doc {
|
||||
|
||||
export interface ExecutionLog extends Doc {
|
||||
execution: Ref<Execution>
|
||||
card: Ref<Card>
|
||||
process: Ref<Process>
|
||||
transition?: Ref<Transition>
|
||||
action: ExecutionLogAction
|
||||
}
|
||||
@@ -217,7 +219,8 @@ export default plugin(processId, {
|
||||
States: '' as Asset,
|
||||
ToDo: '' as Asset,
|
||||
WaitSubprocesses: '' as Asset,
|
||||
ToDoRemove: '' as Asset
|
||||
ToDoRemove: '' as Asset,
|
||||
Start: '' as Asset
|
||||
},
|
||||
function: {
|
||||
FirstValue: '' as Ref<ProcessFunction>,
|
||||
|
||||
@@ -177,6 +177,8 @@ async function executeTransition (
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(process.class.ExecutionLog, execution.space, {
|
||||
execution: execution._id,
|
||||
process: execution.process,
|
||||
card: execution.card,
|
||||
transition: transition._id,
|
||||
action: ExecutionLogAction.Transition
|
||||
})
|
||||
@@ -479,6 +481,8 @@ async function initState (execution: Execution, control: TriggerControl): Promis
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(process.class.ExecutionLog, execution.space, {
|
||||
execution: execution._id,
|
||||
process: execution.process,
|
||||
card: execution.card,
|
||||
transition: transition._id,
|
||||
action: ExecutionLogAction.Started
|
||||
})
|
||||
@@ -546,6 +550,8 @@ export async function OnProcessToDoRemove (txes: Tx[], control: TriggerControl):
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(process.class.ExecutionLog, execution.space, {
|
||||
execution: execution._id,
|
||||
process: execution.process,
|
||||
card: execution.card,
|
||||
action: ExecutionLogAction.Rollback
|
||||
})
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user