@@ -35,8 +35,11 @@ import { InstanceType } from "../code-lens-provider";
35
35
import { DATA_CONNECT_EVENT_NAME , AnalyticsLogger } from "../../analytics" ;
36
36
import { getDefaultScalarValue } from "../ad-hoc-mutations" ;
37
37
import { EmulatorsController } from "../../core/emulators" ;
38
- import { getConnectorGQLText } from "../file-utils" ;
38
+ import { getConnectorGQLText , insertQueryAt } from "../file-utils" ;
39
39
import { pluginLogger } from "../../logger-wrapper" ;
40
+ import * as gif from "../../../../src/gemini/fdcExperience" ;
41
+ import { ensureGIFApiTos } from "../../../../src/dataconnect/ensureApis" ;
42
+ import { configstore } from "../../../../src/configstore" ;
40
43
41
44
interface TypedInput {
42
45
varName : string ;
@@ -49,6 +52,14 @@ interface ExecutionInput {
49
52
instance : InstanceType ;
50
53
}
51
54
55
+ export interface GenerateOperationInput {
56
+ projectId : string ;
57
+ document : vscode . TextDocument ;
58
+ description : string ;
59
+ insertPosition : number ;
60
+ existingQuery : string ;
61
+ }
62
+
52
63
export const lastExecutionInputSignal = new Signal < ExecutionInput | null > ( null ) ;
53
64
54
65
export function registerExecution (
@@ -302,6 +313,54 @@ export function registerExecution(
302
313
}
303
314
}
304
315
316
+ async function generateOperation ( arg : GenerateOperationInput ) {
317
+ try {
318
+ const schema = await dataConnectService . schema ( ) ;
319
+ const prompt = `Generate a Data Connect operation to match this description: ${ arg . description }
320
+ ${ arg . existingQuery ? `\n\nRefine this existing operation:\n${ arg . existingQuery } ` : '' }
321
+ ${ schema ? `\n\nUse the Data Connect Schema:\n\`\`\`graphql
322
+ ${ schema }
323
+ \`\`\`` : "" } `;
324
+ const serviceName = await dataConnectService . servicePath ( arg . document . fileName ) ;
325
+ if ( ! ( await ensureGIFApiTos ( arg . projectId ) ) ) {
326
+ if ( ! ( await showGiFToSModal ( arg . projectId ) ) ) {
327
+ return ; // ToS isn't accepted.
328
+ }
329
+ }
330
+ const res = await gif . generateOperation ( prompt , serviceName , arg . projectId ) ;
331
+ await insertQueryAt ( arg . document . uri , arg . insertPosition , arg . existingQuery , res ) ;
332
+ } catch ( e : any ) {
333
+ vscode . window . showErrorMessage ( `Failed to generate query: ${ e . message } ` ) ;
334
+ }
335
+ }
336
+
337
+ async function showGiFToSModal ( projectId : string ) : Promise < boolean > {
338
+ const tos = "Terms of Service" ;
339
+ const enable = "Enable" ;
340
+ const result = await vscode . window . showWarningMessage (
341
+ "Gemini in Firebase" ,
342
+ {
343
+ modal : ! process . env . VSCODE_TEST_MODE ,
344
+ detail : "Gemini in Firebase helps you write Data Connect queries." ,
345
+ } ,
346
+ enable ,
347
+ tos ,
348
+ ) ;
349
+ switch ( result ) {
350
+ case enable :
351
+ configstore . set ( "gemini" , true ) ;
352
+ await ensureGIFApiTos ( projectId ) ;
353
+ return true ;
354
+ case tos :
355
+ vscode . env . openExternal (
356
+ vscode . Uri . parse (
357
+ "https://firebase.google.com/docs/gemini-in-firebase#how-gemini-in-firebase-uses-your-data" ,
358
+ ) ,
359
+ ) ;
360
+ }
361
+ return false ;
362
+ }
363
+
305
364
const sub4 = broker . on (
306
365
"definedDataConnectArgs" ,
307
366
( value ) => ( executionArgsJSON . value = value ) ,
@@ -333,7 +392,16 @@ export function registerExecution(
333
392
: DATA_CONNECT_EVENT_NAME . RUN_PROD ,
334
393
) ;
335
394
await vscode . window . activeTextEditor ?. document . save ( ) ;
336
- executeOperation ( ast , location , instanceType ) ;
395
+ await executeOperation ( ast , location , instanceType ) ;
396
+ } ,
397
+ ) ,
398
+ vscode . commands . registerCommand (
399
+ "firebase.dataConnect.generateOperation" ,
400
+ async ( arg : GenerateOperationInput ) => {
401
+ analyticsLogger . logger . logUsage (
402
+ DATA_CONNECT_EVENT_NAME . GENERATE_OPERATION ,
403
+ ) ;
404
+ await generateOperation ( arg ) ;
337
405
} ,
338
406
) ,
339
407
vscode . commands . registerCommand (
0 commit comments