This commit introduces native operating system file dialogs in the desktop application replacing the existing web-based dialogs. It lays the foundation for future enhancements such as: - Providing error messages when saving or executing files, addressing #264. - Creating system restore points, addressing #50. Documentation updates: - Update `desktop-vs-web-features.md` with added functionality. - Update `README.md` with security feature highlights. - Update home page documentation to emphasize security features. Other supporting changes include: - Integrate IPC communication channels for secure Electron dialog API interactions. - Refactor `IpcRegistration` for more type-safety and simplicity. - Introduce a Vue hook to encapsulate dialog functionality. - Improve errors during IPC registration for easier troubleshooting. - Move `ClientLoggerFactory` for consistency in hooks organization and remove `LoggerFactory` interface for simplicity. - Add tests for the save file dialog in the browser context. - Add `Blob` polyfill in tests to compensate for the missing `blob.text()` function in `jsdom` (see jsdom/jsdom#2555). Improve environment detection logic: - Treat test environment as browser environments to correctly activate features based on the environment. This resolves issues where the environment is misidentified as desktop, but Electron preloader APIs are missing. - Rename `isDesktop` environment identification variable to `isRunningAsDesktopApplication` for better clarity and to avoid confusion with desktop environments in web/browser/test environments. - Simplify `BrowserRuntimeEnvironment` to consistently detect non-desktop application environments. - Improve environment detection for Electron main process (electron/electron#2288).
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
import { RuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironment';
|
||||
import { ConsoleLogger } from '@/infrastructure/Log/ConsoleLogger';
|
||||
import { Logger } from '@/application/Common/Log/Logger';
|
||||
import { LoggerFactory } from '@/application/Common/Log/LoggerFactory';
|
||||
import { NoopLogger } from '@/infrastructure/Log/NoopLogger';
|
||||
import { WindowInjectedLogger } from '@/infrastructure/Log/WindowInjectedLogger';
|
||||
import { CurrentEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironmentFactory';
|
||||
|
||||
export class ClientLoggerFactory implements LoggerFactory {
|
||||
public static readonly Current: LoggerFactory = new ClientLoggerFactory();
|
||||
|
||||
public readonly logger: Logger;
|
||||
|
||||
protected constructor(
|
||||
environment: RuntimeEnvironment = CurrentEnvironment,
|
||||
windowAccessor: WindowAccessor = () => globalThis.window,
|
||||
noopLoggerFactory: LoggerCreationFunction = () => new NoopLogger(),
|
||||
windowInjectedLoggerFactory: LoggerCreationFunction = () => new WindowInjectedLogger(),
|
||||
consoleLoggerFactory: LoggerCreationFunction = () => new ConsoleLogger(),
|
||||
) {
|
||||
if (isUnitOrIntegrationTests(environment, windowAccessor)) {
|
||||
this.logger = noopLoggerFactory(); // keep the test outputs clean
|
||||
return;
|
||||
}
|
||||
if (environment.isDesktop) {
|
||||
this.logger = windowInjectedLoggerFactory();
|
||||
return;
|
||||
}
|
||||
if (environment.isNonProduction) {
|
||||
this.logger = consoleLoggerFactory();
|
||||
return;
|
||||
}
|
||||
this.logger = noopLoggerFactory();
|
||||
}
|
||||
}
|
||||
|
||||
export type WindowAccessor = () => OptionalWindow;
|
||||
|
||||
export type LoggerCreationFunction = () => Logger;
|
||||
|
||||
type OptionalWindow = Window | undefined | null;
|
||||
|
||||
function isUnitOrIntegrationTests(
|
||||
environment: RuntimeEnvironment,
|
||||
windowAccessor: WindowAccessor,
|
||||
): boolean {
|
||||
/*
|
||||
In a desktop application context, Electron preloader process inject a logger into
|
||||
the global window object. If we're in a desktop (Node) environment and the logger isn't
|
||||
injected, it indicates a testing environment.
|
||||
*/
|
||||
return environment.isDesktop && !windowAccessor()?.log;
|
||||
}
|
||||
@@ -11,9 +11,10 @@ import {
|
||||
} from '@/presentation/injectionSymbols';
|
||||
import { PropertyKeys } from '@/TypeHelpers';
|
||||
import { useUserSelectionState } from '@/presentation/components/Shared/Hooks/UseUserSelectionState';
|
||||
import { useLogger } from '@/presentation/components/Shared/Hooks/UseLogger';
|
||||
import { useLogger } from '@/presentation/components/Shared/Hooks/Log/UseLogger';
|
||||
import { useCodeRunner } from '@/presentation/components/Shared/Hooks/UseCodeRunner';
|
||||
import { CurrentEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironmentFactory';
|
||||
import { useDialog } from '@/presentation/components/Shared/Hooks/Dialog/UseDialog';
|
||||
|
||||
export function provideDependencies(
|
||||
context: IApplicationContext,
|
||||
@@ -67,6 +68,10 @@ export function provideDependencies(
|
||||
InjectionKeys.useCodeRunner,
|
||||
useCodeRunner,
|
||||
),
|
||||
useDialog: (di) => di.provide(
|
||||
InjectionKeys.useDialog,
|
||||
useDialog,
|
||||
),
|
||||
};
|
||||
registerAll(Object.values(resolvers), api);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Logger } from '@/application/Common/Log/Logger';
|
||||
import { ClientLoggerFactory } from '@/presentation/components/Shared/Hooks/Log/ClientLoggerFactory';
|
||||
import { Bootstrapper } from '../Bootstrapper';
|
||||
import { ClientLoggerFactory } from '../ClientLoggerFactory';
|
||||
|
||||
export class AppInitializationLogger implements Bootstrapper {
|
||||
constructor(
|
||||
|
||||
Reference in New Issue
Block a user