Skip to content

Commit

Permalink
Merge branch 'master' into leoortizz/frameworksActionFixes
Browse files Browse the repository at this point in the history
  • Loading branch information
leoortizz committed May 8, 2024
2 parents 9d74393 + 652b0d0 commit 6db3e92
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 132 deletions.
10 changes: 10 additions & 0 deletions firebase-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Change Log

## 0.1.8

- Update Extensions page Logo
- Update README for Extensions page
- Emulator Bump 1.1.15

## 0.1.7

- Emulator Bump 1.1.14

## 0.1.6

- Fix deploy command
Expand Down
73 changes: 9 additions & 64 deletions firebase-vscode/README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,12 @@
# firebase-vscode README
# Firebase Extension

This extension is in the development and exploration stage.
VSCode extension for Firebase. The Firebase Extension currently supports the Data Connect product.

## Running
## Data Connect features

1. In order to make sure f5 launches the extension properly, first open your
VS Code session from the `firebase-vscode` subdirectory (not the `firebase-tools` directory).
2. npm i (run this in both `firebase-tools` and `firebase-vscode`)
3. Make sure the extension `amodio.tsl-problem-matcher` is installed - this
enables the watcher to work, otherwise the Extension Development Host
will not automatically open on F5 when the compilation is done.
4. f5 to run opens new window
f5 -> npm run watch defined in tasks.json
My terminal didn't have npm available but yours might

Workaround if f5 doesnt work:

1. Execute `npm run watch` from within the vscode directory
Aside: Running `npm run watch` or `npm run build` the extension is compiled into dist (extension.js)
Changing code within extension is hot-reloaded
Modifying extensions.js will not hot-reload
source file src/extension.ts
2. Wait for completion
3. Hit play from the left nav

New code changes are automatically rebuilt if you have `watch` running, however the new VSCode Plugin-enabled window will not reflect changes until reloaded.
Manual reload from new window: "Developer: Reload Window" Default hotkey: cmd + R

The communication between UI and extension done via the broker (see webview.postMessage)
Web view uses react (carry-over from the hackweek project courtesy of Roman and Prakhar)

## Structure

Extention.ts main entry point, calls sidebar.ts and workflow.ts
sidebar.ts loads the UI from the webviews folder
workflow.ts is the driving component (logic source)
cli.ts wraps CLI methods, importing from firebase-tools/src

When workflow.ts needs to execute some CLI command, it defers to cli.ts

## State

currentOptions maintains the currentState of the plugin and is passed as a whole object to populate calls to the firebase-tools methods
`prepare` in the command includes a lot of

## Logic

Calling firebase-tools in general follows the stuff:

1. instead of calling `before`, call `requireAuth` instead
requireAuth is a prerequisite for the plugin UI, needed
Zero-state (before login) directs the user to sign in with google (using firebase-tools CLI)
2. prepare is an implicit command in the cmd class
3. action

requireAuth -> login with service account or check that you're already logged in via firebase-tools

## Open issues

Login changes in the CLI are not immediately reflected in the Plugin, requires restart
If logged-out in the middle of a plugin session, handle requireAuth errors gracefully
Plugin startup is flaky sometimes
Unit/Integration tests are not developed
Code cleanliness/structure TODOs
tsconfig.json's rootDirs includes ["src", "../src", "common"] which causes some issues with import autocomplete
Three package.jsons - one for monospace and one for the standalone plugin, and then root to copy the correct version
- Inline CodeLenses allow for one-click execution of operations
- Pass in arguments
- Impersonate user authentication
- Generate queries and mutations from your schema with one click
- Run against the emulator for offline development
- Deploy and execute against production
67 changes: 67 additions & 0 deletions firebase-vscode/README_DEV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# firebase-vscode README

This extension is in the development and exploration stage.

## Running

1. In order to make sure f5 launches the extension properly, first open your
VS Code session from the `firebase-vscode` subdirectory (not the `firebase-tools` directory).
2. npm i (run this in both `firebase-tools` and `firebase-vscode`)
3. Make sure the extension `amodio.tsl-problem-matcher` is installed - this
enables the watcher to work, otherwise the Extension Development Host
will not automatically open on F5 when the compilation is done.
4. f5 to run opens new window
f5 -> npm run watch defined in tasks.json
My terminal didn't have npm available but yours might

Workaround if f5 doesnt work:

1. Execute `npm run watch` from within the vscode directory
Aside: Running `npm run watch` or `npm run build` the extension is compiled into dist (extension.js)
Changing code within extension is hot-reloaded
Modifying extensions.js will not hot-reload
source file src/extension.ts
2. Wait for completion
3. Hit play from the left nav

