11/**
22 * @typedef {import('./types').ExecutionLogEntry } ExecutionLogEntry
3- * @typedef {import('./types').TaskExecutionStatus } TaskExecutionStatus
3+ * @typedef {import('./types').ExecutionLogEntryStatus } TaskExecutionStatus
4+ * @typedef {import('./types').ExecutionLogElementInstanceEntry } ElementInstanceEntry
45 * @typedef {import('./types').TaskExecutionPollData } TaskExecutionPollData
5- * @typedef {import('./types').ElementInstanceEntry } ElementInstanceEntry
6+ * @typedef {import('./types').TaskExecutionState } TaskExecutionState
7+ *
8+ * @typedef {import('@camunda8/sdk/dist/c8/lib/C8Dto').DeployResourceResponse } DeployResourceResponse
9+ * @typedef {import('./types').ApiResponse<DeployResourceResponse> } DeployResponse
10+ *
11+ * @typedef {import('@camunda8/sdk/dist/c8/lib/C8Dto').CreateProcessInstanceResponse } CreateProcessInstanceResponse
12+ * @typedef {import('./types').ApiResponse<CreateProcessInstanceResponse> } StartInstanceResponse
613 */
714
8- const ENTRY_TYPE = /** @type { const } */ ( {
15+ export const EXECUTION_LOG_ENTRY_TYPE = {
916 STATUS : 'status' ,
1017 JOB : 'job' ,
1118 USER_TASK : 'user-task' ,
1219 MESSAGE_SUBSCRIPTION : 'message-subscription' ,
1320 ELEMENT_INSTANCE : 'element-instance'
14- } ) ;
15-
16- const TASK_STATUS = /** @type {const } */ ( {
17- EXECUTING : 'executing' ,
18- COMPLETED : 'completed' ,
19- INCIDENT : 'incident' ,
20- TERMINATED : 'terminated' ,
21- CANCELED : 'canceled'
22- } ) ;
21+ } ;
2322
2423const TIMESTAMP_FIELDS = {
25- [ ENTRY_TYPE . JOB ] : [ 'endTime' ] ,
26- [ ENTRY_TYPE . USER_TASK ] : [ 'completionDate' , 'creationDate' ] ,
27- [ ENTRY_TYPE . ELEMENT_INSTANCE ] : [ 'endDate' , 'startDate' ]
24+ [ EXECUTION_LOG_ENTRY_TYPE . JOB ] : [ 'endTime' ] ,
25+ [ EXECUTION_LOG_ENTRY_TYPE . USER_TASK ] : [ 'completionDate' , 'creationDate' ] ,
26+ [ EXECUTION_LOG_ENTRY_TYPE . ELEMENT_INSTANCE ] : [ 'endDate' , 'startDate' ]
2827} ;
2928
30- const SIMPLE_POLL_SLICES = [
29+ const POLL_RESPONSE_FIELDS = [
3130 {
3231 resultField : 'jobsResult' ,
33- entryType : ENTRY_TYPE . JOB
32+ entryType : EXECUTION_LOG_ENTRY_TYPE . JOB
3433 } ,
3534 {
3635 resultField : 'userTasksResult' ,
37- entryType : ENTRY_TYPE . USER_TASK
36+ entryType : EXECUTION_LOG_ENTRY_TYPE . USER_TASK
3837 } ,
3938 {
4039 resultField : 'messageSubscriptionsResult' ,
41- entryType : ENTRY_TYPE . MESSAGE_SUBSCRIPTION
40+ entryType : EXECUTION_LOG_ENTRY_TYPE . MESSAGE_SUBSCRIPTION
4241 }
4342] ;
4443
45- const SNAPSHOT_ENTRY_TYPES = [
46- ENTRY_TYPE . JOB ,
47- ENTRY_TYPE . USER_TASK ,
48- ENTRY_TYPE . MESSAGE_SUBSCRIPTION ,
49- ENTRY_TYPE . ELEMENT_INSTANCE
50- ] ;
51-
52- function createEmptyPollEntriesByType ( ) {
53- return {
54- [ ENTRY_TYPE . JOB ] : [ ] ,
55- [ ENTRY_TYPE . USER_TASK ] : [ ] ,
56- [ ENTRY_TYPE . MESSAGE_SUBSCRIPTION ] : [ ] ,
57- [ ENTRY_TYPE . ELEMENT_INSTANCE ] : [ ]
58- } ;
59- }
60-
6144/**
62- * Check whether a set of log entries represents a finished execution.
63- *
64- * @param {ExecutionLogEntry[] } entries
65- *
66- * @returns {boolean }
67- */
68- export function isFinished ( entries ) {
69- return entries . some (
70- e => e . type === ENTRY_TYPE . STATUS && (
71- e . status === TASK_STATUS . COMPLETED
72- || e . status === TASK_STATUS . INCIDENT
73- || e . status === TASK_STATUS . TERMINATED
74- || e . status === TASK_STATUS . CANCELED
75- )
76- ) ;
77- }
78-
79- /**
80- * Derive the display-ready list of entries from raw entries.
81- * - When finished, the transient `executing` status is dropped entirely.
82- * - While running, `executing` is moved to the end so it always appears last.
83- *
84- * @param {ExecutionLogEntry[] } entries
85- *
86- * @returns {ExecutionLogEntry[] }
87- */
88- export function getDisplayEntries ( entries ) {
89- const finished = isFinished ( entries ) ;
90- const withoutExecuting = [ ] ;
91- const executing = [ ] ;
92-
93- for ( const entry of entries ) {
94- if ( entry . type === ENTRY_TYPE . STATUS && entry . status === TASK_STATUS . EXECUTING ) {
95- executing . push ( entry ) ;
96- } else {
97- withoutExecuting . push ( entry ) ;
98- }
99- }
100-
101- withoutExecuting . sort ( ( a , b ) => a . timestamp - b . timestamp ) ;
102-
103- if ( finished ) {
104- return withoutExecuting ;
105- }
106-
107- return [ ...withoutExecuting , ...executing ] ;
108- }
109-
110- /**
111- * Get the most meaningful timestamp from an API result item.
45+ * Get the most meaningful timestamp from
11246 *
11347 * job → endTime (when the job last changed state)
11448 * user-task → completionDate, then creationDate
@@ -117,11 +51,10 @@ export function getDisplayEntries(entries) {
11751 *
11852 * @param {string } type
11953 * @param {any } data
120- * @param {number } pollTimestamp
12154 *
12255 * @returns {number }
12356 */
124- function getTimestamp ( type , data , pollTimestamp ) {
57+ function getTimestamp ( type , data ) {
12558 const candidateFields = TIMESTAMP_FIELDS [ type ] || [ ] ;
12659
12760 for ( const field of candidateFields ) {
@@ -137,7 +70,8 @@ function getTimestamp(type, data, pollTimestamp) {
13770 }
13871 }
13972
140- return pollTimestamp ;
73+ // TODO: for message-subscription, we currently have no reliable timestamp field. We could consider using the poll timestamp, but that would require passing it through multiple layers. For now, we just use the current time as a fallback.
74+ return Date . now ( ) ;
14175}
14276
14377/**
@@ -171,12 +105,13 @@ export default class ExecutionLog {
171105 * @param {Object } [injector]
172106 */
173107 constructor ( injector ) {
108+ this . _state = null ;
174109
175- /** @type {ExecutionLogEntry[] } */
176- this . _statusEntries = [ ] ;
110+ this . _deployResponse = null ;
111+
112+ this . _startInstanceResponse = null ;
177113
178- /** @type {Record<string, ExecutionLogEntry[]> } */
179- this . _pollEntriesByType = createEmptyPollEntriesByType ( ) ;
114+ this . _pollResponse = null ;
180115
181116 /** @type {ExecutionLogEntry[] } */
182117 this . _entries = [ ] ;
@@ -186,135 +121,103 @@ export default class ExecutionLog {
186121 }
187122
188123 /**
189- * Record a status entry .
124+ * Add state .
190125 *
191- * @param {TaskExecutionStatus } status
126+ * @param {TaskExecutionState } state
192127 * @param {number } [timestamp]
193- * @param {Object } [data]
194128 *
195129 * @returns {ExecutionLogEntry[] }
196130 */
197- recordStatus ( status , timestamp = Date . now ( ) , data = { } ) {
198- this . _statusEntries = [ ...this . _statusEntries , {
199- type : ENTRY_TYPE . STATUS ,
200- status,
201- timestamp,
202- data
203- } ] ;
131+ addState ( state , timestamp = Date . now ( ) ) {
132+ this . _state = { type : state , timestamp } ;
204133
205134 this . _updateEntries ( ) ;
206135
207136 return this . _entries ;
208137 }
209138
210139 /**
211- * Record a poll entry and refresh poll snapshots .
140+ * Set deploy response .
212141 *
213- * @param {TaskExecutionPollData } pollEntry
142+ * @param {DeployResponse } deployResponse
214143 *
215144 * @returns {ExecutionLogEntry[] }
216145 */
217- recordPoll ( pollEntry ) {
218- const {
219- jobsResult,
220- userTasksResult,
221- messageSubscriptionsResult,
222- elementInstancesResult,
223- elementId,
224- timestamp
225- } = /** @type {any } */ ( pollEntry ) ;
226-
227- const pollData = {
228- jobsResult,
229- userTasksResult,
230- messageSubscriptionsResult
231- } ;
232-
233- const nextPollEntriesByType = { ...this . _pollEntriesByType } ;
234-
235- // Simple slices (jobs, user tasks, message subscriptions)
236- for ( const { resultField, entryType } of SIMPLE_POLL_SLICES ) {
237- const result = pollData [ resultField ] ;
238-
239- if ( result . success ) {
240- nextPollEntriesByType [ entryType ] = this . _buildSimpleSliceEntries (
241- result . response . items ,
242- entryType ,
243- timestamp
244- ) ;
245- }
246- }
247-
248- // Element instances
249- if ( elementInstancesResult . success ) {
250- nextPollEntriesByType [ ENTRY_TYPE . ELEMENT_INSTANCE ] = this . _buildElementInstanceEntries ( {
251- allInstances : elementInstancesResult . response . items || [ ] ,
252- elementId,
253- timestamp
254- } ) ;
255- }
256-
257- this . _pollEntriesByType = nextPollEntriesByType ;
146+ setDeployResponse ( deployResponse ) {
147+ this . _deployResponse = deployResponse ;
258148
259149 this . _updateEntries ( ) ;
260150
261151 return this . _entries ;
262152 }
263153
264154 /**
155+ * Set start instance response.
156+ *
157+ * @param {StartInstanceResponse } startInstanceResponse
158+ *
265159 * @returns {ExecutionLogEntry[] }
266160 */
267- getEntries ( ) {
161+ setStartInstanceResponse ( startInstanceResponse ) {
162+ this . _instanceStartedData = startInstanceResponse ;
163+
164+ this . _updateEntries ( ) ;
165+
268166 return this . _entries ;
269167 }
270168
271169 /**
272- * Get entries projected for display.
170+ * Set poll response.
171+ *
172+ * @param {TaskExecutionPollData } pollResponse
273173 *
274174 * @returns {ExecutionLogEntry[] }
275175 */
276- getDisplayEntries ( ) {
277- return getDisplayEntries ( this . _entries ) ;
176+ setPollResponse ( pollResponse ) {
177+ this . _pollResponse = pollResponse ;
178+
179+ this . _updateEntries ( ) ;
180+
181+ return this . _entries ;
278182 }
279183
280184 /**
281- * Whether the log contains a terminal status (completed, incident, canceled).
282- *
283- * @returns {boolean }
185+ * @returns {ExecutionLogEntry[] }
284186 */
285- isFinished ( ) {
286- return isFinished ( this . _entries ) ;
187+ getEntries ( ) {
188+ return this . _entries ;
287189 }
288190
289191 /**
290- * Clear all entries.
192+ * Clear all data and entries.
291193 */
292194 reset ( ) {
293- this . _statusEntries = [ ] ;
294- this . _pollEntriesByType = createEmptyPollEntriesByType ( ) ;
195+ this . _state = null ;
196+ this . _deployResponse = null ;
197+ this . _startInstanceResponse = null ;
198+ this . _pollResponse = null ;
295199 this . _entries = [ ] ;
296200 }
297201
298202 /**
299203 * Update merged entries from status history + poll snapshots.
300204 */
301205 _updateEntries ( ) {
302- const pollEntries = SNAPSHOT_ENTRY_TYPES . flatMap ( type => this . _pollEntriesByType [ type ] ) ;
303- this . _entries = [ ... this . _statusEntries , ... pollEntries ] ;
206+
207+ // TODO: implement entire entries logic based on state and all available data (deploy, start instance, poll)
304208 }
305209
306210 /**
307211 * @param {any[] } items
308212 * @param {'job'|'user-task'|'message-subscription' } type
309- * @param {number } pollTimestamp
310213 *
311214 * @returns {ExecutionLogEntry[] }
312215 */
313- _buildSimpleSliceEntries ( items , type , pollTimestamp ) {
216+ _buildSimpleSliceEntries ( items , type ) {
314217 return ( items || [ ] ) . map ( data => ( {
315218 type,
316219 data,
317- timestamp : getTimestamp ( type , data , pollTimestamp )
220+ timestamp : getTimestamp ( type , data )
318221 } ) ) ;
319222 }
320223
@@ -326,10 +229,10 @@ export default class ExecutionLog {
326229 * @returns {ElementInstanceEntry }
327230 */
328231 _createElementInstanceEntry ( { instance, timestamp } ) {
329- return /** @type {import('./types').ElementInstanceEntry } */ ( {
330- type : ENTRY_TYPE . ELEMENT_INSTANCE ,
232+ return /** @type {import('./types').ExecutionLogElementInstanceEntry } */ ( {
233+ type : EXECUTION_LOG_ENTRY_TYPE . ELEMENT_INSTANCE ,
331234 data : instance ,
332- timestamp : getTimestamp ( ENTRY_TYPE . ELEMENT_INSTANCE , instance , timestamp )
235+ timestamp : getTimestamp ( EXECUTION_LOG_ENTRY_TYPE . ELEMENT_INSTANCE , instance , timestamp )
333236 } ) ;
334237 }
335238
0 commit comments