Skip to content

Commit 65e48c9

Browse files
author
Diler Zaza
committed
feat(stepfunctions): enable hardcoded execution details page
1 parent 3ee7bf2 commit 65e48c9

File tree

7 files changed

+262
-6
lines changed

7 files changed

+262
-6
lines changed

packages/core/package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
"AWS.stepFunctions.executeStateMachine.info.executing": "Starting execution of '{0}' in {1}...",
3333
"AWS.stepFunctions.executeStateMachine.info.started": "Execution started",
3434
"AWS.stepFunctions.executeStateMachine.error.failedToStart": "There was an error starting execution for '{0}', check AWS Toolkit logs for more information.",
35-
"AWS.stepfunctions.viewExecutionDetailsByExecutionARN": "View Execution Details by Execution ARN",
3635
"AWS.stepFunctions.asl.format.enable.desc": "Enables the default formatter used with Amazon States Language files",
3736
"AWS.stepFunctions.asl.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).",
3837
"AWS.stepFunctions.workflowStudio.actions.progressMessage": "Opening asl file in Workflow Studio",
@@ -229,6 +228,7 @@
229228
"AWS.command.stepFunctions.createStateMachineFromTemplate": "Create a new Step Functions state machine",
230229
"AWS.command.stepFunctions.publishStateMachine": "Publish state machine to Step Functions",
231230
"AWS.command.stepFunctions.openWithWorkflowStudio": "Open with Workflow Studio",
231+
"AWS.command.stepFunctions.viewExecutionDetailsByExecutionARN": "View Execution Details by Execution ARN",
232232
"AWS.command.cdk.previewStateMachine": "Render state machine graph from CDK application",
233233
"AWS.command.copyLogResource": "Copy Log Stream or Group",
234234
"AWS.command.saveCurrentLogDataContent": "Save Log to File",

packages/core/src/shared/clients/stepFunctionsClient.ts

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export class DefaultStepFunctionsClient {
2121
if (response.stateMachines) {
2222
yield* response.stateMachines
2323
}
24-
2524
request.nextToken = response.nextToken
2625
} while (request.nextToken)
2726
}
@@ -32,20 +31,88 @@ export class DefaultStepFunctionsClient {
3231
const request: StepFunctions.DescribeStateMachineInput = {
3332
stateMachineArn: arn,
3433
}
35-
3634
const response: StepFunctions.DescribeStateMachineOutput = await client.describeStateMachine(request).promise()
3735

3836
return response
3937
}
4038

