Skip to content

Conversation

Microchesst
Copy link
Contributor

Pull Request Template

Title

Implement Concurrent Digital Twin Execution with IndexedDB Integration

Type of Change

  • New feature
  • Bug fix
  • Documentation update
  • Refactoring
  • Security patch
  • UI/UX improvement

Description

This PR implements concurrent execution for Digital Twins with IndexedDB integration. Users can now start multiple executions of the same Digital Twin simultaneously, with execution history persisted in the browser's IndexedDB. The implementation includes a new execution history data model, IndexedDB service, and UI components to display and manage execution history.

##Working on Testing

  • Added unit tests for the IndexedDB service and Redux store
  • Manually tested concurrent execution functionality
  • Verified persistence of execution history across browser sessions
  • Fixed existing tests to accommodate the new functionality

Impact

  • Improves user experience by allowing multiple executions to run in parallel
  • Adds local persistence of execution history using IndexedDB
  • Enhances the UI with execution history list and status indicators

Checklist

  • My code adheres to the coding and style guidelines of the project.
  • I have added tests for all the new code and any changes made to existing code.
  • I have made corresponding changes to the documentation.

@Microchesst
Copy link
Contributor Author

I know the test are not working currently. Its just to show the feature, i will work on the test. I am having trouble with getting test of redux to work 😕

@prasadtalasila
Copy link
Contributor

@Microchesst thanks for the PR. I will get back to you by Monday.

Copy link
Contributor

@prasadtalasila prasadtalasila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Microchesst Thanks for the PR. The feature looks really nice. Please see the comments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move all the *.ts files in route/digitaltwins/execute to model/backend/gitlab/execution directory. Do remember to

  1. create an interface for each class so that testing becomes easier. The interfaces related to pipelines can be kept in model/backend/gitlab/execution/interfaces.ts
  2. always have preview/ code depend on stable codebase rather than other way around

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do think about the appropriate location for these slices. Is it src/store or src/model/store?

Copy link

codecov bot commented May 15, 2025

Codecov Report

Attention: Patch coverage is 76.21832% with 244 lines in your changes missing coverage. Please review.

Project coverage is 86.61%. Comparing base (664266b) to head (1c0f14c).
Report is 1 commits behind head on feature/distributed-demo.

Files with missing lines Patch % Lines
...c/model/backend/gitlab/execution/statusChecking.ts 16.07% 47 Missing ⚠️
.../backend/gitlab/services/ExecutionStatusService.ts 13.15% 33 Missing ⚠️
.../src/model/backend/gitlab/execution/logFetching.ts 58.66% 31 Missing ⚠️
...del/backend/gitlab/state/executionHistory.slice.ts 77.58% 26 Missing ⚠️
client/src/database/digitalTwins.ts 84.00% 20 Missing ⚠️
...e/digitaltwins/execution/executionStatusManager.ts 77.21% 18 Missing ⚠️
...oute/digitaltwins/execution/executionUIHandlers.ts 71.18% 17 Missing ⚠️
client/src/preview/util/digitalTwin.ts 82.25% 11 Missing ⚠️
client/src/preview/util/init.ts 16.66% 10 Missing ⚠️
.../src/components/execution/ExecutionHistoryList.tsx 93.69% 7 Missing ⚠️
... and 9 more
Additional details and impacted files
@@                     Coverage Diff                      @@
##           feature/distributed-demo    #1235      +/-   ##
============================================================
- Coverage                     92.08%   86.61%   -5.48%     
============================================================
  Files                            92      106      +14     
  Lines                          2526     3346     +820     
  Branches                        406      560     +154     
============================================================
+ Hits                           2326     2898     +572     
- Misses                          197      445     +248     
  Partials                          3        3              
Files with missing lines Coverage Δ
client/src/components/asset/HistoryButton.tsx 100.00% <100.00%> (ø)
client/src/database/types.ts 100.00% <100.00%> (ø)
client/src/model/backend/gitlab/constants.ts 100.00% <100.00%> (ø)
...rc/model/backend/gitlab/state/digitalTwin.slice.ts 100.00% <ø> (ø)
...src/model/backend/gitlab/types/executionHistory.ts 100.00% <100.00%> (ø)
client/src/preview/components/asset/AssetBoard.tsx 97.82% <100.00%> (ø)
client/src/preview/components/asset/AssetCard.tsx 88.70% <100.00%> (ø)
...lient/src/preview/components/asset/StartButton.tsx 100.00% <100.00%> (ø)
...eview/route/digitaltwins/create/CreateDTDialog.tsx 100.00% <100.00%> (ø)
...c/preview/route/digitaltwins/execute/LogDialog.tsx 100.00% <100.00%> (ø)
... and 22 more

