Skip to content

Commit efeefb8

Browse files
committed
Adds generating patch message to Inspect view
1 parent e946d3e commit efeefb8

File tree

5 files changed

+152
-3
lines changed

5 files changed

+152
-3
lines changed

src/webviews/apps/commitDetails/components/commit-details-app.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ExecuteFileActionCommand,
1919
ExplainRequest,
2020
FetchCommand,
21+
GenerateRequest,
2122
NavigateCommand,
2223
OpenFileCommand,
2324
OpenFileComparePreviousCommand,
@@ -43,6 +44,7 @@ import {
4344
} from '../../../commitDetails/protocol';
4445
import type { IpcMessage } from '../../../protocol';
4546
import { ExecuteCommand } from '../../../protocol';
47+
import type { CreatePatchMetadataEventDetail } from '../../plus/patchDetails/components/gl-patch-create';
4648
import type { IssuePullRequest } from '../../shared/components/rich/issue-pull-request';
4749
import type { WebviewPane, WebviewPaneExpandedChangeEventDetail } from '../../shared/components/webview-pane';
4850
import type { Disposable } from '../../shared/dom';
@@ -51,7 +53,7 @@ import { assertsSerialized, HostIpc } from '../../shared/ipc';
5153
import type { GlCommitDetails } from './gl-commit-details';
5254
import type { FileChangeListItemDetail } from './gl-details-base';
5355
import type { GlInspectNav } from './gl-inspect-nav';
54-
import type { CreatePatchEventDetail } from './gl-inspect-patch';
56+
import type { CreatePatchEventDetail, GenerateState } from './gl-inspect-patch';
5557
import type { GlWipDetails } from './gl-wip-details';
5658
import '../../shared/components/code-icon';
5759
import '../../shared/components/indicators/indicator';
@@ -78,6 +80,9 @@ export class GlCommitDetailsApp extends LitElement {
7880
@property({ type: Object })
7981
explain?: ExplainState;
8082

83+
@property({ type: Object })
84+
generate?: GenerateState;
85+
8186
@state()
8287
draftState: DraftState = { inReview: false };
8388

@@ -253,6 +258,9 @@ export class GlCommitDetailsApp extends LitElement {
253258
DOM.on<GlWipDetails, CreatePatchEventDetail>('gl-wip-details', 'gl-inspect-create-suggestions', e =>
254259
this.onSuggestChanges(e.detail),
255260
),
261+
DOM.on<GlWipDetails, CreatePatchMetadataEventDetail>('gl-wip-details', 'gl-patch-generate-title', e =>
262+
this.onCreateGenerateTitle(e.detail),
263+
),
256264
DOM.on<GlWipDetails, { id: string }>('gl-wip-details', 'gl-show-code-suggestion', e =>
257265
this.onShowCodeSuggestion(e.detail),
258266
),
@@ -507,6 +515,7 @@ export class GlCommitDetailsApp extends LitElement {
507515
.files=${wip?.changes?.files}
508516
.preferences=${this.state?.preferences}
509517
.orgSettings=${this.state?.orgSettings}
518+
.generate=${this.generate}
510519
.isUncommitted=${true}
511520
.emptyText=${'No working changes'}
512521
.draftState=${this.draftState}
@@ -600,6 +609,35 @@ export class GlCommitDetailsApp extends LitElement {
600609
}
601610
}
602611

612+
private async onCreateGenerateTitle(_e: CreatePatchMetadataEventDetail) {
613+
try {
614+
const result = await this._hostIpc.sendRequest(GenerateRequest, undefined);
615+
616+
if (result.error) {
617+
this.generate = { error: { message: result.error.message ?? 'Error retrieving content' } };
618+
} else if (result.title || result.description) {
619+
this.generate = {
620+
title: result.title,
621+
description: result.description,
622+
};
623+
// this.state = {
624+
// ...this.state,
625+
// create: {
626+
// ...this.state.create!,
627+
// title: result.title ?? this.state.create?.title,
628+
// description: result.description ?? this.state.create?.description,
629+
// },
630+
// };
631+
// this.setState(this.state);
632+
} else {
633+
this.generate = undefined;
634+
}
635+
} catch (ex) {
636+
this.generate = { error: { message: 'Error retrieving content' } };
637+
}
638+
this.requestUpdate('generate');
639+
}
640+
603641
private onToggleFilesLayout(e: MouseEvent) {
604642
const layout = ((e.target as HTMLElement)?.dataset.filesLayout as ViewFilesLayout) ?? undefined;
605643
if (layout === this.state?.preferences?.files?.layout) return;

src/webviews/apps/commitDetails/components/gl-inspect-patch.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ export interface CreatePatchEventDetail {
2424
userSelections: DraftUserSelection[] | undefined;
2525
}
2626

27+
export interface GenerateState {
28+
cancelled?: boolean;
29+
error?: { message: string };
30+
title?: string;
31+
description?: string;
32+
}
33+
2734
@customElement('gl-inspect-patch')
2835
export class InspectPatch extends GlElement {
2936
static override styles = [
@@ -33,6 +40,12 @@ export class InspectPatch extends GlElement {
3340
flex: 1;
3441
}
3542
43+
*,
44+
*::before,
45+
*::after {
46+
box-sizing: border-box;
47+
}
48+
3649
a {
3750
color: var(--vscode-textLink-foreground);
3851
text-decoration: none;
@@ -96,6 +109,7 @@ export class InspectPatch extends GlElement {
96109
.message-input {
97110
padding-top: 0.8rem;
98111
}
112+
99113
.message-input__control {
100114
flex: 1;
101115
border: 1px solid var(--vscode-input-border);
@@ -108,6 +122,7 @@ export class InspectPatch extends GlElement {
108122
color: var(--vscode-input-foreground);
109123
font-family: inherit;
110124
}
125+
111126
.message-input__control::placeholder {
112127
color: var(--vscode-input-placeholderForeground);
113128
}
@@ -122,6 +137,12 @@ export class InspectPatch extends GlElement {
122137
outline-offset: -1px;
123138
}
124139
140+
.message-input__control:disabled {
141+
opacity: 0.4;
142+
cursor: not-allowed;
143+
pointer-events: none;
144+
}
145+
125146
.message-input__control--text {
126147
overflow: hidden;
127148
white-space: nowrap;
@@ -170,13 +191,27 @@ export class InspectPatch extends GlElement {
170191
padding-right: 2.4rem;
171192
}
172193
194+
.message-input__menu {
195+
position: absolute;
196+
top: 0.8rem;
197+
right: 0;
198+
}
199+
200+
.section--action > :first-child .message-input__menu {
201+
top: 0;
202+
}
203+
173204
.message-input--group {
174205
display: flex;
175206
flex-direction: row;
176207
align-items: stretch;
177208
gap: 0.6rem;
178209
}
179210
211+
.message-input--with-menu {
212+
position: relative;
213+
}
214+
180215
textarea.message-input__control {
181216
resize: vertical;
182217
min-height: 4rem;
@@ -236,6 +271,9 @@ export class InspectPatch extends GlElement {
236271
@property({ type: Object })
237272
preferences?: Preferences;
238273

274+
@property({ type: Object })
275+
generate?: GenerateState;
276+
239277
@property({ type: Object })
240278
createState?: CreatePatchState;
241279

@@ -250,6 +288,7 @@ export class InspectPatch extends GlElement {
250288
override render() {
251289
return html`<gl-patch-create
252290
.state=${this.patchCreateState}
291+
.generate=${this.generate}
253292
review
254293
@gl-patch-file-compare-working=${(e: CustomEvent) => {
255294
console.log('gl-patch-file-compare-working', e);

src/webviews/apps/commitDetails/components/gl-wip-details.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Avatar, defineGkElement } from '@gitkraken/shared-web-components';
2+
import type { PropertyValueMap } from 'lit';
23
import { css, html, nothing } from 'lit';
34
import { customElement, property, state } from 'lit/decorators.js';
45
import { repeat } from 'lit/directives/repeat.js';
@@ -7,6 +8,7 @@ import type { DraftState, State, Wip } from '../../../commitDetails/protocol';
78
import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base';
89
import type { File } from './gl-details-base';
910
import { GlDetailsBase } from './gl-details-base';
11+
import type { GenerateState } from './gl-inspect-patch';
1012
import '../../shared/components/button';
1113
import '../../shared/components/code-icon';
1214
import '../../shared/components/panes/pane-group';
@@ -33,6 +35,9 @@ export class GlWipDetails extends GlDetailsBase {
3335
@property({ type: Object })
3436
draftState?: DraftState;
3537

38+
@property({ type: Object })
39+
generate?: GenerateState;
40+
3641
@state()
3742
get inReview() {
3843
return this.draftState?.inReview ?? false;
@@ -61,6 +66,12 @@ export class GlWipDetails extends GlDetailsBase {
6166
};
6267
}
6368

69+
@state()
70+
patchCreateMetadata: { title: string | undefined; description: string | undefined } = {
71+
title: undefined,
72+
description: undefined,
73+
};
74+
6475
get patchCreateState() {
6576
const wip = this.wip!;
6677
const key = wip.repo.uri;
@@ -76,8 +87,7 @@ export class GlWipDetails extends GlDetailsBase {
7687
};
7788

7889
return {
79-
title: undefined,
80-
description: undefined,
90+
...this.patchCreateMetadata,
8191
changes: {
8292
[key]: change,
8393
},
@@ -97,6 +107,17 @@ export class GlWipDetails extends GlDetailsBase {
97107
defineGkElement(Avatar);
98108
}
99109

110+
protected override updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
111+
super.updated(changedProperties);
112+
113+
if (changedProperties.has('generate')) {
114+
this.patchCreateMetadata = {
115+
title: this.generate?.title ?? this.patchCreateMetadata.title,
116+
description: this.generate?.description ?? this.patchCreateMetadata.description,
117+
};
118+
}
119+
}
120+
100121
override get filesChangedPaneLabel() {
101122
return 'Working Changes';
102123
}
@@ -317,6 +338,7 @@ export class GlWipDetails extends GlDetailsBase {
317338
return html`<gl-inspect-patch
318339
.orgSettings=${this.orgSettings}
319340
.preferences=${this.preferences}
341+
.generate=${this.generate}
320342
.createState=${this.patchCreateState}
321343
@gl-patch-create-patch=${(e: CustomEvent) => {
322344
// this.onDataActionClick('create-patch');

src/webviews/commitDetails/commitDetailsWebview.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EntityIdentifierUtils } from '@gitkraken/provider-apis';
22
import type { CancellationToken, ConfigurationChangeEvent, TextDocumentShowOptions } from 'vscode';
33
import { CancellationTokenSource, Disposable, env, Uri, window } from 'vscode';
4+
import { extractDraftMessage } from '../../ai/aiProviderService';
45
import type { MaybeEnrichedAutolink } from '../../annotations/autolinks';
56
import { serializeAutolink } from '../../annotations/autolinks';
67
import { getAvatarUri } from '../../avatars';
@@ -70,6 +71,7 @@ import type {
7071
CreatePatchFromWipParams,
7172
DidChangeWipStateParams,
7273
DidExplainParams,
74+
DidGenerateParams,
7375
ExecuteFileActionParams,
7476
GitBranchShape,
7577
Mode,
@@ -94,6 +96,7 @@ import {
9496
ExecuteFileActionCommand,
9597
ExplainRequest,
9698
FetchCommand,
99+
GenerateRequest,
97100
messageHeadlineSplitterToken,
98101
NavigateCommand,
99102
OpenFileCommand,
@@ -462,6 +465,10 @@ export class CommitDetailsWebviewProvider
462465
void this.explainRequest(ExplainRequest, e);
463466
break;
464467

468+
case GenerateRequest.is(e):
469+
void this.generateRequest(GenerateRequest, e);
470+
break;
471+
465472
case StageFileCommand.is(e):
466473
void this.stageFile(e.params);
467474
break;
@@ -1087,6 +1094,40 @@ export class CommitDetailsWebviewProvider
10871094
void this.host.respond(requestType, msg, params);
10881095
}
10891096

1097+
private async generateRequest<T extends typeof GenerateRequest>(requestType: T, msg: IpcCallMessageType<T>) {
1098+
const repo: Repository | undefined = this._context.wip?.repo;
1099+
1100+
if (!repo) {
1101+
void this.host.respond(requestType, msg, { error: { message: 'Unable to find changes' } });
1102+
return;
1103+
}
1104+
1105+
let params: DidGenerateParams;
1106+
1107+
try {
1108+
// TODO@eamodio HACK -- only works for the first patch
1109+
// const patch = await this.getDraftPatch(this._context.draft);
1110+
// if (patch == null) throw new Error('Unable to find patch');
1111+
1112+
// const commit = await this.getOrCreateCommitForPatch(patch.gkRepositoryId);
1113+
// if (commit == null) throw new Error('Unable to find commit');
1114+
1115+
const summary = await (
1116+
await this.container.ai
1117+
)?.generateDraftMessage(repo, {
1118+
progress: { location: { viewId: this.host.id } },
1119+
});
1120+
if (summary == null) throw new Error('Error retrieving content');
1121+
1122+
params = extractDraftMessage(summary);
1123+
} catch (ex) {
1124+
debugger;
1125+
params = { error: { message: ex.message } };
1126+
}
1127+
1128+
void this.host.respond(requestType, msg, params);
1129+
}
1130+
10901131
private navigateStack(direction: 'back' | 'forward') {
10911132
const commit = this._commitStack.navigate(direction);
10921133
if (commit == null) return;

src/webviews/commitDetails/protocol.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ export type DidExplainParams =
209209
| { error: { message: string } };
210210
export const ExplainRequest = new IpcRequest<void, DidExplainParams>(scope, 'explain');
211211

212+
export type DidGenerateParams =
213+
| {
214+
title: string | undefined;
215+
description: string | undefined;
216+
error?: undefined;
217+
}
218+
| { error: { message: string } };
219+
export const GenerateRequest = new IpcRequest<void, DidGenerateParams>(scope, 'generate');
220+
212221
// NOTIFICATIONS
213222

214223
export interface DidChangeParams {

0 commit comments

Comments
 (0)