mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
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:
1 parent
b57d48e39e
commit
54b92aa9b6
302 files changed
+6388
-2025
No files matched your search
@@ -5,13 +5,19 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiBase } from "../../common/k8s-api";
|
||||
import { onApiError } from "./on-api-error";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
|
||||
const setupOnApiErrorListenersInjectable = getInjectable({
|
||||
id: "setup-on-api-error-listeners",
|
||||
setup: () => {
|
||||
apiBase?.onError.addListener(onApiError);
|
||||
},
|
||||
instantiate: () => undefined,
|
||||
|
||||
instantiate: () => ({
|
||||
run: () => {
|
||||
apiBase?.onError.addListener(onApiError);
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default setupOnApiErrorListenersInjectable;
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 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 "../../common/app-paths/app-path-injection-token";
|
||||
import { appPathsInjectionToken, appPathsIpcChannel } from "../../common/app-paths/app-path-injection-token";
|
||||
import getValueFromRegisteredChannelInjectable from "./get-value-from-registered-channel/get-value-from-registered-channel.injectable";
|
||||
|
||||
let syncAppPaths: AppPaths;
|
||||
|
||||
const appPathsInjectable = getInjectable({
|
||||
id: "app-paths",
|
||||
|
||||
setup: async (di) => {
|
||||
const getValueFromRegisteredChannel = await di.inject(
|
||||
getValueFromRegisteredChannelInjectable,
|
||||
);
|
||||
|
||||
syncAppPaths = await getValueFromRegisteredChannel(appPathsIpcChannel);
|
||||
},
|
||||
|
||||
instantiate: () => syncAppPaths,
|
||||
|
||||
injectionToken: appPathsInjectionToken,
|
||||
});
|
||||
|
||||
export default appPathsInjectable;
|
||||
@@ -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";
|
||||
import { appPathsIpcChannel } from "../../common/app-paths/app-path-injection-token";
|
||||
import getValueFromRegisteredChannelInjectable from "./get-value-from-registered-channel/get-value-from-registered-channel.injectable";
|
||||
import appPathsStateInjectable from "../../common/app-paths/app-paths-state.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
|
||||
const setupAppPathsInjectable = getInjectable({
|
||||
id: "setup-app-paths",
|
||||
|
||||
instantiate: (di) => ({
|
||||
run: async () => {
|
||||
const getValueFromRegisteredChannel = di.inject(
|
||||
getValueFromRegisteredChannelInjectable,
|
||||
);
|
||||
|
||||
const syncAppPaths = await getValueFromRegisteredChannel(appPathsIpcChannel);
|
||||
|
||||
const appPathsState = di.inject(appPathsStateInjectable);
|
||||
|
||||
appPathsState.set(syncAppPaths);
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupAppPathsInjectable;
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../../common/runnable/run-many-for";
|
||||
|
||||
export const beforeFrameStartsInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "before-frame-starts",
|
||||
});
|
||||
@@ -46,6 +46,8 @@ import { init } from "@sentry/electron/renderer";
|
||||
import kubernetesClusterCategoryInjectable from "../common/catalog/categories/kubernetes-cluster.injectable";
|
||||
import autoRegistrationInjectable from "../common/k8s-api/api-manager/auto-registration.injectable";
|
||||
import assert from "assert";
|
||||
import { beforeFrameStartsInjectionToken } from "./before-frame-starts/before-frame-starts-injection-token";
|
||||
import { runManyFor } from "../common/runnable/run-many-for";
|
||||
|
||||
configurePackages(); // global packages
|
||||
registerCustomThemes(); // monaco editor themes
|
||||
@@ -66,7 +68,9 @@ export async function bootstrap(di: DiContainer) {
|
||||
initializeSentryReporting(init);
|
||||
}
|
||||
|
||||
await di.runSetups();
|
||||
const beforeFrameStarts = runManyFor(di)(beforeFrameStartsInjectionToken);
|
||||
|
||||
await beforeFrameStarts();
|
||||
|
||||
// TODO: Consolidate import time side-effect to setup time
|
||||
bindEvents();
|
||||
@@ -136,7 +140,7 @@ export async function bootstrap(di: DiContainer) {
|
||||
await clusterStore.loadInitialOnRenderer();
|
||||
|
||||
// HotbarStore depends on: ClusterStore
|
||||
di.inject(hotbarStoreInjectable);
|
||||
di.inject(hotbarStoreInjectable).load();
|
||||
|
||||
// ThemeStore depends on: UserStore
|
||||
// TODO: Remove temporal dependencies
|
||||
@@ -174,9 +178,11 @@ export async function bootstrap(di: DiContainer) {
|
||||
});
|
||||
}
|
||||
|
||||
const history = di.inject(historyInjectable);
|
||||
|
||||
render(
|
||||
<DiContextProvider value={{ di }}>
|
||||
<Router history={di.inject(historyInjectable)}>
|
||||
<Router history={history}>
|
||||
{DefaultProps(App)}
|
||||
</Router>
|
||||
</DiContextProvider>,
|
||||
|
||||
@@ -28,6 +28,7 @@ import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.i
|
||||
import { computed } from "mobx";
|
||||
import ipcRendererInjectable from "../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable";
|
||||
|
||||
mockWindow();
|
||||
jest.mock("electron", () => ({
|
||||
@@ -88,15 +89,16 @@ describe("<Catalog />", () => {
|
||||
let catalogEntityItem: MockCatalogEntity;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
|
||||
di.override(broadcastMessageInjectable, () => async () => {});
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
mockFs();
|
||||
CatalogEntityDetailRegistry.createInstance();
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ describe("Extensions", () => {
|
||||
let extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
@@ -71,8 +71,6 @@ describe("Extensions", () => {
|
||||
"some-directory-for-user-data": {},
|
||||
});
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
installFromInput = jest.fn();
|
||||
|
||||
@@ -79,6 +79,8 @@ class NonInjectedHelmCharts extends Component<Dependencies> {
|
||||
render() {
|
||||
return (
|
||||
<SiblingsInTabLayout>
|
||||
<div data-testid="page-for-helm-charts" style={{ display: "none" }}/>
|
||||
|
||||
<ItemListLayout
|
||||
isConfigurable
|
||||
tableId="helm_charts"
|
||||
|
||||
@@ -6,16 +6,15 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { asyncComputed } from "@ogre-tools/injectable-react";
|
||||
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
||||
import { listReleases } from "../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
|
||||
|
||||
const releasesInjectable = getInjectable({
|
||||
id: "releases",
|
||||
|
||||
instantiate: (di) => {
|
||||
const clusterContext = di.inject(clusterFrameContextInjectable);
|
||||
const namespaceStore = di.inject(namespaceStoreInjectable);
|
||||
|
||||
// TODO: Inject clusterContext directly instead of accessing dependency of a dependency
|
||||
const clusterContext = namespaceStore.context;
|
||||
|
||||
return asyncComputed(async () => {
|
||||
const contextNamespaces = namespaceStore.contextNamespaces || [];
|
||||
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ const extensionPreferenceItemRegistratorInjectable = getInjectable({
|
||||
}),
|
||||
);
|
||||
|
||||
injectables.forEach(di.register);
|
||||
di.register(...injectables);
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ const extensionTelemetryPreferenceItemRegistratorInjectable = getInjectable({
|
||||
}),
|
||||
);
|
||||
|
||||
injectables.forEach(di.register);
|
||||
di.register(...injectables);
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
+1
-3
@@ -17,7 +17,7 @@ import ipcRendererInjectable from "../../../../app-paths/get-value-from-register
|
||||
describe("ClusterRoleBindingDialog tests", () => {
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
@@ -26,8 +26,6 @@ describe("ClusterRoleBindingDialog tests", () => {
|
||||
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
|
||||
} as never));
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
const store = di.inject(clusterRoleStoreInjectable);
|
||||
|
||||
@@ -18,7 +18,7 @@ import ipcRendererInjectable from "../../../../app-paths/get-value-from-register
|
||||
describe("RoleBindingDialog tests", () => {
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
@@ -28,8 +28,6 @@ describe("RoleBindingDialog tests", () => {
|
||||
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
|
||||
} as never));
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
const store = di.inject(clusterRoleStoreInjectable);
|
||||
|
||||
@@ -30,7 +30,7 @@ describe("<Welcome/>", () => {
|
||||
let di: DiContainer;
|
||||
let welcomeBannersStub: WelcomeBannerRegistration[];
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
render = renderFor(di);
|
||||
welcomeBannersStub = [];
|
||||
|
||||
@@ -37,7 +37,7 @@ const tolerations: Toleration[] =[
|
||||
describe("<PodTolerations />", () => {
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForLensLocalStorageInjectable, () => "some-directory-for-lens-local-storage" );
|
||||
|
||||
+4
-4
@@ -3,11 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterFrameHandler } from "./lens-views";
|
||||
import { ClusterFrameHandler } from "./cluster-frame-handler";
|
||||
|
||||
const clusterFramesInjectable = getInjectable({
|
||||
id: "cluster-frames",
|
||||
const clusterFrameHandlerInjectable = getInjectable({
|
||||
id: "cluster-frame-handler",
|
||||
instantiate: () => new ClusterFrameHandler(),
|
||||
});
|
||||
|
||||
export default clusterFramesInjectable;
|
||||
export default clusterFrameHandlerInjectable;
|
||||
File renamed without changes.
@@ -9,7 +9,7 @@ import type { IComputedValue } from "mobx";
|
||||
import { computed, makeObservable, reaction } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ClusterStatus } from "./cluster-status";
|
||||
import type { ClusterFrameHandler } from "./lens-views";
|
||||
import type { ClusterFrameHandler } from "./cluster-frame-handler";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
import { requestClusterActivation } from "../../ipc";
|
||||
@@ -17,7 +17,7 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
import clusterViewRouteParametersInjectable from "./cluster-view-route-parameters.injectable";
|
||||
import clusterFramesInjectable from "./lens-views.injectable";
|
||||
import clusterFrameHandlerInjectable from "./cluster-frame-handler.injectable";
|
||||
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||
|
||||
@@ -107,7 +107,7 @@ export const ClusterView = withInjectables<Dependencies>(NonInjectedClusterView,
|
||||
getProps: (di) => ({
|
||||
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
clusterFrames: di.inject(clusterFramesInjectable),
|
||||
clusterFrames: di.inject(clusterFrameHandlerInjectable),
|
||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
+154
-107
@@ -4,23 +4,28 @@
|
||||
*/
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { fireEvent, screen } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import mockFs from "mock-fs";
|
||||
import React from "react";
|
||||
import * as selectEvent from "react-select-event";
|
||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||
import { DeleteClusterDialog } from "../view";
|
||||
import type { ClusterModel } from "../../../../common/cluster-types";
|
||||
import { getDisForUnitTesting } from "../../../../test-utils/get-dis-for-unit-testing";
|
||||
import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token";
|
||||
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import type { OpenDeleteClusterDialog } from "../open.injectable";
|
||||
import openDeleteClusterDialogInjectable from "../open.injectable";
|
||||
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
|
||||
import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
|
||||
import ipcRendererInjectable from "../../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
import type { ApplicationBuilder } from "../../test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../test-utils/get-application-builder";
|
||||
import { routeInjectionToken } from "../../../../common/front-end-routing/route-injection-token";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../routes/route-specific-component-injection-token";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
@@ -38,33 +43,29 @@ jest.mock("electron", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const kubeconfig = `
|
||||
const multiClusterConfig = `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://localhost
|
||||
name: test
|
||||
name: some-current-context-cluster
|
||||
- cluster:
|
||||
server: http://localhost
|
||||
name: other-cluster
|
||||
name: some-non-current-context-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: test
|
||||
cluster: some-current-context-cluster
|
||||
user: some-user
|
||||
name: some-current-context
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: test2
|
||||
- context:
|
||||
cluster: other-cluster
|
||||
user: test
|
||||
name: other-context
|
||||
current-context: other-context
|
||||
cluster: some-non-current-context-cluster
|
||||
user: some-user
|
||||
name: some-non-current-context
|
||||
current-context: some-current-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: test
|
||||
- name: some-user
|
||||
user:
|
||||
token: kubeconfig-user-q4lm4:xxxyyyy
|
||||
`;
|
||||
@@ -74,17 +75,17 @@ apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: http://localhost
|
||||
name: other-cluster
|
||||
name: some-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: other-cluster
|
||||
user: test
|
||||
name: other-context
|
||||
current-context: other-context
|
||||
cluster: some-cluster
|
||||
user: some-user
|
||||
name: some-context
|
||||
current-context: some-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: test
|
||||
- name: some-user
|
||||
user:
|
||||
token: kubeconfig-user-q4lm4:xxxyyyy
|
||||
`;
|
||||
@@ -92,60 +93,107 @@ users:
|
||||
let config: KubeConfig;
|
||||
|
||||
describe("<DeleteClusterDialog />", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let createCluster: (model: ClusterModel) => Cluster;
|
||||
let openDeleteClusterDialog: OpenDeleteClusterDialog;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { mainDi, rendererDi, runSetups } = getDisForUnitTesting({ doGeneralOverrides: true });
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
|
||||
mainDi.override(createContextHandlerInjectable, () => () => undefined as any);
|
||||
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as any);
|
||||
|
||||
rendererDi.override(hotbarStoreInjectable, () => ({}));
|
||||
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
});
|
||||
|
||||
const { rendererDi } = applicationBuilder.dis;
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
});
|
||||
|
||||
render = renderFor(rendererDi);
|
||||
mainDi.override(createContextHandlerInjectable, () => () => undefined);
|
||||
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined);
|
||||
mockFs();
|
||||
|
||||
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
rendererDi.override(ipcRendererInjectable, () => ({
|
||||
on: jest.fn(),
|
||||
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
|
||||
} as never));
|
||||
|
||||
await runSetups();
|
||||
|
||||
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
|
||||
createCluster = mainDi.inject(createClusterInjectionToken);
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
|
||||
createCluster = rendererDi.inject(createClusterInjectionToken);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("shows context switcher when deleting current cluster", async () => {
|
||||
const mockOpts = {
|
||||
"temp-kube-config": multiClusterConfig,
|
||||
};
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
config = new KubeConfig();
|
||||
config.loadFromString(multiClusterConfig);
|
||||
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
const createCluster = rendererDi.inject(createClusterInjectionToken);
|
||||
|
||||
const cluster = createCluster({
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
});
|
||||
|
||||
const rendered = await applicationBuilder.render();
|
||||
|
||||
const { getByText } = rendered;
|
||||
|
||||
const menu = getByText("Select new context...");
|
||||
|
||||
expect(menu).toBeInTheDocument();
|
||||
selectEvent.openMenu(menu);
|
||||
|
||||
expect(getByText("some-current-context")).toBeInTheDocument();
|
||||
expect(getByText("some-non-current-context")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
describe("Kubeconfig with different clusters", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockOpts = {
|
||||
"temp-kube-config": kubeconfig,
|
||||
"temp-kube-config": multiClusterConfig,
|
||||
};
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
config = new KubeConfig();
|
||||
config.loadFromString(kubeconfig);
|
||||
});
|
||||
config.loadFromString(multiClusterConfig);
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<DeleteClusterDialog />);
|
||||
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
expect(rendered.container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("shows warning when deleting non-current-context cluster", async () => {
|
||||
it("shows warning when deleting non-current-context cluster", () => {
|
||||
const cluster = createCluster({
|
||||
id: "test",
|
||||
contextName: "test",
|
||||
id: "some-non-current-context-cluster",
|
||||
contextName: "some-non-current-context",
|
||||
preferences: {
|
||||
clusterName: "minikube",
|
||||
},
|
||||
@@ -154,99 +202,78 @@ describe("<DeleteClusterDialog />", () => {
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
|
||||
render(<DeleteClusterDialog />);
|
||||
const message = "The contents of kubeconfig file will be changed!";
|
||||
|
||||
expect(await screen.findByText(message)).toBeInstanceOf(HTMLElement);
|
||||
expect(rendered.getByText(message)).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("shows warning when deleting current-context cluster", async () => {
|
||||
it("shows warning when deleting current-context cluster", () => {
|
||||
const cluster = createCluster({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
render(<DeleteClusterDialog />);
|
||||
|
||||
expect(await screen.findByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
|
||||
expect(rendered.getByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("shows context switcher when deleting current cluster", async () => {
|
||||
it("shows context switcher after checkbox click", () => {
|
||||
const cluster = createCluster({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
render(<DeleteClusterDialog />);
|
||||
|
||||
const menu = await screen.findByText("Select new context...");
|
||||
|
||||
expect(menu).toBeInTheDocument();
|
||||
selectEvent.openMenu(menu);
|
||||
|
||||
expect(await screen.findByText("test")).toBeInTheDocument();
|
||||
expect(await screen.findByText("test2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows context switcher after checkbox click", async () => {
|
||||
const cluster = createCluster({
|
||||
id: "some-cluster",
|
||||
contextName: "test",
|
||||
preferences: {
|
||||
clusterName: "test",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
render(<DeleteClusterDialog />);
|
||||
|
||||
const link = await screen.findByTestId("context-switch");
|
||||
const { getByText, getByTestId } = rendered;
|
||||
const link = getByTestId("context-switch");
|
||||
|
||||
expect(link).toBeInstanceOf(HTMLElement);
|
||||
fireEvent.click(link);
|
||||
|
||||
const menu = await screen.findByText("Select new context...");
|
||||
const menu = getByText("Select new context...");
|
||||
|
||||
expect(menu).toBeInTheDocument();
|
||||
selectEvent.openMenu(menu);
|
||||
|
||||
expect(await screen.findByText("test")).toBeInTheDocument();
|
||||
expect(await screen.findByText("test2")).toBeInTheDocument();
|
||||
expect(getByText("some-current-context")).toBeInTheDocument();
|
||||
expect(getByText("some-non-current-context")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows warning for internal kubeconfig cluster", async () => {
|
||||
it("given cluster in internal kubeconfig, when deleting cluster outside of current context, shows warning for internal kubeconfig cluster", () => {
|
||||
const cluster = createCluster({
|
||||
id: "some-cluster",
|
||||
contextName: "test",
|
||||
id: "some-non-current-context-cluster",
|
||||
contextName: "some-non-current-context",
|
||||
|
||||
preferences: {
|
||||
clusterName: "test",
|
||||
clusterName: "some-non-current-context-cluster",
|
||||
},
|
||||
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
render(<DeleteClusterDialog />);
|
||||
|
||||
expect(await screen.findByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
|
||||
expect(rendered.getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Kubeconfig with single cluster", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockOpts = {
|
||||
"temp-kube-config": singleClusterConfig,
|
||||
@@ -256,26 +283,46 @@ describe("<DeleteClusterDialog />", () => {
|
||||
|
||||
config = new KubeConfig();
|
||||
config.loadFromString(singleClusterConfig);
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("shows warning if no other contexts left", async () => {
|
||||
it("shows warning if no other contexts left", () => {
|
||||
const cluster = createCluster({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-cluster",
|
||||
contextName: "some-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
render(<DeleteClusterDialog />);
|
||||
|
||||
expect(await screen.findByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
|
||||
expect(rendered.getByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "some-test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/some-test-path",
|
||||
clusterFrame: false,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "some-test-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
Component: () => <DeleteClusterDialog />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
@@ -22,7 +22,7 @@ const initialTabs: DockTab[] = [
|
||||
describe("DockStore", () => {
|
||||
let dockStore: DockStore;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||
|
||||
@@ -91,8 +91,6 @@ describe("<DockTabs />", () => {
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
dockStore = di.inject(dockStoreInjectable);
|
||||
|
||||
await dockStore.whenReady;
|
||||
|
||||
@@ -5,20 +5,21 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import path from "path";
|
||||
import { hasCorrectExtension } from "./has-correct-extension";
|
||||
import { staticFilesDirectory } from "../../../../common/vars";
|
||||
import readFileInjectable from "../../../../common/fs/read-file.injectable";
|
||||
import readDirInjectable from "../../../../common/fs/read-dir.injectable";
|
||||
import type { RawTemplates } from "./create-resource-templates.injectable";
|
||||
import type { GetAbsolutePath } from "../../../../common/path/get-absolute-path.injectable";
|
||||
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
|
||||
import staticFilesDirectoryInjectable from "../../../../common/vars/static-files-directory.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
readDir: (dirPath: string) => Promise<string[]>;
|
||||
readFile: (filePath: string) => Promise<string>;
|
||||
getAbsolutePath: GetAbsolutePath;
|
||||
staticFilesDirectory: string;
|
||||
}
|
||||
|
||||
async function getTemplates({ readDir, readFile, getAbsolutePath }: Dependencies) {
|
||||
async function getTemplates({ readDir, readFile, getAbsolutePath, staticFilesDirectory }: Dependencies) {
|
||||
const templatesFolder = getAbsolutePath(staticFilesDirectory, "../templates/create-resource");
|
||||
|
||||
/**
|
||||
@@ -43,6 +44,7 @@ const lensCreateResourceTemplatesInjectable = getInjectable({
|
||||
readFile: di.inject(readFileInjectable),
|
||||
readDir: di.inject(readDirInjectable),
|
||||
getAbsolutePath: di.inject(getAbsolutePathInjectable),
|
||||
staticFilesDirectory: di.inject(staticFilesDirectoryInjectable),
|
||||
});
|
||||
|
||||
return ["lens", templates];
|
||||
|
||||
@@ -127,7 +127,7 @@ const getFewPodsTabData = (tabId: TabId, deps: Partial<LogTabViewModelDependenci
|
||||
describe("<LogResourceSelector />", () => {
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
@@ -142,8 +142,6 @@ describe("<LogResourceSelector />", () => {
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
mockFs({
|
||||
"tmp": {},
|
||||
});
|
||||
|
||||
@@ -60,12 +60,10 @@ const getOnePodViewModel = (tabId: TabId, deps: Partial<LogTabViewModelDependenc
|
||||
describe("LogSearch tests", () => {
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
await di.runSetups();
|
||||
});
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
|
||||
@@ -63,7 +63,7 @@ describe("<HotbarRemoveCommand />", () => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("renders w/o errors", async () => {
|
||||
it("renders w/o errors", () => {
|
||||
di.override(hotbarStoreInjectable, () => ({
|
||||
hotbars: [mockHotbars["1"]],
|
||||
getById: (id: string) => mockHotbars[id],
|
||||
@@ -73,14 +73,12 @@ describe("<HotbarRemoveCommand />", () => {
|
||||
getDisplayLabel: () => "1: Default",
|
||||
}) as unknown as HotbarStore);
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
const { container } = render(<HotbarRemoveCommand />);
|
||||
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("calls remove if you click on the entry", async () => {
|
||||
it("calls remove if you click on the entry", () => {
|
||||
const removeMock = jest.fn();
|
||||
|
||||
di.override(hotbarStoreInjectable, () => ({
|
||||
@@ -91,8 +89,6 @@ describe("<HotbarRemoveCommand />", () => {
|
||||
getDisplayLabel: () => "1: Default",
|
||||
}) as unknown as HotbarStore);
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
const { getByText } = render(
|
||||
<>
|
||||
<HotbarRemoveCommand />
|
||||
|
||||
@@ -24,10 +24,11 @@ import type { ThemeStore } from "../../themes/store";
|
||||
import { MenuActions } from "../menu/menu-actions";
|
||||
import { MenuItem } from "../menu";
|
||||
import { Checkbox } from "../checkbox";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import type { UserStore } from "../../../common/user-store";
|
||||
import type { ItemListStore } from "./list-layout";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
import pageFiltersStoreInjectable from "./page-filters/store.injectable";
|
||||
import type { OpenConfirmDialog } from "../confirm-dialog/open.injectable";
|
||||
import openConfirmDialogInjectable from "../confirm-dialog/open.injectable";
|
||||
@@ -69,6 +70,7 @@ export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStor
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
userStore: UserStore;
|
||||
pageFiltersStore: PageFiltersStore;
|
||||
openConfirmDialog: OpenConfirmDialog;
|
||||
}
|
||||
@@ -333,7 +335,7 @@ class NonInjectedItemListLayoutContent<
|
||||
showColumn({ id: columnId, showWithColumn }: TableCellProps): boolean {
|
||||
const { tableId, isConfigurable } = this.props;
|
||||
|
||||
return !isConfigurable || !tableId || !UserStore.getInstance().isTableColumnHidden(tableId, columnId, showWithColumn);
|
||||
return !isConfigurable || !tableId || !this.props.userStore.isTableColumnHidden(tableId, columnId, showWithColumn);
|
||||
}
|
||||
|
||||
renderColumnVisibilityMenu() {
|
||||
@@ -356,7 +358,7 @@ class NonInjectedItemListLayoutContent<
|
||||
value={this.showColumn(cellProps)}
|
||||
onChange={(
|
||||
tableId
|
||||
? (() => cellProps.id && UserStore.getInstance().toggleTableColumnVisibility(tableId, cellProps.id))
|
||||
? (() => cellProps.id && this.props.userStore.toggleTableColumnVisibility(tableId, cellProps.id))
|
||||
: undefined
|
||||
)}
|
||||
/>
|
||||
@@ -373,6 +375,7 @@ export const ItemListLayoutContent = withInjectables<Dependencies, ItemListLayou
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
pageFiltersStore: di.inject(pageFiltersStoreInjectable),
|
||||
openConfirmDialog: di.inject(openConfirmDialogInjectable),
|
||||
}),
|
||||
|
||||
@@ -57,7 +57,7 @@ describe("kube-object-menu", () => {
|
||||
let di: DiContainer;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const MenuItemComponent = () => <li>Some menu item</li>;
|
||||
const someTestExtension = new SomeTestExtension([
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ describe("kube-object-status-icon", () => {
|
||||
let render: DiRender;
|
||||
let kubeObjectStatusRegistrations: KubeObjectStatusRegistration[];
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
// TODO: Make mocking of date in unit tests global
|
||||
global.Date.now = () => new Date("2015-10-21T07:28:00Z").getTime();
|
||||
|
||||
@@ -35,8 +35,6 @@ describe("kube-object-status-icon", () => {
|
||||
di.override(rendererExtensionsInjectable, () =>
|
||||
computed(() => [someTestExtension]),
|
||||
);
|
||||
|
||||
await di.runSetups();
|
||||
});
|
||||
|
||||
it("given no statuses, when rendered, renders as empty", () => {
|
||||
|
||||
@@ -45,7 +45,7 @@ export const TabLayout = observer(({ className, contentClass, tabs = [], childre
|
||||
key={url}
|
||||
label={title}
|
||||
value={url}
|
||||
active={!!matchPath(currentLocation, { path: routePath, exact })}
|
||||
active={!!matchPath(currentLocation, { path: routePath, exact })}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
|
||||
@@ -76,15 +76,13 @@ describe("<TopBar/>", () => {
|
||||
let di: DiContainer;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
mockFs();
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
render = renderFor(di);
|
||||
});
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ class NonInjectedMenuActions extends React.Component<MenuActionsProps & Dependen
|
||||
removeConfirmationMessage: "Remove item?",
|
||||
};
|
||||
|
||||
// TODO: Make deterministic
|
||||
public id = uniqueId("menu_actions_");
|
||||
|
||||
@observable isOpen = !!this.props.toolbar;
|
||||
|
||||
@@ -30,7 +30,7 @@ describe("<Select />", () => {
|
||||
let di: DiContainer;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
render = renderFor(di);
|
||||
|
||||
|
||||
@@ -39,15 +39,13 @@ describe("<StatusBar />", () => {
|
||||
let di: DiContainer;
|
||||
let statusBarItems: IObservableArray<any>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
statusBarItems = observable.array([]);
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
render = renderFor(di);
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(rendererExtensionsInjectable, () => computed(() => [new SomeTestExtension(statusBarItems)]));
|
||||
|
||||
await di.runSetups();
|
||||
});
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { extensionRegistratorInjectionToken } from "../../../extensions/extensio
|
||||
import type { IObservableArray } from "mobx";
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import { renderFor } from "./renderFor";
|
||||
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
|
||||
import React from "react";
|
||||
import { Router } from "react-router";
|
||||
import { Observer } from "mobx-react";
|
||||
@@ -18,7 +17,6 @@ import allowedResourcesInjectable from "../../../common/cluster-store/allowed-re
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import type { KubeResource } from "../../../common/rbac";
|
||||
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import { Sidebar } from "../layout/sidebar";
|
||||
import { getDisForUnitTesting } from "../../../test-utils/get-dis-for-unit-testing";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
@@ -34,6 +32,18 @@ import type { MenuItemOpts } from "../../../main/menu/application-menu-items.inj
|
||||
import applicationMenuItemsInjectable from "../../../main/menu/application-menu-items.injectable";
|
||||
import type { MenuItem, MenuItemConstructorOptions } from "electron";
|
||||
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
|
||||
import navigateToHelmChartsInjectable from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable";
|
||||
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable";
|
||||
import { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
|
||||
import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable";
|
||||
import startFrameInjectable from "../../start-frame/start-frame.injectable";
|
||||
import { flushPromises } from "../../../common/test-utils/flush-promises";
|
||||
import type { NamespaceStore } from "../+namespaces/store";
|
||||
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
||||
import historyInjectable from "../../navigation/history.injectable";
|
||||
|
||||
type Callback = (dis: DiContainers) => void | Promise<void>;
|
||||
|
||||
@@ -42,12 +52,12 @@ export interface ApplicationBuilder {
|
||||
setEnvironmentToClusterFrame: () => ApplicationBuilder;
|
||||
addExtensions: (...extensions: LensRendererExtension[]) => Promise<ApplicationBuilder>;
|
||||
allowKubeResource: (resourceName: KubeResource) => ApplicationBuilder;
|
||||
beforeSetups: (callback: Callback) => ApplicationBuilder;
|
||||
beforeApplicationStart: (callback: Callback) => ApplicationBuilder;
|
||||
beforeRender: (callback: Callback) => ApplicationBuilder;
|
||||
render: () => Promise<RenderResult>;
|
||||
|
||||
applicationMenu: {
|
||||
click: (path: string) => void;
|
||||
click: (path: string) => Promise<void>;
|
||||
};
|
||||
|
||||
preferences: {
|
||||
@@ -57,6 +67,10 @@ export interface ApplicationBuilder {
|
||||
click: (id: string) => void;
|
||||
};
|
||||
};
|
||||
|
||||
helmCharts: {
|
||||
navigate: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
interface DiContainers {
|
||||
@@ -70,13 +84,14 @@ interface Environment {
|
||||
}
|
||||
|
||||
export const getApplicationBuilder = () => {
|
||||
const { rendererDi, mainDi, runSetups } = getDisForUnitTesting({
|
||||
const { rendererDi, mainDi } = getDisForUnitTesting({
|
||||
doGeneralOverrides: true,
|
||||
});
|
||||
|
||||
const dis = { rendererDi, mainDi };
|
||||
|
||||
const clusterStoreStub = {
|
||||
provideInitialFromMain: () => {},
|
||||
getById: (): null => null,
|
||||
} as unknown as ClusterStore;
|
||||
|
||||
@@ -84,7 +99,7 @@ export const getApplicationBuilder = () => {
|
||||
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
mainDi.override(clusterStoreInjectable, () => clusterStoreStub);
|
||||
|
||||
const beforeSetupsCallbacks: Callback[] = [];
|
||||
const beforeApplicationStartCallbacks: Callback[] = [];
|
||||
const beforeRenderCallbacks: Callback[] = [];
|
||||
|
||||
const extensionsState = observable.array<LensRendererExtension>();
|
||||
@@ -130,7 +145,7 @@ export const getApplicationBuilder = () => {
|
||||
dis,
|
||||
|
||||
applicationMenu: {
|
||||
click: (path: string) => {
|
||||
click: async (path: string) => {
|
||||
const applicationMenuItems = mainDi.inject(
|
||||
applicationMenuItemsInjectable,
|
||||
);
|
||||
@@ -160,6 +175,8 @@ export const getApplicationBuilder = () => {
|
||||
undefined,
|
||||
{},
|
||||
);
|
||||
|
||||
await flushPromises();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -199,6 +216,14 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
},
|
||||
|
||||
helmCharts: {
|
||||
navigate: () => {
|
||||
const navigateToHelmCharts = rendererDi.inject(navigateToHelmChartsInjectable);
|
||||
|
||||
navigateToHelmCharts();
|
||||
},
|
||||
},
|
||||
|
||||
setEnvironmentToClusterFrame: () => {
|
||||
environment = environments.clusterFrame;
|
||||
|
||||
@@ -208,11 +233,29 @@ export const getApplicationBuilder = () => {
|
||||
computed(() => new Set([...allowedResourcesState])),
|
||||
);
|
||||
|
||||
rendererDi.override(
|
||||
directoryForLensLocalStorageInjectable,
|
||||
() => "/irrelevant",
|
||||
const clusterStub = {
|
||||
accessibleNamespaces: [],
|
||||
} as unknown as Cluster;
|
||||
|
||||
const namespaceStoreStub = {
|
||||
contextNamespaces: [],
|
||||
} as unknown as NamespaceStore;
|
||||
|
||||
const clusterFrameContextFake = new ClusterFrameContext(
|
||||
clusterStub,
|
||||
|
||||
{
|
||||
namespaceStore: namespaceStoreStub,
|
||||
},
|
||||
);
|
||||
|
||||
rendererDi.override(namespaceStoreInjectable, () => namespaceStoreStub);
|
||||
rendererDi.override(hostedClusterInjectable, () => clusterStub);
|
||||
rendererDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake);
|
||||
|
||||
// Todo: get rid of global state.
|
||||
KubeObjectStore.defaultContext.set(clusterFrameContextFake);
|
||||
|
||||
return builder;
|
||||
},
|
||||
|
||||
@@ -254,8 +297,8 @@ export const getApplicationBuilder = () => {
|
||||
return builder;
|
||||
},
|
||||
|
||||
beforeSetups(callback: (dis: DiContainers) => void) {
|
||||
beforeSetupsCallbacks.push(callback);
|
||||
beforeApplicationStart(callback: (dis: DiContainers) => void) {
|
||||
beforeApplicationStartCallbacks.push(callback);
|
||||
|
||||
return builder;
|
||||
},
|
||||
@@ -267,14 +310,20 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
async render() {
|
||||
for (const callback of beforeSetupsCallbacks) {
|
||||
for (const callback of beforeApplicationStartCallbacks) {
|
||||
await callback(dis);
|
||||
}
|
||||
|
||||
await runSetups();
|
||||
const startMainApplication = mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
await startMainApplication();
|
||||
|
||||
const startFrame = rendererDi.inject(startFrameInjectable);
|
||||
|
||||
await startFrame();
|
||||
|
||||
const render = renderFor(rendererDi);
|
||||
const history = rendererDi.inject(observableHistoryInjectable);
|
||||
const history = rendererDi.inject(historyInjectable);
|
||||
const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable);
|
||||
|
||||
for (const callback of beforeRenderCallbacks) {
|
||||
|
||||
@@ -15,12 +15,17 @@ const createClusterInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const dependencies: ClusterDependencies = {
|
||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||
createKubeconfigManager: () => undefined,
|
||||
logger: di.inject(loggerInjectable),
|
||||
|
||||
// TODO: Dismantle wrong abstraction
|
||||
// Note: "as never" to get around strictness in unnatural scenario
|
||||
createKubeconfigManager: () => undefined as never,
|
||||
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
|
||||
createContextHandler: () => undefined,
|
||||
createContextHandler: () => undefined as never,
|
||||
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
logger: di.inject(loggerInjectable),
|
||||
detectorRegistry: undefined as never,
|
||||
createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
};
|
||||
|
||||
return (model) => new Cluster(dependencies, model);
|
||||
|
||||
+11
-14
@@ -4,25 +4,22 @@
|
||||
*/
|
||||
|
||||
import { createContainer } from "@ogre-tools/injectable";
|
||||
import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
|
||||
export const getDi = () => {
|
||||
const di = createContainer(
|
||||
getRequireContextForRendererCode,
|
||||
getRequireContextForCommonExtensionCode,
|
||||
getRequireContextForCommonCode,
|
||||
);
|
||||
const di = createContainer();
|
||||
|
||||
autoRegister({
|
||||
di,
|
||||
requireContexts: [
|
||||
require.context("./", true, /\.injectable\.(ts|tsx)$/),
|
||||
require.context("../common", true, /\.injectable\.(ts|tsx)$/),
|
||||
require.context("../extensions", true, /\.injectable\.(ts|tsx)$/),
|
||||
],
|
||||
});
|
||||
|
||||
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
|
||||
|
||||
return di;
|
||||
};
|
||||
|
||||
const getRequireContextForRendererCode = () =>
|
||||
require.context("./", true, /\.injectable\.(ts|tsx)$/);
|
||||
|
||||
const getRequireContextForCommonCode = () =>
|
||||
require.context("../common", true, /\.injectable\.(ts|tsx)$/);
|
||||
|
||||
const getRequireContextForCommonExtensionCode = () =>
|
||||
require.context("../extensions", true, /\.injectable\.(ts|tsx)$/);
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import glob from "glob";
|
||||
import { memoize } from "lodash/fp";
|
||||
import { memoize, noop } from "lodash/fp";
|
||||
import { createContainer } from "@ogre-tools/injectable";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import getValueFromRegisteredChannelInjectable from "./app-paths/get-value-from-registered-channel/get-value-from-registered-channel.injectable";
|
||||
@@ -34,12 +34,21 @@ import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-
|
||||
import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable";
|
||||
import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing";
|
||||
import historyInjectable from "./navigation/history.injectable";
|
||||
import { noop } from "./utils";
|
||||
import { ApiManager } from "../common/k8s-api/api-manager";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
|
||||
import apiManagerInjectable from "../common/k8s-api/api-manager/manager.injectable";
|
||||
import ipcRendererInjectable
|
||||
from "./app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
import type { IpcRenderer } from "electron";
|
||||
import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.injectable";
|
||||
import { observable } from "mobx";
|
||||
|
||||
export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
|
||||
const {
|
||||
doGeneralOverrides = false,
|
||||
} = opts;
|
||||
|
||||
const di = createContainer();
|
||||
|
||||
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
|
||||
@@ -68,6 +77,17 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
|
||||
|
||||
di.override(historyInjectable, () => createMemoryHistory());
|
||||
|
||||
di.override(lensResourcesDirInjectable, () => "/irrelevant");
|
||||
|
||||
di.override(ipcRendererInjectable, () => ({
|
||||
invoke: () => {},
|
||||
on: () => {},
|
||||
}) as unknown as IpcRenderer);
|
||||
|
||||
di.override(broadcastMessageInjectable, () => () => {
|
||||
throw new Error("Tried to broadcast message over IPC without explicit override.");
|
||||
});
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
di.override(extensionsStoreInjectable, () => ({ isEnabled: ({ id, isBundled }) => false }) as ExtensionsStore);
|
||||
|
||||
@@ -77,7 +97,22 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
|
||||
di.override(userStoreInjectable, () => ({}) as UserStore);
|
||||
|
||||
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
|
||||
|
||||
di.override(
|
||||
userStoreInjectable,
|
||||
() =>
|
||||
({
|
||||
isTableColumnHidden: () => false,
|
||||
extensionRegistryUrl: { customUrl: "some-custom-url" },
|
||||
syncKubeconfigEntries: observable.map(),
|
||||
terminalConfig: { fontSize: 42 },
|
||||
editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
|
||||
} as unknown as UserStore),
|
||||
);
|
||||
|
||||
di.override(apiManagerInjectable, () => new ApiManager());
|
||||
|
||||
di.override(getValueFromRegisteredChannelInjectable, () => () => Promise.resolve(undefined as never));
|
||||
di.override(registerIpcChannelListenerInjectable, () => () => undefined);
|
||||
|
||||
@@ -3,25 +3,26 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { noop } from "lodash/fp";
|
||||
import { ipcChannelListenerInjectionToken } from "./ipc-channel-listener-injection-token";
|
||||
import registerIpcChannelListenerInjectable
|
||||
from "../app-paths/get-value-from-registered-channel/register-ipc-channel-listener.injectable";
|
||||
import registerIpcChannelListenerInjectable from "../app-paths/get-value-from-registered-channel/register-ipc-channel-listener.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
|
||||
const registerIpcChannelListenersInjectable = getInjectable({
|
||||
id: "register-ipc-channel-listeners",
|
||||
|
||||
setup: async di => {
|
||||
const registerIpcChannelListener = await di.inject(registerIpcChannelListenerInjectable);
|
||||
instantiate: di => ({
|
||||
run: async () => {
|
||||
const registerIpcChannelListener = di.inject(registerIpcChannelListenerInjectable);
|
||||
|
||||
const listeners = await di.injectMany(ipcChannelListenerInjectionToken);
|
||||
const listeners = di.injectMany(ipcChannelListenerInjectionToken);
|
||||
|
||||
listeners.forEach(listener => {
|
||||
registerIpcChannelListener(listener);
|
||||
});
|
||||
},
|
||||
listeners.forEach(listener => {
|
||||
registerIpcChannelListener(listener);
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
instantiate: () => noop,
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default registerIpcChannelListenersInjectable;
|
||||
@@ -4,10 +4,11 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { createBrowserHistory } from "history";
|
||||
import type { History } from "history";
|
||||
|
||||
const historyInjectable = getInjectable({
|
||||
id: "history",
|
||||
instantiate: () => createBrowserHistory(),
|
||||
instantiate: (): History => createBrowserHistory(),
|
||||
});
|
||||
|
||||
export default historyInjectable;
|
||||
@@ -10,6 +10,7 @@ import historyInjectable from "./history.injectable";
|
||||
|
||||
const observableHistoryInjectable = getInjectable({
|
||||
id: "observable-history",
|
||||
|
||||
instantiate: (di) => {
|
||||
const history = di.inject(historyInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainerForInstantiate } from "@ogre-tools/injectable";
|
||||
import type { DiContainerForInjection } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||
@@ -35,7 +35,7 @@ const extensionRouteRegistratorInjectable = getInjectable({
|
||||
...extension.clusterPages.map(toRouteInjectable(true)),
|
||||
].flat();
|
||||
|
||||
routeInjectables.forEach(di.register as never);
|
||||
di.register(...routeInjectables);
|
||||
};
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ export default extensionRouteRegistratorInjectable;
|
||||
|
||||
const toRouteInjectableFor =
|
||||
(
|
||||
di: DiContainerForInstantiate,
|
||||
di: DiContainerForInjection,
|
||||
extension: LensRendererExtension,
|
||||
extensionInstallationCount: number,
|
||||
) =>
|
||||
|
||||
@@ -7,14 +7,15 @@ import observableHistoryInjectable from "../navigation/observable-history.inject
|
||||
import { runInAction } from "mobx";
|
||||
import type { NavigateToUrl } from "../../common/front-end-routing/navigate-to-url-injection-token";
|
||||
import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token";
|
||||
import { broadcastMessage } from "../../common/ipc";
|
||||
import { IpcRendererNavigationEvents } from "../navigation/events";
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
|
||||
const navigateToUrlInjectable = getInjectable({
|
||||
id: "navigate-to-url",
|
||||
|
||||
instantiate: (di): NavigateToUrl => {
|
||||
const observableHistory = di.inject(observableHistoryInjectable);
|
||||
const broadcastMessage = di.inject(broadcastMessageInjectable);
|
||||
|
||||
return (url, options = {}): void => {
|
||||
if (options.forceRootFrame) {
|
||||
|
||||
@@ -28,13 +28,11 @@ const logs = [
|
||||
describe("search store tests", () => {
|
||||
let searchStore: SearchStore;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
searchStore = di.inject(searchStoreInjectable);
|
||||
});
|
||||
|
||||
|
||||
@@ -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 { runManyFor } from "../../common/runnable/run-many-for";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
|
||||
const startFrameInjectable = getInjectable({
|
||||
id: "start-frame",
|
||||
|
||||
// TODO: Consolidate contents of bootstrap.tsx here
|
||||
instantiate: (di) => async () => {
|
||||
const beforeFrameStarts = runManyFor(di)(beforeFrameStartsInjectionToken);
|
||||
|
||||
await beforeFrameStarts();
|
||||
},
|
||||
});
|
||||
|
||||
export default startFrameInjectable;
|
||||
Reference in new issue
Block a user