Skip to content

Commit

Permalink
Handle workspace settings update (#202)
Browse files Browse the repository at this point in the history
* stop fetching dependency errors once they are resolved

* handle workspace update

* run format

* add todo
  • Loading branch information
bartolomej authored Nov 4, 2023
1 parent 343a9f8 commit 68db663
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import React, { ReactElement } from 'react';
import { ActionDialog } from '@onflowser/ui/src/common/overlays/dialogs/action/ActionDialog';
import { ReactElement } from 'react';
import useSWR, { SWRResponse } from 'swr';
import classes from './DependencyErrors.module.scss';
import {
FlowserDependencyError,
FlowserDependencyErrorType,
} from '../../../services/types';
import useSWR, { SWRResponse } from 'swr';

export function DependencyErrors(): ReactElement | null {
const { data: errors } = useGetDependencyErrors();
Expand All @@ -29,8 +28,15 @@ export function DependencyErrors(): ReactElement | null {
}

function useGetDependencyErrors(): SWRResponse<FlowserDependencyError[]> {
return useSWR(`dependency-errors`, () =>
window.electron.app.listDependencyErrors(),
return useSWR<FlowserDependencyError[]>(
`dependency-errors`,
() => window.electron.app.listDependencyErrors(),
{
// Let's assume that once the user resolves the errors,
// there will be no need to validate them again within the same app session.
// They will always be re-validated on the next app run.
refreshInterval: (data) => (data?.length === 0 ? 0 : 1000),
},
);
}

Expand Down
48 changes: 36 additions & 12 deletions apps/electron/src/services/flowser-app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import path from 'path';
import crypto from 'crypto';
import { app, BrowserWindow, dialog } from 'electron';
import { FlowserWorkspace } from '@onflowser/api';
import { WorkspaceEvent, WorkspaceService } from './workspace.service';
import { BlockchainIndexService } from './blockchain-index.service';
import { FileStorageService } from './file-storage.service';
Expand Down Expand Up @@ -177,6 +178,13 @@ export class FlowserAppService {
'Failed to close workspace',
).bind(this),
);
this.workspaceService.on(
WorkspaceEvent.WORKSPACE_UPDATE,
this.handleListenerError(
this.onWorkspaceUpdate.bind(this),
'Failed to update workspace',
).bind(this),
);
this.flowSnapshotsService.on(
FlowSnapshotsEvent.ROLLBACK_TO_HEIGHT,
this.handleListenerError(
Expand Down Expand Up @@ -208,6 +216,7 @@ export class FlowserAppService {
try {
await listener(...args);
} catch (error) {
this.logger.error(error);
const result = await dialog.showMessageBox(this.window, {
message: errorMessage,
detail: isErrorWithMessage(error) ? error.message : undefined,
Expand Down Expand Up @@ -241,36 +250,50 @@ export class FlowserAppService {
await this.walletService.synchronizeIndex();
}

private async onWorkspaceUpdate(workspaceId: string) {
const workspace = await this.workspaceService.findByIdOrThrow(workspaceId);

await this.flowEmulatorService.stopAndCleanup();

await this.startAndReindexEmulator(workspace);
}

private async onWorkspaceOpen(workspaceId: string) {
const workspace = await this.workspaceService.findByIdOrThrow(workspaceId);

await this.flowConfigService.configure({
workspacePath: workspace.filesystemPath,
});

this.flowGatewayService.configure({
flowJSON: this.flowConfigService.getFlowJSON(),
restServerAddress: `http://localhost:${
workspace.emulator?.restServerPort ?? 8888
}`,
});
// Separately store of each workspaces' data.
this.flowSnapshotsStorageService.setFileName(
`flowser-snapshots-${workspaceId}.json`,
);

this.walletStorageService.setFileName(`flowser-wallet-${workspaceId}.json`);

this.processingScheduler.start();
await this.startAndReindexEmulator(workspace);
}

private async startAndReindexEmulator(workspace: FlowserWorkspace) {
if (workspace.emulator) {
// TODO: Sometimes when we restart the emulator,
// it complains that port 8080 is already taken.
await this.flowEmulatorService.start({
workspacePath: workspace.filesystemPath,
config: workspace.emulator,
});
}

// Separately store of each workspaces' data.
this.flowSnapshotsStorageService.setFileName(
`flowser-snapshots-${workspaceId}.json`,
);
this.flowGatewayService.configure({
flowJSON: this.flowConfigService.getFlowJSON(),
restServerAddress: `http://localhost:${
workspace.emulator?.restServerPort ?? 8888
}`,
});

this.walletStorageService.setFileName(`flowser-wallet-${workspaceId}.json`);
await this.walletService.synchronizeIndex();
this.blockchainIndexService.clear();

if (workspace.emulator) {
this.flowSnapshotsService.configure({
Expand All @@ -283,6 +306,7 @@ export class FlowserAppService {
});
}

await this.walletService.synchronizeIndex();
await this.flowSnapshotsService.synchronizeIndex();
}

Expand Down
3 changes: 3 additions & 0 deletions apps/electron/src/services/workspace.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PersistentStorage } from '@onflowser/core/src/persistent-storage';
export enum WorkspaceEvent {
WORKSPACE_OPEN = 'WORKSPACE_OPEN',
WORKSPACE_CLOSE = 'WORKSPACE_CLOSE',
WORKSPACE_UPDATE = 'WORKSPACE_UPDATE',
}

export class WorkspaceService extends EventEmitter {
Expand Down Expand Up @@ -84,6 +85,8 @@ export class WorkspaceService extends EventEmitter {
: existingWorkspace,
),
);

this.emit(WorkspaceEvent.WORKSPACE_UPDATE, updatedWorkspace.id);
}

async findById(id: string): Promise<FlowserWorkspace | undefined> {
Expand Down
8 changes: 5 additions & 3 deletions packages/nodejs/src/flow-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type FlowConfigServiceConfig = {
};

export enum FlowConfigEvent {
FLOW_JSON_UPDATE = "FLOW_JSON_UPDATE"
FLOW_JSON_UPDATE = "FLOW_JSON_UPDATE",
}

export class FlowConfigService extends EventEmitter {
Expand Down Expand Up @@ -206,9 +206,11 @@ export class FlowConfigService extends EventEmitter {
// @ts-ignore AbortController type (because it's a polyfill)
const watcher = watch(this.getConfigPath(), { signal });
for await (const event of watcher) {
this.logger.debug("Detected file change, reloading config from flow.json")
this.logger.debug(
"Detected file change, reloading config from flow.json",
);
await this.load();
this.emit(FlowConfigEvent.FLOW_JSON_UPDATE)
this.emit(FlowConfigEvent.FLOW_JSON_UPDATE);
}
} catch (error) {
if (isObject(error) && error["name"] !== "AbortError") {
Expand Down
5 changes: 4 additions & 1 deletion packages/nodejs/src/flow-emulator.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ManagedProcess } from "./processes/managed-process";
import {
ManagedProcess,
ManagedProcessOutput,
} from "./processes/managed-process";
import {
FlowApiStatus,
FlowGatewayService,
Expand Down
8 changes: 4 additions & 4 deletions packages/nodejs/src/processes/managed-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,20 @@ export class ManagedProcess extends EventEmitter {
if (!this.childProcess) {
return;
}
const isKilledSuccessfully = this.childProcess.kill("SIGINT");
this.childProcess.once("error", (error) => {
reject(error);
});
this.childProcess.once("exit", (exitCode) => {
resolve(exitCode);
});
const isKilledSuccessfully = this.childProcess.kill("SIGINT");
if (!isKilledSuccessfully) {
this.logger.debug(
`Process ${this.name} (${this.id}) didn't shutdown given SIGINT`,
);
// If the SIGINT signal doesn't work, force kill with SIGINT
this.childProcess.kill("SIGKILL");
}
this.childProcess.once("exit", (exitCode) => {
resolve(exitCode);
});
// In the worst case, just inform the user that shutdown failed
const rejectionTimeoutSec = 6;
setTimeout(() => {
Expand Down
4 changes: 1 addition & 3 deletions packages/ui/src/common/status/ErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,5 @@ type TransactionErrorProps = {
};

export function TransactionError(props: TransactionErrorProps): ReactElement {
return (
<pre className={classes.root}>{props.errorMessage}</pre>
);
return <pre className={classes.root}>{props.errorMessage}</pre>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export function AddressBuilder(props: CadenceValueBuilder): ReactElement {

function toggleOrSelect(address: string) {
if (type.optional && value === address) {
setValue("")
setValue("");
} else {
setValue(address)
setValue(address);
}
}

Expand Down

0 comments on commit 68db663

Please sign in to comment.