@finos/legend-application-studio 28.21.44 → 28.21.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/lib/__lib__/LegendStudioEvent.d.ts +55 -1
  2. package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioEvent.js +77 -0
  4. package/lib/__lib__/LegendStudioEvent.js.map +1 -1
  5. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +491 -1
  6. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendStudioTelemetryHelper.js +594 -1
  8. package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
  9. package/lib/components/editor/side-bar/WorkflowManager.d.ts.map +1 -1
  10. package/lib/components/editor/side-bar/WorkflowManager.js +15 -0
  11. package/lib/components/editor/side-bar/WorkflowManager.js.map +1 -1
  12. package/lib/index.css +1 -1
  13. package/lib/index.d.ts +1 -1
  14. package/lib/index.d.ts.map +1 -1
  15. package/lib/index.js +1 -1
  16. package/lib/index.js.map +1 -1
  17. package/lib/package.json +1 -1
  18. package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
  19. package/lib/stores/editor/EditorGraphState.js +17 -1
  20. package/lib/stores/editor/EditorGraphState.js.map +1 -1
  21. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  22. package/lib/stores/editor/EditorStore.js +10 -0
  23. package/lib/stores/editor/EditorStore.js.map +1 -1
  24. package/lib/stores/editor/EditorTabManagerState.d.ts +18 -1
  25. package/lib/stores/editor/EditorTabManagerState.d.ts.map +1 -1
  26. package/lib/stores/editor/EditorTabManagerState.js +90 -1
  27. package/lib/stores/editor/EditorTabManagerState.js.map +1 -1
  28. package/lib/stores/editor/EditorTabTelemetryHelper.d.ts +31 -0
  29. package/lib/stores/editor/EditorTabTelemetryHelper.d.ts.map +1 -0
  30. package/lib/stores/editor/EditorTabTelemetryHelper.js +55 -0
  31. package/lib/stores/editor/EditorTabTelemetryHelper.js.map +1 -0
  32. package/lib/stores/editor/GraphEditFormModeState.d.ts.map +1 -1
  33. package/lib/stores/editor/GraphEditFormModeState.js +11 -1
  34. package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
  35. package/lib/stores/editor/editor-state/GraphGenerationState.d.ts.map +1 -1
  36. package/lib/stores/editor/editor-state/GraphGenerationState.js +25 -0
  37. package/lib/stores/editor/editor-state/GraphGenerationState.js.map +1 -1
  38. package/lib/stores/editor/editor-state/ModelImporterState.d.ts.map +1 -1
  39. package/lib/stores/editor/editor-state/ModelImporterState.js +2 -1
  40. package/lib/stores/editor/editor-state/ModelImporterState.js.map +1 -1
  41. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.d.ts.map +1 -1
  42. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.js +14 -0
  43. package/lib/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.js.map +1 -1
  44. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.d.ts +5 -0
  45. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.d.ts.map +1 -1
  46. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.js +13 -0
  47. package/lib/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.js.map +1 -1
  48. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts +5 -0
  49. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
  50. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +13 -0
  51. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
  52. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +7 -0
  53. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
  54. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +19 -0
  55. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
  56. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts +5 -0
  57. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts.map +1 -1
  58. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js +13 -0
  59. package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js.map +1 -1
  60. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts +7 -0
  61. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
  62. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +34 -0
  63. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
  64. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
  65. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js +29 -0
  66. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
  67. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
  68. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +2 -0
  69. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
  70. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts +3 -0
  71. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
  72. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +7 -0
  73. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
  74. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.d.ts.map +1 -1
  75. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.js +46 -17
  76. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.js.map +1 -1
  77. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts +7 -0
  78. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts.map +1 -1
  79. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js +110 -16
  80. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js.map +1 -1
  81. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts +2 -1
  82. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts.map +1 -1
  83. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js +10 -4
  84. package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js.map +1 -1
  85. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.d.ts.map +1 -1
  86. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js +11 -0
  87. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js.map +1 -1
  88. package/lib/stores/editor/sidebar-state/ProjectOverviewState.d.ts.map +1 -1
  89. package/lib/stores/editor/sidebar-state/ProjectOverviewState.js +51 -0
  90. package/lib/stores/editor/sidebar-state/ProjectOverviewState.js.map +1 -1
  91. package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts +14 -0
  92. package/lib/stores/editor/sidebar-state/WorkflowManagerState.d.ts.map +1 -1
  93. package/lib/stores/editor/sidebar-state/WorkflowManagerState.js +141 -26
  94. package/lib/stores/editor/sidebar-state/WorkflowManagerState.js.map +1 -1
  95. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.d.ts.map +1 -1
  96. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js +41 -0
  97. package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js.map +1 -1
  98. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.d.ts.map +1 -1
  99. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.js +71 -9
  100. package/lib/stores/editor/sidebar-state/testable/GlobalTestRunnerState.js.map +1 -1
  101. package/lib/stores/project-reviewer/ProjectReviewerStore.d.ts.map +1 -1
  102. package/lib/stores/project-reviewer/ProjectReviewerStore.js +45 -0
  103. package/lib/stores/project-reviewer/ProjectReviewerStore.js.map +1 -1
  104. package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts.map +1 -1
  105. package/lib/stores/workspace-setup/WorkspaceSetupStore.js +48 -4
  106. package/lib/stores/workspace-setup/WorkspaceSetupStore.js.map +1 -1
  107. package/package.json +9 -9
  108. package/src/__lib__/LegendStudioEvent.ts +88 -0
  109. package/src/__lib__/LegendStudioTelemetryHelper.ts +1389 -204
  110. package/src/components/editor/side-bar/WorkflowManager.tsx +24 -0
  111. package/src/index.ts +4 -1
  112. package/src/stores/editor/EditorGraphState.ts +30 -1
  113. package/src/stores/editor/EditorStore.ts +19 -0
  114. package/src/stores/editor/EditorTabManagerState.ts +128 -1
  115. package/src/stores/editor/EditorTabTelemetryHelper.ts +70 -0
  116. package/src/stores/editor/GraphEditFormModeState.ts +19 -1
  117. package/src/stores/editor/editor-state/GraphGenerationState.ts +53 -0
  118. package/src/stores/editor/editor-state/ModelImporterState.ts +2 -0
  119. package/src/stores/editor/editor-state/element-editor-state/ElementExternalFormatGenerationState.ts +30 -0
  120. package/src/stores/editor/editor-state/element-editor-state/availability/testable/AvailabilityTestableState.ts +17 -0
  121. package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +17 -0
  122. package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +25 -0
  123. package/src/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.ts +17 -0
  124. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +57 -0
  125. package/src/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.ts +56 -0
  126. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +10 -0
  127. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +9 -0
  128. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestableState.ts +78 -21
  129. package/src/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.ts +205 -18
  130. package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.ts +38 -3
  131. package/src/stores/editor/sidebar-state/BulkServiceRegistrationState.ts +27 -0
  132. package/src/stores/editor/sidebar-state/ProjectOverviewState.ts +114 -0
  133. package/src/stores/editor/sidebar-state/WorkflowManagerState.ts +259 -29
  134. package/src/stores/editor/sidebar-state/WorkspaceReviewState.ts +84 -0
  135. package/src/stores/editor/sidebar-state/testable/GlobalTestRunnerState.ts +124 -17
  136. package/src/stores/project-reviewer/ProjectReviewerStore.ts +97 -0
  137. package/src/stores/workspace-setup/WorkspaceSetupStore.ts +87 -4
  138. package/tsconfig.json +1 -0