New code changes are automatically rebuilt if you have `watch` running, however the new VSCode Plugin-enabled window will not reflect changes until reloaded.
Manual reload from new window: "Developer: Reload Window" Default hotkey: cmd + R

The communication between UI and extension done via the broker (see webview.postMessage)
Web view uses react (carry-over from the hackweek project courtesy of Roman and Prakhar)

## Structure

Extention.ts main entry point, calls sidebar.ts and workflow.ts
sidebar.ts loads the UI from the webviews folder
workflow.ts is the driving component (logic source)
cli.ts wraps CLI methods, importing from firebase-tools/src

When workflow.ts needs to execute some CLI command, it defers to cli.ts

## State

currentOptions maintains the currentState of the plugin and is passed as a whole object to populate calls to the firebase-tools methods
`prepare` in the command includes a lot of

## Logic

Calling firebase-tools in general follows the stuff:

1. instead of calling `before`, call `requireAuth` instead
requireAuth is a prerequisite for the plugin UI, needed
Zero-state (before login) directs the user to sign in with google (using firebase-tools CLI)
2. prepare is an implicit command in the cmd class
3. action

requireAuth -> login with service account or check that you're already logged in via firebase-tools

## Open issues

Login changes in the CLI are not immediately reflected in the Plugin, requires restart
If logged-out in the middle of a plugin session, handle requireAuth errors gracefully
Plugin startup is flaky sometimes
Unit/Integration tests are not developed
Code cleanliness/structure TODOs
tsconfig.json's rootDirs includes ["src", "../src", "common"] which causes some issues with import autocomplete
Three package.jsons - one for monospace and one for the standalone plugin, and then root to copy the correct version
3 changes: 2 additions & 1 deletion firebase-vscode/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "firebase-vscode",
"displayName": "firebase-vscode",
"displayName": "Firebase",
"publisher": "firebase",
"icon": "./resources/firebase_logo.png",
"description": "VSCode Extension for Firebase",
"version": "0.1.6",
"engines": {
Expand Down
Binary file added firebase-vscode/resources/firebase_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 3 additions & 5 deletions firebase-vscode/src/core/emulators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "../../common/messaging/protocol";
import { firebaseRC } from "./config";
import { EmulatorUiSelections } from "../messaging/types";
import { emulatorOutputChannel } from "../data-connect/emulator-stream";

export class EmulatorsController implements Disposable {
constructor(private broker: ExtensionBrokerImpl) {
Expand Down Expand Up @@ -108,9 +109,6 @@ export class EmulatorsController implements Disposable {
this.stopEmulators.bind(this)
);

readonly outputChannel =
vscode.window.createOutputChannel("Firebase Emulators");

// TODO(christhompson): Load UI selections from the current workspace.
// Requires context object.
readonly uiSelections = signal(DEFAULT_EMULATOR_UI_SELECTIONS);
Expand Down Expand Up @@ -206,7 +204,7 @@ export class EmulatorsController implements Disposable {
);

dataConnectEmulatorDetails.instance.stdout?.on("data", (data) => {
this.outputChannel.appendLine("DEBUG: " + data.toString());
emulatorOutputChannel.appendLine("DEBUG: " + data.toString());
});
dataConnectEmulatorDetails.instance.stderr?.on("data", (data) => {
if (data.toString().includes("Finished reloading")) {
Expand All @@ -215,7 +213,7 @@ export class EmulatorsController implements Disposable {
"firebase.dataConnect.executeIntrospection"
);
} else {
this.outputChannel.appendLine("ERROR: " + data.toString());
emulatorOutputChannel.appendLine("ERROR: " + data.toString());
}
});
}
Expand Down
9 changes: 5 additions & 4 deletions firebase-vscode/src/data-connect/core-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ export async function getCompilerStream(
"Content-Type": "application/json",
"x-mantle-admin": "all",
},
}
)
},
),
);

function fromStream(
stream: NodeJS.ReadableStream,
finishEventName = "end",
dataEventName = "data"
dataEventName = "data",
): Observable<CompilerResponse> {
stream.pause();

Expand Down Expand Up @@ -133,7 +133,8 @@ export async function getCompilerStream(
});
}
return fromStream(resp.body!);
} catch {
} catch (err) {
console.log("Stream failed to connect with error: ", err);
return of({});
}
}
134 changes: 134 additions & 0 deletions firebase-vscode/src/data-connect/emulator-stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import * as vscode from "vscode";
import fetch from "node-fetch";
import { Observable, of } from "rxjs";
import { backOff } from "exponential-backoff";
import { ResolvedDataConnectConfigs } from "./config";