39+
public async getStateMachineDetailsForExecution(
40+
arn: string
41+
): Promise<StepFunctions.DescribeStateMachineForExecutionOutput> {
42+
const client = await this.createSdkClient()
43+
44+
const request: StepFunctions.DescribeStateMachineForExecutionInput = {
45+
executionArn: arn,
46+
}
47+
const response: StepFunctions.DescribeStateMachineForExecutionOutput = await client
48+
.describeStateMachineForExecution(request)
49+
.promise()
50+
51+
return response
52+
}
53+
54+
public async getExecutionDetails(arn: string): Promise<StepFunctions.DescribeExecutionOutput> {
55+
const client = await this.createSdkClient()
56+
57+
const request: StepFunctions.DescribeExecutionInput = {
58+
executionArn: arn,
59+
}
60+
const response: StepFunctions.DescribeExecutionOutput = await client.describeExecution(request).promise()
61+
62+
return response
63+
}
64+
65+
public async getMapRunDetails(arn: string): Promise<StepFunctions.DescribeMapRunOutput> {
66+
const client = await this.createSdkClient()
67+
68+
const request: StepFunctions.DescribeMapRunInput = {
69+
mapRunArn: arn,
70+
}
71+
const response: StepFunctions.DescribeMapRunOutput = await client.describeMapRun(request).promise()
72+
73+
return response
74+
}
75+
76+
public async getExecutionHistory(arn: string): Promise<StepFunctions.GetExecutionHistoryOutput> {
77+
const client = await this.createSdkClient()
78+
79+
const request: StepFunctions.GetExecutionHistoryInput = {
80+
executionArn: arn,
81+
}
82+
const response: StepFunctions.GetExecutionHistoryOutput = await client.getExecutionHistory(request).promise()
83+
84+
return response
85+
}
86+
87+
public async reDriveExecution(arn: string): Promise<StepFunctions.RedriveExecutionOutput> {
88+
const client = await this.createSdkClient()
89+
90+
const request: StepFunctions.RedriveExecutionInput = {
91+
executionArn: arn,
92+
}
93+
const response: StepFunctions.RedriveExecutionOutput = await client.redriveExecution(request).promise()
94+
95+
return response
96+
}
97+
98+
public async stopExecution(arn: string): Promise<StepFunctions.StopExecutionOutput> {
99+
const client = await this.createSdkClient()
100+
101+
const request: StepFunctions.StopExecutionInput = {
102+
executionArn: arn,
103+
}
104+
const response: StepFunctions.StopExecutionOutput = await client.stopExecution(request).promise()
105+
106+
return response
107+
}
108+
41109
public async executeStateMachine(arn: string, input?: string): Promise<StepFunctions.StartExecutionOutput> {
42110
const client = await this.createSdkClient()
43111

44112
const request: StepFunctions.StartExecutionInput = {
45113
stateMachineArn: arn,
46114
input: input,
47115
}
48-
49116
const response: StepFunctions.StartExecutionOutput = await client.startExecution(request).promise()
50117

51118
return response

packages/core/src/stepFunctions/executionDetails/executionDetailProvider.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { getLogger } from '../../shared/logger/logger'
88
import request from '../../shared/request'
99
import { ToolkitError } from '../../shared/errors'
1010
import { i18n } from '../../shared/i18n-helper'
11-
import { ComponentType } from '../workflowStudio/types'
11+
import { ComponentType, WorkflowMode } from '../workflowStudio/types'
1212
import { isLocalDev, localhost, cdn } from '../constants/webviewResources'
13+
import { handleMessage, ExecutionDetailsContext } from './handleMessage'
1314

1415
/**
1516
* Provider for Execution Details panels.
@@ -99,10 +100,26 @@ export class ExecutionDetailProvider {
99100
// Set up the content
100101
panel.webview.html = await this.getWebviewContent()
101102

103+
// Create execution details context
104+
const context: ExecutionDetailsContext = {
105+
stateMachineName: executionArn.split(':').pop() || 'Unknown',
106+
mode: WorkflowMode.Readonly, // Execution details are typically read-only
107+
panel,
108+
textDocument: {} as vscode.TextDocument, // Not applicable for execution details
109+
disposables: [],
110+
workSpacePath: '',
111+
defaultTemplatePath: '',
112+
defaultTemplateName: '',
113+
fileStates: {},
114+
loaderNotification: undefined,
115+
fileId: executionArn,
116+
executionArn,
117+
}
118+
102119
// Handle messages from the webview
103120
panel.webview.onDidReceiveMessage(async (message) => {
104121
this.logger.debug('Received message from execution details webview: %O', message)
105-
// Add message handlers as needed
122+
await handleMessage(message, context)
106123
})
107124
} catch (err) {
108125
void vscode.window.showErrorMessage(i18n('AWS.stepFunctions.executionDetails.failed'))
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
/*!
3+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {
8+
Command,
9+
Message,
10+
MessageType,
11+
WebviewContext,
12+
ApiCallRequestMessage,
13+
UnsupportedMessage,
14+
InitResponseMessage,
15+
} from '../workflowStudio/types'
16+
17+
import { WorkflowStudioApiHandler } from '../workflowStudio/workflowStudioApiHandler'
18+
import globals from '../../shared/extensionGlobals'
19+
import { getLogger } from '../../shared/logger/logger'
20+
21+
// Extended context for execution details
22+
export interface ExecutionDetailsContext extends WebviewContext {
23+
executionArn?: string
24+
}
25+
26+
/**
27+
* Handles messages received from the ExecutionDetails webview. Depending on the message type and command,
28+
* calls the appropriate handler function
29+
* @param message The message received from the webview
30+
* @param context The context object containing information about the execution details webview environment
31+
*/
32+
export async function handleMessage(message: Message, context: ExecutionDetailsContext) {
33+
const { command, messageType } = message
34+
if (messageType === MessageType.REQUEST) {
35+
switch (command) {
36+
case Command.INIT:
37+
void initMessageHandler(context)
38+
break
39+
case Command.API_CALL:
40+
void apiCallMessageHandler(message as ApiCallRequestMessage, context)
41+
break
42+
default:
43+
void handleUnsupportedMessage(context, message)
44+
break
45+
}
46+
} else if (messageType === MessageType.BROADCAST) {
47+
switch (command) {
48+
case Command.LOAD_STAGE:
49+
void loadStageMessageHandler(context)
50+
break
51+
default:
52+
void handleUnsupportedMessage(context, message)
53+
break
54+
}
55+
} else {
56+
void handleUnsupportedMessage(context, message)
57+
}
58+
}
59+
60+
/**
61+
* Handler for when the webview is ready.
62+
* This handler is used to initialize the webview with execution details.
63+
* @param context The context object containing the necessary information for the webview.
64+
*/
65+
async function initMessageHandler(context: ExecutionDetailsContext) {
66+
try {
67+
await context.panel.webview.postMessage({
68+
messageType: MessageType.BROADCAST,
69+
command: Command.INIT,
70+
executionArn: context.executionArn,
71+
})
72+
} catch (e) {
73+
await context.panel.webview.postMessage({
74+
messageType: MessageType.RESPONSE,
75+
command: Command.INIT,
76+
isSuccess: false,
77+
failureReason: (e as Error).message,
78+
} as InitResponseMessage)
79+
}
80+
}
81+
82+
/**
83+
* Handler for managing webview stage load, which updates load notifications.
84+
* @param context The context object containing the necessary information for the webview.
85+
*/
86+
async function loadStageMessageHandler(context: ExecutionDetailsContext) {
87+
context.loaderNotification?.progress.report({ increment: 25 })
88+
setTimeout(() => {
89+
context.loaderNotification?.resolve()
90+
}, 100)
91+
}
92+
93+
/**
94+
* Handler for making API calls from the webview and returning the response.
95+
* @param request The request message containing the API to call and the parameters
96+
* @param context The webview context used for returning the API response to the webview
97+
*/
98+
function apiCallMessageHandler(request: ApiCallRequestMessage, context: WebviewContext) {
99+
const logger = getLogger('stepfunctions')
100+
const apiHandler = new WorkflowStudioApiHandler(globals.awsContext.getCredentialDefaultRegion(), context)
101+
apiHandler.performApiCall(request).catch((error) => logger.error('%s API call failed: %O', request.apiName, error))
102+
}
103+
104+
/**
105+
* Handles unsupported or unrecognized messages by sending a response to the webview. Ensures compatibility with future
106+
* commands and message types, preventing issues if the user has an outdated extension version.
107+
* @param context The context object containing information about the webview environment
108+
* @param originalMessage The original message that was not supported
109+
*/
110+
async function handleUnsupportedMessage(context: ExecutionDetailsContext, originalMessage: Message) {
111+
const logger = getLogger('stepfunctions')
112+
113+
logger.warn('Received unsupported message: %O', originalMessage)
114+
115+
await context.panel.webview.postMessage({
116+
messageType: MessageType.RESPONSE,
117+
command: Command.UNSUPPORTED_COMMAND,
118+
originalMessage,
119+
} as UnsupportedMessage)
120+
}

packages/core/src/stepFunctions/workflowStudio/types.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,27 @@ export interface SyncFileRequestMessage extends SaveFileRequestMessage {
9595
export enum ApiAction {
9696
IAMListRoles = 'iam:ListRoles',
9797
SFNTestState = 'sfn:TestState',
98+
SFNDescribeStateMachine = 'sfn:describeStateMachine',
99+
SFNDescribeStateMachineForExecution = 'sfn:describeStateMachineForExecution',
100+
SFNDescribeExecution = 'sfn:describeExecution',
101+
SFNDescribeMapRun = 'sfn:describeMapRun',
102+
SFNGetExecutionHistory = 'sfn:getExecutionHistory',
103+
SFNRedriveExecution = 'sfn:redriveExecution',
104+
SFNStartExecution = 'sfn:startExecution',
105+
SFNStopExecution = 'sfn:stopExecution',
98106
}
99107

100108
type ApiCallRequestMapping = {
101109
[ApiAction.IAMListRoles]: IAM.ListRolesRequest
102110
[ApiAction.SFNTestState]: StepFunctions.TestStateInput
111+
[ApiAction.SFNDescribeStateMachine]: StepFunctions.DescribeStateMachineInput
112+
[ApiAction.SFNDescribeStateMachineForExecution]: StepFunctions.DescribeStateMachineForExecutionInput
113+
[ApiAction.SFNDescribeExecution]: StepFunctions.DescribeExecutionInput
114+
[ApiAction.SFNDescribeMapRun]: StepFunctions.DescribeMapRunInput
115+
[ApiAction.SFNGetExecutionHistory]: StepFunctions.GetExecutionHistoryInput
116+
[ApiAction.SFNRedriveExecution]: StepFunctions.RedriveExecutionInput
117+
[ApiAction.SFNStartExecution]: StepFunctions.StartExecutionInput
118+
[ApiAction.SFNStopExecution]: StepFunctions.StopExecutionInput
103119
}
104120

105121
interface ApiCallRequestMessageBase<ApiName extends ApiAction> extends Message {
@@ -114,3 +130,11 @@ interface ApiCallRequestMessageBase<ApiName extends ApiAction> extends Message {
114130
export type ApiCallRequestMessage =
115131
| ApiCallRequestMessageBase<ApiAction.IAMListRoles>
116132
| ApiCallRequestMessageBase<ApiAction.SFNTestState>
133+
| ApiCallRequestMessageBase<ApiAction.SFNDescribeStateMachine>
134+
| ApiCallRequestMessageBase<ApiAction.SFNDescribeStateMachineForExecution>
135+
| ApiCallRequestMessageBase<ApiAction.SFNDescribeExecution>
136+
| ApiCallRequestMessageBase<ApiAction.SFNDescribeMapRun>
137+
| ApiCallRequestMessageBase<ApiAction.SFNGetExecutionHistory>
138+
| ApiCallRequestMessageBase<ApiAction.SFNRedriveExecution>
139+
| ApiCallRequestMessageBase<ApiAction.SFNStartExecution>
140+
| ApiCallRequestMessageBase<ApiAction.SFNStopExecution>

packages/core/src/stepFunctions/workflowStudio/workflowStudioApiHandler.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ export class WorkflowStudioApiHandler {
3333
case ApiAction.SFNTestState:
3434
response = await this.testState(params)
3535
break
36+
case ApiAction.SFNDescribeStateMachine:
37+
response = await this.clients.sfn.getStateMachineDetails(params.stateMachineArn)
38+
break
39+
case ApiAction.SFNDescribeStateMachineForExecution:
40+
response = await this.clients.sfn.getStateMachineDetailsForExecution(params.executionArn)
41+
break
42+
case ApiAction.SFNDescribeExecution:
43+
response = await this.clients.sfn.getExecutionDetails(params.executionArn)
44+
break
45+
case ApiAction.SFNDescribeMapRun:
46+
response = await this.clients.sfn.getMapRunDetails(params.mapRunArn)
47+
break
48+
case ApiAction.SFNGetExecutionHistory:
49+
response = await this.clients.sfn.getExecutionHistory(params.executionArn)
50+
break
51+
case ApiAction.SFNRedriveExecution:
52+
response = await this.clients.sfn.reDriveExecution(params.executionArn)
53+
break
54+
case ApiAction.SFNStartExecution:
55+
response = await this.clients.sfn.executeStateMachine(params.stateMachineArn, params.input)
56+
break
57+
case ApiAction.SFNStopExecution:
58+
response = await this.clients.sfn.stopExecution(params.executionArn)
59+
break
3660
default:
3761
throw new Error(`Unknown API: ${apiName}`)
3862
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Added Execution Details Page webview"
4+
}

0 commit comments

Comments
 (0)