Skip to content
Open
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
3bcb8a6
feat(dataconnect): add confirmation for Gemini schema generation
google-labs-jules[bot] Oct 8, 2025
ca20d04
prompts
fredzqm Oct 8, 2025
65c3517
changelog
fredzqm Oct 8, 2025
8eacec9
Merge branch 'master' into feat-dataconnect-gemini-confirm
fredzqm Oct 8, 2025
917d677
m
fredzqm Oct 8, 2025
5037519
Merge remote-tracking branch 'origin/feat-dataconnect-gemini-confirm'…
fredzqm Oct 8, 2025
28066b4
feedback
fredzqm Oct 8, 2025
3b198a7
typo
fredzqm Oct 8, 2025
8f56a02
metrics
fredzqm Oct 8, 2025
c262070
Merge branch 'master' into feat-dataconnect-gemini-confirm
fredzqm Oct 9, 2025
c54d915
Update index.ts
fredzqm Oct 9, 2025
de2e555
Merge branch 'master' into feat-dataconnect-gemini-confirm
fredzqm Oct 9, 2025
0fec8de
Add more VS Code metrics
fredzqm Oct 10, 2025
13a45a4
vars edits
fredzqm Oct 10, 2025
264cca7
merge
fredzqm Oct 10, 2025
81d8321
m
fredzqm Oct 10, 2025
b737bda
revert
fredzqm Oct 10, 2025
408ba12
save
fredzqm Oct 10, 2025
b5a280d
sve
fredzqm Oct 11, 2025
3b2c322
save
fredzqm Oct 11, 2025
70f11e6
varsHint
fredzqm Oct 11, 2025
0465394
auth & message
fredzqm Oct 11, 2025
60e602c
nullptr
fredzqm Oct 11, 2025
32ac9d6
fix ui
fredzqm Oct 12, 2025
33a3e12
fix ui
fredzqm Oct 12, 2025
78c1d5c
display
fredzqm Oct 12, 2025
7704556
style
fredzqm Oct 12, 2025
19e04b2
m
fredzqm Oct 12, 2025
5fce3cb
m
fredzqm Oct 12, 2025
e7160a4
rename
fredzqm Oct 12, 2025
68a4308
update params when history entry is selected
fredzqm Oct 13, 2025
5c63261
rerun in result view
fredzqm Oct 13, 2025
47fb77e
css
fredzqm Oct 13, 2025
b17202a
css
fredzqm Oct 13, 2025
d18149f
tweaks
fredzqm Oct 13, 2025
c22811a
fix
fredzqm Oct 13, 2025
2e8baae
tweaks
fredzqm Oct 13, 2025
de80467
polish
fredzqm Oct 13, 2025
740f7b3
clean
fredzqm Oct 13, 2025
fec96f4
rename
fredzqm Oct 13, 2025
3ab012f
rename
fredzqm Oct 13, 2025
f26d990
rename
fredzqm Oct 13, 2025
b04ed2a
m
fredzqm Oct 13, 2025
af3e7e8
Merge branch 'master' into fz/vscode-edit-vars
fredzqm Oct 13, 2025
9ab24dc
Merge branch 'master' into fz/vscode-edit-vars
fredzqm Oct 13, 2025
cdca6f2
changelog
fredzqm Oct 13, 2025
baf8aa3
Update firebase-vscode/webviews/data-connect/data-connect-execution-p…
fredzqm Oct 13, 2025
f2f428d
feedbacks
fredzqm Oct 13, 2025
71b5168
nits
fredzqm Oct 13, 2025
fad60fe
m
fredzqm Oct 13, 2025
67c60a4
m
fredzqm Oct 13, 2025
ec5a264
m
fredzqm Oct 13, 2025
8ea9345
m
fredzqm Oct 13, 2025
1456d18
merge
fredzqm Oct 14, 2025
cc8021a
Merge branch 'master' into fz/vscode-edit-vars
fredzqm Oct 14, 2025
6e9b538
Merge remote-tracking branch 'origin/master' into fz/vscode-edit-vars
fredzqm Oct 14, 2025
f9a4a50
Merge remote-tracking branch 'origin/master' into fz/vscode-edit-vars
fredzqm Oct 15, 2025
2318b8f
apply previous change
fredzqm Oct 15, 2025
20b5961
m
fredzqm Oct 15, 2025
5050106
feat: Ignore test output artifacts
fredzqm Oct 15, 2025
7d3383f
m
fredzqm Oct 15, 2025
5111f04
m
fredzqm Oct 15, 2025
bbfaa74
test
fredzqm Oct 15, 2025
b152886
imports
fredzqm Oct 15, 2025
7837c69
test-fix
fredzqm Oct 15, 2025
a339a81
Merge remote-tracking branch 'origin/master' into fz/vscode-edit-vars
fredzqm Oct 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions firebase-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## NEXT