@@ -42,6 +42,10 @@ import {
42
42
  type WorkspaceType,
43
43
  } from '@finos/legend-server-sdlc';
44
44
  import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
45
+ import {
46
+ LegendStudioTelemetryHelper,
47
+ PROJECT_OVERVIEW_ACTION,
48
+ } from '../../../__lib__/LegendStudioTelemetryHelper.js';
45
49
  import { LegendStudioUserDataHelper } from '../../../__lib__/LegendStudioUserDataHelper.js';
46
50
 
47
51
  export enum PROJECT_OVERVIEW_ACTIVITY_MODE {
@@ -147,6 +151,19 @@ export class ProjectOverviewState {
147
151
  }
148
152
 
149
153
  *deleteWorkspace(workspace: Workspace): GeneratorFn<void> {
154
+ const startTime = Date.now();
155
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
156
+ const identity = {
157
+ action: PROJECT_OVERVIEW_ACTION.DELETE_WORKSPACE,
158
+ projectId: this.sdlcState.activeProject.projectId,
159
+ patchReleaseVersionId: workspace.source,
160
+ workspaceType: workspace.workspaceType.toString(),
161
+ };
162
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionLaunched(
163
+ this.editorStore.applicationStore.telemetryService,
164
+ sourceInfo,
165
+ identity,
166
+ );
150
167
  try {
151
168
  this.isDeletingWorkspace = true;
152
169
  yield this.editorStore.sdlcServerClient.deleteWorkspace(
@@ -189,12 +206,22 @@ export class ProjectOverviewState {
189
206
  },
190
207
  );
191
208
  }
209
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionSucceeded(
210
+ this.editorStore.applicationStore.telemetryService,
211
+ sourceInfo,
212
+ { ...identity, durationMs: Date.now() - startTime },
213
+ );
192
214
  } catch (error) {
193
215
  assertErrorThrown(error);
194
216
  this.editorStore.applicationStore.logService.error(
195
217
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
196
218
  error,
197
219
  );
220
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionFailure(
221
+ this.editorStore.applicationStore.telemetryService,
222
+ sourceInfo,
223
+ { ...identity, errorMessage: error.message },
224
+ );
198
225
  } finally {
199
226
  this.isDeletingWorkspace = false;
200
227
  }
@@ -205,6 +232,17 @@ export class ProjectOverviewState {
205
232
  description: string,
206
233
  tags: string[],
207
234
  ): GeneratorFn<void> {
235
+ const startTime = Date.now();
236
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
237
+ const identity = {
238
+ action: PROJECT_OVERVIEW_ACTION.UPDATE_PROJECT,
239
+ projectId: this.sdlcState.activeProject.projectId,
240
+ };
241
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionLaunched(
242
+ this.editorStore.applicationStore.telemetryService,
243
+ sourceInfo,
244
+ identity,
245
+ );
208
246
  try {
209
247
  this.updatingProjectState.inProgress();
210
248
  yield this.editorStore.sdlcServerClient.updateProject(
@@ -223,9 +261,19 @@ export class ProjectOverviewState {
223
261
  this.sdlcState.activeProject.projectId,
224
262
  ),
225
263
  );
264
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionSucceeded(
265
+ this.editorStore.applicationStore.telemetryService,
266
+ sourceInfo,
267
+ { ...identity, durationMs: Date.now() - startTime },
268
+ );
226
269
  } catch (error) {
227
270
  assertErrorThrown(error);
228
271
  this.editorStore.applicationStore.notificationService.notifyError(error);
272
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionFailure(
273
+ this.editorStore.applicationStore.telemetryService,
274
+ sourceInfo,
275
+ { ...identity, errorMessage: error.message },
276
+ );
229
277
  } finally {
230
278
  this.updatingProjectState.complete();
231
279
  }
@@ -346,6 +394,17 @@ export class ProjectOverviewState {
346
394
  return;
347
395
  }
348
396
  this.isCreatingVersion = true;
397
+ const startTime = Date.now();
398
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
399
+ const identity = {
400
+ action: PROJECT_OVERVIEW_ACTION.CREATE_VERSION,
401
+ projectId: this.sdlcState.activeProject.projectId,
402
+ };
403
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionLaunched(
404
+ this.editorStore.applicationStore.telemetryService,
405
+ sourceInfo,
406
+ identity,
407
+ );
349
408
  try {
350
409
  this.releaseVersion.versionType = versionType;
351
410
  this.releaseVersion.validate();
@@ -356,6 +415,11 @@ export class ProjectOverviewState {
356
415
  )) as PlainObject<Version>,
357
416
  );
358
417
  yield flowResult(this.fetchLatestProjectVersion());
418
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionSucceeded(
419
+ this.editorStore.applicationStore.telemetryService,
420
+ sourceInfo,
421
+ { ...identity, durationMs: Date.now() - startTime },
422
+ );
359
423
  } catch (error) {
360
424
  assertErrorThrown(error);
361
425
  this.editorStore.applicationStore.logService.error(
@@ -363,6 +427,11 @@ export class ProjectOverviewState {
363
427
  error,
364
428
  );
365
429
  this.editorStore.applicationStore.notificationService.notifyError(error);
430
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionFailure(
431
+ this.editorStore.applicationStore.telemetryService,
432
+ sourceInfo,
433
+ { ...identity, errorMessage: error.message },
434
+ );
366
435
  } finally {
367
436
  this.isCreatingVersion = false;
368
437
  }
@@ -370,6 +439,18 @@ export class ProjectOverviewState {
370
439
 
371
440
  *createPatchVersion(id: string): GeneratorFn<void> {
372
441
  this.isCreatingVersion = true;
442
+ const startTime = Date.now();
443
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
444
+ const identity = {
445
+ action: PROJECT_OVERVIEW_ACTION.RELEASE_PATCH,
446
+ projectId: this.sdlcState.activeProject.projectId,
447
+ patchReleaseVersionId: id,
448
+ };
449
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionLaunched(
450
+ this.editorStore.applicationStore.telemetryService,
451
+ sourceInfo,
452
+ identity,
453
+ );
373
454
  try {
374
455
  const version = Version.serialization.fromJson(
375
456
  (yield this.editorStore.sdlcServerClient.releasePatch(
@@ -380,6 +461,11 @@ export class ProjectOverviewState {
380
461
  this.editorStore.applicationStore.notificationService.notifySuccess(
381
462
  `${version.id.id} is released successfully`,
382
463
  );
464
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionSucceeded(
465
+ this.editorStore.applicationStore.telemetryService,
466
+ sourceInfo,
467
+ { ...identity, durationMs: Date.now() - startTime },
468
+ );
383
469
  } catch (error) {
384
470
  assertErrorThrown(error);
385
471
  this.editorStore.applicationStore.logService.error(
@@ -387,6 +473,11 @@ export class ProjectOverviewState {
387
473
  error,
388
474
  );
389
475
  this.editorStore.applicationStore.notificationService.notifyError(error);
476
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionFailure(
477
+ this.editorStore.applicationStore.telemetryService,
478
+ sourceInfo,
479
+ { ...identity, errorMessage: error.message },
480
+ );
390
481
  } finally {
391
482
  this.isCreatingVersion = false;
392
483
  }
@@ -404,6 +495,19 @@ export class ProjectOverviewState {
404
495
  }
405
496
  this.createPatchState.inProgress();
406
497
  this.createPatchState.setMessage(`Creating patch...`);
498
+ const startTime = Date.now();
499
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
500
+ const identity = {
501
+ action: PROJECT_OVERVIEW_ACTION.CREATE_PATCH,
502
+ projectId: this.sdlcState.activeProject.projectId,
503
+ patchReleaseVersionId: sourceVersion,
504
+ workspaceType: workspaceType.toString(),
505
+ };
506
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionLaunched(
507
+ this.editorStore.applicationStore.telemetryService,
508
+ sourceInfo,
509
+ identity,
510
+ );
407
511
  try {
408
512
  const newPatch = Patch.serialization.fromJson(
409
513
  (yield this.editorStore.sdlcServerClient.createPatch(
@@ -427,6 +531,11 @@ export class ProjectOverviewState {
427
531
  this.editorStore.applicationStore.notificationService.notifySuccess(
428
532
  `Workspace '${newWorkspace.workspaceId}' is succesfully created`,
429
533
  );
534
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionSucceeded(
535
+ this.editorStore.applicationStore.telemetryService,
536
+ sourceInfo,
537
+ { ...identity, durationMs: Date.now() - startTime },
538
+ );
430
539
  this.editorStore.applicationStore.navigationService.navigator.goToLocation(
431
540
  generateEditorRoute(
432
541
  this.sdlcState.activeProject.projectId,
@@ -442,6 +551,11 @@ export class ProjectOverviewState {
442
551
  error,
443
552
  );
444
553
  this.editorStore.applicationStore.notificationService.notifyError(error);
554
+ LegendStudioTelemetryHelper.logEvent_ProjectOverviewActionFailure(
555
+ this.editorStore.applicationStore.telemetryService,
556
+ sourceInfo,
557
+ { ...identity, errorMessage: error.message },
558
+ );
445
559
  } finally {
446
560
  this.createPatchState.reset();
447
561
  }
@@ -29,6 +29,12 @@ import {
29
29
  filterByType,
30
30
  } from '@finos/legend-shared';
31
31
  import { type Version, WorkflowJob, Workflow } from '@finos/legend-server-sdlc';
32
+ import {
33
+ LegendStudioTelemetryHelper,
34
+ WORKFLOW_MANAGER_JOB_ACTION,
35
+ WORKFLOW_MANAGER_SCOPE,
36
+ type WorkflowManagerStatusBreakdown,
37
+ } from '../../../__lib__/LegendStudioTelemetryHelper.js';
32
38
 
33
39
  export abstract class WorkflowExplorerTreeNodeData implements TreeNodeData {
34
40
  isSelected?: boolean | undefined;
@@ -94,6 +100,16 @@ const updateWorkflowJobData = (
94
100
  }
95
101
  };
96
102
 
103
+ const computeStatusBreakdown = <T extends { status: string }>(
104
+ items: T[],
105
+ ): WorkflowManagerStatusBreakdown => {
106
+ const breakdown: WorkflowManagerStatusBreakdown = {};
107
+ items.forEach((item) => {
108
+ breakdown[item.status] = (breakdown[item.status] ?? 0) + 1;
109
+ });
110
+ return breakdown;
111
+ };
112
+
97
113
  export class WorkflowLogState {
98
114
  readonly editorStore: EditorStore;
99
115
  readonly workflowManagerState: WorkflowManagerState;
@@ -101,6 +117,11 @@ export class WorkflowLogState {
101
117
 
102
118
  job: WorkflowJob | undefined;
103
119
  logs: string;
120
+ // Telemetry-only session state (non-observable): tracks how long the log
121
+ // viewer is open and how many times the user hit refresh so we can emit a
122
+ // summary on close.
123
+ private openedAt: number | undefined;
124
+ private refreshCount = 0;
104
125
 
105
126
  constructor(
106
127
  editorStore: EditorStore,
@@ -133,11 +154,35 @@ export class WorkflowLogState {
133
154
  }
134
155
 
135
156
  closeModal(): void {
157
+ if (this.job && this.openedAt !== undefined) {
158
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsClosed(
159
+ this.editorStore.applicationStore.telemetryService,
160
+ this.editorStore.editorMode.getSourceInfo(),
161
+ {
162
+ scope: this.workflowManagerState.scope,
163
+ jobName: this.job.name,
164
+ dwellMs: Date.now() - this.openedAt,
165
+ refreshCount: this.refreshCount,
166
+ },
167
+ );
168
+ }
169
+ this.openedAt = undefined;
170
+ this.refreshCount = 0;
136
171
  this.setJob(undefined);
137
172
  this.setLogs('');
138
173
  }
139
174
 
140
175
  *refreshJobLogs(workflowJob: WorkflowJob): GeneratorFn<void> {
176
+ this.refreshCount += 1;
177
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsRefresh(
178
+ this.editorStore.applicationStore.telemetryService,
179
+ this.editorStore.editorMode.getSourceInfo(),
180
+ {
181
+ scope: this.workflowManagerState.scope,
182
+ jobName: workflowJob.name,
183
+ },
184
+ );
185
+ const started = Date.now();
141
186
  try {
142
187
  this.fetchJobLogState.inProgress();
143
188
  const job = (yield flowResult(
@@ -148,6 +193,16 @@ export class WorkflowLogState {
148
193
  this.workflowManagerState.getJobLogs(workflowJob),
149
194
  )) as string;
150
195
  this.setLogs(logs);
196
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsFetchSucceeded(
197
+ this.editorStore.applicationStore.telemetryService,
198
+ this.editorStore.editorMode.getSourceInfo(),
199
+ {
200
+ scope: this.workflowManagerState.scope,
201
+ jobName: workflowJob.name,
202
+ durationMs: Date.now() - started,
203
+ logSizeBytes: logs.length,
204
+ },
205
+ );
151
206
  this.fetchJobLogState.pass();
152
207
  } catch (error) {
153
208
  assertErrorThrown(error);
@@ -155,12 +210,33 @@ export class WorkflowLogState {
155
210
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
156
211
  error,
157
212
  );
213
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsFetchFailure(
214
+ this.editorStore.applicationStore.telemetryService,
215
+ this.editorStore.editorMode.getSourceInfo(),
216
+ {
217
+ scope: this.workflowManagerState.scope,
218
+ jobName: workflowJob.name,
219
+ errorMessage: error.message,
220
+ },
221
+ );
158
222
  this.editorStore.applicationStore.notificationService.notifyError(error);
159
223
  this.fetchJobLogState.fail();
160
224
  }
161
225
  }
162
226
 
163
227
  *viewJobLogs(workflowJob: WorkflowJob): GeneratorFn<void> {
228
+ this.openedAt = Date.now();
229
+ this.refreshCount = 0;
230
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsOpened(
231
+ this.editorStore.applicationStore.telemetryService,
232
+ this.editorStore.editorMode.getSourceInfo(),
233
+ {
234
+ scope: this.workflowManagerState.scope,
235
+ jobName: workflowJob.name,
236
+ jobStatus: workflowJob.status,
237
+ },
238
+ );
239
+ const started = Date.now();
164
240
  try {
165
241
  this.setJob(workflowJob);
166
242
  this.fetchJobLogState.inProgress();
@@ -168,6 +244,16 @@ export class WorkflowLogState {
168
244
  this.workflowManagerState.getJobLogs(workflowJob),
169
245
  )) as string;
170
246
  this.setLogs(logs);
247
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsFetchSucceeded(
248
+ this.editorStore.applicationStore.telemetryService,
249
+ this.editorStore.editorMode.getSourceInfo(),
250
+ {
251
+ scope: this.workflowManagerState.scope,
252
+ jobName: workflowJob.name,
253
+ durationMs: Date.now() - started,
254
+ logSizeBytes: logs.length,
255
+ },
256
+ );
171
257
  this.fetchJobLogState.pass();
172
258
  } catch (error) {
173
259
  assertErrorThrown(error);
@@ -175,6 +261,15 @@ export class WorkflowLogState {
175
261
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
176
262
  error,
177
263
  );
264
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobLogsFetchFailure(
265
+ this.editorStore.applicationStore.telemetryService,
266
+ this.editorStore.editorMode.getSourceInfo(),
267
+ {
268
+ scope: this.workflowManagerState.scope,
269
+ jobName: workflowJob.name,
270
+ errorMessage: error.message,
271
+ },
272
+ );
178
273
  this.editorStore.applicationStore.notificationService.notifyError(error);
179
274
  this.fetchJobLogState.fail();
180
275
  }
@@ -205,6 +300,7 @@ export class WorkflowState {
205
300
  refreshWorkflow: flow,
206
301
  retryJob: flow,
207
302
  runManualJob: flow,
303
+ runJobAction: flow,
208
304
  });
209
305
 
210
306
  this.editorStore = editorStore;
@@ -237,6 +333,15 @@ export class WorkflowState {
237
333
  workflowId: string,
238
334
  treeData: TreeData<WorkflowExplorerTreeNodeData>,
239
335
  ): GeneratorFn<void> {
336
+ const telemetryService = this.editorStore.applicationStore.telemetryService;
337
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
338
+ const scope = this.workflowManagerState.scope;
339
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchJobsLaunched(
340
+ telemetryService,
341
+ sourceInfo,
342
+ { scope },
343
+ );
344
+ const started = Date.now();
240
345
  try {
241
346
  this.isExecutingWorkflowRequest = true;
242
347
  const workflowJobs = (
@@ -246,12 +351,27 @@ export class WorkflowState {
246
351
  ).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
247
352
  updateWorkflowJobData(workflowJobs, workflowId, treeData);
248
353
  this.setWorkflowTreeData({ ...treeData });
354
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchJobsSucceeded(
355
+ telemetryService,
356
+ sourceInfo,
357
+ {
358
+ scope,
359
+ durationMs: Date.now() - started,
360
+ jobCount: workflowJobs.length,
361
+ statusBreakdown: computeStatusBreakdown(workflowJobs),
362
+ },
363
+ );
249
364
  } catch (error) {
250
365
  assertErrorThrown(error);
251
366
  this.editorStore.applicationStore.logService.error(
252
367
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
253
368
  error,
254
369
  );
370
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchJobsFailure(
371
+ telemetryService,
372
+ sourceInfo,
373
+ { scope, errorMessage: error.message },
374
+ );
255
375
  this.editorStore.applicationStore.notificationService.notifyError(error);
256
376
  } finally {
257
377
  this.isExecutingWorkflowRequest = false;
@@ -263,6 +383,18 @@ export class WorkflowState {
263
383
  treeData: TreeData<WorkflowExplorerTreeNodeData>,
264
384
  ): GeneratorFn<void> {
265
385
  if (node instanceof WorkflowTreeNodeData) {
386
+ // Only emit the expand event when the user is opening the node (not
387
+ // collapsing) so we don't double-count toggles.
388
+ if (!node.isOpen) {
389
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerWorkflowExpand(
390
+ this.editorStore.applicationStore.telemetryService,
391
+ this.editorStore.editorMode.getSourceInfo(),
392
+ {
393
+ scope: this.workflowManagerState.scope,
394
+ workflowStatus: node.workflow.status,
395
+ },
396
+ );
397
+ }
266
398
  if (!node.childrenIds) {
267
399
  yield flowResult(
268
400
  this.fetchAllWorkspaceWorkJobs(node.workflow.id, treeData),
@@ -277,20 +409,20 @@ export class WorkflowState {
277
409
  workflowJob: WorkflowJob,
278
410
  treeData: TreeData<WorkflowExplorerTreeNodeData>,
279
411
  ): GeneratorFn<void> {
280
- try {
281
- this.isExecutingWorkflowRequest = true;
282
- this.workflowManagerState.cancelJob(workflowJob);
283
- yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData));
284
- } catch (error) {
285
- assertErrorThrown(error);
286
- this.editorStore.applicationStore.logService.error(
287
- LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
288
- error,
289
- );
290
- this.editorStore.applicationStore.notificationService.notifyError(error);
291
- } finally {
292
- this.isExecutingWorkflowRequest = false;
293
- }
412
+ yield flowResult(
413
+ this.runJobAction(
414
+ WORKFLOW_MANAGER_JOB_ACTION.CANCEL,
415
+ workflowJob,
416
+ treeData,
417
+ // NOTE: unlike retry/runManual, the current implementation does not
418
+ // `yield` the underlying cancel call — see `cancelJob` below. The
419
+ // launch event will still fire, and success will fire after the
420
+ // refresh completes.
421
+ () => {
422
+ this.workflowManagerState.cancelJob(workflowJob);
423
+ },
424
+ ),
425
+ );
294
426
  }
295
427
 
296
428
  *refreshWorkflow(
@@ -303,6 +435,14 @@ export class WorkflowState {
303
435
  this.workflowManagerState.getWorkflow(workflowId),
304
436
  )) as Workflow;
305
437
  node.workflow = workflow;
438
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerWorkflowRefresh(
439
+ this.editorStore.applicationStore.telemetryService,
440
+ this.editorStore.editorMode.getSourceInfo(),
441
+ {
442
+ scope: this.workflowManagerState.scope,
443
+ workflowStatus: workflow.status,
444
+ },
445
+ );
306
446
  }
307
447
  yield flowResult(this.fetchAllWorkspaceWorkJobs(workflowId, treeData));
308
448
  }
@@ -311,36 +451,83 @@ export class WorkflowState {
311
451
  workflowJob: WorkflowJob,
312
452
  treeData: TreeData<WorkflowExplorerTreeNodeData>,
313
453
  ): GeneratorFn<void> {
314
- try {
315
- this.isExecutingWorkflowRequest = true;
316
- yield flowResult(this.workflowManagerState.retryJob(workflowJob));
317
- yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData));
318
- } catch (error) {
319
- assertErrorThrown(error);
320
- this.editorStore.applicationStore.logService.error(
321
- LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
322
- error,
323
- );
324
- this.editorStore.applicationStore.notificationService.notifyError(error);
325
- } finally {
326
- this.isExecutingWorkflowRequest = false;
327
- }
454
+ yield flowResult(
455
+ this.runJobAction(
456
+ WORKFLOW_MANAGER_JOB_ACTION.RETRY,
457
+ workflowJob,
458
+ treeData,
459
+ () => flowResult(this.workflowManagerState.retryJob(workflowJob)),
460
+ ),
461
+ );
328
462
  }
329
463
 
330
464
  *runManualJob(
331
465
  workflowJob: WorkflowJob,
332
466
  treeData: TreeData<WorkflowExplorerTreeNodeData>,
333
467
  ): GeneratorFn<void> {
468
+ yield flowResult(
469
+ this.runJobAction(
470
+ WORKFLOW_MANAGER_JOB_ACTION.RUN_MANUAL,
471
+ workflowJob,
472
+ treeData,
473
+ () => flowResult(this.workflowManagerState.runManualJob(workflowJob)),
474
+ ),
475
+ );
476
+ }
477
+
478
+ *runJobAction(
479
+ jobAction: WORKFLOW_MANAGER_JOB_ACTION,
480
+ workflowJob: WorkflowJob,
481
+ treeData: TreeData<WorkflowExplorerTreeNodeData>,
482
+ invoke: () => Promise<void> | void,
483
+ ): GeneratorFn<void> {
484
+ const telemetryService = this.editorStore.applicationStore.telemetryService;
485
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
486
+ const scope = this.workflowManagerState.scope;
487
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobActionLaunched(
488
+ telemetryService,
489
+ sourceInfo,
490
+ {
491
+ scope,
492
+ action: jobAction,
493
+ jobName: workflowJob.name,
494
+ jobStatus: workflowJob.status,
495
+ },
496
+ );
497
+ const started = Date.now();
334
498
  try {
335
499
  this.isExecutingWorkflowRequest = true;
336
- yield flowResult(this.workflowManagerState.runManualJob(workflowJob));
500
+ const result = invoke();
501
+ if (result) {
502
+ yield result;
503
+ }
337
504
  yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData));
505
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobActionSucceeded(
506
+ telemetryService,
507
+ sourceInfo,
508
+ {
509
+ scope,
510
+ action: jobAction,
511
+ jobName: workflowJob.name,
512
+ durationMs: Date.now() - started,
513
+ },
514
+ );
338
515
  } catch (error) {
339
516
  assertErrorThrown(error);
340
517
  this.editorStore.applicationStore.logService.error(
341
518
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
342
519
  error,
343
520
  );
521
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerJobActionFailure(
522
+ telemetryService,
523
+ sourceInfo,
524
+ {
525
+ scope,
526
+ action: jobAction,
527
+ jobName: workflowJob.name,
528
+ errorMessage: error.message,
529
+ },
530
+ );
344
531
  this.editorStore.applicationStore.notificationService.notifyError(error);
345
532
  } finally {
346
533
  this.isExecutingWorkflowRequest = false;
@@ -382,6 +569,14 @@ export abstract class WorkflowManagerState {
382
569
  );
383
570
  }
384
571
 
572
+ /**
573
+ * Discriminator for telemetry so dashboards can slice workflow-manager
574
+ * events by which surface emitted them (workspace sidebar vs. read-only
575
+ * project viewer vs. project-version viewer) without joining on
576
+ * `sourceInfo.sourceType`.
577
+ */
578
+ abstract get scope(): WORKFLOW_MANAGER_SCOPE;
579
+
385
580
  abstract getWorkflows(): GeneratorFn<Workflow[]>;
386
581
  abstract getWorkflow(workflowId: string): GeneratorFn<Workflow>;
387
582
  abstract getJobs(workflowId: string): GeneratorFn<WorkflowJob[]>;
@@ -392,6 +587,14 @@ export abstract class WorkflowManagerState {
392
587
  abstract getJobLogs(workflowJob: WorkflowJob): GeneratorFn<string>;
393
588
 
394
589
  *fetchAllWorkflows(): GeneratorFn<void> {
590
+ const telemetryService = this.editorStore.applicationStore.telemetryService;
591
+ const sourceInfo = this.editorStore.editorMode.getSourceInfo();
592
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchWorkflowsLaunched(
593
+ telemetryService,
594
+ sourceInfo,
595
+ { scope: this.scope },
596
+ );
597
+ const started = Date.now();
395
598
  try {
396
599
  this.fetchWorkflowsState.inProgress();
397
600
  // NOTE: this network call can take a while, so we might consider limiting the number of workflows to 10 or so
@@ -429,6 +632,16 @@ export abstract class WorkflowManagerState {
429
632
  jobsIndex.get(workflow.id),
430
633
  ),
431
634
  );
635
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchWorkflowsSucceeded(
636
+ telemetryService,
637
+ sourceInfo,
638
+ {
639
+ scope: this.scope,
640
+ durationMs: Date.now() - started,
641
+ workflowCount: workflows.length,
642
+ statusBreakdown: computeStatusBreakdown(workflows),
643
+ },
644
+ );
432
645
  this.fetchWorkflowsState.pass();
433
646
  } catch (error) {
434
647
  assertErrorThrown(error);
@@ -436,6 +649,11 @@ export abstract class WorkflowManagerState {
436
649
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
437
650
  error,
438
651
  );
652
+ LegendStudioTelemetryHelper.logEvent_WorkflowManagerFetchWorkflowsFailure(
653
+ telemetryService,
654
+ sourceInfo,
655
+ { scope: this.scope, errorMessage: error.message },
656
+ );
439
657
  this.editorStore.applicationStore.notificationService.notifyError(error);
440
658
  this.fetchWorkflowsState.fail();
441
659
  }
@@ -443,6 +661,10 @@ export abstract class WorkflowManagerState {
443
661
  }
444
662
 
445
663
  export class WorkspaceWorkflowManagerState extends WorkflowManagerState {
664
+ override get scope(): WORKFLOW_MANAGER_SCOPE {
665
+ return WORKFLOW_MANAGER_SCOPE.WORKSPACE;
666
+ }
667
+
446
668
  override *getJobs(workflowId: string): GeneratorFn<WorkflowJob[]> {
447
669
  return (
448
670
  (yield this.editorStore.sdlcServerClient.getWorkflowJobs(
@@ -532,6 +754,10 @@ export class ProjectVersionWorkflowManagerState extends WorkflowManagerState {
532
754
  this.version = version;
533
755
  }
534
756
 
757
+ override get scope(): WORKFLOW_MANAGER_SCOPE {
758
+ return WORKFLOW_MANAGER_SCOPE.PROJECT_VERSION;
759
+ }
760
+
535
761
  override *getJobs(workflowId: string): GeneratorFn<WorkflowJob[]> {
536
762
  return (
537
763
  (yield this.editorStore.sdlcServerClient.getWorkflowJobsByVersion(
@@ -611,6 +837,10 @@ export class ProjectVersionWorkflowManagerState extends WorkflowManagerState {
611
837
  }
612
838
 
613
839
  export class ProjectWorkflowManagerState extends WorkflowManagerState {
840
+ override get scope(): WORKFLOW_MANAGER_SCOPE {
841
+ return WORKFLOW_MANAGER_SCOPE.PROJECT;
842
+ }
843
+
614
844
  override *getJobs(workflowId: string): GeneratorFn<WorkflowJob[]> {
615
845
  return (
616
846
  (yield this.editorStore.sdlcServerClient.getWorkflowJobs(