Make starting of application modular and unit testable (#5324)

* Introduce injection token as competition for injectable setup to have better control of timing of different setups

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using competition to setup app paths

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using competition for setupping IPC channel listeners

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Stop running setups in unit tests without need

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to running injection token based setups over legacy DI setups in unit tests

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate naming for running setups

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to running injection token based setups over legacy DI setups in application roots

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Adapt to typing changes in injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Update injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce concept of runnable as a way to delegate runs to Open Closed Principle compliant runnables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Deprecate vars in favor of injectables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate loading of extensions to injectable instead of setup-code

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Flag injectable causing side effects

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Adapt injectable to auto register using a plugin instead of internal feature that no longer exists

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Simplify late registrations

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce tokens for runnables of specific application events for Open Closed Principle

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate setup events to more granular timeslots

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for catalog syncing using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for application menu using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for electron application name using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for immer using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for MobX strictness using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for application proxy using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for system certifications using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for system shutdown using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for main window visibility using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for application quit using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for after application is ready using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for application tray using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for deep linking using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Reimplement setup for root frame using runnables instead of non-OCP in index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove multiple usages of shared global state

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove recently reimplemented stuff from index.ts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract implementation for intent over technical phenomena (here electron events)

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate naming of event timing window

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Move directories for timing windows among peers

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate event naming

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Introduce function to remove duplication from things that are startable and stoppable

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate implementation of something startable and stoppable

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate naming

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate more startables and stoppables

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Introduce abstractions for electron application events

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce more abstractions for electron

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Abstract even more Electron specifics to make them overridable in unit tests

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Override dependency for causing side effects

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make running of many delegatees able to be hierarchical

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Bump async-fn

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make startable-stoppable also restartable

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Extract "isIntegrationTesting" as dependency for having a side-effect

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make temporal dependency apparent

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate all setupping related to single feature to same runnable

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Abstract command line arguments to make them overridable in tests

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Deprecate some globals

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce injectable for __static directory to eliminate side effect on import

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract responsibilities from electron

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract async initialization from sync-injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Accumulate more global overrides

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make lifecycle of injectable store work as expected

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Extract responsibilities to delegatees

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Rename delegate for accuracy

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Rename another delegate for accuracy

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Rename yet another delegate for accuracy

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Add new global overrides

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Consolidate variable naming

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Rename injectable for accuracy

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make difference between soft and hard quit of application apparent

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make quit triggered by auto update manifest as hard quit instead of just soft quit

Soft quit is the stand-by quit where only the renderer quits. Hard quit is the full quit of also main.

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Introduce abstraction for publishing and subscribing between processes

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Revert "Introduce abstraction for publishing and subscribing between processes"

This reverts commit 46f2d5a5f28bddcf5ffe124b1c590b19e7b9a15f.

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Adapt code and unit tests to recent changes in application setup and event handling

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Group overrides by category

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Abstract event of application activation from electron

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Abstract event of device shutdown from electron

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate runnables related to Electron

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make startableStoppables have ID for better error logging

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make navigating to Helm Charts not blow up

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Add general override for behavioural tests

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Update snapshot

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Adapt vars after merge

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix error about multiple states for React Router being present at once

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Kludge around test setup which is difficult because of circular dependencies

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix setupping of sentry after rebase

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Ensure that LensProxy is setupped before starting the main window

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant import

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate to use injectable instead of var for static file directory

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Deprecate another var with injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak timing of runnables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract tray icon path as injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make splash screen not blow up by providing compile-time environment variables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce a way to run many synchronous runnables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make runnables for before application is ready synchronous as this is technical limitation of Electron

See: https://github.com/electron/electron/issues/21370

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Kill dead code

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix application quit by calling Electron's event.preventDefault in a very specific way and preventing async

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix missing injectable postfix in file name

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak timeslot of a runnable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make it possible to not stop something that was never started

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make quit of hidden Lens not blow up

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract responsibilities of WindowManager as injectables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate code for application window

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Simplify directory structures for runnables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Flag injectable causing side-effect

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract helpers for testing promises to test-utils

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make script for running unit tests support targeting

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make startable stoppable support async starting

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce reactive way to get theme from operating system

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Update yarn.lock after rebase

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove code-style changes that are not welcome

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using dependency over using explicit side-effect

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Simplify naming

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Kill dead code

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Add empty mocks comply to lint

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove global state

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract responsibility of setting dependencies to own injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Flag injectable causing side effects

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract responsibility to injectable

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak typing

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak naming of runnables

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Revert code-style changes

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak types

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Extract injectable with side-effect for exact overriding

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak name of timeslot to make it more apparent that new content for application load can be added

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak name of the splash window for loading to avoid confusion with similarly named phenomenon

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Tweak comment

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Rename injectable for brevity

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Consolidate LensProxy related stuff to directory

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Rename injectables for accuracy

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove usage of extension for injectable for being YAGNI

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Prevent restarting a startableStoppable when already being started

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Rename callback in ApplicationBuilder for accuracy

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix conflicts after rebase

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix merge conflicts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Revert switch to react-router-dom by installing history as dependency

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make test more strict

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make runnable give friendly error about incorrect hierarchy for easier debugging

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code-style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using dependency instead of legacy-di

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix timing of injects

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

Co-authored-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
Janne SavolainenandMikko Aspiala authored and GitHub committed 2022-05-18 16:18:02 +03:00
1 parent b57d48e39e
commit 54b92aa9b6
302 files changed
+6388 -2025

No files matched your search

+1 -3
View File
@@ -81,15 +81,13 @@ class TestStore extends BaseStore<TestStoreModel> {
describe("BaseStore", () => {
let store: TestStore;
beforeEach(async () => {
beforeEach(() => {
const mainDi = getDiForUnitTesting({ doGeneralOverrides: true });
mainDi.override(directoryForUserDataInjectable, () => "some-user-data-directory");
mainDi.permitSideEffects(getConfigurationFileModelInjectable);
mainDi.permitSideEffects(appVersionInjectable);
await mainDi.runSetups();
TestStore.resetInstance();
const mockOpts = {
+15 -14
View File
@@ -8,7 +8,7 @@ import mockFs from "mock-fs";
import path from "path";
import fse from "fs-extra";
import type { Cluster } from "../cluster/cluster";
import { ClusterStore } from "../cluster-store/cluster-store";
import type { ClusterStore } from "../cluster-store/cluster-store";
import { Console } from "console";
import { stdout, stderr } from "process";
import getCustomKubeConfigDirectoryInjectable from "../app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
@@ -21,6 +21,7 @@ import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
import assert from "assert";
import directoryForTempInjectable from "../app-paths/directory-for-temp/directory-for-temp.injectable";
console = new Console(stdout, stderr);
@@ -81,15 +82,14 @@ describe("cluster-store", () => {
mockFs();
mainDi.override(clusterStoreInjectable, (di) => ClusterStore.createInstance({ createCluster: di.inject(createClusterInjectionToken) }));
mainDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
mainDi.override(directoryForTempInjectable, () => "some-temp-directory");
mainDi.permitSideEffects(getConfigurationFileModelInjectable);
mainDi.permitSideEffects(appVersionInjectable);
mainDi.permitSideEffects(clusterStoreInjectable);
await mainDi.runSetups();
createCluster = mainDi.inject(createClusterInjectionToken);
mainDi.unoverride(clusterStoreInjectable);
});
afterEach(() => {
@@ -104,10 +104,6 @@ describe("cluster-store", () => {
getCustomKubeConfigDirectoryInjectable,
);
// TODO: Remove these by removing Singleton base-class from BaseStore
ClusterStore.getInstance(false)?.unregisterIpcListener();
ClusterStore.resetInstance();
const mockOpts = {
"some-directory-for-user-data": {
"lens-cluster-store.json": JSON.stringify({}),
@@ -116,7 +112,11 @@ describe("cluster-store", () => {
mockFs(mockOpts);
createCluster = mainDi.inject(createClusterInjectionToken);
clusterStore = mainDi.inject(clusterStoreInjectable);
clusterStore.unregisterIpcListener();
});
afterEach(() => {
@@ -198,8 +198,6 @@ describe("cluster-store", () => {
describe("config with existing clusters", () => {
beforeEach(() => {
ClusterStore.resetInstance();
const mockOpts = {
"temp-kube-config": kubeconfig,
"some-directory-for-user-data": {
@@ -238,6 +236,8 @@ describe("cluster-store", () => {
mockFs(mockOpts);
createCluster = mainDi.inject(createClusterInjectionToken);
clusterStore = mainDi.inject(clusterStoreInjectable);
});
@@ -288,8 +288,6 @@ users:
token: kubeconfig-user-q4lm4:xxxyyyy
`;
ClusterStore.resetInstance();
const mockOpts = {
"invalid-kube-config": invalidKubeconfig,
"valid-kube-config": kubeconfig,
@@ -322,6 +320,8 @@ users:
mockFs(mockOpts);
createCluster = mainDi.inject(createClusterInjectionToken);
clusterStore = mainDi.inject(clusterStoreInjectable);
});
@@ -338,7 +338,6 @@ users:
describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
beforeEach(() => {
ClusterStore.resetInstance();
const mockOpts = {
"some-directory-for-user-data": {
"lens-cluster-store.json": JSON.stringify({
@@ -364,6 +363,8 @@ users:
mockFs(mockOpts);
createCluster = mainDi.inject(createClusterInjectionToken);
clusterStore = mainDi.inject(clusterStoreInjectable);
});
+10 -9
View File
@@ -18,8 +18,7 @@ import hasCategoryForEntityInjectable from "../catalog/has-category-for-entity.i
import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
import loggerInjectable from "../logger.injectable";
import type { Logger } from "../logger";
console.log("I am here as reminder against mockfs (and to fix console logging)");
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
function getMockCatalogEntity(data: Partial<CatalogEntityData> & CatalogEntityKindData): CatalogEntity {
return {
@@ -101,6 +100,8 @@ describe("HotbarStore", () => {
di.override(loggerInjectable, () => loggerMock);
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
@@ -121,12 +122,12 @@ describe("HotbarStore", () => {
});
describe("given no previous data in store, running all migrations", () => {
beforeEach(async () => {
beforeEach(() => {
mockFs();
await di.runSetups();
hotbarStore = di.inject(hotbarStoreInjectable);
hotbarStore.load();
});
describe("load", () => {
@@ -283,9 +284,9 @@ describe("HotbarStore", () => {
});
describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => {
beforeEach(async () => {
beforeEach(() => {
const configurationToBeMigrated = {
"some-electron-app-path-for-user-data": {
"some-directory-for-user-data": {
"lens-hotbar-store.json": JSON.stringify({
__internal__: {
migrations: {
@@ -350,9 +351,9 @@ describe("HotbarStore", () => {
di.override(appVersionInjectable, () => "5.0.0-beta.10");
await di.runSetups();
hotbarStore = di.inject(hotbarStoreInjectable);
hotbarStore.load();
});
it("allows to retrieve a hotbar", () => {
+3 -7
View File
@@ -33,10 +33,8 @@ import type { ClusterStoreModel } from "../cluster-store/cluster-store";
import { defaultThemeId } from "../vars";
import writeFileInjectable from "../fs/write-file.injectable";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable
from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../get-configuration-file-model/app-version/app-version.injectable";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
console = new Console(stdout, stderr);
@@ -44,7 +42,7 @@ describe("user store tests", () => {
let userStore: UserStore;
let di: DiContainer;
beforeEach(async () => {
beforeEach(() => {
di = getDiForUnitTesting({ doGeneralOverrides: true });
mockFs();
@@ -55,8 +53,6 @@ describe("user store tests", () => {
di.permitSideEffects(getConfigurationFileModelInjectable);
di.permitSideEffects(appVersionInjectable);
await di.runSetups();
});
afterEach(() => {
@@ -8,6 +8,7 @@ import { appEventBus } from "./event-bus";
const appEventBusInjectable = getInjectable({
id: "app-event-bus",
instantiate: () => appEventBus,
causesSideEffects: true,
});
export default appEventBusInjectable;
@@ -0,0 +1,34 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { AppPaths } from "./app-path-injection-token";
const appPathsStateInjectable = getInjectable({
id: "app-paths-state",
instantiate: () => {
let state: AppPaths;
return {
get: () =>{
if (!state) {
throw new Error("Tried to get app paths before state is setupped.");
}
return state;
},
set: (newState: AppPaths) => {
if (state) {
throw new Error("Tried to overwrite existing state of app paths.");
}
state = newState;
},
};
},
});
export default appPathsStateInjectable;
@@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { appPathsInjectionToken } from "./app-path-injection-token";
import appPathsStateInjectable from "./app-paths-state.injectable";
const appPathsInjectable = getInjectable({
id: "app-paths",
instantiate: (di) => di.inject(appPathsStateInjectable).get(),
injectionToken: appPathsInjectionToken,
});
export default appPathsInjectable;
+33 -29
View File
@@ -2,27 +2,27 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainer } from "@ogre-tools/injectable";
import type { AppPaths } from "./app-path-injection-token";
import { appPathsInjectionToken } from "./app-path-injection-token";
import getElectronAppPathInjectable from "../../main/app-paths/get-electron-app-path/get-electron-app-path.injectable";
import { getDisForUnitTesting } from "../../test-utils/get-dis-for-unit-testing";
import type { PathName } from "./app-path-names";
import setElectronAppPathInjectable from "../../main/app-paths/set-electron-app-path/set-electron-app-path.injectable";
import appNameInjectable from "../../main/app-paths/app-name/app-name.injectable";
import directoryForIntegrationTestingInjectable from "../../main/app-paths/directory-for-integration-testing/directory-for-integration-testing.injectable";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import type { DiContainer } from "@ogre-tools/injectable";
describe("app-paths", () => {
let mainDi: DiContainer;
let applicationBuilder: ApplicationBuilder;
let rendererDi: DiContainer;
let runSetups: () => Promise<void[]>;
let mainDi: DiContainer;
beforeEach(() => {
const dis = getDisForUnitTesting({ doGeneralOverrides: true });
applicationBuilder = getApplicationBuilder();
mainDi = dis.mainDi;
rendererDi = dis.rendererDi;
runSetups = dis.runSetups;
rendererDi = applicationBuilder.dis.rendererDi;
mainDi = applicationBuilder.dis.mainDi;
const defaultAppPathsStub: AppPaths = {
appData: "some-app-data",
@@ -40,30 +40,32 @@ describe("app-paths", () => {
recent: "some-recent",
temp: "some-temp",
videos: "some-videos",
userData: "some-irrelevant",
userData: "some-irrelevant-user-data",
};
mainDi.override(
getElectronAppPathInjectable,
() =>
(key: PathName): string | null =>
defaultAppPathsStub[key],
);
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
mainDi.override(
getElectronAppPathInjectable,
() =>
(key: PathName): string | null =>
defaultAppPathsStub[key],
);
mainDi.override(
setElectronAppPathInjectable,
() =>
(key: PathName, path: string): void => {
defaultAppPathsStub[key] = path;
},
);
mainDi.override(
setElectronAppPathInjectable,
() =>
(key: PathName, path: string): void => {
defaultAppPathsStub[key] = path;
},
);
mainDi.override(appNameInjectable, () => "some-app-name");
mainDi.override(appNameInjectable, () => "some-app-name");
});
});
describe("normally", () => {
beforeEach(async () => {
await runSetups();
await applicationBuilder.render();
});
it("given in renderer, when injecting app paths, returns application specific app paths", () => {
@@ -115,12 +117,14 @@ describe("app-paths", () => {
describe("when running integration tests", () => {
beforeEach(async () => {
mainDi.override(
directoryForIntegrationTestingInjectable,
() => "some-integration-testing-app-data",
);
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
mainDi.override(
directoryForIntegrationTestingInjectable,
() => "some-integration-testing-app-data",
);
});
await runSetups();
await applicationBuilder.render();
});
it("given in renderer, when injecting path for app data, has integration specific app data path", () => {
@@ -10,6 +10,7 @@ export type HasCategoryForEntity = (data: CatalogEntityData & CatalogEntityKindD
const hasCategoryForEntityInjectable = getInjectable({
id: "has-category-for-entity",
instantiate: (di): HasCategoryForEntity => {
const registry = di.inject(catalogCategoryRegistryInjectable);
+14
View File
@@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { clusterFrameMap } from "./cluster-frames";
const clusterFramesInjectable = getInjectable({
id: "cluster-frames",
instantiate: () => clusterFrameMap,
causesSideEffects: true,
});
export default clusterFramesInjectable;
@@ -9,10 +9,13 @@ import { createClusterInjectionToken } from "../cluster/create-cluster-injection
const clusterStoreInjectable = getInjectable({
id: "cluster-store",
instantiate: (di) =>
ClusterStore.createInstance({
instantiate: (di) => {
ClusterStore.resetInstance();
return ClusterStore.createInstance({
createCluster: di.inject(createClusterInjectionToken),
}),
});
},
causesSideEffects: true,
});
+8 -6
View File
@@ -13,8 +13,8 @@ import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig
import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers";
import type { KubeApiResource, KubeResource } from "../rbac";
import { apiResourceRecord, apiResources } from "../rbac";
import { VersionDetector } from "../../main/cluster-detectors/version-detector";
import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
import plimit from "p-limit";
import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate } from "../cluster-types";
import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus } from "../cluster-types";
@@ -29,11 +29,13 @@ import type { Logger } from "../logger";
export interface ClusterDependencies {
readonly directoryForKubeConfigs: string;
readonly logger: Logger;
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager | undefined;
createContextHandler: (cluster: Cluster) => ClusterContextHandler | undefined;
readonly detectorRegistry: DetectorRegistry;
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
createContextHandler: (cluster: Cluster) => ClusterContextHandler;
createKubectl: (clusterVersion: string) => Kubectl;
createAuthorizationReview: (config: KubeConfig) => CanI;
createListNamespaces: (config: KubeConfig) => ListNamespaces;
createVersionDetector: (cluster: Cluster) => VersionDetector;
}
/**
@@ -441,7 +443,7 @@ export class Cluster implements ClusterModel, ClusterState {
@action
async refreshMetadata() {
this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
const metadata = await this.dependencies.detectorRegistry.detectForCluster(this);
const existingMetadata = this.metadata;
this.metadata = Object.assign(existingMetadata, metadata);
@@ -504,7 +506,7 @@ export class Cluster implements ClusterModel, ClusterState {
protected async getConnectionStatus(): Promise<ClusterStatus> {
try {
const versionDetector = new VersionDetector(this);
const versionDetector = this.dependencies.createVersionDetector(this);
const versionData = await versionDetector.detect();
this.metadata.version = versionData.value;
@@ -11,7 +11,7 @@ import type { ClusterStore } from "../cluster-store/cluster-store";
import { pipeline } from "@ogre-tools/fp";
describe("verify-that-all-routes-have-component", () => {
it("verify that routes have route component", async () => {
it("verify that routes have route component", () => {
const rendererDi = getDiForUnitTesting({ doGeneralOverrides: true });
rendererDi.override(clusterStoreInjectable, () => ({
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import fsInjectable from "./fs.injectable";
const ensureDirInjectable = getInjectable({
id: "ensure-dir",
// TODO: Remove usages of ensureDir from business logic.
// TODO: Read, Write, Watch etc. operations should do this internally.
instantiate: (di) => di.inject(fsInjectable).ensureDir,
causesSideEffects: true,
});
export default ensureDirInjectable;
+1 -1
View File
@@ -40,8 +40,8 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
},
migrations,
});
makeObservable(this);
this.load();
}
@computed get activeHotbarId() {
@@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { broadcastMessage } from "./ipc";
const broadcastMessageInjectable = getInjectable({
id: "broadcast-message",
instantiate: () => broadcastMessage,
causesSideEffects: true,
});
export default broadcastMessageInjectable;
@@ -23,11 +23,9 @@ const mockFetch = fetch as FetchMock;
describe("forRemoteCluster", () => {
let apiManager: jest.Mocked<ApiManager>;
beforeEach(async () => {
beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
await di.runSetups();
apiManager = new ApiManager() as jest.Mocked<ApiManager>;
di.override(apiManagerInjectable, () => apiManager);
@@ -87,11 +85,9 @@ describe("KubeApi", () => {
let request: KubeJsonApi;
let apiManager: jest.Mocked<ApiManager>;
beforeEach(async () => {
beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
await di.runSetups();
request = new KubeJsonApi({
serverAddress: `http://127.0.0.1:9999`,
apiBase: "/api-kube",
+267
View File
@@ -0,0 +1,267 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest";
import { createContainer, getInjectable, getInjectionToken } from "@ogre-tools/injectable";
import type { Runnable } from "./run-many-for";
import { runManyFor } from "./run-many-for";
import { getPromiseStatus } from "../test-utils/get-promise-status";
describe("runManyFor", () => {
describe("given no hierarchy, when running many", () => {
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
let actualPromise: Promise<void>;
beforeEach(() => {
const rootDi = createContainer();
runMock = asyncFn();
const someInjectionTokenForRunnables = getInjectionToken<Runnable>({
id: "some-injection-token",
});
const someInjectable = getInjectable({
id: "some-injectable",
instantiate: () => ({ run: () => runMock("some-call") }),
injectionToken: someInjectionTokenForRunnables,
});
const someOtherInjectable = getInjectable({
id: "some-other-injectable",
instantiate: () => ({ run: () => runMock("some-other-call") }),
injectionToken: someInjectionTokenForRunnables,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManyFor(rootDi)(someInjectionTokenForRunnables);
actualPromise = runMany() as Promise<void>;
});
it("runs all runnables at the same time", () => {
expect(runMock.mock.calls).toEqual([
["some-call"],
["some-other-call"],
]);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("when all runnables resolve, resolves", async () => {
await Promise.all([runMock.resolve(), runMock.resolve()]);
expect(await actualPromise).toBe(undefined);
});
});
describe("given hierarchy that is three levels deep, when running many", () => {
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
let actualPromise: Promise<void>;
beforeEach(() => {
const di = createContainer();
runMock = asyncFn();
const someInjectionTokenForRunnables = getInjectionToken<Runnable>({
id: "some-injection-token",
});
const someInjectable1 = getInjectable({
id: "some-injectable-1",
instantiate: (di) => ({
run: () => runMock("third-level-run"),
runAfter: di.inject(someInjectable2),
}),
injectionToken: someInjectionTokenForRunnables,
});
const someInjectable2 = getInjectable({
id: "some-injectable-2",
instantiate: (di) => ({
run: () => runMock("second-level-run"),
runAfter: di.inject(someInjectable3),
}),
injectionToken: someInjectionTokenForRunnables,
});
const someInjectable3 = getInjectable({
id: "some-injectable-3",
instantiate: () => ({ run: () => runMock("first-level-run") }),
injectionToken: someInjectionTokenForRunnables,
});
di.register(someInjectable1, someInjectable2, someInjectable3);
const runMany = runManyFor(di)(someInjectionTokenForRunnables);
actualPromise = runMany() as Promise<void>;
});
it("runs first level runnables", () => {
expect(runMock.mock.calls).toEqual([["first-level-run"]]);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
describe("when first level runnables resolve", () => {
beforeEach(async () => {
runMock.mockClear();
await runMock.resolveSpecific(["first-level-run"]);
});
it("runs second level runnables", async () => {
expect(runMock.mock.calls).toEqual([["second-level-run"]]);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
describe("when second level runnables resolve", () => {
beforeEach(async () => {
runMock.mockClear();
await runMock.resolveSpecific(["second-level-run"]);
});
it("runs final third level runnables", async () => {
expect(runMock.mock.calls).toEqual([["third-level-run"]]);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
describe("when final third level runnables resolve", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["third-level-run"]);
});
it("resolves", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
});
});
});
});
it("given invalid hierarchy, when running runnables, throws", () => {
const rootDi = createContainer();
const runMock = asyncFn<(...args: unknown[]) => void>();
const someInjectionToken = getInjectionToken<Runnable>({
id: "some-injection-token",
});
const someOtherInjectionToken = getInjectionToken<Runnable>({
id: "some-other-injection-token",
});
const someInjectable = getInjectable({
id: "some-runnable-1",
instantiate: (di) => ({
run: () => runMock("some-runnable-1"),
runAfter: di.inject(someOtherInjectable),
}),
injectionToken: someInjectionToken,
});
const someOtherInjectable = getInjectable({
id: "some-runnable-2",
instantiate: () => ({
run: () => runMock("some-runnable-2"),
}),
injectionToken: someOtherInjectionToken,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManyFor(rootDi)(
someInjectionToken,
);
return expect(() => runMany()).rejects.toThrow(
"Tried to run runnable after other runnable which does not same injection token.",
);
});
describe("when running many with parameter", () => {
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
beforeEach(() => {
const rootDi = createContainer();
runMock = asyncFn();
const someInjectionTokenForRunnablesWithParameter = getInjectionToken<
Runnable<string>
>({
id: "some-injection-token",
});
const someInjectable = getInjectable({
id: "some-runnable-1",
instantiate: () => ({
run: (parameter) => runMock("run-of-some-runnable-1", parameter),
}),
injectionToken: someInjectionTokenForRunnablesWithParameter,
});
const someOtherInjectable = getInjectable({
id: "some-runnable-2",
instantiate: () => ({
run: (parameter) => runMock("run-of-some-runnable-2", parameter),
}),
injectionToken: someInjectionTokenForRunnablesWithParameter,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManyFor(rootDi)(
someInjectionTokenForRunnablesWithParameter,
);
runMany("some-parameter");
});
it("runs all runnables using the parameter", () => {
expect(runMock.mock.calls).toEqual([
["run-of-some-runnable-1", "some-parameter"],
["run-of-some-runnable-2", "some-parameter"],
]);
});
});
});
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import type {
DiContainerForInjection,
InjectionToken,
} from "@ogre-tools/injectable";
import { filter, forEach, map, tap } from "lodash/fp";
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for";
export interface Runnable<TParameter = void> {
run: Run<TParameter>;
runAfter?: this;
}
type Run<Param> = (parameter: Param) => Promise<void> | void;
export type RunMany = <Param>(
injectionToken: InjectionToken<Runnable<Param>, void>
) => Run<Param>;
export function runManyFor(di: DiContainerForInjection): RunMany {
return (injectionToken) => async (parameter) => {
const allRunnables = di.injectMany(injectionToken);
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor(allRunnables);
const recursedRun = async (
runAfterRunnable: Runnable<any> | undefined = undefined,
) =>
await pipeline(
allRunnables,
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
filter((runnable) => runnable.runAfter === runAfterRunnable),
map(async (runnable) => {
await runnable.run(parameter);
await recursedRun(runnable);
}),
(promises) => Promise.all(promises),
);
await recursedRun();
};
}
@@ -0,0 +1,197 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { createContainer, getInjectable, getInjectionToken } from "@ogre-tools/injectable";
import type { RunnableSync } from "./run-many-sync-for";
import { runManySyncFor } from "./run-many-sync-for";
describe("runManySyncFor", () => {
describe("given hierarchy, when running many", () => {
let runMock: jest.Mock;
beforeEach(() => {
const rootDi = createContainer();
runMock = jest.fn();
const someInjectionTokenForRunnables = getInjectionToken<RunnableSync>({
id: "some-injection-token",
});
const someInjectable = getInjectable({
id: "some-injectable",
instantiate: () => ({ run: () => runMock("some-call") }),
injectionToken: someInjectionTokenForRunnables,
});
const someOtherInjectable = getInjectable({
id: "some-other-injectable",
instantiate: () => ({ run: () => runMock("some-other-call") }),
injectionToken: someInjectionTokenForRunnables,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManySyncFor(rootDi)(someInjectionTokenForRunnables);
runMany();
});
it("runs all runnables at the same time", () => {
expect(runMock.mock.calls).toEqual([
["some-call"],
["some-other-call"],
]);
});
});
describe("given hierarchy that is three levels deep, when running many", () => {
let runMock: jest.Mock<(arg: string) => void>;
beforeEach(() => {
const di = createContainer();
runMock = jest.fn();
const someInjectionTokenForRunnables = getInjectionToken<RunnableSync>({
id: "some-injection-token",
});
const someInjectable1 = getInjectable({
id: "some-injectable-1",
instantiate: (di) => ({
run: () => runMock("third-level-run"),
runAfter: di.inject(someInjectable2),
}),
injectionToken: someInjectionTokenForRunnables,
});
const someInjectable2 = getInjectable({
id: "some-injectable-2",
instantiate: (di) => ({
run: () => runMock("second-level-run"),
runAfter: di.inject(someInjectable3),
}),
injectionToken: someInjectionTokenForRunnables,
});
const someInjectable3 = getInjectable({
id: "some-injectable-3",
instantiate: () => ({ run: () => runMock("first-level-run") }),
injectionToken: someInjectionTokenForRunnables,
});
di.register(someInjectable1, someInjectable2, someInjectable3);
const runMany = runManySyncFor(di)(someInjectionTokenForRunnables);
runMany();
});
it("runs runnables in order", () => {
expect(runMock.mock.calls).toEqual([["first-level-run"], ["second-level-run"], ["third-level-run"]]);
});
});
it("given invalid hierarchy, when running runnables, throws", () => {
const rootDi = createContainer();
const runMock = jest.fn();
const someInjectionToken = getInjectionToken<RunnableSync>({
id: "some-injection-token",
});
const someOtherInjectionToken = getInjectionToken<RunnableSync>({
id: "some-other-injection-token",
});
const someInjectable = getInjectable({
id: "some-runnable-1",
instantiate: (di) => ({
run: () => runMock("some-runnable-1"),
runAfter: di.inject(someOtherInjectable),
}),
injectionToken: someInjectionToken,
});
const someOtherInjectable = getInjectable({
id: "some-runnable-2",
instantiate: () => ({
run: () => runMock("some-runnable-2"),
}),
injectionToken: someOtherInjectionToken,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManySyncFor(rootDi)(
someInjectionToken,
);
return expect(() => runMany()).rejects.toThrow(
"Tried to run runnable after other runnable which does not same injection token.",
);
});
describe("when running many with parameter", () => {
let runMock: jest.Mock<(arg: string, arg2: string) => void>;
beforeEach(() => {
const rootDi = createContainer();
runMock = jest.fn();
const someInjectionTokenForRunnablesWithParameter = getInjectionToken<
RunnableSync<string>
>({
id: "some-injection-token",
});
const someInjectable = getInjectable({
id: "some-runnable-1",
instantiate: () => ({
run: (parameter) => runMock("run-of-some-runnable-1", parameter),
}),
injectionToken: someInjectionTokenForRunnablesWithParameter,
});
const someOtherInjectable = getInjectable({
id: "some-runnable-2",
instantiate: () => ({
run: (parameter) => runMock("run-of-some-runnable-2", parameter),
}),
injectionToken: someInjectionTokenForRunnablesWithParameter,
});
rootDi.register(someInjectable, someOtherInjectable);
const runMany = runManySyncFor(rootDi)(
someInjectionTokenForRunnablesWithParameter,
);
runMany("some-parameter");
});
it("runs all runnables using the parameter", () => {
expect(runMock.mock.calls).toEqual([
["run-of-some-runnable-1", "some-parameter"],
["run-of-some-runnable-2", "some-parameter"],
]);
});
});
});
+50
View File
@@ -0,0 +1,50 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import type {
DiContainerForInjection,
InjectionToken,
} from "@ogre-tools/injectable";
import { filter, forEach, map, tap } from "lodash/fp";
import type { Runnable } from "./run-many-for";
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for";
export interface RunnableSync<TParameter = void> {
run: RunSync<TParameter>;
runAfter?: this;
}
type RunSync<Param> = (parameter: Param) => void;
export type RunManySync = <Param>(
injectionToken: InjectionToken<Runnable<Param>, void>
) => RunSync<Param>;
export function runManySyncFor(di: DiContainerForInjection): RunManySync {
return (injectionToken) => async (parameter) => {
const allRunnables = di.injectMany(injectionToken);
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor(allRunnables);
const recursedRun = (
runAfterRunnable: RunnableSync<any> | undefined = undefined,
) =>
pipeline(
allRunnables,
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
filter((runnable) => runnable.runAfter === runAfterRunnable),
map((runnable) => {
runnable.run(parameter);
recursedRun(runnable);
}),
);
recursedRun();
};
}
@@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Runnable } from "./run-many-for";
import type { RunnableSync } from "./run-many-sync-for";
export const throwWithIncorrectHierarchyFor =
(allRunnables: Runnable<any>[] | RunnableSync<any>[]) =>
(runnable: Runnable<any> | RunnableSync<any>) => {
if (runnable.runAfter && !allRunnables.includes(runnable.runAfter)) {
throw new Error(
"Tried to run runnable after other runnable which does not same injection token.",
);
}
};
+5
View File
@@ -0,0 +1,5 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export const flushPromises = () => new Promise(setImmediate);
@@ -0,0 +1,17 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { flushPromises } from "./flush-promises";
export const getPromiseStatus = async (promise: Promise<unknown>) => {
const status = { fulfilled: false };
promise.finally(() => {
status.fulfilled = true;
});
await flushPromises();
return status;
};
@@ -0,0 +1,31 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const environmentVariablesInjectable = getInjectable({
id: "environment-variables",
instantiate: () => {
// IMPORTANT: The syntax needs to be exactly this in order to make environment variable values
// hard-coded at compile-time by Webpack.
const NODE_ENV = process.env.NODE_ENV;
const JEST_WORKER_ID = process.env.JEST_WORKER_ID;
const CICD = process.env.CICD;
return {
// Compile-time environment variables
NODE_ENV,
JEST_WORKER_ID,
CICD,
// Runtime environment variables
LENS_DISABLE_GPU: process.env.LENS_DISABLE_GPU,
};
},
causesSideEffects: true,
});
export default environmentVariablesInjectable;
@@ -0,0 +1,235 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest";
import { getStartableStoppable } from "./get-startable-stoppable";
import { getPromiseStatus } from "../test-utils/get-promise-status";
import { flushPromises } from "../test-utils/flush-promises";
describe("getStartableStoppable", () => {
let stopMock: AsyncFnMock<() => Promise<void>>;
let startMock: AsyncFnMock<() => Promise<() => Promise<void>>>;
let actual: { stop: () => Promise<void>; start: () => Promise<void>; started: boolean };
beforeEach(() => {
stopMock = asyncFn();
startMock = asyncFn();
actual = getStartableStoppable("some-id", startMock);
});
it("does not start yet", () => {
expect(startMock).not.toHaveBeenCalled();
});
it("does not stop yet", () => {
expect(stopMock).not.toHaveBeenCalled();
});
it("when stopping before ever starting, throws", () => {
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has not started yet.");
});
it("is not started", () => {
expect(actual.started).toBe(false);
});
describe("when started", () => {
let startPromise: Promise<void>;
beforeEach(() => {
startPromise = actual.start();
});
it("starts starting", () => {
expect(startMock).toHaveBeenCalled();
});
it("starting does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(startPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when started again before the start has finished", () => {
let error: Error;
beforeEach(() => {
startMock.mockClear();
actual.start().catch((e) => { error = e; });
});
it("does not start starting again", () => {
expect(startMock).not.toHaveBeenCalled();
});
it("throws", () => {
expect(error.message).toBe("Tried to start \"some-id\", but it is already being started.");
});
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("is started", () => {
expect(actual.started).toBe(true);
});
it("starting resolves", async () => {
const promiseStatus = await getPromiseStatus(startPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
it("when started again, throws", () => {
expect(actual.start).rejects.toThrow("Tried to start \"some-id\", but it has already started.");
});
it("does not stop yet", () => {
expect(stopMock).not.toHaveBeenCalled();
});
describe("when stopped", () => {
let stopPromise: Promise<void>;
beforeEach(() => {
stopPromise = actual.stop();
});
it("starts stopping", () => {
expect(stopMock).toHaveBeenCalled();
});
it("stopping does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not stopped yet", () => {
expect(actual.started).toBe(true);
});
describe("when stopping finishes", () => {
beforeEach(async () => {
await stopMock.resolve();
});
it("is not started", () => {
expect(actual.started).toBe(false);
});
it("stopping resolves", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
it("when stopped again, throws", () => {
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has already stopped.");
});
describe("when started again", () => {
beforeEach(
() => {
startMock.mockClear();
actual.start();
});
it("starts", () => {
expect(startMock).toHaveBeenCalled();
});
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("is started", () => {
expect(actual.started).toBe(true);
});
it("when stopped again, starts stopping again", async () => {
stopMock.mockClear();
actual.stop();
await flushPromises();
expect(stopMock).toHaveBeenCalled();
});
});
});
});
});
});
describe("when stopped before starting finishes", () => {
let stopPromise: Promise<void>;
beforeEach(() => {
stopPromise = actual.stop();
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("starts stopping", () => {
expect(stopMock).toHaveBeenCalled();
});
it("is not stopped yet", () => {
expect(actual.started).toBe(true);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
describe("when stopping finishes", () => {
beforeEach(async () => {
await stopMock.resolve();
});
it("is stopped", () => {
expect(actual.started).toBe(false);
});
it("resolves", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
});
});
});
});
});
@@ -0,0 +1,60 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
type Stopper = () => Promise<void> | void;
type Starter = () => Promise<Stopper> | Stopper;
export const getStartableStoppable = (
id: string,
startAndGetStopCallback: Starter,
) => {
let stop: Stopper;
let stopped = false;
let started = false;
let starting = false;
let startingPromise: Promise<Stopper> | Stopper;
return {
get started() {
return started;
},
start: async () => {
if (starting) {
throw new Error(`Tried to start "${id}", but it is already being started.`);
}
starting = true;
if (started) {
throw new Error(`Tried to start "${id}", but it has already started.`);
}
startingPromise = startAndGetStopCallback();
stop = await startingPromise;
stopped = false;
started = true;
starting = false;
},
stop: async () => {
await startingPromise;
if (stopped) {
throw new Error(`Tried to stop "${id}", but it has already stopped.`);
}
if (!started) {
throw new Error(`Tried to stop "${id}", but it has not started yet.`);
}
await stop();
started = false;
stopped = true;
},
};
};
+31 -10
View File
@@ -10,21 +10,48 @@ import packageInfo from "../../package.json";
import type { ThemeId } from "../renderer/themes/store";
import { lazyInitialized } from "./utils/lazy-initialized";
/**
* @deprecated Switch to using isMacInjectable
*/
export const isMac = process.platform === "darwin";
/**
* @deprecated Switch to using isWindowsInjectable
*/
export const isWindows = process.platform === "win32";
/**
* @deprecated Switch to using isLinuxInjectable
*/
export const isLinux = process.platform === "linux";
export const isDebugging = ["true", "1", "yes", "y", "on"].includes((process.env.DEBUG ?? "").toLowerCase());
export const isSnap = !!process.env.SNAP;
export const isProduction = process.env.NODE_ENV === "production";
/**
* @deprecated Switch to using isTestEnvInjectable
*/
export const isTestEnv = !!process.env.JEST_WORKER_ID;
/**
* @deprecated Switch to using isProductionInjectable
*/
export const isProduction = process.env.NODE_ENV === "production";
/**
* @deprecated Switch to using isDevelopmentInjectable
*/
export const isDevelopment = !isTestEnv && !isProduction;
export const isPublishConfigured = Object.keys(packageInfo.build).includes("publish");
export const integrationTestingArg = "--integration-testing";
export const isIntegrationTesting = process.argv.includes(integrationTestingArg);
export const productName = packageInfo.productName;
/**
* @deprecated Switch to using appNameInjectable
*/
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
export const publicPath = "/build/" as string;
export const defaultThemeId: ThemeId = "lens-dark";
export const defaultFontSize = 12;
@@ -101,12 +128,6 @@ export const kubectlBinaryName = getBinaryName("kubectl");
* @deprecated for being explicit side effect.
*/
export const kubectlBinaryPath = lazyInitialized(() => path.join(baseBinariesDir.get(), kubectlBinaryName));
export const staticFilesDirectory = path.resolve(
!isProduction
? process.cwd()
: process.resourcesPath,
"static",
);
// Apis
export const apiPrefix = "/api"; // local router apis
+9 -2
View File
@@ -3,11 +3,18 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { isDevelopment } from "../vars";
import isProductionInjectable from "./is-production.injectable";
import isTestEnvInjectable from "./is-test-env.injectable";
const isDevelopmentInjectable = getInjectable({
id: "is-development",
instantiate: () => isDevelopment,
instantiate: (di) => {
const isProduction = di.inject(isProductionInjectable);
const isTestEnv = di.inject(isTestEnvInjectable);
return !isTestEnv && !isProduction;
},
});
export default isDevelopmentInjectable;
@@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import commandLineArgumentsInjectable from "../../main/utils/command-line-arguments.injectable";
const isIntegrationTestingInjectable = getInjectable({
id: "is-integration-testing",
instantiate: (di) => {
const commandLineArguments = di.inject(commandLineArgumentsInjectable);
return commandLineArguments.includes("--integration-testing");
},
});
export default isIntegrationTestingInjectable;
+7 -3
View File
@@ -3,12 +3,16 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { isLinux } from "../vars";
import platformInjectable from "./platform.injectable";
const isLinuxInjectable = getInjectable({
id: "is-linux",
instantiate: () => isLinux,
causesSideEffects: true,
instantiate: (di) => {
const platform = di.inject(platformInjectable);
return platform === "linux";
},
});
export default isLinuxInjectable;
+7 -3
View File
@@ -3,12 +3,16 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { isMac } from "../vars";
import platformInjectable from "./platform.injectable";
const isMacInjectable = getInjectable({
id: "is-mac",
instantiate: () => isMac,
causesSideEffects: true,
instantiate: (di) => {
const platform = di.inject(platformInjectable);
return platform === "darwin";
},
});
export default isMacInjectable;
@@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import environmentVariablesInjectable from "../utils/environment-variables.injectable";
const isProductionInjectable = getInjectable({
id: "is-production",
instantiate: (di) => {
const { NODE_ENV: nodeEnv } = di.inject(environmentVariablesInjectable);
return nodeEnv === "production";
},
});
export default isProductionInjectable;
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import environmentVariablesInjectable from "../utils/environment-variables.injectable";
const isTestEnvInjectable = getInjectable({
id: "is-test-env",
instantiate: (di) => {
const { JEST_WORKER_ID: jestWorkerId } = di.inject(environmentVariablesInjectable);
return !!jestWorkerId;
},
});
export default isTestEnvInjectable;
+7 -3
View File
@@ -3,12 +3,16 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { isWindows } from "../vars";
import platformInjectable from "./platform.injectable";
const isWindowsInjectable = getInjectable({
id: "is-windows",
instantiate: () => isWindows,
causesSideEffects: true,
instantiate: (di) => {
const platform = di.inject(platformInjectable);
return platform === "win32";
},
});
export default isWindowsInjectable;
@@ -0,0 +1,22 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import isProductionInjectable from "./is-production.injectable";
const lensResourcesDirInjectable = getInjectable({
id: "lens-resources-dir",
instantiate: (di) => {
const isProduction = di.inject(isProductionInjectable);
return !isProduction
? process.cwd()
: process.resourcesPath;
},
causesSideEffects: true,
});
export default lensResourcesDirInjectable;
+13
View File
@@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const platformInjectable = getInjectable({
id: "platform",
instantiate: () => process.platform,
causesSideEffects: true,
});
export default platformInjectable;
@@ -0,0 +1,20 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import getAbsolutePathInjectable from "../path/get-absolute-path.injectable";
import lensResourcesDirInjectable from "./lens-resources-dir.injectable";
const staticFilesDirectoryInjectable = getInjectable({
id: "static-files-directory",
instantiate: (di) => {
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
const lensResourcesDir = di.inject(lensResourcesDirInjectable);
return getAbsolutePath(lensResourcesDir, "static");
},
});
export default staticFilesDirectoryInjectable;
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { WeblinkStore } from "./weblink-store";
const weblinkStoreInjectable = getInjectable({
id: "weblink-store",
instantiate: () => {
WeblinkStore.resetInstance();
return WeblinkStore.createInstance();
},
});
export default weblinkStoreInjectable;