Skip to content

Commit 11883b0

Browse files
committed
modify job status table to show transformation history; store diff patches locally; write history details to local log file
1 parent 187f27a commit 11883b0

File tree

9 files changed

+161
-14
lines changed

9 files changed

+161
-14
lines changed

packages/amazonq/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@
746746
},
747747
{
748748
"command": "aws.amazonq.showHistoryInHub",
749-
"title": "%AWS.command.q.transform.viewJobStatus%"
749+
"title": "%AWS.command.q.transform.viewJobHistory%"
750750
},
751751
{
752752
"command": "aws.amazonq.selectCustomization",

packages/core/package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@
281281
"AWS.command.q.transform.rejectChanges": "Reject",
282282
"AWS.command.q.transform.stopJobInHub": "Stop job",
283283
"AWS.command.q.transform.viewJobProgress": "View job progress",
284-
"AWS.command.q.transform.viewJobStatus": "View job status",
284+
"AWS.command.q.transform.viewJobHistory": "View job history",
285285
"AWS.command.q.transform.showTransformationPlan": "View plan",
286286
"AWS.command.q.transform.showChangeSummary": "View summary",
287287
"AWS.command.threatComposer.createNew": "Create New Threat Composer File",

packages/core/src/amazonqGumby/chat/controller/controller.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
5858
import { getAuthType } from '../../../auth/utils'
5959
import fs from '../../../shared/fs/fs'
60+
import { setContext } from '../../../shared/vscode/setContext'
6061

6162
// These events can be interactions within the chat,
6263
// or elsewhere in the IDE
@@ -188,6 +189,8 @@ export class GumbyController {
188189
}
189190

190191
private async transformInitiated(message: any) {
192+
this.messenger.sendViewHistoryMessage(message.tabID)
193+
191194
// silently check for projects eligible for SQL conversion
192195
let embeddedSQLProjects: TransformationCandidateProject[] = []
193196
try {
@@ -383,6 +386,11 @@ export class GumbyController {
383386
case ButtonActions.VIEW_TRANSFORMATION_HUB:
384387
await vscode.commands.executeCommand(GumbyCommands.FOCUS_TRANSFORMATION_HUB, CancelActionPositions.Chat)
385388
break
389+
case ButtonActions.VIEW_JOB_HISTORY:
390+
await setContext('gumby.wasQCodeTransformationUsed', true)
391+
await vscode.commands.executeCommand(GumbyCommands.FOCUS_TRANSFORMATION_HUB)
392+
await vscode.commands.executeCommand(GumbyCommands.FOCUS_JOB_HISTORY, CancelActionPositions.Chat)
393+
break
386394
case ButtonActions.VIEW_SUMMARY:
387395
await vscode.commands.executeCommand('aws.amazonq.transformationHub.summary.reveal')
388396
break

packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,27 @@ export class Messenger {
377377
this.dispatcher.sendChatMessage(jobSubmittedMessage)
378378
}
379379

380+
public sendViewHistoryMessage(tabID: string) {
381+
const buttons: ChatItemButton[] = []
382+
383+
buttons.push({
384+
keepCardAfterClick: true,
385+
text: 'Open job history',
386+
id: ButtonActions.VIEW_JOB_HISTORY,
387+
disabled: false,
388+
})
389+
390+
const message = new ChatMessage(
391+
{
392+
message: 'View previous transformations run from the IDE',
393+
messageType: 'ai-prompt',
394+
buttons,
395+
},
396+
tabID
397+
)
398+
this.dispatcher.sendChatMessage(message)
399+
}
400+
380401
public sendMessage(prompt: string, tabID: string, type: 'prompt' | 'ai-prompt') {
381402
this.dispatcher.sendChatMessage(
382403
new ChatMessage(

packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import DependencyVersions from '../../../models/dependencies'
1313
export enum ButtonActions {
1414
STOP_TRANSFORMATION_JOB = 'gumbyStopTransformationJob',
1515
VIEW_TRANSFORMATION_HUB = 'gumbyViewTransformationHub',
16+
VIEW_JOB_HISTORY = 'gumbyViewJobHistory',
1617
VIEW_SUMMARY = 'gumbyViewSummary',
1718
CONFIRM_LANGUAGE_UPGRADE_TRANSFORMATION_FORM = 'gumbyLanguageUpgradeTransformFormConfirm',
1819
CONFIRM_SQL_CONVERSION_TRANSFORMATION_FORM = 'gumbySQLConversionTransformFormConfirm',
@@ -33,6 +34,7 @@ export enum GumbyCommands {
3334
CLEAR_CHAT = 'aws.awsq.clearchat',
3435
START_TRANSFORMATION_FLOW = 'aws.awsq.transform',
3536
FOCUS_TRANSFORMATION_HUB = 'aws.amazonq.showTransformationHub',
37+
FOCUS_JOB_HISTORY = 'aws.amazonq.showHistoryInHub',
3638
}
3739

3840
export default class MessengerUtils {

packages/core/src/codewhisperer/commands/startTransformByQ.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
TransformationType,
2121
TransformationCandidateProject,
2222
RegionProfile,
23+
sessionJobHistory,
2324
} from '../models/model'
2425
import {
2526
createZipManifest,
@@ -78,6 +79,7 @@ import { convertDateToTimestamp } from '../../shared/datetime'
7879
import { findStringInDirectory } from '../../shared/utilities/workspaceUtils'
7980
import { makeTemporaryToolkitFolder } from '../../shared/filesystemUtilities'
8081
import { AuthUtil } from '../util/authUtil'
82+
import { homedir } from 'os'
8183

8284
export function getFeedbackCommentData() {
8385
const jobId = transformByQState.getJobId()
@@ -739,6 +741,33 @@ export async function postTransformationJob() {
739741
if (transformByQState.isSucceeded() || transformByQState.isPartiallySucceeded()) {
740742
await vscode.commands.executeCommand('aws.amazonq.transformationHub.reviewChanges.startReview')
741743
}
744+
745+
// store job details and diff path locally (history)
746+
// TODO: ideally when job is cancelled, should be stored as CANCELLED instead of FAILED (remove this if statement after bug is fixed)
747+
if (!transformByQState.isCancelled()) {
748+
const jobHistoryFilePath = path.join(homedir(), '.aws', 'transform', 'transformation-history.tsv')
749+
// create transform folder if necessary
750+
if (!fs.existsSync(jobHistoryFilePath)) {
751+
fs.mkdirSync(path.dirname(jobHistoryFilePath), { recursive: true })
752+
// create headers of new transformation history file
753+
fs.writeFileSync(jobHistoryFilePath, 'date\tproject_name\tstatus\tduration\tdiff_path\tjob_id\n')
754+
}
755+
const latest = sessionJobHistory[transformByQState.getJobId()]
756+
const jobDetails: string =
757+
latest.startTime +
758+
'\t' +
759+
latest.projectName +
760+
'\t' +
761+
latest.status +
762+
'\t' +
763+
latest.duration +
764+
'\t' +
765+
transformByQState.getDiffPatchFilePath() +
766+
'\t' +
767+
transformByQState.getJobId() +
768+
'\n'
769+
fs.writeFileSync(jobHistoryFilePath, jobDetails, { flag: 'a' })
770+
}
742771
}
743772

744773
export async function transformationJobErrorHandler(error: any) {

packages/core/src/codewhisperer/models/model.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ export class TransformByQState {
730730
private planFilePath: string = ''
731731
private summaryFilePath: string = ''
732732
private preBuildLogFilePath: string = ''
733+
private diffPatchFilePath: string = ''
733734

734735
private resultArchiveFilePath: string = ''
735736
private projectCopyFilePath: string = ''
@@ -881,6 +882,10 @@ export class TransformByQState {
881882
return this.summaryFilePath
882883
}
883884

885+
public getDiffPatchFilePath() {
886+
return this.diffPatchFilePath
887+
}
888+
884889
public getResultArchiveFilePath() {
885890
return this.resultArchiveFilePath
886891
}
@@ -1055,6 +1060,10 @@ export class TransformByQState {
10551060
this.summaryFilePath = filePath
10561061
}
10571062

1063+
public setDiffPatchFilePath(filePath: string) {
1064+
return (this.diffPatchFilePath = filePath)
1065+
}
1066+
10581067
public setResultArchiveFilePath(filePath: string) {
10591068
this.resultArchiveFilePath = filePath
10601069
}

packages/core/src/codewhisperer/service/transformByQ/transformationHubViewProvider.ts

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import { startInterval } from '../../commands/startTransformByQ'
2424
import { CodeTransformTelemetryState } from '../../../amazonqGumby/telemetry/codeTransformTelemetryState'
2525
import { convertToTimeString } from '../../../shared/datetime'
2626
import { AuthUtil } from '../../util/authUtil'
27+
import fs from 'fs'
28+
import path from 'path'
29+
import { homedir } from 'os'
2730

2831
export class TransformationHubViewProvider implements vscode.WebviewViewProvider {
2932
public static readonly viewType = 'aws.amazonq.transformationHub'
@@ -88,6 +91,48 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
8891
}
8992

9093
private showJobHistory(): string {
94+
const history: {
95+
startTime: string
96+
projectName: string
97+
status: string
98+
duration: string
99+
diffPath: string
100+
jobId: string
101+
}[] = []
102+
const jobHistoryFilePath = path.join(homedir(), '.aws', 'transform', 'transformation-history.tsv')
103+
if (fs.existsSync(jobHistoryFilePath)) {
104+
const historyFile = fs.readFileSync(jobHistoryFilePath, { encoding: 'utf8', flag: 'r' })
105+
const jobs = historyFile.split('\n')
106+
jobs.shift() // removes headers
107+
if (jobs.length > 0) {
108+
jobs.forEach((job) => {
109+
if (job) {
110+
const jobInfo = job.split('\t')
111+
const jobObject = {
112+
startTime: jobInfo[0],
113+
projectName: jobInfo[1],
114+
status: jobInfo[2],
115+
duration: jobInfo[3],
116+
diffPath: jobInfo[4],
117+
jobId: jobInfo[5],
118+
}
119+
history.push(jobObject)
120+
}
121+
})
122+
}
123+
}
124+
if (transformByQState.isRunning()) {
125+
const current = sessionJobHistory[transformByQState.getJobId()]
126+
history.push({
127+
startTime: current.startTime,
128+
projectName: current.projectName,
129+
status: current.status,
130+
duration: current.duration,
131+
diffPath: transformByQState.getDiffPatchFilePath(),
132+
jobId: transformByQState.getJobId(),
133+
})
134+
}
135+
history.reverse() // to show in descending order, chronologically
91136
return `<!DOCTYPE html>
92137
<html lang="en">
93138
<head>
@@ -99,17 +144,26 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
99144
</style>
100145
</head>
101146
<body>
102-
<p><b>Transformation Status</b></p>
147+
<p><b>Transformation History</b></p>
103148
${
104-
Object.keys(sessionJobHistory).length === 0
149+
history.length === 0
105150
? `<p>${CodeWhispererConstants.nothingToShowMessage}</p>`
106-
: this.getTableMarkup(sessionJobHistory[transformByQState.getJobId()])
151+
: this.getTableMarkup(history)
107152
}
108153
</body>
109154
</html>`
110155
}
111156

112-
private getTableMarkup(job: { startTime: string; projectName: string; status: string; duration: string }) {
157+
private getTableMarkup(
158+
history: {
159+
startTime: string
160+
projectName: string
161+
status: string
162+
duration: string
163+
diffPath: string
164+
jobId: string
165+
}[]
166+
) {
113167
return `
114168
<table border="1" style="border-collapse:collapse">
115169
<thead>
@@ -118,17 +172,25 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
118172
<th>Project</th>
119173
<th>Status</th>
120174
<th>Duration</th>
121-
<th>Id</th>
175+
<th>Diff Path</th>
176+
<th>Job Id</th>
122177
</tr>
123178
</thead>
124179
<tbody>
125-
<tr>
126-
<td>${job.startTime}</td>
127-
<td>${job.projectName}</td>
128-
<td>${job.status}</td>
129-
<td>${job.duration}</td>
130-
<td>${transformByQState.getJobId()}</td>
131-
</tr>
180+
${history
181+
.map(
182+
(job) => `
183+
<tr>
184+
<td>${job.startTime}</td>
185+
<td>${job.projectName}</td>
186+
<td>${job.status}</td>
187+
<td>${job.duration}</td>
188+
<td><a href="vscode://file${job.diffPath}">${job.diffPath}</a></td>
189+
<td>${job.jobId}</td>
190+
</tr>
191+
`
192+
)
193+
.join('')}
132194
</tbody>
133195
</table>
134196
`

packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,29 @@ export class ProposedTransformationExplorer {
426426
let deserializeErrorMessage = undefined
427427
let pathContainingArchive = ''
428428
patchFiles = [] // reset patchFiles if there was a previous transformation
429+
430+
// create transform, project, and job folders if needed (to store diff patch)
431+
const jobDiffPath = path.join(
432+
os.homedir(),
433+
'.aws',
434+
'transform',
435+
transformByQState.getProjectName(),
436+
transformByQState.getJobId(),
437+
'diff.patch'
438+
)
439+
if (!fs.existsSync(jobDiffPath)) {
440+
fs.mkdirSync(path.dirname(jobDiffPath), { recursive: true })
441+
}
442+
transformByQState.setDiffPatchFilePath(jobDiffPath)
443+
429444
try {
430445
// Download and deserialize the zip
431446
pathContainingArchive = path.dirname(pathToArchive)
432447
const zip = new AdmZip(pathToArchive)
433448
zip.extractAllTo(pathContainingArchive)
434449
const files = fs.readdirSync(path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch))
435450
singlePatchFile = path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch, files[0])
451+
fs.copyFileSync(singlePatchFile, transformByQState.getDiffPatchFilePath()) // store diff patch locally
436452
patchFiles.push(singlePatchFile)
437453
diffModel.parseDiff(patchFiles[0], transformByQState.getProjectPath())
438454

0 commit comments

Comments
 (0)