... and 3 files with indirect coverage changes

Components Coverage Δ
Website 86.61% <76.21%> (-5.48%) ⬇️
Lib Microservice ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@prasadtalasila
Copy link
Contributor

@Microchesst please move your pure typescript files (*.ts) to model/backend/gitlab/execution.

@prasadtalasila
Copy link
Contributor

The redux slices can be placed on model/backend/gitlab/state and import the same into the aggregation modules in src/store.

@prasadtalasila prasadtalasila requested a review from Copilot May 24, 2025 19:28
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds concurrent execution support for Digital Twins by persisting and managing execution history in IndexedDB and enhancing the UI to display and control multiple runs.

  • Migrate digital-twin state and actions to model/backend/gitlab slices and introduce IndexedDB schema/service.
  • Introduce ExecutionHistoryLoader for initial load and polling, plus ExecutionHistoryList, updated dialogs/buttons to surface history.
  • Extend pipeline handlers (pipelineUtils, pipelineHandler, pipelineChecks) to create, track, and update concurrent executions.

Reviewed Changes

Copilot reviewed 65 out of 65 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
client/src/preview/route/digitaltwins/execute/LogDialog.tsx Fetch execution history via thunk and render ExecutionHistoryList instead of inline logs
client/src/preview/route/digitaltwins/editor/Sidebar.tsx Updated selectDigitalTwinByName import to new model/backend slice
client/src/preview/route/digitaltwins/create/CreateDTDialog.tsx Switched setDigitalTwin import to new model/backend slice
client/src/preview/components/execution/ExecutionHistoryLoader.tsx New component to load all history on startup and poll running executions
client/src/preview/components/execution/ExecutionHistoryList.tsx New list component displaying sorted history with stop/delete controls and log details
client/src/preview/components/asset/StartStopButton.tsx Show running count, integrate handleStart, and replace loading indicator
client/src/preview/components/asset/LogButton.tsx Add badge count for history entries and disable logic based on execution count
client/src/preview/components/asset/DetailsButton.tsx Updated selectDigitalTwinByName import path
client/src/preview/components/asset/AssetCard.tsx Initialize logButtonDisabled to false and pass assetName to LogButton
client/src/preview/components/asset/AssetBoard.tsx Updated setShouldFetchDigitalTwins import to new model/backend slice
client/src/model/backend/gitlab/types/executionHistory.ts New ExecutionStatus, JobLog, ExecutionHistoryEntry, and IndexedDB schema/types
client/src/model/backend/gitlab/state/executionHistory.slice.ts New slice with CRUD thunks, selectors, and polling logic for concurrent execution tracking
client/src/model/backend/gitlab/state/digitalTwin.slice.ts Aligned JobLog type import and added selectDigitalTwins selector
client/src/model/backend/gitlab/execution/pipelineUtils.ts Refactored pipeline state helpers to support execution history updates and concurrent flows
client/src/model/backend/gitlab/execution/pipelineHandler.ts Updated handleStart/handleStop to dispatch history fetch and pass executionId
client/src/model/backend/gitlab/execution/pipelineChecks.ts Enhanced status checks to update IndexedDB, handle timeouts, and use new interfaces
client/src/model/backend/gitlab/execution/interfaces.ts Defined PipelineStatusParams and PipelineHandlerDispatch for typed thunk usage
client/src/database/digitalTwins.ts IndexedDB service implementation conforming to new schema for persisting execution history
client/src/AppProvider.tsx Registered ExecutionHistoryLoader at the app root
client/package.json Added uuid, @types/uuid, fake-indexeddb and updated dependencies for IndexedDB and IDs
Comments suppressed due to low confidence (3)

client/src/preview/components/execution/ExecutionHistoryLoader.tsx:15

  • ExecutionHistoryLoader handles initial data fetch and polling but has no associated unit or integration tests. Consider adding tests to cover its effect logic and cleanup of the interval.