enum Kind {
KIND_UNSPECIFIED = "KIND_UNSPECIFIED",
SQL_CONNECTION = "SQL_CONNECTION",
SQL_MIGRATION = "SQL_MIGRATION",
VERTEX_AI = "VERTEX_AI",
}
enum Severity {
SEVERITY_UNSPECIFIED = "SEVERITY_UNSPECIFIED",
DEBUG = "DEBUG",
NOTICE = "NOTICE",
ALERT = "ALERT",
}
interface EmulatorIssue {
kind: Kind;
severity: Severity;
message: string;
}

type EmulatorIssueResponse = { result?: { issues?: EmulatorIssue[] } };

export const emulatorOutputChannel =
vscode.window.createOutputChannel("Firebase Emulators");

/**
*
* @param fdcEndpoint FDC Emulator endpoint
*/
export async function runEmulatorIssuesStream(
configs: ResolvedDataConnectConfigs,
fdcEndpoint: string,
) {
const obsErrors = await getEmulatorIssuesStream(configs, fdcEndpoint);
const obsConverter = {
next(nextCompilerResponse: CompilerResponse) {
if (nextCompilerResponse.result?.issues?.length) {
for (const issue of nextCompilerResponse.result.issues) {
displayIssue(issue);
}
}
},
error(e: Error) {
console.log("Stream closed with: ", e);
},
complete() {
console.log("Stream Closed");
},
};
obsErrors.subscribe(obsConverter);
}

/**
* Based on the severity of the issue, either log, display notification, or display interactive popup to the user
*/
export function displayIssue(issue: EmulatorIssue) {
const issueMessage = `Data Connect Emulator: ${issue.kind.toString()} - ${issue.message}`;
if (issue.severity === Severity.ALERT) {
vscode.window.showErrorMessage(issueMessage);
} else if (issue.severity === Severity.NOTICE) {
vscode.window.showWarningMessage(issueMessage);
}
emulatorOutputChannel.appendLine(issueMessage);
}

/**
* Calls the DataConnect.StreamEmulatorIssues api.
* Converts ReadableStream into Observable
*
*/
export async function getEmulatorIssuesStream(
configs: ResolvedDataConnectConfigs,
dataConnectEndpoint: string,
): Promise<Observable<EmulatorIssueResponse>> {
try {
// TODO: eventually support multiple services
const serviceId = configs.serviceIds[0];

const resp = await backOff(() =>
fetch(
dataConnectEndpoint + `/emulator/stream_issues?serviceId=${serviceId}`,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-mantle-admin": "all",
},
},
),
);

function fromStream(
stream: NodeJS.ReadableStream,
finishEventName = "end",
dataEventName = "data",
): Observable<EmulatorIssueResponse> {
stream.pause();

return new Observable((observer) => {
function dataHandler(data: any) {
observer.next(JSON.parse(data));
}

function errorHandler(err: any) {
observer.error(JSON.parse(err));
}

function endHandler() {
observer.complete();
}

stream.addListener(dataEventName, dataHandler);
stream.addListener("error", errorHandler);
stream.addListener(finishEventName, endHandler);

stream.resume();

return () => {
stream.removeListener(dataEventName, dataHandler);
stream.removeListener("error", errorHandler);
stream.removeListener(finishEventName, endHandler);
};
});
}
return fromStream(resp.body!);
} catch (err) {
console.log("Stream failed to connect with error: ", err);
return of({});
}
}
3 changes: 2 additions & 1 deletion firebase-vscode/src/data-connect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { runDataConnectCompiler } from "./core-compiler";
import { setVSCodeEnvVars } from "../../../src/utils";
import { Result } from "../result";
import { setTerminalEnvVars } from "./terminal";
import { runEmulatorIssuesStream } from "./emulator-stream";

class CodeActionsProvider implements vscode.CodeActionProvider {
constructor(
Expand Down Expand Up @@ -169,7 +170,7 @@ export function registerFdc(
vscode.commands.executeCommand(
"firebase.dataConnect.executeIntrospection",
);

runEmulatorIssuesStream(configs,fdcService.localEndpoint.value);
runDataConnectCompiler(configs, fdcService.localEndpoint.value);
}
}),
Expand Down
Loading

0 comments on commit 6db3e92

Please sign in to comment.