mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor and transform "Application update", "Preferences" and "Application menu" into Features (#6437)
* Move some code for application update to feature directory The rest of the code could not be moved yet because of work-in-progress refactorings for OCP compliance. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce helper to get a global override for a function-injectable Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract global override-files from bloated getDiForUnitTesting Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Move some more code for application update to feature directory Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce competition for top bar items to achieve OCP-compliance Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for opening context menu using the new competition Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for navigating to home as OCP Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for navigating to back as OCP Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for navigating to forward as OCP Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for application update as OCP Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Format code to make ongoing refactoring a bit easier Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Add missing unit tests for top bar extendability using extension API This makes ongoing refactoring easier. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Replace implementation for old top-bar items for losing competition Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract top menu item for window controls as OCP Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce reusable component for spacing between other components Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce helper component to render list of React elements Features: - Placeholder for empty list - Separators between items - No boilerplate for "key" prop in React Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix double-clicking and dragging of window from top bar Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update snapshots Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix stuff broken in rebase Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Update snapshots after rebase Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make fake time have a default value for "now" Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Migrate some application menu items to injectables Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate separators of application menu in single file Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove duplication from separators in application menu Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract some operation system actions from application menu as injectables Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract menu item for quitting application as injectable Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce way to type narrow a string property Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make the di's for unit testing able to auto-register also named exports Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make global override less strict to simplify setup of many unit tests There's a better solution for this in the horizon, as this overridden thing is better faked than stubbed. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify a test Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce way to create hierarchical composites from a flat array Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Implement hierarchy of application menu items using "many-root" composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Migrate more application menu items to injectables Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Simplify hierarchy of application menu items using "single-root" composite Also solve composed typing of application menu by using Discriminated Unions of TypeScript, see: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update snapshot Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify creation of composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make composite able to have custom handler for missing parent ids This will be useful next for application menu items, where a missing parent id cannot be fatal. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Defend against self-referencing composites Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Reintroduce non-fatal handling of orphan application menu items Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make faked, yet weak, typing a bit stronger Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify getting of composite paths Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make registrator for application menu items support all known scenarios Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Add logging for unrecognizable application menu item types Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Rename id of menu item to keep it discoverable by existing extensions Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate code to check for updates closer to feature Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce reusable horizontal line Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for preferences as a Feature Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for terminal preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for editor preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for proxy preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for telemetry preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for application preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move code related to helm chart preferences under related Feature in preparation for competition Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for kubernetes preference tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for application preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for editor preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for kubernetes preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for proxy preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add missing observer to make sure component updates Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for telemetry preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for terminal preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak UI for preferences Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove dead code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak more UI of preferences Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Revert "Introduce reusable horizontal line" This reverts commit 4d8c147fe0f1a14bd884f73cf345e7d3a28b954a. Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove dead code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce utility to find exactly one item from array Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for preferences navigation Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move code under a Feature Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove usage of old code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove dead code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add extensions tab group to preferences Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce way to find out if composite has a descendant This will serve eg. hiding of empty preference tab groups. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make tab groups and tabs in preferences not render when there is no content Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove code made redundant with hiding of preference tabs without content Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Tweak UI for preference navigation tab groups Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce test helper to abstract discovery of HTML elements 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> * Consolidate discovery of HTML elements in some tests Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update snapshots Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Adapt application builder to changes in preference navigation Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Adapt test setup to changes in preference navigation Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove uninteresting technical tests that are covered by behavioural ones Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate discovery of HTML elements in a test Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove test ID made redundant by consolidating discovery of HTML elements Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove duplication from preference pages Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix import Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make queries in element discovery return matching attribute values for easier testing Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make element discovery able to do nested discovery Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make element discovery able to discover without value for attribute Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Implement registrator for preference items Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update snapshots Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make styling less brittle by not relying on static HTML-element structures with CSS-rules Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Add todo Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove "group" from preference types, as it is exact replica of "item" Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Update snapshots Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Replace usages of react-component factory with actual components for simplicity Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Start considering application preferences as default tab Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate naming Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make sense in horizontal lines Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Clean public interface of a normalize composite Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate name of function Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate directory structure of composite Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move utility functions to common Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Rename a preference item type to better communicate intent in UI Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move shared UI component to more common place Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate sizing of horizontal line to t-shirts Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move application update related preferences under application update feature Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make winner of competition to use original route for preferences Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make HTML element discovery require less parameters Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Extract "composable-responsibilities" for Discriminable, Labelable, Orderable, and Showable Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Update snapshot Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove dead code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move code under a feature Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate navigating to preferences Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move code under a feature Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Relocate code under a sub-feature Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add TODO Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove dead code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix merge conflicts Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update snapshots after rebase Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix import path after rebase Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove duplication from exhaustiveness checks for discriminating unions Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add TODO Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update link to a more recent article Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify static Showability of a PreferenceItem Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Move general function to general directory Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract responsibility of "separability" Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make separator in Map-component know left and right item Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove additional separators when separated items are not shown for having no content Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Update snapshots Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix lint error Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Adapt integration test to recent changes Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Adapt more integration tests to recent changes Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make composite not care about in formatting of ids Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Adapt application builder and tests to array-like paths over string-like paths Array-like paths do not have weakness for special characters as part of id, such as ".". Also note: the error messaging for clicking of application menu in application builder is a bit worse now I think, but the simplification of the test code is worth it in this case IMHO. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make composite not care about formatting of ids Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Adapt application builder and tests to array-like paths over string-like paths Array-like paths do not have weakness for special characters as part of id, such as ".". Also note: the error messaging for clicking of application menu in application builder is a bit worse now I think, but the simplification of the test code is worth it in this case IMHO. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate output of get-composite-path to match find-composite's input Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make global overrides for functions log args of the call for devability Also make the thrown error suggest how to fix the problem. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make attempts to log error throw in unit tests Errors cannot be allowed to happen without a unit test explicitly causing it. Errors cannot be allowed to happen without author of unit test knowing it. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make composite not know about how children are transformed Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove some duplication from tests of composite Also make the thrown error suggest how to fix the problem. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make composite unit test an unrealistic test scenario about undefined ids Also make the thrown error suggest how to fix the problem. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Kill dead code Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify unit tests for composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate tests to now point-free composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify "Showable" Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make non-shown application menu items not break composite structure This was made apparent by adding related unit tests for all known environments. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify usages of Orderable and Showable Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract being maybe Showable as explicit composable responsibility Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make more showables maybe showable Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate logic for application menu for Windows to be based on composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Start using named export for composite Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Rename type for accuracy Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove unnecessary type and value Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make composable responsibilities readonly to nudge towards immutability Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove a bit of duplication to create TS-constants Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make a comment and test name make more sense Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify fallthrough in a switch/case Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Replace inline styles with proper CSS Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Switch to correct type to indicate "object which might not contain a property" Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify overriding of platform in a unit test Also make typing of platforms more strict, and remove some magic strings. Also add a TODO for further OCP-ification. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Consolidate some "maybe-types" and arguments using them Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Update snapshots Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
1 parent
38feab813c
commit
37eb236948
418 files changed
+39647
-27024
No files matched your search
+97
-61
@@ -11,43 +11,61 @@ exports[`extension special characters in page registrations renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -211,44 +229,62 @@ exports[`extension special characters in page registrations when navigating to r
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
|
||||
@@ -11,43 +11,61 @@ exports[`navigate to extension page renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -211,44 +229,62 @@ exports[`navigate to extension page when extension navigates to child route rend
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -332,44 +368,62 @@ exports[`navigate to extension page when extension navigates to route with param
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -469,44 +523,62 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -606,44 +678,62 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
|
||||
@@ -11,44 +11,62 @@ exports[`navigating between routes given route with optional path parameters whe
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -135,44 +153,62 @@ exports[`navigating between routes given route without path parameters when navi
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
|
||||
+97
-61
@@ -11,43 +11,61 @@ exports[`add-cluster - navigation using application menu renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -211,44 +229,62 @@ exports[`add-cluster - navigation using application menu when navigating to add
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
data-testid="home-button"
|
||||
tabindex="0"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
|
||||
@@ -29,7 +29,11 @@ describe("add-cluster - navigation using application menu", () => {
|
||||
|
||||
describe("when navigating to add cluster using application menu", () => {
|
||||
beforeEach(async () => {
|
||||
await applicationBuilder.applicationMenu.click("file.add-cluster");
|
||||
await applicationBuilder.applicationMenu.click(
|
||||
"root",
|
||||
"file",
|
||||
"add-cluster",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`application-menu, given platform is 'darwin' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> mac",
|
||||
"root -> mac -> about",
|
||||
"root -> mac -> separator-1",
|
||||
"root -> mac -> navigate-to-preferences",
|
||||
"root -> mac -> navigate-to-extensions",
|
||||
"root -> mac -> separator-2",
|
||||
"root -> mac -> services",
|
||||
"root -> mac -> separator-3",
|
||||
"root -> mac -> hide",
|
||||
"root -> mac -> hide-others",
|
||||
"root -> mac -> unhide",
|
||||
"root -> mac -> separator-4",
|
||||
"root -> mac -> quit",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> separator-1-for-file",
|
||||
"root -> file -> close-window",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`application-menu, given platform is 'linux' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> navigate-to-preferences",
|
||||
"root -> file -> navigate-to-extensions",
|
||||
"root -> file -> quit",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
"root -> help -> about",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`application-menu, given platform is 'win32' given enough time passes populates application menu 1`] = `
|
||||
Array [
|
||||
"root",
|
||||
"root -> file",
|
||||
"root -> file -> add-cluster",
|
||||
"root -> file -> navigate-to-preferences",
|
||||
"root -> file -> navigate-to-extensions",
|
||||
"root -> file -> quit",
|
||||
"root -> edit",
|
||||
"root -> edit -> undo",
|
||||
"root -> edit -> redo",
|
||||
"root -> edit -> separator-1-in-edit",
|
||||
"root -> edit -> cut",
|
||||
"root -> edit -> copy",
|
||||
"root -> edit -> paste",
|
||||
"root -> edit -> delete",
|
||||
"root -> edit -> separator-2-in-edit",
|
||||
"root -> edit -> selectAll",
|
||||
"root -> view",
|
||||
"root -> view -> navigate-to-catalog",
|
||||
"root -> view -> open-command-palette",
|
||||
"root -> view -> separator-1-for-view",
|
||||
"root -> view -> go-back",
|
||||
"root -> view -> go-forward",
|
||||
"root -> view -> reload",
|
||||
"root -> view -> toggle-dev-tools",
|
||||
"root -> view -> separator-2-for-view",
|
||||
"root -> view -> reset-zoom",
|
||||
"root -> view -> zoom-in",
|
||||
"root -> view -> zoom-out",
|
||||
"root -> view -> separator-3-for-view",
|
||||
"root -> view -> toggle-full-screen",
|
||||
"root -> help",
|
||||
"root -> help -> navigate-to-welcome",
|
||||
"root -> help -> open-documentation",
|
||||
"root -> help -> open-support",
|
||||
"root -> help -> about",
|
||||
]
|
||||
`;
|
||||
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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 { noop } from "lodash/fp";
|
||||
import { runInAction } from "mobx";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
|
||||
import applicationMenuItemInjectionToken from "./main/menu-items/application-menu-item-injection-token";
|
||||
import logErrorInjectable from "../../common/log-error.injectable";
|
||||
|
||||
describe("application-menu-in-legacy-extension-api", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let logErrorMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(
|
||||
(mainDi) => {
|
||||
runInAction(() => {
|
||||
mainDi.register(
|
||||
someTopMenuItemInjectable,
|
||||
someNonExtensionBasedMenuItemInjectable,
|
||||
);
|
||||
});
|
||||
|
||||
logErrorMock = jest.fn();
|
||||
|
||||
mainDi.override(logErrorInjectable, () => logErrorMock);
|
||||
},
|
||||
);
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
describe("when extension with application menu items is enabled", () => {
|
||||
let onClickMock: jest.Mock;
|
||||
let testExtensionOptions: FakeExtensionOptions;
|
||||
|
||||
beforeEach(() => {
|
||||
onClickMock = jest.fn();
|
||||
|
||||
testExtensionOptions = {
|
||||
id: "some-test-extension",
|
||||
name: "some-extension-name",
|
||||
|
||||
mainOptions: {
|
||||
appMenus: [
|
||||
{
|
||||
id: "some-non-shown-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: noop,
|
||||
label: "Irrelevant",
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-clickable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: onClickMock,
|
||||
},
|
||||
|
||||
{
|
||||
parentId: "some-top-menu-item",
|
||||
type: "separator",
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-os-action-menu-item-id",
|
||||
parentId: "some-top-menu-item",
|
||||
role: "help",
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-submenu-with-explicit-children",
|
||||
parentId: "some-top-menu-item",
|
||||
|
||||
submenu: [
|
||||
{ id: "some-explicit-child", label: "Some explicit child", click: noop },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("related menu items exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-clickable-item"],
|
||||
// Note: anonymous index "1" is used by the non-visible menu item.
|
||||
["root", "some-top-menu-item", "some-extension-name/2-separator"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-os-action-menu-item-id"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children", "some-extension-name/some-submenu-with-explicit-children/some-explicit-child"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("when the extension-based clickable menu item is clicked, does so", () => {
|
||||
builder.applicationMenu.click(
|
||||
"root", "some-top-menu-item", "some-extension-name/some-clickable-item",
|
||||
);
|
||||
|
||||
expect(onClickMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when the extension is disabled", () => {
|
||||
beforeEach(() => {
|
||||
builder.extensions.disable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("when related menu items no longer exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([]);
|
||||
});
|
||||
|
||||
it("when the extension is enabled again, also related menu items exist again", () => {
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-clickable-item"],
|
||||
["root", "some-top-menu-item", "some-extension-name/2-separator"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-os-action-menu-item-id"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children"],
|
||||
["root", "some-top-menu-item", "some-extension-name/some-submenu-with-explicit-children", "some-extension-name/some-submenu-with-explicit-children/some-explicit-child"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when extension with unrecognizable application menu items is enabled", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const testExtensionOptions: FakeExtensionOptions = {
|
||||
id: "some-test-extension",
|
||||
name: "some-extension-name",
|
||||
|
||||
mainOptions: {
|
||||
appMenus: [
|
||||
{
|
||||
id: "some-recognizable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
click: noop,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-unrecognizable-item",
|
||||
parentId: "some-top-menu-item",
|
||||
// Note: there is no way to recognize this
|
||||
// click: noop,
|
||||
// role: "help"
|
||||
// submenu: []
|
||||
// type: "separator"
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
builder.extensions.enable(testExtensionOptions);
|
||||
});
|
||||
|
||||
it("only recognizable menu items from extension exist", () => {
|
||||
const menuItemPathsForExtension = builder.applicationMenu.items.filter(
|
||||
(x) =>
|
||||
x.join(".").startsWith("root.some-top-menu-item.some-extension-name"),
|
||||
);
|
||||
|
||||
expect(menuItemPathsForExtension).toEqual([
|
||||
["root", "some-top-menu-item", "some-extension-name/some-recognizable-item"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("logs about the unrecognizable item", () => {
|
||||
expect(logErrorMock).toHaveBeenCalledWith(
|
||||
'[MENU]: Tried to register menu item "some-extension-name/some-unrecognizable-item" but it is not recognizable as any of ApplicationMenuItemTypes',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const someTopMenuItemInjectable = getInjectable({
|
||||
id: "some-top-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-top-menu-item",
|
||||
parentId: "root" as const,
|
||||
kind: "top-level-menu" as const,
|
||||
label: "Some existing root menu item",
|
||||
orderNumber: 42,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
const someNonExtensionBasedMenuItemInjectable = getInjectable({
|
||||
id: "some-non-extension-based-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-non-extension-based-menu-item",
|
||||
parentId: "some-top-menu-item",
|
||||
kind: "clickable-menu-item" as const,
|
||||
label: "Some menu item",
|
||||
onClick: () => {},
|
||||
orderNumber: 42,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import populateApplicationMenuInjectable from "./main/populate-application-menu.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import { getCompositePaths } from "../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import platformInjectable, { allPlatforms } from "../../common/vars/platform.injectable";
|
||||
|
||||
describe.each(allPlatforms)("application-menu, given platform is '%s'", (platform) => {
|
||||
let builder: ApplicationBuilder;
|
||||
let populateApplicationMenuMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
useFakeTime();
|
||||
|
||||
populateApplicationMenuMock = jest.fn();
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(platformInjectable, () => platform);
|
||||
|
||||
mainDi.override(
|
||||
populateApplicationMenuInjectable,
|
||||
() => populateApplicationMenuMock,
|
||||
);
|
||||
});
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
it("when insufficient time passes, does not populate menu items yet", () => {
|
||||
advanceFakeTime(99);
|
||||
|
||||
expect(populateApplicationMenuMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("given enough time passes", () => {
|
||||
let applicationMenuPaths: string[][];
|
||||
|
||||
beforeEach(() => {
|
||||
advanceFakeTime(100);
|
||||
applicationMenuPaths = getCompositePaths(
|
||||
populateApplicationMenuMock.mock.calls[0][0],
|
||||
);
|
||||
});
|
||||
|
||||
it("populates application menu with at least something", () => {
|
||||
expect(applicationMenuPaths.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("populates application menu", () => {
|
||||
expect(applicationMenuPaths.map(x => x.join(" -> "))).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import populateApplicationMenuInjectable from "./main/populate-application-menu.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import { getCompositePaths } from "../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import applicationMenuItemInjectionToken from "./main/menu-items/application-menu-item-injection-token";
|
||||
import { runInAction } from "mobx";
|
||||
import logErrorInjectable from "../../common/log-error.injectable";
|
||||
|
||||
describe("handling-of-orphan-application-menu-items, given orphan menu item", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let populateApplicationMenuMock: jest.Mock;
|
||||
let logErrorMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
useFakeTime();
|
||||
|
||||
populateApplicationMenuMock = jest.fn();
|
||||
logErrorMock = jest.fn();
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
const someOrphanMenuItemInjectable = getInjectable({
|
||||
id: "some-orphan-menu-item",
|
||||
instantiate: () => ({
|
||||
kind: "sub-menu" as const,
|
||||
id: "some-item-id",
|
||||
// Note: unknown id makes this item an orphan.
|
||||
parentId: "some-unknown-parent-id",
|
||||
orderNumber: 0,
|
||||
label: "irrelevant",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
runInAction(() => {
|
||||
mainDi.register(someOrphanMenuItemInjectable);
|
||||
});
|
||||
|
||||
mainDi.override(logErrorInjectable, () => logErrorMock);
|
||||
|
||||
mainDi.override(
|
||||
populateApplicationMenuInjectable,
|
||||
() => populateApplicationMenuMock,
|
||||
);
|
||||
});
|
||||
|
||||
await builder.startHidden();
|
||||
});
|
||||
|
||||
describe("given some time passes", () => {
|
||||
let applicationMenuPaths: string[][];
|
||||
|
||||
beforeEach(() => {
|
||||
advanceFakeTime(100);
|
||||
|
||||
applicationMenuPaths = getCompositePaths(
|
||||
populateApplicationMenuMock.mock.calls[0][0],
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps showing the other application menu items without throwing", () => {
|
||||
expect(applicationMenuPaths.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("does not show orphan application menu item", () => {
|
||||
expect(applicationMenuPaths.find(x => x.join(".").endsWith("some-item-id")));
|
||||
});
|
||||
|
||||
it("logs about bad menu item", () => {
|
||||
expect(logErrorMock).toHaveBeenCalledWith('[MENU]: cannot render menu item for missing parentIds: "some-unknown-parent-id"');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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 applicationMenuItemsInjectable from "./application-menu-items.injectable";
|
||||
import type { Composite } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import { getCompositeFor } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import { computed } from "mobx";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import type { ApplicationMenuItemTypes } from "./menu-items/application-menu-item-injection-token";
|
||||
import type { RootComposite } from "../../../common/utils/composite/interfaces";
|
||||
import type { Discriminable } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
import { orderByOrderNumber } from "../../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
import logErrorInjectable from "../../../common/log-error.injectable";
|
||||
import { isShown } from "../../../common/utils/composable-responsibilities/showable/showable";
|
||||
|
||||
export type MenuItemRoot = Discriminable<"root"> & RootComposite<"root">;
|
||||
|
||||
const applicationMenuItemCompositeInjectable = getInjectable({
|
||||
id: "application-menu-item-composite",
|
||||
|
||||
instantiate: (di) => {
|
||||
const menuItems = di.inject(applicationMenuItemsInjectable);
|
||||
const logError = di.inject(logErrorInjectable);
|
||||
|
||||
return computed((): Composite<ApplicationMenuItemTypes | MenuItemRoot> => {
|
||||
const items = menuItems.get();
|
||||
|
||||
return pipeline(
|
||||
[
|
||||
{
|
||||
parentId: undefined,
|
||||
id: "root",
|
||||
kind: "root",
|
||||
} as const,
|
||||
|
||||
...items,
|
||||
],
|
||||
|
||||
getCompositeFor({
|
||||
getId: (x) => x.id,
|
||||
getParentId: (x) => x.parentId,
|
||||
transformChildren: (children) =>
|
||||
pipeline(
|
||||
children,
|
||||
orderByOrderNumber,
|
||||
(children) => children.filter(isShown),
|
||||
),
|
||||
|
||||
handleMissingParentIds: ({ missingParentIds }) => {
|
||||
logError(
|
||||
`[MENU]: cannot render menu item for missing parentIds: "${missingParentIds.join(
|
||||
'", "',
|
||||
)}"`,
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default applicationMenuItemCompositeInjectable;
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Injectable } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { LensExtension } from "../../../extensions/lens-extension";
|
||||
import type { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||
import type {
|
||||
ApplicationMenuItemTypes,
|
||||
ClickableMenuItem,
|
||||
OsActionMenuItem,
|
||||
Separator,
|
||||
} from "./menu-items/application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./menu-items/application-menu-item-injection-token";
|
||||
import type { MenuRegistration } from "./menu-registration";
|
||||
import logErrorInjectable from "../../../common/log-error.injectable";
|
||||
|
||||
const applicationMenuItemRegistratorInjectable = getInjectable({
|
||||
id: "application-menu-item-registrator",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logError = di.inject(logErrorInjectable);
|
||||
const toRecursedInjectables = toRecursedInjectablesFor(logError);
|
||||
|
||||
return (ext: LensExtension) => {
|
||||
const extension = ext as LensMainExtension;
|
||||
|
||||
return extension.appMenus.flatMap(
|
||||
toRecursedInjectables([extension.sanitizedExtensionId]),
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: extensionRegistratorInjectionToken,
|
||||
});
|
||||
|
||||
export default applicationMenuItemRegistratorInjectable;
|
||||
|
||||
const toRecursedInjectablesFor = (logError: (errorMessage: string) => void) => {
|
||||
const toRecursedInjectables = (previousIdPath: string[]) =>
|
||||
(
|
||||
registration: MenuRegistration,
|
||||
index: number,
|
||||
// Todo: new version of injectable would require less type parameters with defaults.
|
||||
): Injectable<
|
||||
ApplicationMenuItemTypes,
|
||||
ApplicationMenuItemTypes,
|
||||
void
|
||||
>[] => {
|
||||
const previousIdPathString = previousIdPath.join("/");
|
||||
const registrationId = registration.id || index.toString();
|
||||
const currentIdPath = [...previousIdPath, registrationId];
|
||||
const currentIdPathString = currentIdPath.join("/");
|
||||
const parentId = registration.parentId || previousIdPathString;
|
||||
|
||||
const menuItem = getApplicationMenuItem({
|
||||
registration,
|
||||
parentId,
|
||||
currentIdPathString,
|
||||
index,
|
||||
});
|
||||
|
||||
if (!menuItem) {
|
||||
logError(`[MENU]: Tried to register menu item "${currentIdPathString}" but it is not recognizable as any of ApplicationMenuItemTypes`);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
getInjectable({
|
||||
id: `${currentIdPathString}/application-menu-item`,
|
||||
|
||||
instantiate: () => menuItem,
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
}),
|
||||
|
||||
...((registration.submenu as MenuRegistration[])
|
||||
? (registration.submenu as MenuRegistration[]).flatMap(
|
||||
toRecursedInjectables(currentIdPath),
|
||||
)
|
||||
: []),
|
||||
];
|
||||
};
|
||||
|
||||
return toRecursedInjectables;
|
||||
};
|
||||
|
||||
const getApplicationMenuItem = ({
|
||||
registration,
|
||||
index,
|
||||
currentIdPathString,
|
||||
parentId,
|
||||
}: {
|
||||
registration: MenuRegistration;
|
||||
index: number;
|
||||
currentIdPathString: string;
|
||||
parentId: string;
|
||||
}): ApplicationMenuItemTypes | undefined => {
|
||||
const orderNumber = 1000 + index * 10;
|
||||
|
||||
if (registration.type === "separator") {
|
||||
return {
|
||||
kind: "separator" as const,
|
||||
id: `${currentIdPathString}-separator`,
|
||||
parentId,
|
||||
orderNumber,
|
||||
} as Separator;
|
||||
}
|
||||
|
||||
if (registration.submenu) {
|
||||
return {
|
||||
kind: "sub-menu" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
label: registration.label || "",
|
||||
};
|
||||
}
|
||||
|
||||
if (registration.click) {
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
// Todo: hide electron events from this abstraction.
|
||||
onClick: registration.click,
|
||||
label: registration.label,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
|
||||
...(registration.accelerator
|
||||
? { keyboardShortcut: registration.accelerator as string }
|
||||
: {}),
|
||||
} as ClickableMenuItem;
|
||||
}
|
||||
|
||||
if (registration.role) {
|
||||
return {
|
||||
kind: "os-action-menu-item" as const,
|
||||
id: currentIdPathString,
|
||||
parentId,
|
||||
label: registration.label,
|
||||
isShown: registration.visible ?? true,
|
||||
orderNumber,
|
||||
actionName: registration.role,
|
||||
|
||||
...(registration.accelerator
|
||||
? { keyboardShortcut: registration.accelerator as string }
|
||||
: {}),
|
||||
} as OsActionMenuItem;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 { MenuItemConstructorOptions } from "electron";
|
||||
import { computed } from "mobx";
|
||||
import applicationMenuItemInjectionToken from "./menu-items/application-menu-item-injection-token";
|
||||
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
|
||||
export interface MenuItemOpts extends MenuItemConstructorOptions {
|
||||
submenu?: MenuItemConstructorOptions[];
|
||||
}
|
||||
|
||||
const applicationMenuItemsInjectable = getInjectable({
|
||||
id: "application-menu-items",
|
||||
|
||||
instantiate: (di) => {
|
||||
const computedInjectMany = di.inject(computedInjectManyInjectable);
|
||||
|
||||
return computed(() =>
|
||||
computedInjectMany(applicationMenuItemInjectionToken).get(),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export default applicationMenuItemsInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { autorun } from "mobx";
|
||||
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
|
||||
import populateApplicationMenuInjectable from "./populate-application-menu.injectable";
|
||||
import applicationMenuItemCompositeInjectable from "./application-menu-item-composite.injectable";
|
||||
|
||||
const applicationMenuReactivityInjectable = getInjectable({
|
||||
id: "application-menu-reactivity",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
|
||||
const populateApplicationMenu = di.inject(populateApplicationMenuInjectable);
|
||||
|
||||
return getStartableStoppable("application-menu-reactivity", () =>
|
||||
autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), {
|
||||
delay: 100,
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default applicationMenuReactivityInjectable;
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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 { BrowserWindow, KeyboardEvent, MenuItemConstructorOptions, MenuItem as ElectronMenuItem } from "electron";
|
||||
import type { SetOptional } from "type-fest";
|
||||
import type { ChildOfParentComposite, ParentOfChildComposite } from "../../../../common/utils/composite/interfaces";
|
||||
import type { MaybeShowable } from "../../../../common/utils/composable-responsibilities/showable/showable";
|
||||
import type { Discriminable } from "../../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
import type { Orderable } from "../../../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
|
||||
export interface MayHaveKeyboardShortcut {
|
||||
keyboardShortcut?: string;
|
||||
}
|
||||
|
||||
export interface ElectronClickable {
|
||||
// TODO: This leaky abstraction is exposed in Extension API, therefore cannot be updated
|
||||
onClick: (menuItem: ElectronMenuItem, browserWindow: (BrowserWindow) | (undefined), event: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
export interface Labeled {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface MaybeLabeled extends SetOptional<Labeled, "label"> {}
|
||||
|
||||
type ApplicationMenuItemType<T extends string> =
|
||||
// Note: "kind" is being used for Discriminated unions of TypeScript to achieve type narrowing.
|
||||
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions
|
||||
& Discriminable<T>
|
||||
& ParentOfChildComposite
|
||||
& ChildOfParentComposite
|
||||
& MaybeShowable
|
||||
& Orderable;
|
||||
|
||||
export type TopLevelMenu =
|
||||
& ApplicationMenuItemType<"top-level-menu">
|
||||
& { parentId: "root" }
|
||||
& Labeled
|
||||
& MayHaveElectronRole;
|
||||
|
||||
interface MayHaveElectronRole {
|
||||
role?: ElectronRoles;
|
||||
}
|
||||
|
||||
type ElectronRoles = Exclude<MenuItemConstructorOptions["role"], undefined>;
|
||||
|
||||
export type SubMenu =
|
||||
& ApplicationMenuItemType<"sub-menu">
|
||||
& Labeled
|
||||
& ChildOfParentComposite;
|
||||
|
||||
export type ClickableMenuItem =
|
||||
& ApplicationMenuItemType<"clickable-menu-item">
|
||||
& MenuItem
|
||||
& Labeled
|
||||
& ElectronClickable;
|
||||
|
||||
export type OsActionMenuItem =
|
||||
& ApplicationMenuItemType<"os-action-menu-item">
|
||||
& MenuItem
|
||||
& MaybeLabeled
|
||||
& TriggersElectronAction;
|
||||
|
||||
type MenuItem =
|
||||
& ChildOfParentComposite
|
||||
& MayHaveKeyboardShortcut;
|
||||
|
||||
interface TriggersElectronAction {
|
||||
actionName: ElectronRoles;
|
||||
}
|
||||
|
||||
// Todo: SeparatorMenuItem
|
||||
export type Separator =
|
||||
& ApplicationMenuItemType<"separator">
|
||||
& ChildOfParentComposite;
|
||||
|
||||
export type ApplicationMenuItemTypes =
|
||||
| TopLevelMenu
|
||||
| SubMenu
|
||||
| OsActionMenuItem
|
||||
| ClickableMenuItem
|
||||
| Separator
|
||||
;
|
||||
|
||||
const applicationMenuItemInjectionToken = getInjectionToken<ApplicationMenuItemTypes>({
|
||||
id: "application-menu-item-injection-token",
|
||||
});
|
||||
|
||||
export default applicationMenuItemInjectionToken;
|
||||
@@ -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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const editMenuItemInjectable = getInjectable({
|
||||
id: "edit-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "edit",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 30,
|
||||
label: "Edit",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default editMenuItemInjectable;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getApplicationMenuOperationSystemActionInjectable } from "../../get-application-menu-operation-system-action-injectable";
|
||||
import { getApplicationMenuSeparatorInjectable } from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const actionForUndo = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "undo",
|
||||
parentId: "edit",
|
||||
orderNumber: 10,
|
||||
actionName: "undo",
|
||||
});
|
||||
|
||||
export const actionForRedo = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "redo",
|
||||
parentId: "edit",
|
||||
orderNumber: 20,
|
||||
actionName: "redo",
|
||||
});
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-in-edit",
|
||||
parentId: "edit",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const actionForCut = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "cut",
|
||||
parentId: "edit",
|
||||
orderNumber: 40,
|
||||
actionName: "cut",
|
||||
});
|
||||
|
||||
export const actionForCopy = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "copy",
|
||||
parentId: "edit",
|
||||
orderNumber: 50,
|
||||
actionName: "copy",
|
||||
});
|
||||
|
||||
export const actionForPaste = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "paste",
|
||||
parentId: "edit",
|
||||
orderNumber: 60,
|
||||
actionName: "paste",
|
||||
});
|
||||
|
||||
export const actionForDelete = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "delete",
|
||||
parentId: "edit",
|
||||
orderNumber: 70,
|
||||
actionName: "delete",
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2-in-edit",
|
||||
parentId: "edit",
|
||||
orderNumber: 80,
|
||||
});
|
||||
|
||||
export const actionForSelectAll = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "selectAll",
|
||||
parentId: "edit",
|
||||
orderNumber: 90,
|
||||
actionName: "selectAll",
|
||||
});
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToAddClusterInjectable from "../../../../../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
|
||||
|
||||
const addClusterMenuItemInjectable = getInjectable({
|
||||
id: "add-cluster-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "file",
|
||||
id: "add-cluster",
|
||||
orderNumber: 10,
|
||||
label: "Add Cluster",
|
||||
keyboardShortcut: "CmdOrCtrl+Shift+A",
|
||||
|
||||
onClick: () => {
|
||||
navigateToAddCluster();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default addClusterMenuItemInjectable;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const closeWindowMenuItemInjectable = getInjectable({
|
||||
id: "close-window-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
id: "close-window",
|
||||
kind: "os-action-menu-item" as const,
|
||||
parentId: "file",
|
||||
orderNumber: 60,
|
||||
actionName: "close" as const,
|
||||
label: "Close Window",
|
||||
keyboardShortcut: "Shift+Cmd+W",
|
||||
isShown: isMac,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default closeWindowMenuItemInjectable;
|
||||
@@ -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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const fileMenuItemInjectable = getInjectable({
|
||||
id: "file-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "file",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 20,
|
||||
label: "File",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default fileMenuItemInjectable;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-for-file",
|
||||
parentId: "file",
|
||||
orderNumber: 20,
|
||||
isShownOnlyOnMac: true,
|
||||
});
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 { OsActionMenuItem } from "./application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./application-menu-item-injection-token";
|
||||
|
||||
const getApplicationMenuOperationSystemActionInjectable = ({
|
||||
id,
|
||||
...rest
|
||||
}: Omit<OsActionMenuItem, "kind" >) =>
|
||||
getInjectable({
|
||||
id: `application-menu-operation-system-action/${id}`,
|
||||
|
||||
instantiate: () => ({
|
||||
...rest,
|
||||
id,
|
||||
kind: "os-action-menu-item" as const,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export { getApplicationMenuOperationSystemActionInjectable };
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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 { Separator } from "./application-menu-item-injection-token";
|
||||
import applicationMenuItemInjectionToken from "./application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const getApplicationMenuSeparatorInjectable = ({
|
||||
id,
|
||||
isShownOnlyOnMac = false,
|
||||
...rest
|
||||
}: { isShownOnlyOnMac?: boolean } & Omit<
|
||||
Separator,
|
||||
"kind" | "isShown"
|
||||
>) =>
|
||||
getInjectable({
|
||||
id: `application-menu-separator/${id}`,
|
||||
|
||||
instantiate: (di) => {
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const isShown = isShownOnlyOnMac ? isMac : true;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
id,
|
||||
kind: "separator" as const,
|
||||
isShown,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export { getApplicationMenuSeparatorInjectable };
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const helpMenuItemInjectable = getInjectable({
|
||||
id: "help-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
id: "help",
|
||||
parentId: "root" as const,
|
||||
orderNumber: 50,
|
||||
label: "Help",
|
||||
role: "help" as const,
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default helpMenuItemInjectable;
|
||||
+31
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToWelcomeInjectable from "../../../../../../common/front-end-routing/routes/welcome/navigate-to-welcome.injectable";
|
||||
|
||||
const navigateToWelcomeMenuItem = getInjectable({
|
||||
id: "navigate-to-welcome-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToWelcome = di.inject(navigateToWelcomeInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "navigate-to-welcome",
|
||||
orderNumber: 10,
|
||||
label: "Welcome",
|
||||
|
||||
onClick: () => {
|
||||
navigateToWelcome();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToWelcomeMenuItem;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { docsUrl } from "../../../../../../common/vars";
|
||||
import openLinkInBrowserInjectable from "../../../../../../common/utils/open-link-in-browser.injectable";
|
||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
|
||||
const openDocumentationMenuItemInjectable = getInjectable({
|
||||
id: "open-documentation-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "open-documentation",
|
||||
orderNumber: 20,
|
||||
label: "Documentation",
|
||||
|
||||
// TODO: Convert to async/await
|
||||
onClick: () => {
|
||||
openLinkInBrowser(docsUrl).catch((error) => {
|
||||
logger.error("[MENU]: failed to open browser", { error });
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openDocumentationMenuItemInjectable;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { supportUrl } from "../../../../../../common/vars";
|
||||
import openLinkInBrowserInjectable from "../../../../../../common/utils/open-link-in-browser.injectable";
|
||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
|
||||
const openSupportItemInjectable = getInjectable({
|
||||
id: "open-support-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "help",
|
||||
id: "open-support",
|
||||
orderNumber: 30,
|
||||
label: "Support",
|
||||
|
||||
// TODO: Convert to async/await
|
||||
onClick: () => {
|
||||
openLinkInBrowser(supportUrl).catch((error) => {
|
||||
logger.error("[MENU]: failed to open browser", { error });
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openSupportItemInjectable;
|
||||
+34
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToExtensionsInjectable from "../../../../../../common/front-end-routing/routes/extensions/navigate-to-extensions.injectable";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const navigateToExtensionsMenuItem = getInjectable({
|
||||
id: "navigate-to-extensions-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToExtensions = di.inject(navigateToExtensionsInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: isMac ? "mac" : "file",
|
||||
id: "navigate-to-extensions",
|
||||
orderNumber: isMac ? 50 : 40,
|
||||
label: "Extensions",
|
||||
keyboardShortcut: isMac ? "CmdOrCtrl+Shift+E" : "Ctrl+Shift+E",
|
||||
|
||||
onClick: () => {
|
||||
navigateToExtensions();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToExtensionsMenuItem;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuOperationSystemActionInjectable,
|
||||
} from "../../get-application-menu-operation-system-action-injectable";
|
||||
|
||||
export const actionForServices = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "services",
|
||||
parentId: "mac",
|
||||
orderNumber: 80,
|
||||
actionName: "services",
|
||||
});
|
||||
|
||||
export const actionForHide = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "hide",
|
||||
parentId: "mac",
|
||||
orderNumber: 100,
|
||||
actionName: "hide",
|
||||
});
|
||||
|
||||
export const actionForHideOthers = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "hide-others",
|
||||
parentId: "mac",
|
||||
orderNumber: 110,
|
||||
actionName: "hideOthers",
|
||||
});
|
||||
|
||||
export const actionForUnhide = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "unhide",
|
||||
parentId: "mac",
|
||||
orderNumber: 120,
|
||||
actionName: "unhide",
|
||||
});
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
import appNameInjectable from "../../../../../common/vars/app-name.injectable";
|
||||
import isMacInjectable from "../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const primaryMenuItemInjectable = getInjectable({
|
||||
id: "primary-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const appName = di.inject(appNameInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "top-level-menu" as const,
|
||||
parentId: "root" as const,
|
||||
id: "mac",
|
||||
orderNumber: 10,
|
||||
label: appName,
|
||||
isShown: isMac,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default primaryMenuItemInjectable;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import stopServicesAndExitAppInjectable from "../../../../../../main/stop-services-and-exit-app.injectable";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const quitApplicationMenuItemInjectable = getInjectable({
|
||||
id: "quit-application-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: "quit",
|
||||
label: "Quit",
|
||||
|
||||
parentId: isMac ? "mac" : "file",
|
||||
orderNumber: isMac ? 140 : 70,
|
||||
keyboardShortcut: isMac ? "Cmd+Q" : "Alt+F4",
|
||||
|
||||
onClick: () => {
|
||||
stopServicesAndExitApp();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default quitApplicationMenuItemInjectable;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1",
|
||||
parentId: "mac",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2",
|
||||
parentId: "mac",
|
||||
orderNumber: 70,
|
||||
});
|
||||
|
||||
export const separator3 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-3",
|
||||
parentId: "mac",
|
||||
orderNumber: 90,
|
||||
});
|
||||
|
||||
export const separator4 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-4",
|
||||
parentId: "mac",
|
||||
orderNumber: 130,
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 productNameInjectable from "../../../../../../common/vars/product-name.injectable";
|
||||
import showAboutInjectable from "./show-about.injectable";
|
||||
import applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import isMacInjectable from "../../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const aboutMenuItemInjectable = getInjectable({
|
||||
id: "about-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const productName = di.inject(productNameInjectable);
|
||||
const showAbout = di.inject(showAboutInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: "about",
|
||||
parentId: isMac ? "mac" : "help",
|
||||
orderNumber: isMac ? 10 : 40,
|
||||
label: `About ${productName}`,
|
||||
|
||||
onClick() {
|
||||
showAbout();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default aboutMenuItemInjectable;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 showMessagePopupInjectable from "../../../../../../main/electron-app/features/show-message-popup.injectable";
|
||||
import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable";
|
||||
import appNameInjectable from "../../../../../../common/vars/app-name.injectable";
|
||||
import productNameInjectable from "../../../../../../common/vars/product-name.injectable";
|
||||
import buildVersionInjectable from "../../../../../../main/vars/build-version/build-version.injectable";
|
||||
import extensionApiVersionInjectable from "../../../../../../common/vars/extension-api-version.injectable";
|
||||
import applicationCopyrightInjectable from "../../../../../../common/vars/application-copyright.injectable";
|
||||
|
||||
const showAboutInjectable = getInjectable({
|
||||
id: "show-about",
|
||||
|
||||
instantiate: (di) => {
|
||||
const buildVersion = di.inject(buildVersionInjectable);
|
||||
const extensionApiVersion = di.inject(extensionApiVersionInjectable);
|
||||
const showMessagePopup = di.inject(showMessagePopupInjectable);
|
||||
const isWindows = di.inject(isWindowsInjectable);
|
||||
const appName = di.inject(appNameInjectable);
|
||||
const productName = di.inject(productNameInjectable);
|
||||
const applicationCopyright = di.inject(applicationCopyrightInjectable);
|
||||
|
||||
return () => {
|
||||
const appInfo = [
|
||||
`${appName}: ${buildVersion.get()}`,
|
||||
`Extension API: ${extensionApiVersion}`,
|
||||
`Electron: ${process.versions.electron}`,
|
||||
`Chrome: ${process.versions.chrome}`,
|
||||
`Node: ${process.versions.node}`,
|
||||
applicationCopyright,
|
||||
];
|
||||
|
||||
showMessagePopup(
|
||||
`${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
productName,
|
||||
appInfo.join("\r\n"),
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default showAboutInjectable;
|
||||
+31
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { webContents } from "electron";
|
||||
|
||||
const goBackMenuItemInjectable = getInjectable({
|
||||
id: "go-back-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "go-back",
|
||||
orderNumber: 40,
|
||||
label: "Back",
|
||||
keyboardShortcut: "CmdOrCtrl+[",
|
||||
|
||||
onClick: () => {
|
||||
webContents
|
||||
.getAllWebContents()
|
||||
.filter((wc) => wc.getType() === "window")
|
||||
.forEach((wc) => wc.goBack());
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default goBackMenuItemInjectable;
|
||||
+31
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import { webContents } from "electron";
|
||||
|
||||
const goForwardMenuItemInjectable = getInjectable({
|
||||
id: "go-forward-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "go-forward",
|
||||
orderNumber: 50,
|
||||
label: "Forward",
|
||||
keyboardShortcut: "CmdOrCtrl+]",
|
||||
|
||||
onClick: () => {
|
||||
webContents
|
||||
.getAllWebContents()
|
||||
.filter((wc) => wc.getType() === "window")
|
||||
.forEach((wc) => wc.goForward());
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default goForwardMenuItemInjectable;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import navigateToCatalogInjectable from "../../../../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
|
||||
const navigateToCatalogMenuItemInjectable = getInjectable({
|
||||
id: "navigate-to-catalog-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToCatalog = di.inject(navigateToCatalogInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "navigate-to-catalog",
|
||||
orderNumber: 10,
|
||||
label: "Catalog",
|
||||
keyboardShortcut: "Shift+CmdOrCtrl+C",
|
||||
|
||||
onClick: () => {
|
||||
navigateToCatalog();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default navigateToCatalogMenuItemInjectable;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import broadcastMessageInjectable from "../../../../../../common/ipc/broadcast-message.injectable";
|
||||
|
||||
const openCommandPaletteMenuItemInjectable = getInjectable({
|
||||
id: "open-command-palette-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const broadcastMessage = di.inject(broadcastMessageInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "open-command-palette",
|
||||
orderNumber: 20,
|
||||
label: "Command Palette...",
|
||||
keyboardShortcut: "Shift+CmdOrCtrl+P",
|
||||
|
||||
onClick(_m, _b, event) {
|
||||
/**
|
||||
* Don't broadcast unless it was triggered by menu iteration so that
|
||||
* there aren't double events in renderer
|
||||
*
|
||||
* NOTE: this `?` is required because of a bug in playwright. https://github.com/microsoft/playwright/issues/10554
|
||||
*/
|
||||
if (!event?.triggeredByAccelerator) {
|
||||
broadcastMessage("command-palette:open");
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default openCommandPaletteMenuItemInjectable;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import {
|
||||
getApplicationMenuOperationSystemActionInjectable,
|
||||
} from "../../get-application-menu-operation-system-action-injectable";
|
||||
|
||||
export const actionForToggleDevTools = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "toggle-dev-tools",
|
||||
parentId: "view",
|
||||
orderNumber: 70,
|
||||
actionName: "toggleDevTools",
|
||||
});
|
||||
|
||||
export const actionForResetZoom = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "reset-zoom",
|
||||
parentId: "view",
|
||||
orderNumber: 90,
|
||||
actionName: "resetZoom",
|
||||
});
|
||||
|
||||
export const actionForZoomIn = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "zoom-in",
|
||||
parentId: "view",
|
||||
orderNumber: 100,
|
||||
actionName: "zoomIn",
|
||||
});
|
||||
|
||||
export const actionForZoomOut = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "zoom-out",
|
||||
parentId: "view",
|
||||
orderNumber: 110,
|
||||
actionName: "zoomOut",
|
||||
});
|
||||
|
||||
export const actionForToggleFullScreen = getApplicationMenuOperationSystemActionInjectable({
|
||||
id: "toggle-full-screen",
|
||||
parentId: "view",
|
||||
orderNumber: 130,
|
||||
actionName: "togglefullscreen",
|
||||
});
|
||||
+34
@@ -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 applicationMenuItemInjectionToken from "../../application-menu-item-injection-token";
|
||||
import reloadCurrentApplicationWindowInjectable from "../../../../../../main/start-main-application/lens-window/reload-current-application-window.injectable";
|
||||
|
||||
const reloadMenuItemInjectable = getInjectable({
|
||||
id: "reload-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const reloadApplicationWindow = di.inject(
|
||||
reloadCurrentApplicationWindowInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
parentId: "view",
|
||||
id: "reload",
|
||||
orderNumber: 60,
|
||||
label: "Reload",
|
||||
keyboardShortcut: "CmdOrCtrl+R",
|
||||
|
||||
onClick: () => {
|
||||
reloadApplicationWindow();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default reloadMenuItemInjectable;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getApplicationMenuSeparatorInjectable,
|
||||
} from "../../get-application-menu-separator-injectable";
|
||||
|
||||
export const separator1 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-1-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 30,
|
||||
});
|
||||
|
||||
export const separator2 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-2-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 80,
|
||||
});
|
||||
|
||||
export const separator3 = getApplicationMenuSeparatorInjectable({
|
||||
id: "separator-3-for-view",
|
||||
parentId: "view",
|
||||
orderNumber: 120,
|
||||
});
|
||||
@@ -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 applicationMenuItemInjectionToken from "../application-menu-item-injection-token";
|
||||
|
||||
const viewMenuItemInjectable = getInjectable({
|
||||
id: "view-application-menu-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "top-level-menu" as const,
|
||||
parentId: "root" as const,
|
||||
id: "view",
|
||||
orderNumber: 40,
|
||||
label: "View",
|
||||
}),
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default viewMenuItemInjectable;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { MenuItemConstructorOptions } from "electron";
|
||||
|
||||
export interface MenuRegistration extends MenuItemConstructorOptions {
|
||||
parentId: string;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { Menu } from "electron";
|
||||
import type { MenuItemOpts } from "./application-menu-items.injectable";
|
||||
|
||||
export type MenuTopId = "mac" | "file" | "edit" | "view" | "help";
|
||||
|
||||
export function buildMenu(applicationMenuItems: MenuItemOpts[]) {
|
||||
Menu.setApplicationMenu(
|
||||
Menu.buildFromTemplate(applicationMenuItems),
|
||||
);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import populateApplicationMenuInjectable from "./populate-application-menu.injectable";
|
||||
import { getGlobalOverride } from "../../../common/test-utils/get-global-override";
|
||||
|
||||
export default getGlobalOverride(populateApplicationMenuInjectable, () => () => {});
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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 { Menu } from "electron";
|
||||
import type { MenuItemOpts } from "./application-menu-items.injectable";
|
||||
import type { Composite } from "../../../common/utils/composite/get-composite/get-composite";
|
||||
import type { ApplicationMenuItemTypes } from "./menu-items/application-menu-item-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { map, sortBy } from "lodash/fp";
|
||||
import type { MenuItemRoot } from "./application-menu-item-composite.injectable";
|
||||
import { checkThatAllDiscriminablesAreExhausted } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||
|
||||
const populateApplicationMenuInjectable = getInjectable({
|
||||
id: "populate-application-menu",
|
||||
|
||||
instantiate:
|
||||
() => (composite: Composite<ApplicationMenuItemTypes | MenuItemRoot>) => {
|
||||
const electronTemplate = getApplicationMenuTemplate(composite);
|
||||
const menu = Menu.buildFromTemplate(electronTemplate);
|
||||
|
||||
Menu.setApplicationMenu(menu);
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default populateApplicationMenuInjectable;
|
||||
|
||||
export const getApplicationMenuTemplate = (composite: Composite<ApplicationMenuItemTypes | MenuItemRoot>) => {
|
||||
const topLevelMenus = composite.children.filter(
|
||||
(x): x is Composite<ApplicationMenuItemTypes> => x.value.kind !== "root",
|
||||
);
|
||||
|
||||
return topLevelMenus.map(toHierarchicalElectronMenuItem);
|
||||
};
|
||||
|
||||
const toHierarchicalElectronMenuItem = (
|
||||
composite: Composite<ApplicationMenuItemTypes>,
|
||||
): MenuItemOpts => {
|
||||
const value = composite.value;
|
||||
|
||||
switch (value.kind) {
|
||||
case "top-level-menu": {
|
||||
const { id } = composite;
|
||||
const { label, role } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
...(role ? { role } : {}),
|
||||
label,
|
||||
|
||||
submenu: pipeline(
|
||||
composite.children,
|
||||
sortBy((childComposite) => childComposite.value.orderNumber),
|
||||
map(toHierarchicalElectronMenuItem),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
case "sub-menu": {
|
||||
const { id } = composite;
|
||||
const { label } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
label,
|
||||
|
||||
submenu: pipeline(
|
||||
composite.children,
|
||||
sortBy((childComposite) => childComposite.value.orderNumber),
|
||||
map(toHierarchicalElectronMenuItem),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
case "clickable-menu-item": {
|
||||
const { id } = composite;
|
||||
const { label, onClick, keyboardShortcut } = value;
|
||||
|
||||
return {
|
||||
...(id ? { id } : {}),
|
||||
...(label ? { label } : {}),
|
||||
...(keyboardShortcut ? { accelerator: keyboardShortcut }: {}),
|
||||
click: onClick,
|
||||
};
|
||||
}
|
||||
|
||||
case "os-action-menu-item": {
|
||||
const { label, keyboardShortcut, actionName } = value;
|
||||
|
||||
return {
|
||||
...(label ? { label } : {}),
|
||||
...(keyboardShortcut ? { accelerator: keyboardShortcut } : {}),
|
||||
role: actionName,
|
||||
};
|
||||
}
|
||||
|
||||
case "separator": {
|
||||
return {
|
||||
type: "separator",
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
throw checkThatAllDiscriminablesAreExhausted(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 applicationMenuReactivityInjectable from "./application-menu-reactivity.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../../../main/start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
|
||||
const startApplicationMenuInjectable = getInjectable({
|
||||
id: "start-application-menu",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenu = di.inject(
|
||||
applicationMenuReactivityInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
id: "start-application-menu",
|
||||
run: async () => {
|
||||
await applicationMenu.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default startApplicationMenuInjectable;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 applicationMenuReactivityInjectable from "./application-menu-reactivity.injectable";
|
||||
import { beforeQuitOfBackEndInjectionToken } from "../../../main/start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
|
||||
|
||||
const stopApplicationMenuInjectable = getInjectable({
|
||||
id: "stop-application-menu",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenu = di.inject(
|
||||
applicationMenuReactivityInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
id: "stop-application-menu",
|
||||
run: async () => {
|
||||
await applicationMenu.stop();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
});
|
||||
|
||||
export default stopApplicationMenuInjectable;
|
||||
@@ -12,43 +12,61 @@ exports[`installing update when started renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -214,43 +232,61 @@ exports[`installing update when started when user checks for updates renders 1`]
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -416,43 +452,61 @@ exports[`installing update when started when user checks for updates when new up
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -618,61 +672,83 @@ exports[`installing update when started when user checks for updates when new up
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -838,61 +914,83 @@ exports[`installing update when started when user checks for updates when new up
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -1058,43 +1156,61 @@ exports[`installing update when started when user checks for updates when no new
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import publishIsConfiguredInjectable from "./main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { CheckForPlatformUpdates } from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import appEventBusInjectable from "../../common/app-event-bus/app-event-bus.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "./main/process-checking-for-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "./main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "./main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import quitAndInstallUpdateInjectable from "./main/quit-and-install-update.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "./child-features/periodical-checking-of-updates/main/periodical-check-for-updates.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable";
|
||||
@@ -142,7 +142,7 @@ describe("analytics for installing update", () => {
|
||||
it("when checking for updates using application menu, sends event to analytics for being checked from application menu", async () => {
|
||||
analyticsListenerMock.mockClear();
|
||||
|
||||
builder.applicationMenu.click("root.check-for-updates");
|
||||
builder.applicationMenu.click("root", "mac", "check-for-updates");
|
||||
|
||||
expect(analyticsListenerMock.mock.calls).toEqual([
|
||||
[
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 applicationMenuItemInjectionToken from "../../../../application-menu/main/menu-items/application-menu-item-injection-token";
|
||||
import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable";
|
||||
import showApplicationWindowInjectable from "../../../../../main/start-main-application/lens-window/show-application-window.injectable";
|
||||
import updatingIsEnabledInjectable from "../../../main/updating-is-enabled/updating-is-enabled.injectable";
|
||||
import isMacInjectable from "../../../../../common/vars/is-mac.injectable";
|
||||
|
||||
const checkForUpdatesMenuItemInjectable = getInjectable({
|
||||
id: "check-for-updates-menu-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const processCheckingForUpdates = di.inject(
|
||||
processCheckingForUpdatesInjectable,
|
||||
);
|
||||
|
||||
const showApplicationWindow = di.inject(showApplicationWindowInjectable);
|
||||
|
||||
const updatingIsEnabled = di.inject(updatingIsEnabledInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
|
||||
return {
|
||||
kind: "clickable-menu-item" as const,
|
||||
id: "check-for-updates",
|
||||
parentId: isMac ? "mac" : "help",
|
||||
orderNumber: isMac ? 20 : 50,
|
||||
label: "Check for updates",
|
||||
isShown: updatingIsEnabled,
|
||||
|
||||
onClick: () => {
|
||||
// Todo: implement using async/await
|
||||
processCheckingForUpdates("application-menu").then(() =>
|
||||
showApplicationWindow(),
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default checkForUpdatesMenuItemInjectable;
|
||||
+116
-76
@@ -12,61 +12,83 @@ exports[`encourage user to update when sufficient time passed since update was d
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -232,43 +254,61 @@ exports[`encourage user to update when sufficient time passed since update was d
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
+11
-11
@@ -6,17 +6,17 @@ import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { act } from "@testing-library/react";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import type { CheckForPlatformUpdates } from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import electronUpdaterIsActiveInjectable from "../../../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import processCheckingForUpdatesInjectable from "../../main/process-checking-for-updates.injectable";
|
||||
import quitAndInstallUpdateInjectable from "../../main/quit-and-install-update.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../../../common/test-utils/use-fake-time";
|
||||
|
||||
function daysToMilliseconds(days: number) {
|
||||
return Math.round(days * 24 * 60 * 60 * 1000);
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import { topBarItemOnRightSideInjectionToken } from "../../../../../../renderer/components/layout/top-bar/top-bar-items/top-bar-item-injection-token";
|
||||
import { UpdateButton } from "./update-button";
|
||||
import updateWarningLevelInjectable from "./update-warning-level.injectable";
|
||||
|
||||
const updateApplicationTopBarItemInjectable = getInjectable({
|
||||
id: "update-application-top-bar-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const warningLevel = di.inject(updateWarningLevelInjectable);
|
||||
|
||||
return {
|
||||
id: "update-application",
|
||||
isShown: computed(() => !!warningLevel.get()),
|
||||
orderNumber: 50,
|
||||
Component: UpdateButton,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: topBarItemOnRightSideInjectionToken,
|
||||
});
|
||||
|
||||
export default updateApplicationTopBarItemInjectable;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export * from "./update-button";
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
.updateButton {
|
||||
--accent-color: var(--colorOk);
|
||||
|
||||
border: 1px solid var(--accent-color);
|
||||
border-radius: 4px;
|
||||
color: var(--accent-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: calc(var(--padding) / 4) var(--padding);
|
||||
gap: 6px;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
|
||||
&:hover::before{
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 2px var(--blue);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
background: var(--accent-color);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: 0.15;
|
||||
z-index: -1;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.warningMedium {
|
||||
--accent-color: var(--colorWarning);
|
||||
}
|
||||
|
||||
.warningHigh {
|
||||
--accent-color: var(--colorSoftError);
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import styles from "./styles.module.scss";
|
||||
|
||||
import type { HTMLAttributes } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Menu, MenuItem } from "../../../../../../../renderer/components/menu";
|
||||
import { cssNames } from "../../../../../../../renderer/utils";
|
||||
import type { IconProps } from "../../../../../../../renderer/components/icon";
|
||||
import { Icon } from "../../../../../../../renderer/components/icon";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import restartAndInstallUpdateInjectable from "../../../../../renderer/restart-and-install-update.injectable";
|
||||
import updateWarningLevelInjectable from "../update-warning-level.injectable";
|
||||
|
||||
interface UpdateButtonProps extends HTMLAttributes<HTMLButtonElement> {}
|
||||
|
||||
interface Dependencies {
|
||||
warningLevel: IComputedValue<"light" | "medium" | "high" | "">;
|
||||
update: () => void;
|
||||
}
|
||||
|
||||
export const NonInjectedUpdateButton = observer(({ warningLevel, update, id }: UpdateButtonProps & Dependencies) => {
|
||||
const buttonId = id ?? "update-lens-button";
|
||||
const menuIconProps: IconProps = { material: "update", small: true };
|
||||
const [opened, setOpened] = useState(false);
|
||||
const level = warningLevel.get();
|
||||
|
||||
const toggle = () => {
|
||||
setOpened(!opened);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
data-testid="update-button"
|
||||
data-warning-level={level}
|
||||
id={buttonId}
|
||||
className={cssNames(styles.updateButton, {
|
||||
[styles.warningHigh]: level === "high",
|
||||
[styles.warningMedium]: level === "medium",
|
||||
})}
|
||||
>
|
||||
Update
|
||||
<Icon material="arrow_drop_down" className={styles.icon}/>
|
||||
</button>
|
||||
<Menu
|
||||
usePortal
|
||||
htmlFor={buttonId}
|
||||
isOpen={opened}
|
||||
close={toggle}
|
||||
open={toggle}
|
||||
>
|
||||
<MenuItem
|
||||
icon={menuIconProps}
|
||||
onClick={update}
|
||||
data-testid="update-lens-menu-item"
|
||||
>
|
||||
Relaunch to Update Lens
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const UpdateButton = withInjectables<Dependencies, UpdateButtonProps>(
|
||||
NonInjectedUpdateButton,
|
||||
{
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
warningLevel: di.inject(updateWarningLevelInjectable),
|
||||
update: di.inject(restartAndInstallUpdateInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import updateDownloadedDateTimeInjectable from "../../../../common/update-downloaded-date-time/update-downloaded-date-time.injectable";
|
||||
import { reactiveNow } from "../../../../../../common/utils/reactive-now/reactive-now";
|
||||
|
||||
const updateWarningLevelInjectable = getInjectable({
|
||||
id: "update-warning-level",
|
||||
|
||||
instantiate: (di) => {
|
||||
const updateDownloadedDateTime = di.inject(updateDownloadedDateTimeInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const downloadedAt = updateDownloadedDateTime.value.get();
|
||||
|
||||
if (!downloadedAt) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const ONE_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
const downloadedAtTimestamp = new Date(downloadedAt).getTime();
|
||||
const currentDateTimeTimestamp = reactiveNow(ONE_DAY);
|
||||
|
||||
const elapsedTime = currentDateTimeTimestamp - downloadedAtTimestamp;
|
||||
|
||||
const elapsedDays = elapsedTime / ONE_DAY;
|
||||
|
||||
if (elapsedDays < 20) {
|
||||
return "light";
|
||||
}
|
||||
|
||||
if (elapsedDays >= 20 && elapsedDays < 25) {
|
||||
return "medium";
|
||||
}
|
||||
|
||||
return "high";
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default updateWarningLevelInjectable;
|
||||
+328
-212
@@ -12,43 +12,61 @@ exports[`installing update using tray when started renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -214,43 +232,61 @@ exports[`installing update using tray when started when user checks for updates
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -416,43 +452,61 @@ exports[`installing update using tray when started when user checks for updates
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -618,61 +672,83 @@ exports[`installing update using tray when started when user checks for updates
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -838,61 +914,83 @@ exports[`installing update using tray when started when user checks for updates
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -1058,43 +1156,61 @@ exports[`installing update using tray when started when user checks for updates
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
+10
-10
@@ -2,19 +2,19 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import electronUpdaterIsActiveInjectable from "../../../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import type { LensWindow } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import getCurrentApplicationWindowInjectable from "../../main/start-main-application/lens-window/application-window/get-current-application-window.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import type { LensWindow } from "../../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import getCurrentApplicationWindowInjectable from "../../../../main/start-main-application/lens-window/application-window/get-current-application-window.injectable";
|
||||
|
||||
describe("installing update using tray", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
+34
@@ -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 { computed } from "mobx";
|
||||
import getTrayIconPathInjectable from "../../../../../../main/tray/menu-icon/get-tray-icon-path.injectable";
|
||||
import { trayIconInjectionToken } from "../../../../../../main/tray/menu-icon/tray-icon-injection-token";
|
||||
import updatesAreBeingDiscoveredInjectable from "../../../../common/updates-are-being-discovered/updates-are-being-discovered.injectable";
|
||||
import updateIsBeingDownloadedInjectable from "../../../../common/update-is-being-downloaded/update-is-being-downloaded.injectable";
|
||||
|
||||
const checkingForUpdatesTrayIconInjectable = getInjectable({
|
||||
id: "checking-for-updates-tray-icon",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getTrayIconPath = di.inject(getTrayIconPathInjectable);
|
||||
const updatesAreBeingDiscovered = di.inject(updatesAreBeingDiscoveredInjectable);
|
||||
const updateIsBeingDownloaded = di.inject(updateIsBeingDownloadedInjectable);
|
||||
|
||||
return {
|
||||
iconPath: getTrayIconPath("checking-for-updates"),
|
||||
priority: 1,
|
||||
shouldBeShown: computed(
|
||||
() =>
|
||||
updatesAreBeingDiscovered.value.get() ||
|
||||
updateIsBeingDownloaded.value.get(),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: trayIconInjectionToken,
|
||||
});
|
||||
|
||||
export default checkingForUpdatesTrayIconInjectable;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 getTrayIconPathInjectable from "../../../../../../main/tray/menu-icon/get-tray-icon-path.injectable";
|
||||
import { trayIconInjectionToken } from "../../../../../../main/tray/menu-icon/tray-icon-injection-token";
|
||||
import updateIsReadyToBeInstalledInjectable from "../update-is-ready-to-be-installed.injectable";
|
||||
|
||||
const updateIsReadyToBeInstalledTrayIconInjectable = getInjectable({
|
||||
id: "update-is-ready-to-be-installed-tray-icon",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getTrayIconPath = di.inject(getTrayIconPathInjectable);
|
||||
const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable);
|
||||
|
||||
return {
|
||||
iconPath: getTrayIconPath("update-available"),
|
||||
priority: 1,
|
||||
shouldBeShown: updateIsReadyToBeInstalled,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: trayIconInjectionToken,
|
||||
});
|
||||
|
||||
export default updateIsReadyToBeInstalledTrayIconInjectable;
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import updatingIsEnabledInjectable from "../../../../main/updating-is-enabled/updating-is-enabled.injectable";
|
||||
import { trayMenuItemInjectionToken } from "../../../../../../main/tray/tray-menu-item/tray-menu-item-injection-token";
|
||||
import showApplicationWindowInjectable from "../../../../../../main/start-main-application/lens-window/show-application-window.injectable";
|
||||
import discoveredUpdateVersionInjectable from "../../../../common/discovered-update-version/discovered-update-version.injectable";
|
||||
import updateIsBeingDownloadedInjectable from "../../../../common/update-is-being-downloaded/update-is-being-downloaded.injectable";
|
||||
import updatesAreBeingDiscoveredInjectable from "../../../../common/updates-are-being-discovered/updates-are-being-discovered.injectable";
|
||||
import progressOfUpdateDownloadInjectable from "../../../../common/progress-of-update-download/progress-of-update-download.injectable";
|
||||
import assert from "assert";
|
||||
import processCheckingForUpdatesInjectable from "../../../../main/process-checking-for-updates.injectable";
|
||||
import { withErrorSuppression } from "../../../../../../common/utils/with-error-suppression/with-error-suppression";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import withErrorLoggingInjectable from "../../../../../../common/utils/with-error-logging/with-error-logging.injectable";
|
||||
|
||||
const checkForUpdatesTrayItemInjectable = getInjectable({
|
||||
id: "check-for-updates-tray-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const showApplicationWindow = di.inject(showApplicationWindowInjectable);
|
||||
const updatingIsEnabled = di.inject(updatingIsEnabledInjectable);
|
||||
const progressOfUpdateDownload = di.inject(progressOfUpdateDownloadInjectable);
|
||||
const discoveredVersionState = di.inject(discoveredUpdateVersionInjectable);
|
||||
const downloadingUpdateState = di.inject(updateIsBeingDownloadedInjectable);
|
||||
const checkingForUpdatesState = di.inject(updatesAreBeingDiscoveredInjectable);
|
||||
const processCheckingForUpdates = di.inject(processCheckingForUpdatesInjectable);
|
||||
const withErrorLoggingFor = di.inject(withErrorLoggingInjectable);
|
||||
|
||||
return {
|
||||
id: "check-for-updates",
|
||||
parentId: null,
|
||||
orderNumber: 30,
|
||||
|
||||
label: computed(() => {
|
||||
if (downloadingUpdateState.value.get()) {
|
||||
const discoveredVersion = discoveredVersionState.value.get();
|
||||
|
||||
assert(discoveredVersion);
|
||||
|
||||
const roundedPercentage = Math.round(progressOfUpdateDownload.value.get().percentage);
|
||||
|
||||
return `Downloading update ${discoveredVersion.version} (${roundedPercentage}%)...`;
|
||||
}
|
||||
|
||||
if (checkingForUpdatesState.value.get()) {
|
||||
return "Checking for updates...";
|
||||
}
|
||||
|
||||
return "Check for updates";
|
||||
}),
|
||||
|
||||
enabled: computed(() => !checkingForUpdatesState.value.get() && !downloadingUpdateState.value.get()),
|
||||
|
||||
visible: computed(() => updatingIsEnabled),
|
||||
|
||||
click: pipeline(
|
||||
async () => {
|
||||
const { updateIsReadyToBeInstalled } = await processCheckingForUpdates("tray");
|
||||
|
||||
if (updateIsReadyToBeInstalled) {
|
||||
await showApplicationWindow();
|
||||
}
|
||||
},
|
||||
|
||||
withErrorLoggingFor(() => "[TRAY]: Checking for updates failed."),
|
||||
|
||||
// TODO: Find out how to improve typing so that instead of
|
||||
// x => withErrorSuppression(x) there could only be withErrorSuppression
|
||||
(x) => withErrorSuppression(x),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: trayMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default checkForUpdatesTrayItemInjectable;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import { trayMenuItemInjectionToken } from "../../../../../../main/tray/tray-menu-item/tray-menu-item-injection-token";
|
||||
import discoveredUpdateVersionInjectable from "../../../../common/discovered-update-version/discovered-update-version.injectable";
|
||||
import { withErrorSuppression } from "../../../../../../common/utils/with-error-suppression/with-error-suppression";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import withErrorLoggingInjectable from "../../../../../../common/utils/with-error-logging/with-error-logging.injectable";
|
||||
import quitAndInstallUpdateInjectable from "../../../../main/quit-and-install-update.injectable";
|
||||
import updateIsReadyToBeInstalledInjectable from "../update-is-ready-to-be-installed.injectable";
|
||||
|
||||
const installApplicationUpdateTrayItemInjectable = getInjectable({
|
||||
id: "install-update-tray-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const quitAndInstallUpdate = di.inject(quitAndInstallUpdateInjectable);
|
||||
const discoveredVersionState = di.inject(discoveredUpdateVersionInjectable);
|
||||
const withErrorLoggingFor = di.inject(withErrorLoggingInjectable);
|
||||
const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable);
|
||||
|
||||
return {
|
||||
id: "install-update",
|
||||
parentId: null,
|
||||
orderNumber: 50,
|
||||
|
||||
label: computed(() => {
|
||||
const versionToBeInstalled = discoveredVersionState.value.get()?.version;
|
||||
|
||||
return `Install update ${versionToBeInstalled}`;
|
||||
}),
|
||||
|
||||
enabled: computed(() => true),
|
||||
|
||||
visible: updateIsReadyToBeInstalled,
|
||||
|
||||
click: pipeline(
|
||||
quitAndInstallUpdate,
|
||||
|
||||
withErrorLoggingFor(() => "[TRAY]: Update installation failed."),
|
||||
|
||||
// TODO: Find out how to improve typing so that instead of
|
||||
// x => withErrorSuppression(x) there could only be withErrorSuppression
|
||||
(x) => withErrorSuppression(x),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: trayMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default installApplicationUpdateTrayItemInjectable;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import discoveredUpdateVersionInjectable from "../../../common/discovered-update-version/discovered-update-version.injectable";
|
||||
import updateIsBeingDownloadedInjectable from "../../../common/update-is-being-downloaded/update-is-being-downloaded.injectable";
|
||||
|
||||
const updateIsReadyToBeInstalledInjectable = getInjectable({
|
||||
id: "update-is-ready-to-be-installed",
|
||||
|
||||
instantiate: (di) => {
|
||||
const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable);
|
||||
const updateIsBeingDownloaded = di.inject(updateIsBeingDownloadedInjectable);
|
||||
|
||||
return computed(
|
||||
() =>
|
||||
!!discoveredUpdateVersion.value.get() &&
|
||||
!updateIsBeingDownloaded.value.get(),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default updateIsReadyToBeInstalledInjectable;
|
||||
+204
-138
@@ -12,61 +12,83 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -232,61 +254,83 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
@@ -499,61 +543,83 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
data-icon-name="home"
|
||||
>
|
||||
arrow_drop_down
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<button
|
||||
class="updateButton"
|
||||
data-testid="update-button"
|
||||
data-warning-level="light"
|
||||
id="update-lens-button"
|
||||
>
|
||||
Update
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_drop_down"
|
||||
>
|
||||
arrow_drop_down
|
||||
</span>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
+12
-12
@@ -2,23 +2,23 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { CheckForPlatformUpdates } from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { DownloadPlatformUpdate } from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/process-checking-for-updates.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable";
|
||||
import timeAfterUpdateMustBeInstalledInjectable from "../../renderer/application-update/force-update-modal/time-after-update-must-be-installed.injectable";
|
||||
import secondsAfterInstallStartsInjectable from "../../renderer/application-update/force-update-modal/seconds-after-install-starts.injectable";
|
||||
import forceUpdateModalRootFrameComponentInjectable from "../../renderer/application-update/force-update-modal/force-update-modal-root-frame-component.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../../../common/test-utils/use-fake-time";
|
||||
import quitAndInstallUpdateInjectable from "../../main/quit-and-install-update.injectable";
|
||||
import timeAfterUpdateMustBeInstalledInjectable from "./renderer/force-update-modal/time-after-update-must-be-installed.injectable";
|
||||
import secondsAfterInstallStartsInjectable from "./renderer/force-update-modal/seconds-after-install-starts.injectable";
|
||||
import forceUpdateModalRootFrameComponentInjectable from "./renderer/force-update-modal/force-update-modal-root-frame-component.injectable";
|
||||
|
||||
const TIME_AFTER_UPDATE_MUST_BE_INSTALLED = 1000;
|
||||
const TIME_AFTER_INSTALL_STARTS = 5 * 1000;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { computed } from "mobx";
|
||||
import { getGlobalOverride } from "../../../../../../common/test-utils/get-global-override";
|
||||
import forceUpdateModalRootFrameComponentInjectable from "./force-update-modal-root-frame-component.injectable";
|
||||
|
||||
export default getGlobalOverride(
|
||||
forceUpdateModalRootFrameComponentInjectable,
|
||||
|
||||
() => ({
|
||||
id: "force-update-modal",
|
||||
Component: () => null,
|
||||
shouldRender: computed(() => false),
|
||||
}),
|
||||
);
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import { rootFrameChildComponentInjectionToken } from "../../../../../../renderer/frames/root-frame/root-frame-child-component-injection-token";
|
||||
import { ForceUpdateModal } from "./force-update-modal";
|
||||
import timeSinceUpdateWasDownloadedInjectable from "./time-since-update-was-downloaded.injectable";
|
||||
import updateDownloadedDateTimeInjectable from "../../../../common/update-downloaded-date-time/update-downloaded-date-time.injectable";
|
||||
import timeAfterUpdateMustBeInstalledInjectable from "./time-after-update-must-be-installed.injectable";
|
||||
|
||||
const forceUpdateModalRootFrameComponentInjectable = getInjectable({
|
||||
id: "force-update-modal-root-frame-component",
|
||||
|
||||
instantiate: (di) => {
|
||||
const timeSinceUpdateWasDownloaded = di.inject(timeSinceUpdateWasDownloadedInjectable);
|
||||
const updateDownloadedDateTime = di.inject(updateDownloadedDateTimeInjectable);
|
||||
const timeWhenUpdateMustBeInstalled = di.inject(timeAfterUpdateMustBeInstalledInjectable);
|
||||
|
||||
return {
|
||||
id: "force-update-modal",
|
||||
Component: ForceUpdateModal,
|
||||
|
||||
shouldRender: computed(
|
||||
() =>
|
||||
!!updateDownloadedDateTime.value.get() &&
|
||||
timeSinceUpdateWasDownloaded.get() >= timeWhenUpdateMustBeInstalled,
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: rootFrameChildComponentInjectionToken,
|
||||
|
||||
// Note: Globally overridden because it observes the current time which can cause long running tests
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default forceUpdateModalRootFrameComponentInjectable;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
$baseline: 8px;
|
||||
|
||||
.ForceUpdateModal {
|
||||
background-color: white;
|
||||
border-radius: 1 * $baseline;
|
||||
padding: 3 * $baseline;
|
||||
width: 50 * $baseline;
|
||||
|
||||
.header {
|
||||
margin-bottom: 2 * $baseline;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-bottom: 2 * $baseline;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import React from "react";
|
||||
import restartAndInstallUpdateInjectable from "../../../../renderer/restart-and-install-update.injectable";
|
||||
import { Countdown } from "../../../../../../renderer/components/countdown/countdown";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import installUpdateCountdownInjectable from "./install-update-countdown.injectable";
|
||||
import { Dialog } from "../../../../../../renderer/components/dialog";
|
||||
import { Button } from "../../../../../../renderer/components/button";
|
||||
import styles from "./force-update-modal.module.scss";
|
||||
|
||||
interface Dependencies {
|
||||
restartAndInstallUpdate: () => void;
|
||||
secondsTill: IComputedValue<number>;
|
||||
}
|
||||
|
||||
const NonInjectedForceUpdateModal = observer(
|
||||
({ restartAndInstallUpdate, secondsTill }: Dependencies) => (
|
||||
<Dialog isOpen={true} pinned>
|
||||
<div
|
||||
data-testid="must-update-immediately"
|
||||
className={styles.ForceUpdateModal}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<h2>Please update</h2>
|
||||
</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
<p>
|
||||
An update to Lens Desktop is required to continue using the application.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.footer}>
|
||||
<Button
|
||||
primary
|
||||
data-testid="update-now-from-must-update-immediately-modal"
|
||||
onClick={restartAndInstallUpdate}
|
||||
label="Update"
|
||||
>
|
||||
{" "}
|
||||
(
|
||||
<Countdown
|
||||
secondsTill={secondsTill}
|
||||
data-testid="countdown-to-automatic-update"
|
||||
/>
|
||||
)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
),
|
||||
);
|
||||
|
||||
export const ForceUpdateModal = withInjectables<Dependencies>(
|
||||
NonInjectedForceUpdateModal,
|
||||
|
||||
{
|
||||
getProps: (di, props) => ({
|
||||
restartAndInstallUpdate: di.inject(restartAndInstallUpdateInjectable),
|
||||
secondsTill: di.inject(installUpdateCountdownInjectable),
|
||||
...props,
|
||||
}),
|
||||
},
|
||||
);
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 countdownStateInjectable from "../../../../../../renderer/components/countdown/countdown-state.injectable";
|
||||
import secondsAfterInstallStartsInjectable from "./seconds-after-install-starts.injectable";
|
||||
import restartAndInstallUpdateInjectable from "../../../../renderer/restart-and-install-update.injectable";
|
||||
|
||||
const installUpdateCountdownInjectable = getInjectable({
|
||||
id: "install-update-countdown",
|
||||
|
||||
instantiate: (di) => {
|
||||
const secondsAfterInstallStarts = di.inject(secondsAfterInstallStartsInjectable);
|
||||
const restartAndInstallUpdate = di.inject(restartAndInstallUpdateInjectable);
|
||||
|
||||
return di.inject(countdownStateInjectable, {
|
||||
startFrom: secondsAfterInstallStarts,
|
||||
|
||||
onZero: () => {
|
||||
restartAndInstallUpdate();
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default installUpdateCountdownInjectable;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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 secondsAfterInstallStartsInjectable = getInjectable({
|
||||
id: "seconds-after-install-starts",
|
||||
instantiate: () => 90,
|
||||
});
|
||||
|
||||
export default secondsAfterInstallStartsInjectable;
|
||||
+14
@@ -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";
|
||||
|
||||
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const timeAfterUpdateMustBeInstalledInjectable = getInjectable({
|
||||
id: "time-after-update-must-be-installed",
|
||||
instantiate: () => THIRTY_DAYS,
|
||||
});
|
||||
|
||||
export default timeAfterUpdateMustBeInstalledInjectable;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 assert from "assert";
|
||||
import { computed } from "mobx";
|
||||
import moment from "moment";
|
||||
import updateDownloadedDateTimeInjectable from "../../../../common/update-downloaded-date-time/update-downloaded-date-time.injectable";
|
||||
import { reactiveNow } from "../../../../../../common/utils/reactive-now/reactive-now";
|
||||
|
||||
const timeSinceUpdateWasDownloadedInjectable = getInjectable({
|
||||
id: "time-since-update-was-downloaded",
|
||||
|
||||
instantiate: (di) => {
|
||||
const updateDownloadedDateTime = di.inject(updateDownloadedDateTimeInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const currentTimestamp = reactiveNow();
|
||||
|
||||
const downloadedAt = updateDownloadedDateTime.value.get();
|
||||
|
||||
assert(downloadedAt);
|
||||
|
||||
return currentTimestamp - (moment(downloadedAt).unix() * 1000);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default timeSinceUpdateWasDownloadedInjectable;
|
||||
+48
-30
@@ -12,43 +12,61 @@ exports[`periodical checking of updates given updater is enabled and configurati
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import periodicalCheckForUpdatesInjectable from "./periodical-check-for-updates.injectable";
|
||||
import { getGlobalOverride } from "../../../../../common/test-utils/get-global-override";
|
||||
|
||||
export default getGlobalOverride(periodicalCheckForUpdatesInjectable, () => ({
|
||||
start: async () => {},
|
||||
stop: async () => {},
|
||||
started: false,
|
||||
}));
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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 { getStartableStoppable } from "../../../../../common/utils/get-startable-stoppable";
|
||||
import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable";
|
||||
import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable";
|
||||
|
||||
const periodicalCheckForUpdatesInjectable = getInjectable({
|
||||
id: "periodical-check-for-updates",
|
||||
|
||||
instantiate: (di) => {
|
||||
const withOrphanPromise = di.inject(withOrphanPromiseInjectable);
|
||||
const processCheckingForUpdates = withOrphanPromise(di.inject(processCheckingForUpdatesInjectable));
|
||||
|
||||
return getStartableStoppable("periodical-check-for-updates", () => {
|
||||
const TWO_HOURS = 1000 * 60 * 60 * 2;
|
||||
|
||||
processCheckingForUpdates("periodic");
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
|
||||
processCheckingForUpdates("periodic");
|
||||
}, TWO_HOURS);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default periodicalCheckForUpdatesInjectable;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 periodicalCheckForUpdatesInjectable from "./periodical-check-for-updates.injectable";
|
||||
import updatingIsEnabledInjectable from "../../../main/updating-is-enabled/updating-is-enabled.injectable";
|
||||
import { afterApplicationIsLoadedInjectionToken } from "../../../../../main/start-main-application/runnable-tokens/after-application-is-loaded-injection-token";
|
||||
|
||||
const startCheckingForUpdatesInjectable = getInjectable({
|
||||
id: "start-checking-for-updates",
|
||||
|
||||
instantiate: (di) => {
|
||||
const periodicalCheckForUpdates = di.inject(periodicalCheckForUpdatesInjectable);
|
||||
const updatingIsEnabled = di.inject(updatingIsEnabledInjectable);
|
||||
|
||||
return {
|
||||
id: "start-checking-for-updates",
|
||||
run: async () => {
|
||||
if (updatingIsEnabled && !periodicalCheckForUpdates.started) {
|
||||
await periodicalCheckForUpdates.start();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsLoadedInjectionToken,
|
||||
});
|
||||
|
||||
export default startCheckingForUpdatesInjectable;
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 periodicalCheckForUpdatesInjectable from "./periodical-check-for-updates.injectable";
|
||||
import { beforeQuitOfBackEndInjectionToken } from "../../../../../main/start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
|
||||
|
||||
const stopCheckingForUpdatesInjectable = getInjectable({
|
||||
id: "stop-checking-for-updates",
|
||||
|
||||
instantiate: (di) => {
|
||||
const periodicalCheckForUpdates = di.inject(periodicalCheckForUpdatesInjectable);
|
||||
|
||||
return {
|
||||
id: "stop-checking-for-updates",
|
||||
run: async () => {
|
||||
if (periodicalCheckForUpdates.started) {
|
||||
await periodicalCheckForUpdates.stop();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
});
|
||||
|
||||
export default stopCheckingForUpdatesInjectable;
|
||||
+7
-7
@@ -2,14 +2,14 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import electronUpdaterIsActiveInjectable from "../../../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/process-checking-for-updates.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "./main/periodical-check-for-updates.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../../../common/test-utils/use-fake-time";
|
||||
|
||||
const ENOUGH_TIME = 1000 * 60 * 60 * 2;
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { preferenceItemInjectionToken } from "../../../../../preferences/renderer/preference-items/preference-item-injection-token";
|
||||
import { UpdateChannel } from "./update-channel";
|
||||
|
||||
const updateChannelPreferenceBlockInjectable = getInjectable({
|
||||
id: "update-channel-preference-item",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "block" as const,
|
||||
id: "update-channel",
|
||||
parentId: "application-page",
|
||||
orderNumber: 50,
|
||||
Component: UpdateChannel,
|
||||
}),
|
||||
|
||||
injectionToken: preferenceItemInjectionToken,
|
||||
});
|
||||
|
||||
export default updateChannelPreferenceBlockInjectable;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import { updateChannels } from "../../../../common/update-channels";
|
||||
import type { SelectedUpdateChannel } from "../../../../common/selected-update-channel/selected-update-channel.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../../../common/selected-update-channel/selected-update-channel.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { map, toPairs } from "lodash/fp";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
interface Dependencies {
|
||||
selectedUpdateChannel: SelectedUpdateChannel;
|
||||
}
|
||||
|
||||
const updateChannelOptions = pipeline(
|
||||
toPairs(updateChannels),
|
||||
|
||||
map(([, channel]) => ({
|
||||
value: channel.id,
|
||||
label: channel.label,
|
||||
})),
|
||||
);
|
||||
|
||||
|
||||
const NonInjectedUpdateChannel = observer(({ selectedUpdateChannel }: Dependencies) => (
|
||||
<section id="update-channel">
|
||||
<SubTitle title="Update Channel" />
|
||||
<Select
|
||||
id="update-channel-input"
|
||||
options={updateChannelOptions}
|
||||
value={selectedUpdateChannel.value.get().id}
|
||||
onChange={(selected) => selectedUpdateChannel.setValue(selected?.value)}
|
||||
themeName="lens"
|
||||
/>
|
||||
</section>
|
||||
));
|
||||
|
||||
export const UpdateChannel = withInjectables<Dependencies>(
|
||||
NonInjectedUpdateChannel,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
selectedUpdateChannel: di.inject(selectedUpdateChannelInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
+48
-30
@@ -12,43 +12,61 @@ exports[`selection of update stability when started renders 1`] = `
|
||||
<div
|
||||
class="items"
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="home-button"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="home"
|
||||
>
|
||||
home
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_back"
|
||||
>
|
||||
arrow_back
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="size-sm"
|
||||
/>
|
||||
<div
|
||||
class="preventedDragging"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
<i
|
||||
class="Icon material interactive disabled focusable"
|
||||
data-testid="history-forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="arrow_forward"
|
||||
>
|
||||
arrow_forward
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="separator"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="items"
|
||||
/>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
+17
-16
@@ -2,27 +2,28 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import quitAndInstallUpdateInjectable from "../../main/quit-and-install-update.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import electronUpdaterIsActiveInjectable from "../../../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { UpdateChannel, ReleaseChannel } from "../../common/application-update/update-channels";
|
||||
import { updateChannels } from "../../common/application-update/update-channels";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { UpdateChannel, ReleaseChannel } from "../../common/update-channels";
|
||||
import { updateChannels } from "../../common/update-channels";
|
||||
import type { DownloadPlatformUpdate } from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../common/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
|
||||
import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import setUpdateOnQuitInjectable from "../../../../main/electron-app/features/set-update-on-quit.injectable";
|
||||
import showInfoNotificationInjectable from "../../../../renderer/components/notifications/show-info-notification.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/process-checking-for-updates.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable";
|
||||
import getBuildVersionInjectable
|
||||
from "../../../../main/vars/build-version/get-build-version.injectable";
|
||||
|
||||
describe("selection of update stability", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 createSyncBoxInjectable from "../../../../common/utils/sync-box/create-sync-box.injectable";
|
||||
import type { UpdateChannel } from "../update-channels";
|
||||
import type { SyncBox } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { syncBoxInjectionToken } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
|
||||
export type DiscoveredUpdateVersion = SyncBox<{ version: string; updateChannel: UpdateChannel } | null>;
|
||||
|
||||
const discoveredUpdateVersionInjectable = getInjectable({
|
||||
id: "discovered-update-version",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox(
|
||||
"discovered-update-version",
|
||||
null,
|
||||
) as DiscoveredUpdateVersion;
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default discoveredUpdateVersionInjectable;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 createSyncBoxInjectable from "../../../../common/utils/sync-box/create-sync-box.injectable";
|
||||
import type { SyncBox } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { syncBoxInjectionToken } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
|
||||
export interface ProgressOfDownload {
|
||||
percentage: number;
|
||||
failed?: string;
|
||||
}
|
||||
|
||||
export type ProgressOfUpdateDownload = SyncBox<ProgressOfDownload>;
|
||||
|
||||
const progressOfUpdateDownloadInjectable = getInjectable({
|
||||
id: "progress-of-update-download-state",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox<ProgressOfDownload>("progress-of-update-download", { percentage: 0 });
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default progressOfUpdateDownloadInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { MessageChannel } from "../../../common/utils/channel/message-channel-listener-injection-token";
|
||||
|
||||
export type RestartAndInstallUpdateChannel = MessageChannel<void>;
|
||||
|
||||
export const restartAndInstallUpdateChannel: RestartAndInstallUpdateChannel = {
|
||||
id: "restart-and-install-update-channel",
|
||||
};
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import releaseChannelInjectable from "../../../../common/vars/release-channel.injectable";
|
||||
import { updateChannels } from "../update-channels";
|
||||
import { createInitializableState } from "../../../../common/initializable-state/create";
|
||||
|
||||
const defaultUpdateChannelInjectable = createInitializableState({
|
||||
id: "default-update-channel",
|
||||
init: (di) => updateChannels[di.inject(releaseChannelInjectable).get()],
|
||||
});
|
||||
|
||||
export default defaultUpdateChannelInjectable;
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 { IComputedValue } from "mobx";
|
||||
import { action, computed, observable } from "mobx";
|
||||
import type { UpdateChannel, ReleaseChannel } from "../update-channels";
|
||||
import { updateChannels } from "../update-channels";
|
||||
import defaultUpdateChannelInjectable from "./default-update-channel.injectable";
|
||||
|
||||
export interface SelectedUpdateChannel {
|
||||
value: IComputedValue<UpdateChannel>;
|
||||
setValue: (channelId?: ReleaseChannel) => void;
|
||||
}
|
||||
|
||||
const selectedUpdateChannelInjectable = getInjectable({
|
||||
id: "selected-update-channel",
|
||||
|
||||
instantiate: (di): SelectedUpdateChannel => {
|
||||
const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable);
|
||||
const state = observable.box<UpdateChannel>(undefined, { deep: false });
|
||||
|
||||
return {
|
||||
value: computed(() => state.get() ?? defaultUpdateChannel.get()),
|
||||
|
||||
setValue: action((channelId) => {
|
||||
const targetUpdateChannel =
|
||||
channelId && updateChannels[channelId]
|
||||
? updateChannels[channelId]
|
||||
: defaultUpdateChannel.get();
|
||||
|
||||
state.set(targetUpdateChannel);
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default selectedUpdateChannelInjectable;
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
|
||||
export type ReleaseChannel = "alpha" | "beta" | "latest";
|
||||
|
||||
const latestChannel: UpdateChannel = {
|
||||
id: "latest",
|
||||
label: "Stable",
|
||||
moreStableUpdateChannel: null,
|
||||
};
|
||||
|
||||
const betaChannel: UpdateChannel = {
|
||||
id: "beta",
|
||||
label: "Beta",
|
||||
moreStableUpdateChannel: latestChannel,
|
||||
};
|
||||
|
||||
const alphaChannel: UpdateChannel = {
|
||||
id: "alpha",
|
||||
label: "Alpha",
|
||||
moreStableUpdateChannel: betaChannel,
|
||||
};
|
||||
|
||||
export const updateChannels = {
|
||||
latest: latestChannel,
|
||||
beta: betaChannel,
|
||||
alpha: alphaChannel,
|
||||
};
|
||||
|
||||
export interface UpdateChannel {
|
||||
readonly id: ReleaseChannel;
|
||||
readonly label: string;
|
||||
readonly moreStableUpdateChannel: UpdateChannel | null;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 createSyncBoxInjectable from "../../../../common/utils/sync-box/create-sync-box.injectable";
|
||||
import { syncBoxInjectionToken } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
|
||||
const updateDownloadedDateTimeInjectable = getInjectable({
|
||||
id: "update-downloaded-date-time",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox<string | null>(
|
||||
"update-downloaded-date-time",
|
||||
null,
|
||||
);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default updateDownloadedDateTimeInjectable;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 createSyncBoxInjectable from "../../../../common/utils/sync-box/create-sync-box.injectable";
|
||||
import type { SyncBox } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { syncBoxInjectionToken } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
|
||||
export type UpdateIsBeingDownloaded = SyncBox<boolean>;
|
||||
|
||||
const updateIsBeingDownloadedInjectable = getInjectable({
|
||||
id: "update-is-being-downloaded",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox("update-is-being-downloaded", false);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default updateIsBeingDownloadedInjectable;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 createSyncBoxInjectable from "../../../../common/utils/sync-box/create-sync-box.injectable";
|
||||
import type { SyncBox } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { syncBoxInjectionToken } from "../../../../common/utils/sync-box/sync-box-injection-token";
|
||||
|
||||
export type UpdatesAreBeingDiscovered = SyncBox<boolean>;
|
||||
|
||||
const updatesAreBeingDiscoveredInjectable = getInjectable({
|
||||
id: "updates-are-being-discovered",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox("updates-are-being-discovered", false);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default updatesAreBeingDiscoveredInjectable;
|
||||
@@ -5,15 +5,15 @@
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import publishIsConfiguredInjectable from "./main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { CheckForPlatformUpdates } from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "./main/process-checking-for-updates.injectable";
|
||||
import selectedUpdateChannelInjectable from "./common/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { updateChannels } from "../../common/application-update/update-channels";
|
||||
import { updateChannels } from "./common/update-channels";
|
||||
import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable";
|
||||
|
||||
describe("downgrading version update", () => {
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable";
|
||||
import quitAndInstallUpdateInjectable from "./main/quit-and-install-update.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import publishIsConfiguredInjectable from "./main/updating-is-enabled/publish-is-configured/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "./main/check-for-updates/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import type { DownloadPlatformUpdate } from "./main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "./main/download-update/download-platform-update/download-platform-update.injectable";
|
||||
import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "./main/process-checking-for-updates.injectable";
|
||||
import { useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable";
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import checkForPlatformUpdatesInjectable from "./check-for-platform-updates.injectable";
|
||||
import { getGlobalOverrideForFunction } from "../../../../../common/test-utils/get-global-override-for-function";
|
||||
|
||||
export default getGlobalOverrideForFunction(checkForPlatformUpdatesInjectable);
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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 electronUpdaterInjectable from "../../../../../main/electron-app/features/electron-updater.injectable";
|
||||
import type { UpdateChannel } from "../../../common/update-channels";
|
||||
import loggerInjectable from "../../../../../common/logger.injectable";
|
||||
import type { UpdateCheckResult } from "electron-updater";
|
||||
|
||||
export type CheckForUpdatesResult = {
|
||||
updateWasDiscovered: false;
|
||||
} | {
|
||||
updateWasDiscovered: true;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export type CheckForPlatformUpdates = (updateChannel: UpdateChannel, opts: { allowDowngrade: boolean }) => Promise<CheckForUpdatesResult>;
|
||||
|
||||
const checkForPlatformUpdatesInjectable = getInjectable({
|
||||
id: "check-for-platform-updates",
|
||||
|
||||
instantiate: (di): CheckForPlatformUpdates => {
|
||||
const electronUpdater = di.inject(electronUpdaterInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return async (updateChannel, { allowDowngrade }) => {
|
||||
electronUpdater.channel = updateChannel.id;
|
||||
electronUpdater.autoDownload = false;
|
||||
electronUpdater.allowDowngrade = allowDowngrade;
|
||||
|
||||
let result: UpdateCheckResult;
|
||||
|
||||
try {
|
||||
result = await electronUpdater.checkForUpdates();
|
||||
} catch (error) {
|
||||
logger.error("[UPDATE-APP/CHECK-FOR-UPDATES]", error);
|
||||
|
||||
return {
|
||||
updateWasDiscovered: false,
|
||||
};
|
||||
}
|
||||
|
||||
const { updateInfo, cancellationToken } = result;
|
||||
|
||||
if (!cancellationToken) {
|
||||
return {
|
||||
updateWasDiscovered: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
updateWasDiscovered: true,
|
||||
version: updateInfo.version,
|
||||
};
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default checkForPlatformUpdatesInjectable;
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../../../main/getDiForUnitTesting";
|
||||
import electronUpdaterInjectable from "../../../../../main/electron-app/features/electron-updater.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { AppUpdater, UpdateCheckResult } from "electron-updater";
|
||||
import type { CheckForPlatformUpdates } from "./check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "./check-for-platform-updates.injectable";
|
||||
import type { UpdateChannel, ReleaseChannel } from "../../../common/update-channels";
|
||||
import { getPromiseStatus } from "../../../../../common/test-utils/get-promise-status";
|
||||
import loggerInjectable from "../../../../../common/logger.injectable";
|
||||
import type { Logger } from "../../../../../common/logger";
|
||||
|
||||
describe("check-for-platform-updates", () => {
|
||||
let checkForPlatformUpdates: CheckForPlatformUpdates;
|
||||
let electronUpdaterFake: AppUpdater;
|
||||
let checkForUpdatesMock: AsyncFnMock<() => UpdateCheckResult>;
|
||||
let logErrorMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
checkForUpdatesMock = asyncFn();
|
||||
|
||||
electronUpdaterFake = {
|
||||
channel: undefined,
|
||||
autoDownload: undefined,
|
||||
allowDowngrade: undefined,
|
||||
|
||||
checkForUpdates: checkForUpdatesMock,
|
||||
} as unknown as AppUpdater;
|
||||
|
||||
di.override(electronUpdaterInjectable, () => electronUpdaterFake);
|
||||
|
||||
logErrorMock = jest.fn();
|
||||
|
||||
di.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger);
|
||||
|
||||
checkForPlatformUpdates = di.inject(checkForPlatformUpdatesInjectable);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let actualPromise: Promise<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
const testUpdateChannel: UpdateChannel = {
|
||||
id: "some-update-channel" as ReleaseChannel,
|
||||
label: "Some update channel",
|
||||
moreStableUpdateChannel: null,
|
||||
};
|
||||
|
||||
actualPromise = checkForPlatformUpdates(testUpdateChannel, { allowDowngrade: true });
|
||||
});
|
||||
|
||||
it("sets update channel", () => {
|
||||
expect(electronUpdaterFake.channel).toBe("some-update-channel");
|
||||
});
|
||||
|
||||
it("sets flag for allowing downgrade", () => {
|
||||
expect(electronUpdaterFake.allowDowngrade).toBe(true);
|
||||
});
|
||||
|
||||
it("disables auto downloading for being controlled", () => {
|
||||
expect(electronUpdaterFake.autoDownload).toBe(false);
|
||||
});
|
||||
|
||||
it("checks for updates", () => {
|
||||
expect(checkForUpdatesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("when checking for updates resolves with update, resolves with the discovered update", async () => {
|
||||
await checkForUpdatesMock.resolve({
|
||||
updateInfo: {
|
||||
version: "some-version",
|
||||
},
|
||||
|
||||
cancellationToken: "some-cancellation-token",
|
||||
} as unknown as UpdateCheckResult);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toEqual({ updateWasDiscovered: true, version: "some-version" });
|
||||
});
|
||||
|
||||
it("when checking for updates resolves without update, resolves with update not being discovered", async () => {
|
||||
await checkForUpdatesMock.resolve({
|
||||
updateInfo: {
|
||||
version: "some-version-that-matches-to-current-installed-version",
|
||||
},
|
||||
|
||||
cancellationToken: null,
|
||||
} as unknown as UpdateCheckResult);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toEqual({ updateWasDiscovered: false });
|
||||
});
|
||||
|
||||
describe("when checking for updates rejects", () => {
|
||||
let errorStub: Error;
|
||||
|
||||
beforeEach(() => {
|
||||
errorStub = new Error("Some error");
|
||||
|
||||
checkForUpdatesMock.reject(errorStub);
|
||||
});
|
||||
|
||||
it("logs errors", () => {
|
||||
expect(logErrorMock).toHaveBeenCalledWith("[UPDATE-APP/CHECK-FOR-UPDATES]", errorStub);
|
||||
});
|
||||
|
||||
it("resolves with update not being discovered", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toEqual({ updateWasDiscovered: false });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 { UpdateChannel } from "../../common/update-channels";
|
||||
import checkForPlatformUpdatesInjectable from "./check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import updateCanBeDowngradedInjectable from "./update-can-be-downgraded.injectable";
|
||||
|
||||
export type CheckForUpdatesFromChannelResult = {
|
||||
updateWasDiscovered: false;
|
||||
} | {
|
||||
updateWasDiscovered: true;
|
||||
version: string;
|
||||
actualUpdateChannel: UpdateChannel;
|
||||
};
|
||||
|
||||
const checkForUpdatesStartingFromChannelInjectable = getInjectable({
|
||||
id: "check-for-updates-starting-from-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const checkForPlatformUpdates = di.inject(checkForPlatformUpdatesInjectable);
|
||||
const updateCanBeDowngraded = di.inject(updateCanBeDowngradedInjectable);
|
||||
|
||||
const _recursiveCheck = async (
|
||||
updateChannel: UpdateChannel,
|
||||
): Promise<CheckForUpdatesFromChannelResult> => {
|
||||
const result = await checkForPlatformUpdates(updateChannel, {
|
||||
allowDowngrade: updateCanBeDowngraded.get(),
|
||||
});
|
||||
|
||||
if (result.updateWasDiscovered) {
|
||||
return {
|
||||
updateWasDiscovered: true,
|
||||
version: result.version,
|
||||
actualUpdateChannel: updateChannel,
|
||||
};
|
||||
}
|
||||
|
||||
if (updateChannel.moreStableUpdateChannel) {
|
||||
return await _recursiveCheck(updateChannel.moreStableUpdateChannel);
|
||||
}
|
||||
|
||||
return { updateWasDiscovered: false };
|
||||
};
|
||||
|
||||
return _recursiveCheck;
|
||||
},
|
||||
});
|
||||
|
||||
export default checkForUpdatesStartingFromChannelInjectable;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import selectedUpdateChannelInjectable from "../../common/selected-update-channel/selected-update-channel.injectable";
|
||||
import releaseChannelInjectable from "../../../../common/vars/release-channel.injectable";
|
||||
|
||||
const updateCanBeDowngradedInjectable = getInjectable({
|
||||
id: "update-can-be-downgraded",
|
||||
|
||||
instantiate: (di) => {
|
||||
const selectedUpdateChannel = di.inject(selectedUpdateChannelInjectable);
|
||||
const releaseChannel = di.inject(releaseChannelInjectable);
|
||||
|
||||
return computed(() => (
|
||||
selectedUpdateChannel.value.get().id === "latest"
|
||||
&& releaseChannel.get() !== "latest"
|
||||
));
|
||||
},
|
||||
});
|
||||
|
||||
export default updateCanBeDowngradedInjectable;
|
||||
Loaded 100 of 418 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user