- [Fixed] Populate correct default values of missing required variables.
- [Added] Display the execution variables and auth params used.
- [Added] Allow rerun any executions in the history.

## 1.9.0

- [Added] Refine / Generate Operation Code Lens.
Expand Down
35 changes: 20 additions & 15 deletions firebase-vscode/common/messaging/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ import { EmulatorsStatus, RunningEmulatorInfo } from "./types";
import { ExecutionResult } from "graphql";
import { SerializedError } from "../error";

export enum UserMockKind {
export enum AuthParamsKind {
ADMIN = "admin",
UNAUTHENTICATED = "unauthenticated",
AUTHENTICATED = "authenticated",
}
export type UserMock =
| { kind: UserMockKind.ADMIN | UserMockKind.UNAUTHENTICATED }

export const EXAMPLE_CLAIMS = `{
"email_verified": true,
"sub": "exampleUserId"
}`;

export type AuthParams =
| { kind: AuthParamsKind.ADMIN | AuthParamsKind.UNAUTHENTICATED }
| {
kind: UserMockKind.AUTHENTICATED;
kind: AuthParamsKind.AUTHENTICATED;
claims: string;
};

Expand Down Expand Up @@ -84,13 +90,13 @@ export interface WebviewToExtensionParamsMap {

selectEmulatorImportFolder: {};

definedDataConnectArgs: string;
/** Execution parameters */
defineVariables: string;
defineAuthParams: AuthParams;

/** Prompts the user to select a directory in which to place the quickstart */
chooseQuickstartDir: {};

notifyAuthUserMockChange: UserMock;

/** Deploy connectors/services to production */
"fdc.deploy": void;

Expand Down Expand Up @@ -130,10 +136,11 @@ export interface WebviewToExtensionParamsMap {
}

export interface DataConnectResults {
query: string;
displayName: string;
results?: ExecutionResult | SerializedError;
args?: string;
query: string;
results: ExecutionResult | SerializedError;
variables: string;
auth: AuthParams;
}

export type ValueOrError<T> =
Expand Down Expand Up @@ -185,13 +192,11 @@ export interface ExtensionToWebviewParamsMap {
*/
notifyPreviewChannelResponse: { id: string };

// data connect specific
notifyDataConnectArgs: string;

/** Update execution parameters and results panels */
notifyVariables: { variables: string, fixes: string[] };
notifyAuthParams: AuthParams;
notifyDataConnectResults: DataConnectResults;

notifyLastOperation: string;

notifyIsLoadingUser: boolean;

notifyDocksLink: string;
Expand Down
15 changes: 8 additions & 7 deletions firebase-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,21 @@
"firebase-data-connect-execution-view": [
{
"type": "webview",
"id": "data-connect-execution-configuration",
"name": "Configuration",
"when": "firebase-vscode.fdc.enabled"
},
{
"id": "data-connect-execution-history",
"name": "History",
"id": "data-connect-execution-parameters",
"name": "Parameters",
"when": "firebase-vscode.fdc.enabled"
},
{
"type": "webview",
"id": "data-connect-execution-results",
"name": "Results",
"when": "firebase-vscode.fdc.enabled"
},
{
"id": "data-connect-execution-history",
"name": "History",
"when": "firebase-vscode.fdc.enabled",
"visibility": "collapsed"
}
]
},
Expand Down
6 changes: 5 additions & 1 deletion firebase-vscode/src/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ export enum DATA_CONNECT_EVENT_NAME {
RUN_PROD_MUTATION_WARNING_REJECTED = "run_prod_mutation_warning_rejected",
RUN_PROD_MUTATION_WARNING_ACKED = "run_prod_mutation_warning_acked",
RUN_PROD_MUTATION_WARNING_ACKED_ALWAYS = "run_prod_mutation_warning_acked_always",
MISSING_VARIABLES = "missing_variables",
RUN_AUTH_ADMIN = "run_auth_admin",
RUN_AUTH_UNAUTHENTICATED = "run_auth_unauthenticated",
RUN_AUTH_AUTHENTICATED = "run_auth_authenticated",
RUN_UNDEFINED_VARIABLES = "run_undefined_variables",
RUN_MISSING_VARIABLES = "run_missing_variables",
GENERATE_OPERATION = "generate_operation",
GIF_TOS_MODAL = "gif_tos_modal",
GIF_TOS_MODAL_ACKED = "gif_tos_modal_acked",
Expand Down
23 changes: 0 additions & 23 deletions firebase-vscode/src/auth/service.ts

This file was deleted.

12 changes: 6 additions & 6 deletions firebase-vscode/src/data-connect/ad-hoc-mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,16 @@ function getDefaultScalarValueNode(type: string): ValueNode | undefined {
}
}

export function getDefaultScalarValue(type: string): string {
export function getDefaultScalarValue(type: string): any {
switch (type) {
case "Boolean":
return "false";
return false;
case "Date":
return new Date().toISOString().substring(0, 10);
case "Float":
return "0";
return 0.0;
case "Int":
return "0";
return 0;
case "Int64":
return "0";
case "String":
Expand All @@ -303,8 +303,8 @@ export function getDefaultScalarValue(type: string): string {
case "UUID":
return "11111111222233334444555555555555";
case "Vector":
return "[]";
return [1.1, 2.2, 3.3];
default:
return "";
return undefined;
}
}
46 changes: 27 additions & 19 deletions firebase-vscode/src/data-connect/code-lens-provider.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import * as vscode from "vscode";
import { Kind, parse } from "graphql";
import { OperationLocation } from "./types";
import { Disposable } from "vscode";

import { Signal } from "@preact/signals-core";
import { dataConnectConfigs, firebaseRC } from "./config";
import { EmulatorsController } from "../core/emulators";
import { GenerateOperationInput } from "./execution/execution";
import { ExecutionInput, GenerateOperationInput } from "./execution/execution";
import { findCommentsBlocks } from "../utils/find_comments";

export enum InstanceType {
Expand Down Expand Up @@ -91,31 +90,40 @@ export class OperationCodeLensProvider extends ComputedCodeLensProvider {
const line = x.loc.startToken.line - 1;
const range = new vscode.Range(line, 0, line, 0);
const position = new vscode.Position(line, 0);
const operationLocation: OperationLocation = {
document: documentText,
documentPath: document.fileName,
position: position,
};
const service = fdcConfigs.findEnclosingServiceForPath(
document.fileName,
);
const service = fdcConfigs.findEnclosingServiceForPath(document.fileName);
if (service) {
codeLenses.push(
new vscode.CodeLens(range, {
title: `$(play) Run (local)`,
command: "firebase.dataConnect.executeOperation",
tooltip: "Execute the operation (⌘+enter or Ctrl+Enter)",
arguments: [x, operationLocation, InstanceType.LOCAL],
}),
);
{
const arg: ExecutionInput = {
operationAst: x,
document: documentText,
documentPath: document.fileName,
position: position,
instance: InstanceType.LOCAL,
};
codeLenses.push(
new vscode.CodeLens(range, {
title: `$(play) Run (local)`,
command: "firebase.dataConnect.executeOperation",
tooltip: "Execute the operation (⌘+enter or Ctrl+Enter)",
arguments: [arg],
}),
);
}

if (projectId) {
const arg: ExecutionInput = {
operationAst: x,
document: documentText,
documentPath: document.fileName,
position: position,
instance: InstanceType.PRODUCTION,
};
codeLenses.push(
new vscode.CodeLens(range, {
title: `$(play) Run (Production – Project: ${projectId})`,
command: "firebase.dataConnect.executeOperation",
tooltip: "Execute the operation (⌘+enter or Ctrl+Enter)",
arguments: [x, operationLocation, InstanceType.PRODUCTION],
arguments: [arg],
}),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class ExecutionTreeItem extends vscode.TreeItem {
this.item = item;

// Renders arguments in a single line
const prettyArgs = this.item.args?.replaceAll(/[\n \t]+/g, " ");
const prettyArgs = this.item.variables?.replaceAll(/[\n \t]+/g, " ");
this.description = `${timeFormatter.format(
item.timestamp
)} | Arguments: ${prettyArgs}`;
Expand Down
118 changes: 118 additions & 0 deletions firebase-vscode/src/data-connect/execution/execution-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { print, Kind, OperationDefinitionNode } from "graphql";
import { globalSignal } from "../../utils/globals";
import { getDefaultScalarValue } from "../ad-hoc-mutations";
import { AuthParams, AuthParamsKind } from "../../../common/messaging/protocol";
import { Impersonation } from "../../dataconnect/types";
import { Disposable } from "vscode";
import { ExtensionBrokerImpl } from "../../extension-broker";
import { AnalyticsLogger, DATA_CONNECT_EVENT_NAME } from "../../analytics";

/**
* Contains the unparsed JSON object mutation/query variables.
* The JSON may be invalid.
*/
export const executionArgsJSON = globalSignal("{}");
export const executionAuthParams = globalSignal<AuthParams>({kind: AuthParamsKind.ADMIN});

export class ExecutionParamsService implements Disposable {
constructor(readonly broker: ExtensionBrokerImpl, readonly analyticsLogger: AnalyticsLogger) {
this.disposable.push({
dispose: broker.on(
"defineAuthParams",
(auth) => (executionAuthParams.value = auth)
),
});
this.disposable.push({
dispose: broker.on(
"defineVariables",
(value) => (executionArgsJSON.value = value),
)
});
}

disposable: Disposable[] = [];

dispose() {
for (const disposable of this.disposable) {
disposable.dispose();
}
}

executeGraphqlVariables(): Record<string, any> {
const variables = executionArgsJSON.value;
if (!variables) {
return {};
}
try {
return JSON.parse(variables);
} catch (e: any) {
throw new Error(
"Unable to parse variables as JSON. Check the variables pane.\n" + e.message,
);
}
}

executeGraphqlExtensions(): { impersonate?: Impersonation } {
const auth = executionAuthParams.value;
switch (auth.kind) {
case AuthParamsKind.ADMIN:
this.analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.RUN_AUTH_ADMIN);
return {};
case AuthParamsKind.UNAUTHENTICATED:
this.analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.RUN_AUTH_UNAUTHENTICATED);
return { impersonate: { unauthenticated: true, includeDebugDetails: true } };
case AuthParamsKind.AUTHENTICATED:
this.analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.RUN_AUTH_AUTHENTICATED);
try {
return {
impersonate:
{ authClaims: JSON.parse(auth.claims), includeDebugDetails: true }
};
} catch (e: any) {
throw new Error(
"Unable to parse auth claims as JSON. Check the authentication panel.\n" + e.message,
);
}
default:
throw new Error(`Unknown auth params kind: ${auth}`);
}
}

async applyDetectedFixes(ast: OperationDefinitionNode): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be great to unit test this file/function specifically, ensuring it doesn't overwrite user set varisbles.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great suggestion.

With gemini CLI's help, just added a unit test for it~

const userVars = this.executeGraphqlVariables();
const fixes = [];
{
const undefinedVars = [];
for (const varName in userVars) {
if (!ast.variableDefinitions?.find((v) => v.variable.name.value === varName)) {
delete userVars[varName];
undefinedVars.push(varName);
}
}
if (undefinedVars.length > 0) {
this.analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.RUN_UNDEFINED_VARIABLES);
fixes.push(`Removed undefined variables: ${undefinedVars.map((v) => "$" + v).join(", ")}.`);
}
}
{
const missingRequiredVars = [];
for (const variable of ast.variableDefinitions || []) {
const varName = variable.variable.name.value;
if (variable.type.kind === Kind.NON_NULL_TYPE && userVars[varName] === undefined) {
userVars[varName] = getDefaultScalarValue(print(variable.type.type));
missingRequiredVars.push(varName);
}
}
if (missingRequiredVars.length > 0) {
this.analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.RUN_MISSING_VARIABLES);
fixes.push(`Included required variables: ${missingRequiredVars.map((v) => "$" + v).join(", ")}.`);
}
}
if (fixes.length === 0) {
return;
}
executionArgsJSON.value = JSON.stringify(userVars, null, 2);
this.broker.send("notifyVariables", { variables: executionArgsJSON.value, fixes });
return;
}
}
Loading
Loading