const ExecutionHistoryLoader: React.FC = () => {

client/src/preview/route/digitaltwins/execute/LogDialog.tsx:27

  • [nitpick] The component is named LogDialog but now presents execution history. Consider renaming it to ExecutionHistoryDialog for clarity and consistency with its content.
function LogDialog({ showLog, setShowLog, name }: LogDialogProps) {

client/src/model/backend/gitlab/execution/pipelineChecks.ts:76

  • Calling digitalTwin.getExecutionHistoryById assumes the DigitalTwin class exposes that method, but IndexedDB access should use indexedDBService. Replace this with indexedDBService.getExecutionHistoryById to avoid runtime errors.
const pipelineId = executionId

Comment on lines 55 to 57
const setButtonText = () => {}; // Dummy function since we don't need to change button text
handleStart(
'Start',
Copy link

Copilot AI May 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to handleStart always passes 'Start' and you’ve removed any buttonText state, so the UI can never switch to 'Stop'. This breaks the stop functionality—consider managing a local buttonText state or passing the current executionId to toggle correctly.

Suggested change
const setButtonText = () => {}; // Dummy function since we don't need to change button text
handleStart(
'Start',
const newButtonText = buttonText === 'Start' ? 'Stop' : 'Start';
setButtonText(newButtonText);
handleStart(
newButtonText,

Copilot uses AI. Check for mistakes.

}
}, [dispatch, name, showLog]);

const handleViewLogs = () => {};
Copy link

Copilot AI May 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleViewLogs is defined with no parameters but ExecutionHistoryList expects onViewLogs to accept an executionId: string. Either implement log fetching there or remove the unused callback.

Suggested change
const handleViewLogs = () => {};
const handleViewLogs = (executionId: string) => {
console.log(`View logs for execution ID: ${executionId}`);
};

Copilot uses AI. Check for mistakes.

Comment on lines 317 to 318
(jobLog: JobLog, index: number) => (
<div key={index} style={{ marginBottom: '16px' }}>
Copy link

Copilot AI May 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using the array index as a React key can lead to rendering issues if logs change order or new logs are inserted. Use a stable identifier (e.g., jobLog.jobName or a combined ID) instead.

Suggested change
(jobLog: JobLog, index: number) => (
<div key={index} style={{ marginBottom: '16px' }}>
(jobLog: JobLog) => (
<div key={jobLog.jobName} style={{ marginBottom: '16px' }}>

Copilot uses AI. Check for mistakes.

Copy link
Contributor

@prasadtalasila prasadtalasila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Microchesst Thanks for the updates. The feature functionality is much improved and it works as discussed. However, I have a few comments on the existing implementation. Please check the comments. Thanks.

* Interface for IndexedDB operations
*/
class IndexedDBService {
export interface IIndexedDBService {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the name is changed to IExecutionHistory, the ExecutionHistory suffix can be removed from the method names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the code need not know about the use of IndexDB. The interface can be independent of IndexDB and the ExecutionHistory class can include IndexDB inside without letting other parts of the code knowing about it.

<ThemeProvider theme={mdTheme}>
<AuthProvider>
<CssBaseline />
<ExecutionHistoryLoader />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this react component here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of the methods are returning Promise<void>. There are other possible outcomes with the IndexDB operations. Perhaps they should be used to provide meaningful promises?

pipelineId: number; // GitLab pipeline ID
timestamp: number; // Timestamp when the execution was started
status: ExecutionStatus; // Current status of the execution
jobLogs: JobLog[]; // Logs from the execution
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the array collecting logs separately from each of the jobs in a pipeline?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously one button was used for the start and stop actions but now they are separate. The stop is inside History button. Perhaps a HistoryButton.tsx component be placed in src/components/asset. The component responsibility could be:

StartButton.tsx --> manages only start
HistoryButton.tsx --> manages stop and logs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move this to src/components/execution


const intervalId = setInterval(() => {
dispatch(checkRunningExecutions());
}, 10000); // Check every 10 seconds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please give a name to constant and place it in src/model/backend/gitlab/constants.ts

import { RootState } from 'store/store';
import { addOrUpdateLibraryFile } from 'preview/store/libraryConfigFiles.slice';
import { getFilteredFileNames } from 'preview/util/fileUtils';
import { FileState } from '../../../store/file.slice';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paths from src directory

'assets/setAsset',
'assets/deleteAsset',
// Execution history actions
'executionHistory/addExecutionHistoryEntry',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this part be simplified but refactoring the executionHistory.slice and digitaltwin.slice?

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
7.5% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Contributor

@prasadtalasila prasadtalasila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Microchesst you are right about growing size of this PR. There are too many dependencies from src/route/digitaltwins/execution to src/preview. It makes sense to move the dependent files to corresponding locations in src/preview and then proceed with the PR. Hope that decision reduces the time to complete the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename file to executionStatusHandlers.ts and variables to

  1. setButtonText to setLogStatusText
  2. LogButtonDisabled to LogDisabled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These files are importing from preview/. It might take too much of refactoring to remove dependence from preview/ code. If it is so, please place these files in the right location in preview/ itself.

(entries) => entries.find((entry) => entry.id === id),
);

export const selectSelectedExecutionId = (state: RootState) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file depends on IndexDB. Perhaps this should be moved to src/services?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps moving this preview/util will reduce the time required to complete this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants