mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove BaseStore<T> and replace with composition of dependencies (#7002)
* Rename ExtensionStore -> BaseExtensionStore - The name was too close to ExtensionsStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move ExtensionsStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move ClusterStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move UserStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup types to remove multiple cast locations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move HotbarStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move WeblinkStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move FileSystemProvisionerStore to new format Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Clean up impl and rename to better describe intent Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix remaining type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully split apart the enabled extensions storage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully split apart the clusters storage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully split apart the hotbar storage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully split apart the weblinks storage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully split apart the user preferences storage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix crashing Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests and snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix integration test failures Signed-off-by: Sebastian Malton <sebastian@malton.name> * Improve typing to prevent errors in the future. Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup @k8slens/messaging and friends - To fix type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint issue Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix global override not being complete enough causing tests to fail Signed-off-by: Sebastian Malton <sebastian@malton.name> * Bump memory for unit tests on CI Signed-off-by: Sebastian Malton <sebastian@malton.name> * Attempt to fix memory issue on CI again Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fixup test because of new injectables Signed-off-by: Sebastian Malton <sebastian@malton.name> * Upgrade Jest Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix unit tests falling over Signed-off-by: Sebastian Malton <sebastian@malton.name> * Back out jest config change Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove console log Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshot Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests by matching equality instead of snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests by forcing specific snapshot style - Ubuntu CI seems to format arrays in snapshots differently than macOS locally Signed-off-by: Sebastian Malton <sebastian@malton.name> --------- Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
ba4a283af9
commit
49f0a1af9c
365 files changed
+6733
-3972
No files matched your search
+2
-2
@@ -230,7 +230,7 @@ exports[`extension special characters in page registrations renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -434,7 +434,7 @@ exports[`extension special characters in page registrations when navigating to r
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -230,7 +230,7 @@ exports[`navigate to extension page renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -434,7 +434,7 @@ exports[`navigate to extension page when extension navigates to child route rend
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -654,7 +654,7 @@ exports[`navigate to extension page when extension navigates to route with param
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -874,7 +874,7 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1094,7 +1094,7 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -154,7 +154,7 @@ exports[`navigating between routes given route with optional path parameters whe
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -358,7 +358,7 @@ exports[`navigating between routes given route without path parameters when navi
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -230,7 +230,7 @@ exports[`add-cluster - navigation using application menu renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -518,7 +518,7 @@ exports[`add-cluster - navigation using application menu when navigating to add
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+122
-122
@@ -1,132 +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",
|
||||
]
|
||||
"[
|
||||
'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",
|
||||
]
|
||||
"[
|
||||
'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",
|
||||
]
|
||||
"[
|
||||
'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'
|
||||
]"
|
||||
`;
|
||||
@@ -8,6 +8,7 @@ import populateApplicationMenuInjectable from "./main/populate-application-menu.
|
||||
import { advanceFakeTime, testUsingFakeTime } from "../../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";
|
||||
import { inspect } from "util";
|
||||
|
||||
describe.each(allPlatforms)("application-menu, given platform is '%s'", (platform) => {
|
||||
let builder: ApplicationBuilder;
|
||||
@@ -53,7 +54,14 @@ describe.each(allPlatforms)("application-menu, given platform is '%s'", (platfor
|
||||
});
|
||||
|
||||
it("populates application menu", () => {
|
||||
expect(applicationMenuPaths.map(x => x.join(" -> "))).toMatchSnapshot();
|
||||
expect(inspect(applicationMenuPaths.map(x => x.join(" -> ")), {
|
||||
compact: false,
|
||||
breakLength: Infinity,
|
||||
colors: false,
|
||||
depth: Infinity,
|
||||
maxArrayLength: Infinity,
|
||||
maxStringLength: Infinity,
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
+8
-8
@@ -231,7 +231,7 @@ exports[`installing update when started renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -516,7 +516,7 @@ exports[`installing update when started when user checks for updates renders 1`]
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -801,7 +801,7 @@ exports[`installing update when started when user checks for updates when new up
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1086,7 +1086,7 @@ exports[`installing update when started when user checks for updates when new up
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1396,7 +1396,7 @@ exports[`installing update when started when user checks for updates when new up
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1706,7 +1706,7 @@ exports[`installing update when started when user checks for updates when new up
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2016,7 +2016,7 @@ exports[`installing update when started when user checks for updates when new up
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2301,7 +2301,7 @@ exports[`installing update when started when user checks for updates when no new
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -256,7 +256,7 @@ exports[`encourage user to update when sufficient time passed since update was d
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -541,7 +541,7 @@ exports[`encourage user to update when sufficient time passed since update was d
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+6
-6
@@ -231,7 +231,7 @@ exports[`installing update using tray when started renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -516,7 +516,7 @@ exports[`installing update using tray when started when user checks for updates
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -801,7 +801,7 @@ exports[`installing update using tray when started when user checks for updates
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1086,7 +1086,7 @@ exports[`installing update using tray when started when user checks for updates
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1396,7 +1396,7 @@ exports[`installing update using tray when started when user checks for updates
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1681,7 +1681,7 @@ exports[`installing update using tray when started when user checks for updates
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+3
-3
@@ -256,7 +256,7 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -566,7 +566,7 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -923,7 +923,7 @@ exports[`force user to update when too long since update was downloaded when app
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+1
-1
@@ -231,7 +231,7 @@ exports[`periodical checking of updates given updater is enabled and configurati
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+1
-1
@@ -231,7 +231,7 @@ exports[`selection of update stability when started renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -662,7 +662,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1378,7 +1378,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+9
-9
@@ -231,7 +231,7 @@ exports[`opening catalog entity details panel renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1052,7 +1052,7 @@ exports[`opening catalog entity details panel when navigated to the catalog rend
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1873,7 +1873,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2726,7 +2726,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3579,7 +3579,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4683,7 +4683,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -5524,7 +5524,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6365,7 +6365,7 @@ exports[`opening catalog entity details panel when navigated to the catalog when
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6841,7 +6841,7 @@ exports[`opening catalog entity details panel when not navigated to the catalog
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -6,19 +6,18 @@
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { KubernetesCluster, WebLink } from "../../common/catalog-entities";
|
||||
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
|
||||
import { Cluster } from "../../common/cluster/cluster";
|
||||
import navigateToCatalogInjectable from "../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
import { advanceFakeTime, testUsingFakeTime } from "../../test-utils/use-fake-time";
|
||||
import { advanceFakeTime } from "../../test-utils/use-fake-time";
|
||||
import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable";
|
||||
import showEntityDetailsInjectable from "../../renderer/components/+catalog/entity-details/show.injectable";
|
||||
import { type ApplicationBuilder, getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
import addClusterInjectable from "../cluster/storage/common/add.injectable";
|
||||
|
||||
describe("opening catalog entity details panel", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let windowDi: DiContainer;
|
||||
let cluster: Cluster;
|
||||
let clusterEntity: KubernetesCluster;
|
||||
let localClusterEntity: KubernetesCluster;
|
||||
let otherEntity: WebLink;
|
||||
@@ -26,20 +25,7 @@ describe("opening catalog entity details panel", () => {
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeWindowStart(({ windowDi }) => {
|
||||
// TODO: remove once ClusterStore can be used without overriding it
|
||||
windowDi.override(getClusterByIdInjectable, () => (clusterId) => {
|
||||
if (clusterId === cluster?.id) {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
testUsingFakeTime();
|
||||
|
||||
builder.afterWindowStart(({ windowDi }) => {
|
||||
builder.afterWindowStart(async ({ windowDi }) => {
|
||||
clusterEntity = new KubernetesCluster({
|
||||
metadata: {
|
||||
labels: {},
|
||||
@@ -82,12 +68,33 @@ describe("opening catalog entity details panel", () => {
|
||||
phase: "available",
|
||||
},
|
||||
});
|
||||
cluster = new Cluster({
|
||||
contextName: clusterEntity.spec.kubeconfigContext,
|
||||
|
||||
const writeJsonFile = windowDi.inject(writeJsonFileInjectable);
|
||||
const addCluster = windowDi.inject(addClusterInjectable);
|
||||
|
||||
await writeJsonFile(clusterEntity.spec.kubeconfigPath, {
|
||||
contexts: [{
|
||||
name: clusterEntity.spec.kubeconfigContext,
|
||||
context: {
|
||||
cluster: "some-cluster",
|
||||
user: "some-user",
|
||||
},
|
||||
}],
|
||||
clusters: [{
|
||||
name: "some-cluster",
|
||||
cluster: {
|
||||
server: "https://localhost:9999",
|
||||
},
|
||||
}],
|
||||
users: [{
|
||||
name: "some-user",
|
||||
}],
|
||||
});
|
||||
|
||||
addCluster({
|
||||
id: clusterEntity.getId(),
|
||||
kubeConfigPath: clusterEntity.spec.kubeconfigPath,
|
||||
}, {
|
||||
clusterServerUrl: "https://localhost:9999",
|
||||
contextName: clusterEntity.spec.kubeconfigContext,
|
||||
});
|
||||
|
||||
// TODO: replace with proper entity source once syncing entities between main and windows is injectable
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
import clusterConnectionInjectable from "../../../../main/cluster/cluster-connection.injectable";
|
||||
import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable";
|
||||
import { requestClusterActivationInjectionToken } from "../common/request-token";
|
||||
|
||||
const requestClusterActivationInjectable = getInjectable({
|
||||
|
||||
+1
-1
@@ -5,8 +5,8 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import clusterFramesInjectable from "../../../../common/cluster-frames.injectable";
|
||||
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
import clusterConnectionInjectable from "../../../../main/cluster/cluster-connection.injectable";
|
||||
import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable";
|
||||
import { requestClusterDeactivationInjectionToken } from "../common/request-token";
|
||||
|
||||
const requestClusterDeactivationInjectable = getInjectable({
|
||||
|
||||
+5
-5
@@ -542,7 +542,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1194,7 +1194,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1879,7 +1879,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2643,7 +2643,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3407,7 +3407,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+4
-6
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import clusterFramesInjectable from "../../../../common/cluster-frames.injectable";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import directoryForLensLocalStorageInjectable from "../../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import removePathInjectable from "../../../../common/fs/remove.injectable";
|
||||
import joinPathsInjectable from "../../../../common/path/join-paths.injectable";
|
||||
@@ -12,22 +11,23 @@ import clusterConnectionInjectable from "../../../../main/cluster/cluster-connec
|
||||
import { noop } from "@k8slens/utilities";
|
||||
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
|
||||
import { deleteClusterChannel } from "../common/delete-channel";
|
||||
import clustersStateInjectable from "../../storage/common/state.injectable";
|
||||
|
||||
const deleteClusterChannelListenerInjectable = getRequestChannelListenerInjectable({
|
||||
id: "delete-cluster-channel-listener",
|
||||
channel: deleteClusterChannel,
|
||||
getHandler: (di) => {
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const clusterFrames = di.inject(clusterFramesInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const directoryForLensLocalStorage = di.inject(directoryForLensLocalStorageInjectable);
|
||||
const deleteFile = di.inject(removePathInjectable);
|
||||
const clustersState = di.inject(clustersStateInjectable);
|
||||
|
||||
return async (clusterId) => {
|
||||
emitAppEvent({ name: "cluster", action: "remove" });
|
||||
|
||||
const cluster = clusterStore.getById(clusterId);
|
||||
const cluster = clustersState.get(clusterId);
|
||||
|
||||
if (!cluster) {
|
||||
return;
|
||||
@@ -37,9 +37,7 @@ const deleteClusterChannelListenerInjectable = getRequestChannelListenerInjectab
|
||||
|
||||
clusterConnection.disconnect();
|
||||
clusterFrames.delete(cluster.id);
|
||||
|
||||
// Remove from the cluster store as well, this should clear any old settings
|
||||
clusterStore.clusters.delete(cluster.id);
|
||||
clustersState.delete(cluster.id);
|
||||
|
||||
// remove the local storage file
|
||||
const localStorageFilePath = joinPaths(directoryForLensLocalStorage, `${cluster.id}.json`);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { AuthorizationV1Api, CoreV1Api, V1APIGroupList, V1APIVersions, V1NamespaceList, V1SelfSubjectAccessReview, V1SelfSubjectRulesReview } from "@kubernetes/client-node";
|
||||
import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
@@ -26,6 +25,7 @@ import type { KubeAuthProxy } from "../../main/kube-auth-proxy/create-kube-auth-
|
||||
import createKubeAuthProxyInjectable from "../../main/kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import type { Mocked } from "../../test-utils/mock-interface";
|
||||
import { flushPromises } from "@k8slens/test-utils";
|
||||
import addClusterInjectable from "./storage/common/add.injectable";
|
||||
|
||||
describe("Refresh Cluster Accessibility Technical Tests", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
@@ -79,7 +79,7 @@ describe("Refresh Cluster Accessibility Technical Tests", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
const mainDi = builder.mainDi;
|
||||
const clusterStore = mainDi.inject(clusterStoreInjectable);
|
||||
const addCluster = mainDi.inject(addClusterInjectable);
|
||||
const writeJsonFile = mainDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFile("/some-kube-config-path", {
|
||||
@@ -103,13 +103,11 @@ describe("Refresh Cluster Accessibility Technical Tests", () => {
|
||||
}],
|
||||
});
|
||||
|
||||
clusterStore.addCluster({
|
||||
cluster = addCluster({
|
||||
contextName: "some-cluster-context",
|
||||
id: "some-cluster-id",
|
||||
kubeConfigPath: "/some-kube-config-path",
|
||||
});
|
||||
|
||||
cluster = clusterStore.getById("some-cluster-id") ?? (() => { throw new Error("missing cluster"); })();
|
||||
clusterConnection = mainDi.inject(clusterConnectionInjectable, cluster);
|
||||
refreshPromise = clusterConnection.refreshAccessibilityAndMetadata();
|
||||
});
|
||||
|
||||
+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 { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import type { KubeApiResourceDescriptor } from "../../../../common/rbac";
|
||||
|
||||
export const shouldShowResourceInjectionToken = getInjectionToken<IComputedValue<boolean>, KubeApiResourceDescriptor>({
|
||||
id: "should-show-resource",
|
||||
});
|
||||
@@ -2,17 +2,17 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
|
||||
import clustersInjectable from "../../storage/common/clusters.injectable";
|
||||
import { initialClusterStatesChannel } from "../common/channels";
|
||||
|
||||
const handleInitialClusterStateSyncInjectable = getRequestChannelListenerInjectable({
|
||||
id: "handle-initial-cluster-state-sync",
|
||||
channel: initialClusterStatesChannel,
|
||||
getHandler: (di) => {
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const clusters = di.inject(clustersInjectable);
|
||||
|
||||
return () => clusterStore.clustersList.map(cluster => ({
|
||||
return () => clusters.get().map(cluster => ({
|
||||
clusterId: cluster.id,
|
||||
state: cluster.getState(),
|
||||
}));
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { isEqual } from "lodash";
|
||||
import { autorun } from "mobx";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import type { ClusterId, ClusterState } from "../../../../common/cluster-types";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application";
|
||||
import initClusterStoreInjectable from "../../store/main/init.injectable";
|
||||
import initClusterStoreInjectable from "../../storage/main/init.injectable";
|
||||
import emitClusterStateUpdateInjectable from "./emit-update.injectable";
|
||||
import clustersInjectable from "../../storage/common/clusters.injectable";
|
||||
|
||||
const setupClusterStateBroadcastingInjectable = getInjectable({
|
||||
id: "setup-cluster-state-broadcasting",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const emitClusterStateUpdate = di.inject(emitClusterStateUpdateInjectable);
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const clusters = di.inject(clustersInjectable);
|
||||
const prevStates = new Map<ClusterId, ClusterState>();
|
||||
|
||||
autorun(() => {
|
||||
for (const cluster of clusterStore.clusters.values()) {
|
||||
for (const cluster of clusters.get()) {
|
||||
const prevState = prevStates.get(cluster.id);
|
||||
const curState = cluster.getState();
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
import { getMessageChannelListenerInjectable } from "@k8slens/messaging";
|
||||
import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable";
|
||||
import { clusterStateSyncChannel } from "../common/channels";
|
||||
|
||||
const clusterStateListenerInjectable = getMessageChannelListenerInjectable({
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
|
||||
import initClusterStoreInjectable from "../../store/renderer/init.injectable";
|
||||
import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable";
|
||||
import initClusterStoreInjectable from "../../storage/renderer/init.injectable";
|
||||
import requestInitialClusterStatesInjectable from "./request-initial.injectable";
|
||||
|
||||
const setupClusterStateSyncInjectable = getInjectable({
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { GetCustomKubeConfigFilePath } from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
import getCustomKubeConfigFilePathInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting";
|
||||
import assert from "assert";
|
||||
import directoryForTempInjectable from "../../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import kubectlBinaryNameInjectable from "../../../main/kubectl/binary-name.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "../../../main/kubectl/normalized-arch.injectable";
|
||||
import normalizedPlatformInjectable from "../../../common/vars/normalized-platform.injectable";
|
||||
import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable";
|
||||
import type { WriteJsonSync } from "../../../common/fs/write-json-sync.injectable";
|
||||
import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable";
|
||||
import type { ReadFileSync } from "../../../common/fs/read-file-sync.injectable";
|
||||
import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable";
|
||||
import { readFileSync } from "fs";
|
||||
import type { WriteFileSync } from "../../../common/fs/write-file-sync.injectable";
|
||||
import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable";
|
||||
import type { WriteBufferSync } from "../../../common/fs/write-buffer-sync.injectable";
|
||||
import writeBufferSyncInjectable from "../../../common/fs/write-buffer-sync.injectable";
|
||||
import { Cluster } from "../../../common/cluster/cluster";
|
||||
import clustersPersistentStorageInjectable from "./common/storage.injectable";
|
||||
import type { PersistentStorage } from "../../../common/persistent-storage/create.injectable";
|
||||
import type { AddCluster } from "./common/add.injectable";
|
||||
import addClusterInjectable from "./common/add.injectable";
|
||||
import type { GetClusterById } from "./common/get-by-id.injectable";
|
||||
import getClusterByIdInjectable from "./common/get-by-id.injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import clustersInjectable from "./common/clusters.injectable";
|
||||
|
||||
// NOTE: this is intended to read the actual file system
|
||||
const testDataIcon = readFileSync("test-data/cluster-store-migration-icon.png");
|
||||
const clusterServerUrl = "https://localhost";
|
||||
const kubeconfig = `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: ${clusterServerUrl}
|
||||
name: test
|
||||
contexts:
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: foo
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: foo2
|
||||
current-context: test
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: test
|
||||
user:
|
||||
token: kubeconfig-user-q4lm4:xxxyyyy
|
||||
`;
|
||||
|
||||
describe("cluster storage technical tests", () => {
|
||||
let di: DiContainer;
|
||||
let clustersPersistentStorage: PersistentStorage;
|
||||
let writeJsonSync: WriteJsonSync;
|
||||
let writeFileSync: WriteFileSync;
|
||||
let writeBufferSync: WriteBufferSync;
|
||||
let readFileSync: ReadFileSync;
|
||||
let getCustomKubeConfigFilePath: GetCustomKubeConfigFilePath;
|
||||
let writeFileSyncAndReturnPath: (filePath: string, contents: string) => string;
|
||||
let addCluster: AddCluster;
|
||||
let getClusterById: GetClusterById;
|
||||
let clusters: IComputedValue<Cluster[]>;
|
||||
|
||||
beforeEach(async () => {
|
||||
di = getDiForUnitTesting();
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||
di.override(directoryForTempInjectable, () => "/some-temp-directory");
|
||||
di.override(kubectlBinaryNameInjectable, () => "kubectl");
|
||||
di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
di.override(normalizedPlatformInjectable, () => "darwin");
|
||||
writeJsonSync = di.inject(writeJsonSyncInjectable);
|
||||
writeFileSync = di.inject(writeFileSyncInjectable);
|
||||
writeBufferSync = di.inject(writeBufferSyncInjectable);
|
||||
readFileSync = di.inject(readFileSyncInjectable);
|
||||
addCluster = di.inject(addClusterInjectable);
|
||||
getClusterById = di.inject(getClusterByIdInjectable);
|
||||
clusters = di.inject(clustersInjectable);
|
||||
writeFileSyncAndReturnPath = (filePath, contents) => (writeFileSync(filePath, contents), filePath);
|
||||
});
|
||||
|
||||
describe("empty config", () => {
|
||||
beforeEach(async () => {
|
||||
getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable);
|
||||
|
||||
writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {});
|
||||
clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable);
|
||||
clustersPersistentStorage.loadAndStartSyncing();
|
||||
});
|
||||
|
||||
describe("with foo cluster added", () => {
|
||||
beforeEach(() => {
|
||||
const cluster = new Cluster({
|
||||
id: "foo",
|
||||
contextName: "foo",
|
||||
preferences: {
|
||||
terminalCWD: "/some-directory-for-user-data",
|
||||
icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
||||
clusterName: "minikube",
|
||||
},
|
||||
kubeConfigPath: writeFileSyncAndReturnPath(
|
||||
getCustomKubeConfigFilePath("foo"),
|
||||
kubeconfig,
|
||||
),
|
||||
}, {
|
||||
clusterServerUrl,
|
||||
});
|
||||
|
||||
addCluster(cluster);
|
||||
});
|
||||
|
||||
it("adds new cluster to store", async () => {
|
||||
const storedCluster = getClusterById("foo");
|
||||
|
||||
assert(storedCluster);
|
||||
|
||||
expect(storedCluster.id).toBe("foo");
|
||||
expect(storedCluster.preferences.terminalCWD).toBe("/some-directory-for-user-data");
|
||||
expect(storedCluster.preferences.icon).toBe(
|
||||
"data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with prod and dev clusters added", () => {
|
||||
beforeEach(() => {
|
||||
addCluster({
|
||||
id: "prod",
|
||||
contextName: "foo",
|
||||
preferences: {
|
||||
clusterName: "prod",
|
||||
},
|
||||
kubeConfigPath: writeFileSyncAndReturnPath(
|
||||
getCustomKubeConfigFilePath("prod"),
|
||||
kubeconfig,
|
||||
),
|
||||
});
|
||||
addCluster({
|
||||
id: "dev",
|
||||
contextName: "foo2",
|
||||
preferences: {
|
||||
clusterName: "dev",
|
||||
},
|
||||
kubeConfigPath: writeFileSyncAndReturnPath(
|
||||
getCustomKubeConfigFilePath("dev"),
|
||||
kubeconfig,
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
it("check if store can contain multiple clusters", () => {
|
||||
expect(clusters.get().length).toBe(2);
|
||||
});
|
||||
|
||||
it("check if cluster's kubeconfig file saved", () => {
|
||||
const file = writeFileSyncAndReturnPath(getCustomKubeConfigFilePath("boo"), "kubeconfig");
|
||||
|
||||
expect(readFileSync(file)).toBe("kubeconfig");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("config with existing clusters", () => {
|
||||
beforeEach(() => {
|
||||
writeFileSync("/temp-kube-config", kubeconfig);
|
||||
writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {
|
||||
__internal__: {
|
||||
migrations: {
|
||||
version: "99.99.99",
|
||||
},
|
||||
},
|
||||
clusters: [
|
||||
{
|
||||
id: "cluster1",
|
||||
kubeConfigPath: "/temp-kube-config",
|
||||
contextName: "foo",
|
||||
preferences: { terminalCWD: "/foo" },
|
||||
workspace: "default",
|
||||
},
|
||||
{
|
||||
id: "cluster2",
|
||||
kubeConfigPath: "/temp-kube-config",
|
||||
contextName: "foo2",
|
||||
preferences: { terminalCWD: "/foo2" },
|
||||
},
|
||||
{
|
||||
id: "cluster3",
|
||||
kubeConfigPath: "/temp-kube-config",
|
||||
contextName: "foo",
|
||||
preferences: { terminalCWD: "/foo" },
|
||||
workspace: "foo",
|
||||
ownerRef: "foo",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable);
|
||||
|
||||
clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable);
|
||||
clustersPersistentStorage.loadAndStartSyncing();
|
||||
});
|
||||
it("allows to retrieve a cluster", () => {
|
||||
const storedCluster = getClusterById("cluster1");
|
||||
|
||||
assert(storedCluster);
|
||||
|
||||
expect(storedCluster.id).toBe("cluster1");
|
||||
expect(storedCluster.preferences.terminalCWD).toBe("/foo");
|
||||
});
|
||||
|
||||
it("allows getting all of the clusters", async () => {
|
||||
const storedClusters = clusters.get();
|
||||
|
||||
expect(storedClusters.length).toBe(3);
|
||||
expect(storedClusters[0].id).toBe("cluster1");
|
||||
expect(storedClusters[0].preferences.terminalCWD).toBe("/foo");
|
||||
expect(storedClusters[1].id).toBe("cluster2");
|
||||
expect(storedClusters[1].preferences.terminalCWD).toBe("/foo2");
|
||||
expect(storedClusters[2].id).toBe("cluster3");
|
||||
});
|
||||
});
|
||||
|
||||
describe("config with invalid cluster kubeconfig", () => {
|
||||
beforeEach(() => {
|
||||
writeFileSync("/invalid-kube-config", invalidKubeconfig);
|
||||
writeFileSync("/valid-kube-config", kubeconfig);
|
||||
writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {
|
||||
__internal__: {
|
||||
migrations: {
|
||||
version: "99.99.99",
|
||||
},
|
||||
},
|
||||
clusters: [
|
||||
{
|
||||
id: "cluster1",
|
||||
kubeConfigPath: "/invalid-kube-config",
|
||||
contextName: "test",
|
||||
preferences: { terminalCWD: "/foo" },
|
||||
workspace: "foo",
|
||||
},
|
||||
{
|
||||
id: "cluster2",
|
||||
kubeConfigPath: "/valid-kube-config",
|
||||
contextName: "foo",
|
||||
preferences: { terminalCWD: "/foo" },
|
||||
workspace: "default",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable);
|
||||
|
||||
clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable);
|
||||
clustersPersistentStorage.loadAndStartSyncing();
|
||||
});
|
||||
|
||||
it("does not enable clusters with invalid kubeconfig", () => {
|
||||
const storedClusters = clusters.get();
|
||||
|
||||
expect(storedClusters.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
|
||||
beforeEach(() => {
|
||||
di.override(storeMigrationVersionInjectable, () => "3.6.0");
|
||||
|
||||
getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable);
|
||||
|
||||
writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {
|
||||
__internal__: {
|
||||
migrations: {
|
||||
version: "3.5.0",
|
||||
},
|
||||
},
|
||||
clusters: [
|
||||
{
|
||||
id: "cluster1",
|
||||
kubeConfig: minimalValidKubeConfig,
|
||||
contextName: "cluster",
|
||||
preferences: {
|
||||
icon: "store://icon_path",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
writeBufferSync("/some-directory-for-user-data/icon_path", testDataIcon);
|
||||
|
||||
|
||||
clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable);
|
||||
clustersPersistentStorage.loadAndStartSyncing();
|
||||
});
|
||||
|
||||
it("migrates to modern format with kubeconfig in a file", async () => {
|
||||
const configPath = clusters.get()[0].kubeConfigPath.get();
|
||||
|
||||
expect(readFileSync(configPath)).toBe(minimalValidKubeConfig);
|
||||
});
|
||||
|
||||
it("migrates to modern format with icon not in file", async () => {
|
||||
expect(clusters.get()[0].preferences.icon).toMatch(/data:;base64,/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const invalidKubeconfig = JSON.stringify({
|
||||
apiVersion: "v1",
|
||||
clusters: [{
|
||||
cluster: {
|
||||
server: "https://localhost",
|
||||
},
|
||||
name: "test2",
|
||||
}],
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: "test",
|
||||
user: "test",
|
||||
},
|
||||
name: "test",
|
||||
}],
|
||||
"current-context": "test",
|
||||
kind: "Config",
|
||||
preferences: {},
|
||||
users: [{
|
||||
user: {
|
||||
token: "kubeconfig-user-q4lm4:xxxyyyy",
|
||||
},
|
||||
name: "test",
|
||||
}],
|
||||
});
|
||||
|
||||
const minimalValidKubeConfig = JSON.stringify({
|
||||
apiVersion: "v1",
|
||||
clusters: [
|
||||
{
|
||||
name: "minikube",
|
||||
cluster: {
|
||||
server: "https://192.168.64.3:8443",
|
||||
},
|
||||
},
|
||||
],
|
||||
"current-context": "minikube",
|
||||
contexts: [
|
||||
{
|
||||
context: {
|
||||
cluster: "minikube",
|
||||
user: "minikube",
|
||||
},
|
||||
name: "minikube",
|
||||
},
|
||||
],
|
||||
users: [
|
||||
{
|
||||
name: "minikube",
|
||||
user: {
|
||||
"client-certificate": "/Users/foo/.minikube/client.crt",
|
||||
"client-key": "/Users/foo/.minikube/client.key",
|
||||
},
|
||||
},
|
||||
],
|
||||
kind: "Config",
|
||||
preferences: {},
|
||||
});
|
||||
@@ -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 { action } from "mobx";
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import readClusterConfigSyncInjectable from "./read-cluster-config.injectable";
|
||||
import type { ClusterModel } from "../../../../common/cluster-types";
|
||||
import { Cluster } from "../../../../common/cluster/cluster";
|
||||
import clustersStateInjectable from "./state.injectable";
|
||||
|
||||
export type AddCluster = (clusterOrModel: ClusterModel | Cluster) => Cluster;
|
||||
|
||||
const addClusterInjectable = getInjectable({
|
||||
id: "add-cluster",
|
||||
instantiate: (di): AddCluster => {
|
||||
const clustersState = di.inject(clustersStateInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable);
|
||||
|
||||
return action((clusterOrModel) => {
|
||||
emitAppEvent({ name: "cluster", action: "add" });
|
||||
|
||||
const cluster = clusterOrModel instanceof Cluster
|
||||
? clusterOrModel
|
||||
: new Cluster(
|
||||
clusterOrModel,
|
||||
readClusterConfigSync(clusterOrModel),
|
||||
);
|
||||
|
||||
clustersState.set(cluster.id, cluster);
|
||||
|
||||
return cluster;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default addClusterInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import clustersStateInjectable from "./state.injectable";
|
||||
|
||||
const clustersInjectable = getInjectable({
|
||||
id: "clusters",
|
||||
instantiate: (di) => {
|
||||
const clustersState = di.inject(clustersStateInjectable);
|
||||
|
||||
return computed(() => [...clustersState.values()]);
|
||||
},
|
||||
});
|
||||
|
||||
export default clustersInjectable;
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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 { ClusterId } from "../../../../common/cluster-types";
|
||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||
import clustersStateInjectable from "./state.injectable";
|
||||
|
||||
export type GetClusterById = (id: ClusterId) => Cluster | undefined;
|
||||
|
||||
const getClusterByIdInjectable = getInjectable({
|
||||
id: "get-cluster-by-id",
|
||||
instantiate: (di): GetClusterById => {
|
||||
const clustersState = di.inject(clustersStateInjectable);
|
||||
|
||||
return (id) => clustersState.get(id);
|
||||
},
|
||||
});
|
||||
|
||||
export default getClusterByIdInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable";
|
||||
|
||||
export const clusterStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "cluster-store-migration",
|
||||
});
|
||||
@@ -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 type { ClusterConfigData, ClusterModel } from "../../../../common/cluster-types";
|
||||
import readFileSyncInjectable from "../../../../common/fs/read-file-sync.injectable";
|
||||
import { loadConfigFromString, validateKubeConfig } from "../../../../common/kube-helpers";
|
||||
|
||||
export type ReadClusterConfigSync = (model: ClusterModel) => ClusterConfigData;
|
||||
|
||||
const readClusterConfigSyncInjectable = getInjectable({
|
||||
id: "read-cluster-config-sync",
|
||||
instantiate: (di): ReadClusterConfigSync => {
|
||||
const readFileSync = di.inject(readFileSyncInjectable);
|
||||
|
||||
return ({ kubeConfigPath, contextName }) => {
|
||||
const kubeConfigData = readFileSync(kubeConfigPath);
|
||||
const { config } = loadConfigFromString(kubeConfigData);
|
||||
const result = validateKubeConfig(config, contextName);
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
return { clusterServerUrl: result.cluster.server };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default readClusterConfigSyncInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||
|
||||
const clustersStateInjectable = getInjectable({
|
||||
id: "clusters-state",
|
||||
instantiate: () => observable.map<ClusterId, Cluster>(),
|
||||
});
|
||||
|
||||
export default clustersStateInjectable;
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { comparer, action } from "mobx";
|
||||
import { clusterStoreMigrationInjectionToken } from "./migration-token";
|
||||
import readClusterConfigSyncInjectable from "./read-cluster-config.injectable";
|
||||
import type { ClusterId, ClusterModel } from "../../../../common/cluster-types";
|
||||
import { Cluster } from "../../../../common/cluster/cluster";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable";
|
||||
import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable";
|
||||
import storeMigrationVersionInjectable from "../../../../common/vars/store-migration-version.injectable";
|
||||
import clustersStateInjectable from "./state.injectable";
|
||||
|
||||
export interface ClusterStoreModel {
|
||||
clusters?: ClusterModel[];
|
||||
}
|
||||
|
||||
const clustersPersistentStorageInjectable = getInjectable({
|
||||
id: "clusters-persistent-storage",
|
||||
instantiate: (di) => {
|
||||
const createPersistentStorage = di.inject(createPersistentStorageInjectable);
|
||||
const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable);
|
||||
const clustersState = di.inject(clustersStateInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return createPersistentStorage<ClusterStoreModel>({
|
||||
configName: "lens-cluster-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
projectVersion: di.inject(storeMigrationVersionInjectable),
|
||||
migrations: di.inject(persistentStorageMigrationsInjectable, clusterStoreMigrationInjectionToken),
|
||||
fromStore: action(({ clusters = [] }) => {
|
||||
const currentClusters = new Map(clustersState);
|
||||
const newClusters = new Map<ClusterId, Cluster>();
|
||||
|
||||
// update new clusters
|
||||
for (const clusterModel of clusters) {
|
||||
try {
|
||||
let cluster = currentClusters.get(clusterModel.id);
|
||||
|
||||
if (cluster) {
|
||||
cluster.updateModel(clusterModel);
|
||||
} else {
|
||||
cluster = new Cluster(
|
||||
clusterModel,
|
||||
readClusterConfigSync(clusterModel),
|
||||
);
|
||||
}
|
||||
newClusters.set(clusterModel.id, cluster);
|
||||
} catch (error) {
|
||||
logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
clustersState.replace(newClusters);
|
||||
}),
|
||||
toJSON: () => ({
|
||||
clusters: iter.chain(clustersState.values())
|
||||
.map(cluster => cluster.toJSON())
|
||||
.toArray(),
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default clustersPersistentStorageInjectable;
|
||||
+5
-5
@@ -3,19 +3,19 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application";
|
||||
import initUserStoreInjectable from "../../../../main/stores/init-user-store.injectable";
|
||||
import clustersPersistentStorageInjectable from "../common/storage.injectable";
|
||||
import loadUserPreferencesStorageInjectable from "../../../user-preferences/main/load-storage.injectable";
|
||||
|
||||
const initClusterStoreInjectable = getInjectable({
|
||||
id: "init-cluster-store",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const storage = di.inject(clustersPersistentStorageInjectable);
|
||||
|
||||
clusterStore.load();
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
runAfter: initUserStoreInjectable,
|
||||
runAfter: loadUserPreferencesStorageInjectable,
|
||||
}),
|
||||
injectionToken: beforeApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
+4
-4
@@ -3,17 +3,17 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
|
||||
import initUserStoreInjectable from "../../../../renderer/stores/init-user-store.injectable";
|
||||
import initUserStoreInjectable from "../../../user-preferences/renderer/load-storage.injectable";
|
||||
import clustersPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const initClusterStoreInjectable = getInjectable({
|
||||
id: "init-cluster-store",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const storage = di.inject(clustersPersistentStorageInjectable);
|
||||
|
||||
clusterStore.load();
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
runAfter: initUserStoreInjectable,
|
||||
}),
|
||||
@@ -13,7 +13,7 @@ import { frontEndRouteInjectionToken } from "../../common/front-end-routing/fron
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
|
||||
import { shouldShowResourceInjectionToken } from "./showing-kube-resources/common/allowed-resources-injection-token";
|
||||
|
||||
describe("cluster - visibility of sidebar items", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
|
||||
+8
-8
@@ -322,7 +322,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -698,7 +698,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing ESC
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1074,7 +1074,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1462,7 +1462,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1747,7 +1747,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2032,7 +2032,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing ESC
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2317,7 +2317,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2614,7 +2614,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+4
-4
@@ -231,7 +231,7 @@ exports[`Showing correct entity settings renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -593,7 +593,7 @@ exports[`Showing correct entity settings when navigating to local cluster entity
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -976,7 +976,7 @@ exports[`Showing correct entity settings when navigating to non-local cluster en
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1261,7 +1261,7 @@ exports[`Showing correct entity settings when navigating to weblink entity setti
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+29
-21
@@ -6,11 +6,11 @@
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { KubernetesCluster, WebLink } from "../../common/catalog-entities";
|
||||
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
|
||||
import { Cluster } from "../../common/cluster/cluster";
|
||||
import navigateToEntitySettingsInjectable from "../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable";
|
||||
import { type ApplicationBuilder, getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import addClusterInjectable from "../cluster/storage/common/add.injectable";
|
||||
|
||||
describe("Showing correct entity settings", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
@@ -19,23 +19,11 @@ describe("Showing correct entity settings", () => {
|
||||
let clusterEntity: KubernetesCluster;
|
||||
let localClusterEntity: KubernetesCluster;
|
||||
let otherEntity: WebLink;
|
||||
let cluster: Cluster;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeWindowStart(({ windowDi }) => {
|
||||
// TODO: remove once ClusterStore can be used without overriding it
|
||||
windowDi.override(getClusterByIdInjectable, () => (clusterId) => {
|
||||
if (clusterId === cluster.id) {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
builder.afterWindowStart(({ windowDi }) => {
|
||||
builder.afterWindowStart(async ({ windowDi }) => {
|
||||
clusterEntity = new KubernetesCluster({
|
||||
metadata: {
|
||||
labels: {},
|
||||
@@ -78,14 +66,34 @@ describe("Showing correct entity settings", () => {
|
||||
phase: "available",
|
||||
},
|
||||
});
|
||||
cluster = new Cluster({
|
||||
contextName: clusterEntity.spec.kubeconfigContext,
|
||||
id: clusterEntity.getId(),
|
||||
kubeConfigPath: clusterEntity.spec.kubeconfigPath,
|
||||
}, {
|
||||
clusterServerUrl: "https://localhost:9999",
|
||||
|
||||
const writeJsonFile = windowDi.inject(writeJsonFileInjectable);
|
||||
const addCluster = windowDi.inject(addClusterInjectable);
|
||||
|
||||
await writeJsonFile(clusterEntity.spec.kubeconfigPath, {
|
||||
contexts: [{
|
||||
name: clusterEntity.spec.kubeconfigContext,
|
||||
context: {
|
||||
cluster: "some-cluster",
|
||||
user: "some-user",
|
||||
},
|
||||
}],
|
||||
clusters: [{
|
||||
name: "some-cluster",
|
||||
cluster: {
|
||||
server: "https://localhost:9999",
|
||||
},
|
||||
}],
|
||||
users: [{
|
||||
name: "some-user",
|
||||
}],
|
||||
});
|
||||
|
||||
addCluster({
|
||||
id: clusterEntity.getId(),
|
||||
kubeConfigPath: clusterEntity.spec.kubeconfigPath,
|
||||
contextName: clusterEntity.spec.kubeconfigContext,
|
||||
});
|
||||
|
||||
// TODO: replace with proper entity source once syncing entities between main and windows is injectable
|
||||
const catalogEntityRegistry = windowDi.inject(catalogEntityRegistryInjectable);
|
||||
|
||||
+2
-2
@@ -230,7 +230,7 @@ exports[`extensions - navigation using application menu renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -543,7 +543,7 @@ exports[`extensions - navigation using application menu when navigating to exten
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import enabledExtensionsStateInjectable from "./state.injectable";
|
||||
|
||||
const enabledExtensionsInjectable = getInjectable({
|
||||
id: "enabled-extensions",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(enabledExtensionsStateInjectable);
|
||||
|
||||
return computed(() => (
|
||||
iter.chain(state.values())
|
||||
.filter(({ enabled }) => enabled)
|
||||
.map(({ name }) => name)
|
||||
.toArray()
|
||||
));
|
||||
},
|
||||
});
|
||||
|
||||
export default enabledExtensionsInjectable;
|
||||
@@ -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 enabledExtensionsStateInjectable from "./state.injectable";
|
||||
|
||||
export interface IsEnabledExtensionDescriptor {
|
||||
readonly id: string;
|
||||
readonly isBundled: boolean;
|
||||
}
|
||||
|
||||
export type IsExtensionEnabled = (desc: IsEnabledExtensionDescriptor) => boolean;
|
||||
|
||||
const isExtensionEnabledInjectable = getInjectable({
|
||||
id: "is-extension-enabled",
|
||||
instantiate: (di): IsExtensionEnabled => {
|
||||
const state = di.inject(enabledExtensionsStateInjectable);
|
||||
|
||||
return ({ id, isBundled }) => isBundled || (state.get(id)?.enabled ?? false);
|
||||
},
|
||||
});
|
||||
|
||||
export default isExtensionEnabledInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable";
|
||||
|
||||
export const enabledExtensionsMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "enabled-extensions-migration-declaration",
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
|
||||
export interface LensExtensionState {
|
||||
enabled?: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const enabledExtensionsStateInjectable = getInjectable({
|
||||
id: "enabled-extensions-state",
|
||||
instantiate: () => observable.map<LensExtensionId, LensExtensionState>(),
|
||||
});
|
||||
|
||||
export default enabledExtensionsStateInjectable;
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { action, toJS } from "mobx";
|
||||
import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable";
|
||||
import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable";
|
||||
import storageMigrationVersionInjectable from "../../../../common/persistent-storage/storage-migration-version.injectable";
|
||||
import { enabledExtensionsMigrationDeclarationInjectionToken } from "./migrations";
|
||||
import type { LensExtensionState } from "./state.injectable";
|
||||
import enabledExtensionsStateInjectable from "./state.injectable";
|
||||
|
||||
interface EnabledExtensionsStorageModal {
|
||||
extensions: [LensExtensionId, LensExtensionState][];
|
||||
}
|
||||
|
||||
const enabledExtensionsPersistentStorageInjectable = getInjectable({
|
||||
id: "enabled-extensions-persistent-storage",
|
||||
instantiate: (di) => {
|
||||
const createPersistentStorage = di.inject(createPersistentStorageInjectable);
|
||||
const state = di.inject(enabledExtensionsStateInjectable);
|
||||
|
||||
return createPersistentStorage<EnabledExtensionsStorageModal>({
|
||||
configName: "lens-extensions",
|
||||
fromStore: action(({ extensions = [] }) => {
|
||||
state.replace(extensions);
|
||||
}),
|
||||
toJSON: () => ({
|
||||
extensions: [...toJS(state)],
|
||||
}),
|
||||
projectVersion: di.inject(storageMigrationVersionInjectable, enabledExtensionsMigrationDeclarationInjectionToken),
|
||||
migrations: di.inject(persistentStorageMigrationsInjectable, enabledExtensionsMigrationDeclarationInjectionToken),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default enabledExtensionsPersistentStorageInjectable;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IObservableMapInitialValues } from "mobx";
|
||||
import { action } from "mobx";
|
||||
import type { LensExtensionState } from "./state.injectable";
|
||||
import enabledExtensionsStateInjectable from "./state.injectable";
|
||||
|
||||
export type UpdateExtensionsState = (state: IObservableMapInitialValues<LensExtensionId, LensExtensionState>) => void;
|
||||
|
||||
const updateExtensionsStateInjectable = getInjectable({
|
||||
id: "update-extensions-state",
|
||||
instantiate: (di): UpdateExtensionsState => {
|
||||
const state = di.inject(enabledExtensionsStateInjectable);
|
||||
|
||||
return action((newState) => state.merge(newState));
|
||||
},
|
||||
});
|
||||
|
||||
export default updateExtensionsStateInjectable;
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import enabledExtensionsPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const loadEnabledExtensionsStorageInjectable = getInjectable({
|
||||
id: "load-enabled-extensions-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const storage = di.inject(enabledExtensionsPersistentStorageInjectable);
|
||||
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default loadEnabledExtensionsStorageInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { isObject } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { enabledExtensionsMigrationDeclarationInjectionToken } from "../common/migrations";
|
||||
|
||||
const enabledExtensionsMigrationV650Injectable = getInjectable({
|
||||
id: "enabled-extensions-migration-v650",
|
||||
instantiate: () => ({
|
||||
version: "6.5.0",
|
||||
run: (store) => {
|
||||
const extensions = store.get("extensions");
|
||||
|
||||
if (!isObject(extensions)) {
|
||||
store.delete("extensions");
|
||||
} else {
|
||||
store.set("extensions", Object.entries(extensions));
|
||||
}
|
||||
},
|
||||
}),
|
||||
injectionToken: enabledExtensionsMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default enabledExtensionsMigrationV650Injectable;
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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 { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
|
||||
import enabledExtensionsPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const loadEnabledExtensionsStorageInjectable = getInjectable({
|
||||
id: "load-enabled-extensions-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const storage = di.inject(enabledExtensionsPersistentStorageInjectable);
|
||||
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsSecondInjectionToken,
|
||||
});
|
||||
|
||||
export default loadEnabledExtensionsStorageInjectable;
|
||||
+12
-12
@@ -649,7 +649,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1391,7 +1391,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2133,7 +2133,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2986,7 +2986,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3736,7 +3736,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4589,7 +4589,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -5624,7 +5624,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6477,7 +6477,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -7512,7 +7512,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -8366,7 +8366,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -9105,7 +9105,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -9844,7 +9844,7 @@ exports[`add custom helm repository in preferences when navigating to preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+10
-10
@@ -649,7 +649,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1391,7 +1391,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2135,7 +2135,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2928,7 +2928,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3670,7 +3670,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4401,7 +4401,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -5177,7 +5177,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -5955,7 +5955,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6792,7 +6792,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -7523,7 +7523,7 @@ exports[`add helm repository from list in preferences when navigating to prefere
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+10
-10
@@ -649,7 +649,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1380,7 +1380,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2003,7 +2003,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2734,7 +2734,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3357,7 +3357,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4088,7 +4088,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4864,7 +4864,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -5487,7 +5487,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6110,7 +6110,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -6733,7 +6733,7 @@ exports[`listing active helm repositories in preferences when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+4
-4
@@ -649,7 +649,7 @@ exports[`remove helm repository from list of active repositories in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1363,7 +1363,7 @@ exports[`remove helm repository from list of active repositories in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2077,7 +2077,7 @@ exports[`remove helm repository from list of active repositories in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2808,7 +2808,7 @@ exports[`remove helm repository from list of active repositories in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -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 activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import computeHotbarIndexInjectable from "./compute-hotbar-index.injectable";
|
||||
|
||||
const activeHotbarIndexInjectable = getInjectable({
|
||||
id: "active-hotbar-index",
|
||||
instantiate: (di) => {
|
||||
const computeHotbarIndex = di.inject(computeHotbarIndexInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const activeId = activeHotbarId.get();
|
||||
|
||||
return (activeId && computeHotbarIndex(activeId)) || 0;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default activeHotbarIndexInjectable;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
|
||||
const activeHotbarIdInjectable = getInjectable({
|
||||
id: "active-hotbar-id",
|
||||
instantiate: () => observable.box<string>(),
|
||||
});
|
||||
|
||||
export default activeHotbarIdInjectable;
|
||||
@@ -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 activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
const activeHotbarInjectable = getInjectable({
|
||||
id: "active-hotbar",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const id = activeHotbarId.get();
|
||||
|
||||
return (id && state.get(id)) || undefined;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default activeHotbarInjectable;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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 { action } from "mobx";
|
||||
import type { CreateHotbarData, CreateHotbarOptions } from "./types";
|
||||
import activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
import createHotbarInjectable from "./create-hotbar.injectable";
|
||||
|
||||
export type AddHotbar = (data: CreateHotbarData, { setActive }?: CreateHotbarOptions) => void;
|
||||
|
||||
const addHotbarInjectable = getInjectable({
|
||||
id: "add-hotbar",
|
||||
instantiate: (di): AddHotbar => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
const createHotbar = di.inject(createHotbarInjectable);
|
||||
|
||||
return action((data, { setActive = false } = {}) => {
|
||||
const hotbar = createHotbar(data);
|
||||
|
||||
state.set(hotbar.id, hotbar);
|
||||
|
||||
if (setActive) {
|
||||
activeHotbarId.set(hotbar.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default addHotbarInjectable;
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 computeHotbarIndexInjectable from "./compute-hotbar-index.injectable";
|
||||
|
||||
export type ComputeDisplayIndex = (hotbarId: string) => string;
|
||||
|
||||
const computeDisplayIndexInjectable = getInjectable({
|
||||
id: "compute-display-index",
|
||||
instantiate: (di): ComputeDisplayIndex => {
|
||||
const computeHotbarIndex = di.inject(computeHotbarIndexInjectable);
|
||||
|
||||
return (hotbarId) => `${computeHotbarIndex(hotbarId) + 1}`;
|
||||
},
|
||||
});
|
||||
|
||||
export default computeDisplayIndexInjectable;
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
import computeDisplayIndexInjectable from "./compute-display-index.injectable";
|
||||
|
||||
export type ComputeHotbarDisplayLabel = (hotbar: Hotbar) => string;
|
||||
|
||||
const computeHotbarDisplayLabelInjectable = getInjectable({
|
||||
id: "compute-hotbar-display-label",
|
||||
instantiate: (di): ComputeHotbarDisplayLabel => {
|
||||
const computeDisplayIndex = di.inject(computeDisplayIndexInjectable);
|
||||
|
||||
return (hotbar) => `${computeDisplayIndex(hotbar.id)}: ${hotbar.name}`;
|
||||
},
|
||||
});
|
||||
|
||||
export default computeHotbarDisplayLabelInjectable;
|
||||
@@ -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 hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type ComputeHotbarIndex = (hotbarId: string) => number;
|
||||
|
||||
const computeHotbarIndexInjectable = getInjectable({
|
||||
id: "compute-hotbar-index",
|
||||
instantiate: (di): ComputeHotbarIndex => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return (hotbarId) => {
|
||||
let i = 0;
|
||||
|
||||
for (const hotbar of state.values()) {
|
||||
if (hotbar.id === hotbarId) {
|
||||
return i;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default computeHotbarIndexInjectable;
|
||||
@@ -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 type { CreateHotbarData } from "./types";
|
||||
import prefixedLoggerInjectable from "../../../../common/logger/prefixed-logger.injectable";
|
||||
import type { HotbarDependencies } from "./hotbar";
|
||||
import { Hotbar } from "./hotbar";
|
||||
|
||||
export type CreateHotbar = (data: CreateHotbarData) => Hotbar;
|
||||
|
||||
const createHotbarInjectable = getInjectable({
|
||||
id: "create-hotbar",
|
||||
instantiate: (di): CreateHotbar => {
|
||||
const deps: HotbarDependencies = {
|
||||
logger: di.inject(prefixedLoggerInjectable, "HOTBAR"),
|
||||
};
|
||||
|
||||
return (data) => new Hotbar(deps, data);
|
||||
},
|
||||
});
|
||||
|
||||
export default createHotbarInjectable;
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type FindHotbarByName = (name: string) => Hotbar | undefined;
|
||||
|
||||
const findHotbarByNameInjectable = getInjectable({
|
||||
id: "find-hotbar-by-name",
|
||||
instantiate: (di): FindHotbarByName => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return (name) => iter.find(state.values(), hotbar => hotbar.name.get() === name);
|
||||
},
|
||||
});
|
||||
|
||||
export default findHotbarByNameInjectable;
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type GetHotbarById = (id: string) => Hotbar | undefined;
|
||||
|
||||
const getHotbarByIdInjectable = getInjectable({
|
||||
id: "get-hotbar-by-id",
|
||||
instantiate: (di): GetHotbarById => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return (id) => state.get(id);
|
||||
},
|
||||
});
|
||||
|
||||
export default getHotbarByIdInjectable;
|
||||
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { type IObservableValue, type IObservableArray, observable, runInAction, toJS } from "mobx";
|
||||
import type { CatalogEntity } from "../../../../common/catalog";
|
||||
import { getShortName } from "../../../../common/catalog/helpers";
|
||||
import type { HotbarItem, CreateHotbarData } from "./types";
|
||||
import { defaultHotbarCells } from "./types";
|
||||
import { broadcastMessage } from "../../../../common/ipc";
|
||||
import { hotbarTooManyItemsChannel } from "../../../../common/ipc/hotbar";
|
||||
import * as uuid from "uuid";
|
||||
import type { Logger } from "../../../../common/logger";
|
||||
import { tuple } from "@k8slens/utilities";
|
||||
|
||||
export interface HotbarDependencies {
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export interface HotbarData {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly items: (HotbarItem | null)[];
|
||||
}
|
||||
|
||||
export class Hotbar {
|
||||
readonly id: string;
|
||||
readonly name: IObservableValue<string>;
|
||||
readonly items: IObservableArray<HotbarItem | null>;
|
||||
|
||||
constructor(private readonly dependencies: HotbarDependencies, data: CreateHotbarData) {
|
||||
this.id = data.id ?? uuid.v4();
|
||||
this.name = observable.box(data.name);
|
||||
this.items = observable.array(data.items ?? tuple.filled(defaultHotbarCells, null));
|
||||
}
|
||||
|
||||
isFull() {
|
||||
for (const item of this.items) {
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hasEntity(entityId: string) {
|
||||
return this.items.findIndex(item => item?.entity.uid === entityId) >= 0;
|
||||
}
|
||||
|
||||
private findClosestEmptyIndex(from: number, direction = 1) {
|
||||
let index = from;
|
||||
|
||||
while (this.items[index] != null) {
|
||||
index += direction;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
restack(from: number, to: number) {
|
||||
runInAction(() => {
|
||||
const source = this.items[from];
|
||||
const moveDown = from < to;
|
||||
|
||||
if (
|
||||
from < 0 ||
|
||||
to < 0 ||
|
||||
from >= this.items.length ||
|
||||
to >= this.items.length ||
|
||||
isNaN(from) ||
|
||||
isNaN(to)
|
||||
) {
|
||||
throw new Error("Invalid 'from' or 'to' arguments");
|
||||
}
|
||||
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.items.splice(from, 1, null);
|
||||
|
||||
if (this.items[to] == null) {
|
||||
this.items.splice(to, 1, source);
|
||||
} else {
|
||||
// Move cells up or down to closes empty cell
|
||||
this.items.splice(this.findClosestEmptyIndex(to, moveDown ? -1 : 1), 1);
|
||||
this.items.splice(to, 0, source);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggleEntity(item: CatalogEntity) {
|
||||
runInAction(() => {
|
||||
if (this.hasEntity(item.getId())) {
|
||||
this.removeEntity(item.getId());
|
||||
} else {
|
||||
this.addEntity(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removeEntity(uid: string) {
|
||||
runInAction(() => {
|
||||
const index = this.items.findIndex((item) => item?.entity.uid === uid);
|
||||
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.items[index] = null;
|
||||
});
|
||||
}
|
||||
|
||||
addEntity(item: CatalogEntity, cellIndex?: number) {
|
||||
const uid = item.getId();
|
||||
const name = item.getName();
|
||||
const shortName = getShortName(item);
|
||||
|
||||
if (typeof uid !== "string") {
|
||||
throw new TypeError("CatalogEntity's ID must be a string");
|
||||
}
|
||||
|
||||
if (typeof name !== "string") {
|
||||
throw new TypeError("CatalogEntity's NAME must be a string");
|
||||
}
|
||||
|
||||
if (typeof shortName !== "string") {
|
||||
throw new TypeError("CatalogEntity's SHORT_NAME must be a string");
|
||||
}
|
||||
|
||||
if (this.hasEntity(item.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entity = {
|
||||
uid,
|
||||
name,
|
||||
source: item.metadata.source,
|
||||
shortName,
|
||||
};
|
||||
const newItem = { entity };
|
||||
|
||||
if (cellIndex === undefined) {
|
||||
// Add item to empty cell
|
||||
const emptyCellIndex = this.items.indexOf(null);
|
||||
|
||||
if (emptyCellIndex >= 0) {
|
||||
runInAction(() => {
|
||||
this.items[emptyCellIndex] = newItem;
|
||||
});
|
||||
} else {
|
||||
broadcastMessage(hotbarTooManyItemsChannel);
|
||||
}
|
||||
} else if (0 <= cellIndex && cellIndex < this.items.length) {
|
||||
runInAction(() => {
|
||||
this.items[cellIndex] = newItem;
|
||||
});
|
||||
} else {
|
||||
this.dependencies.logger.error(
|
||||
"cannot pin entity to hotbar outside of index range",
|
||||
{ entityId: uid, hotbarId: this.id, cellIndex },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): HotbarData {
|
||||
return {
|
||||
id: this.id,
|
||||
items: toJS(this.items),
|
||||
name: this.name.get(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
const hotbarsInjectable = getInjectable({
|
||||
id: "hotbars",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return computed(() => [...state.values()]);
|
||||
},
|
||||
});
|
||||
|
||||
export default hotbarsInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable";
|
||||
|
||||
export const hotbarStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "hotbar-store-migration-token",
|
||||
});
|
||||
@@ -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 { action } from "mobx";
|
||||
import hotbarsInjectable from "./hotbars.injectable";
|
||||
|
||||
export type RemoveEntityFromAllHotbars = (entityId: string) => void;
|
||||
|
||||
const removeEntityFromAllHotbarsInjectable = getInjectable({
|
||||
id: "remove-entity-from-all-hotbars",
|
||||
instantiate: (di): RemoveEntityFromAllHotbars => {
|
||||
const hotbars = di.inject(hotbarsInjectable);
|
||||
|
||||
return action((entityId) => {
|
||||
for (const hotbar of hotbars.get()) {
|
||||
hotbar.removeEntity(entityId);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default removeEntityFromAllHotbarsInjectable;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
import { action } from "mobx";
|
||||
import activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type RemoveHotbar = (hotbar: Hotbar) => void;
|
||||
|
||||
const removeHotbarInjectable = getInjectable({
|
||||
id: "remove-hotbar",
|
||||
instantiate: (di): RemoveHotbar => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
|
||||
return action((hotbar) => {
|
||||
assert(state.size >= 2, "Cannot remove the last hotbar");
|
||||
|
||||
state.delete(hotbar.id);
|
||||
|
||||
if (activeHotbarId.get() === hotbar.id) {
|
||||
activeHotbarId.set(iter.first(state.values())?.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default removeHotbarInjectable;
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { action } from "mobx";
|
||||
import activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type SetAsActiveHotbar = (desc: Hotbar | number | string) => void;
|
||||
|
||||
const setAsActiveHotbarInjectable = getInjectable({
|
||||
id: "set-as-active-hotbar",
|
||||
instantiate: (di): SetAsActiveHotbar => {
|
||||
const hotbarsState = di.inject(hotbarsStateInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
|
||||
return action((desc) => {
|
||||
if (typeof desc === "number") {
|
||||
const hotbar = iter.nth(hotbarsState.values(), desc);
|
||||
|
||||
if (hotbar) {
|
||||
activeHotbarId.set(hotbar.id);
|
||||
}
|
||||
} else if (typeof desc === "string") {
|
||||
if (hotbarsState.has(desc)) {
|
||||
activeHotbarId.set(desc);
|
||||
}
|
||||
} else {
|
||||
if (hotbarsState.has(desc.id)) {
|
||||
activeHotbarId.set(desc.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default setAsActiveHotbarInjectable;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
|
||||
const hotbarsStateInjectable = getInjectable({
|
||||
id: "hotbars-state",
|
||||
instantiate: () => observable.map<string, Hotbar>(),
|
||||
});
|
||||
|
||||
export default hotbarsStateInjectable;
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { action, comparer } from "mobx";
|
||||
import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||
import { hotbarStoreMigrationInjectionToken } from "./migrations-token";
|
||||
import { defaultHotbarCells } from "./types";
|
||||
import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable";
|
||||
import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable";
|
||||
import storeMigrationVersionInjectable from "../../../../common/vars/store-migration-version.injectable";
|
||||
import activeHotbarIdInjectable from "./active-id.injectable";
|
||||
import createHotbarInjectable from "./create-hotbar.injectable";
|
||||
import type { Hotbar, HotbarData } from "./hotbar";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export interface HotbarStoreModel {
|
||||
hotbars: HotbarData[];
|
||||
activeHotbarId: string | undefined;
|
||||
}
|
||||
|
||||
const hotbarsPersistentStorageInjectable = getInjectable({
|
||||
id: "hotbars-persistent-storage",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
const createPersistentStorage = di.inject(createPersistentStorageInjectable);
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
const activeHotbarId = di.inject(activeHotbarIdInjectable);
|
||||
const createHotbar = di.inject(createHotbarInjectable);
|
||||
|
||||
return createPersistentStorage<HotbarStoreModel>({
|
||||
configName: "lens-hotbar-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
projectVersion: di.inject(storeMigrationVersionInjectable),
|
||||
migrations: di.inject(persistentStorageMigrationsInjectable, hotbarStoreMigrationInjectionToken),
|
||||
fromStore: action((data) => {
|
||||
if (!data.hotbars || !data.hotbars.length) {
|
||||
const hotbar = createHotbar({
|
||||
name: "Default",
|
||||
});
|
||||
const {
|
||||
metadata: {
|
||||
uid,
|
||||
name,
|
||||
source,
|
||||
},
|
||||
} = catalogCatalogEntity;
|
||||
|
||||
hotbar.items[0] = {
|
||||
entity: {
|
||||
uid,
|
||||
name,
|
||||
source,
|
||||
},
|
||||
};
|
||||
state.replace([[hotbar.id, hotbar]]);
|
||||
} else {
|
||||
state.replace(data.hotbars.map((hotbar) => [hotbar.id, createHotbar(hotbar)]));
|
||||
}
|
||||
|
||||
for (const hotbar of state.values()) {
|
||||
ensureExactHotbarItemLength(hotbar);
|
||||
}
|
||||
|
||||
if (data.activeHotbarId) {
|
||||
activeHotbarId.set(data.activeHotbarId);
|
||||
}
|
||||
|
||||
const firstHotbarId = iter.first(state.values())?.id;
|
||||
|
||||
if (!activeHotbarId.get()) {
|
||||
activeHotbarId.set(firstHotbarId);
|
||||
} else if (!iter.find(state.values(), hotbar => hotbar.id === activeHotbarId.get())) {
|
||||
activeHotbarId.set(firstHotbarId);
|
||||
}
|
||||
}),
|
||||
toJSON: () => ({
|
||||
hotbars: iter.chain(state.values())
|
||||
.map(hotbar => hotbar.toJSON())
|
||||
.toArray(),
|
||||
activeHotbarId: activeHotbarId.get(),
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default hotbarsPersistentStorageInjectable;
|
||||
|
||||
/**
|
||||
* This function ensures that there are always exactly `defaultHotbarCells`
|
||||
* worth of items in the hotbar.
|
||||
* @param hotbar The hotbar to modify
|
||||
*/
|
||||
function ensureExactHotbarItemLength(hotbar: Hotbar) {
|
||||
// if there are not enough items
|
||||
while (hotbar.items.length < defaultHotbarCells) {
|
||||
hotbar.items.push(null);
|
||||
}
|
||||
|
||||
// if for some reason the hotbar was overfilled before, remove as many entries
|
||||
// as needed, but prefer empty slots and items at the end first.
|
||||
while (hotbar.items.length > defaultHotbarCells) {
|
||||
const lastNull = hotbar.items.lastIndexOf(null);
|
||||
|
||||
if (lastNull >= 0) {
|
||||
hotbar.items.splice(lastNull, 1);
|
||||
} else {
|
||||
hotbar.items.length = defaultHotbarCells;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 { action } from "mobx";
|
||||
import activeHotbarIndexInjectable from "./active-hotbar-index.injectable";
|
||||
import setAsActiveHotbarInjectable from "./set-as-active.injectable";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type SwitchToNextHotbar = () => void;
|
||||
|
||||
const switchToNextHotbarInjectable = getInjectable({
|
||||
id: "switch-to-next-hotbar",
|
||||
instantiate: (di): SwitchToNextHotbar => {
|
||||
const setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable);
|
||||
const activeHotbarIndex = di.inject(activeHotbarIndexInjectable);
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return action(() => {
|
||||
const index = activeHotbarIndex.get() + 1;
|
||||
|
||||
if (index >= state.size) {
|
||||
setAsActiveHotbar(0);
|
||||
} else {
|
||||
setAsActiveHotbar(index);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default switchToNextHotbarInjectable;
|
||||
@@ -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 { action } from "mobx";
|
||||
import activeHotbarIndexInjectable from "./active-hotbar-index.injectable";
|
||||
import setAsActiveHotbarInjectable from "./set-as-active.injectable";
|
||||
import hotbarsStateInjectable from "./state.injectable";
|
||||
|
||||
export type SwitchToPreviousHotbar = () => void;
|
||||
|
||||
const switchToPreviousHotbarInjectable = getInjectable({
|
||||
id: "switch-to-previous-hotbar",
|
||||
instantiate: (di): SwitchToPreviousHotbar => {
|
||||
const setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable);
|
||||
const activeHotbarIndex = di.inject(activeHotbarIndexInjectable);
|
||||
const state = di.inject(hotbarsStateInjectable);
|
||||
|
||||
return action(() => {
|
||||
const index = activeHotbarIndex.get() - 1;
|
||||
|
||||
if (index < 0) {
|
||||
setAsActiveHotbar(state.size - 1);
|
||||
} else {
|
||||
setAsActiveHotbar(index);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default switchToPreviousHotbarInjectable;
|
||||
@@ -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 activeHotbarInjectable from "./active.injectable";
|
||||
import type { Hotbar } from "./hotbar";
|
||||
|
||||
export type ActiveHotbarModel = Pick<Hotbar, "hasEntity" | "addEntity" | "removeEntity" | "toggleEntity">;
|
||||
|
||||
const activeHotbarModelInjectable = getInjectable({
|
||||
id: "active-hotbar-model",
|
||||
instantiate: (di): ActiveHotbarModel => {
|
||||
const activeHotbar = di.inject(activeHotbarInjectable);
|
||||
|
||||
return {
|
||||
hasEntity: (entityId) => activeHotbar.get()?.hasEntity(entityId) ?? false,
|
||||
toggleEntity: (entity) => activeHotbar.get()?.toggleEntity(entity),
|
||||
addEntity: (entity) => activeHotbar.get()?.addEntity(entity),
|
||||
removeEntity: (entityId) => activeHotbar.get()?.removeEntity(entityId),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default activeHotbarModelInjectable;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
|
||||
export interface HotbarItem {
|
||||
entity: {
|
||||
uid: string;
|
||||
name: string;
|
||||
source?: string;
|
||||
};
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateHotbarData {
|
||||
id?: string;
|
||||
name: string;
|
||||
items?: (HotbarItem | null)[];
|
||||
}
|
||||
|
||||
export interface CreateHotbarOptions {
|
||||
setActive?: boolean;
|
||||
}
|
||||
|
||||
export const defaultHotbarCells = 12; // Number is chosen to easy hit any item with keyboard
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Cleans up a store that had the state related data stored
|
||||
import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token";
|
||||
import createHotbarInjectable from "../common/create-hotbar.injectable";
|
||||
|
||||
const v500Alpha0HotbarStoreMigrationInjectable = getInjectable({
|
||||
id: "v5.0.0-alpha.0-hotbar-store-migration",
|
||||
instantiate: (di) => ({
|
||||
version: "5.0.0-alpha.0",
|
||||
run(store) {
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
const createHotbar = di.inject(createHotbarInjectable);
|
||||
const hotbar = createHotbar({ name: "default" });
|
||||
|
||||
hotbar.addEntity(catalogCatalogEntity);
|
||||
|
||||
store.set("hotbars", [hotbar.toJSON()]);
|
||||
},
|
||||
}),
|
||||
injectionToken: hotbarStoreMigrationInjectionToken,
|
||||
});
|
||||
|
||||
export default v500Alpha0HotbarStoreMigrationInjectable;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Cleans up a store that had the state related data stored
|
||||
import * as uuid from "uuid";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token";
|
||||
import type { HotbarData } from "../common/hotbar";
|
||||
|
||||
const v500Alpha2HotbarStoreMigrationInjectable = getInjectable({
|
||||
id: "v5.0.0-alpha.2-hotbar-store-migration",
|
||||
instantiate: () => ({
|
||||
version: "5.0.0-alpha.2",
|
||||
run(store) {
|
||||
const rawHotbars = store.get("hotbars");
|
||||
const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars : [];
|
||||
|
||||
store.set("hotbars", hotbars.map(({ id, ...rest }) => ({
|
||||
id: id || uuid.v4(),
|
||||
...rest,
|
||||
})));
|
||||
},
|
||||
}),
|
||||
injectionToken: hotbarStoreMigrationInjectionToken,
|
||||
});
|
||||
|
||||
export default v500Alpha2HotbarStoreMigrationInjectable;
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import * as uuid from "uuid";
|
||||
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||
import { isDefined, isErrnoException } from "@k8slens/utilities";
|
||||
import joinPathsInjectable from "../../../../common/path/join-paths.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token";
|
||||
import readJsonSyncInjectable from "../../../../common/fs/read-json-sync.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import { generateNewIdFor } from "../../../../common/utils/generate-new-id-for";
|
||||
import type { ClusterModel } from "../../../../common/cluster-types";
|
||||
import { defaultHotbarCells } from "../common/types";
|
||||
import type { HotbarData } from "../common/hotbar";
|
||||
import createHotbarInjectable from "../common/create-hotbar.injectable";
|
||||
|
||||
interface Pre500WorkspaceStoreModel {
|
||||
workspaces: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface Pre500ClusterModel extends ClusterModel {
|
||||
workspace?: string;
|
||||
workspaces?: string[];
|
||||
}
|
||||
|
||||
interface Pre500ClusterStoreModel {
|
||||
clusters?: Pre500ClusterModel[];
|
||||
}
|
||||
|
||||
const v500Beta10HotbarStoreMigrationInjectable = getInjectable({
|
||||
id: "v5.0.0-beta.10-hotbar-store-migration",
|
||||
instantiate: (di) => ({
|
||||
version: "5.0.0-beta.10",
|
||||
run(store) {
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const readJsonSync = di.inject(readJsonSyncInjectable);
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const createHotbar = di.inject(createHotbarInjectable);
|
||||
const rawHotbars = store.get("hotbars");
|
||||
const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars.filter(h => h && typeof h === "object") : [];
|
||||
|
||||
// Hotbars might be empty, if some of the previous migrations weren't run
|
||||
if (hotbars.length === 0) {
|
||||
const hotbar = createHotbar({ name: "default" });
|
||||
|
||||
hotbar.addEntity(catalogCatalogEntity);
|
||||
hotbars.push(hotbar.toJSON());
|
||||
}
|
||||
|
||||
try {
|
||||
const workspaceStoreData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
|
||||
const { clusters = [] }: Pre500ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json"));
|
||||
const workspaceHotbars = new Map<string, HotbarData>(); // mapping from WorkspaceId to HotBar
|
||||
|
||||
for (const { id, name } of workspaceStoreData.workspaces) {
|
||||
logger.info(`Creating new hotbar for ${name}`);
|
||||
workspaceHotbars.set(id, {
|
||||
id: uuid.v4(),
|
||||
items: [],
|
||||
name: `Workspace: ${name}`,
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// grab the default named hotbar or the first.
|
||||
const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default"));
|
||||
const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1);
|
||||
|
||||
workspaceHotbars.set("default", {
|
||||
name,
|
||||
id,
|
||||
items: items.filter(isDefined),
|
||||
});
|
||||
}
|
||||
|
||||
for (const cluster of clusters) {
|
||||
const uid = generateNewIdFor(cluster);
|
||||
|
||||
for (const workspaceId of cluster.workspaces ?? [cluster.workspace].filter(isDefined)) {
|
||||
const workspaceHotbar = workspaceHotbars.get(workspaceId);
|
||||
|
||||
if (!workspaceHotbar) {
|
||||
logger.info(`Cluster ${uid} has unknown workspace ID, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.info(`Adding cluster ${uid} to ${workspaceHotbar.name}`);
|
||||
|
||||
if (workspaceHotbar?.items.length < defaultHotbarCells) {
|
||||
workspaceHotbar.items.push({
|
||||
entity: {
|
||||
uid: generateNewIdFor(cluster),
|
||||
name: cluster.preferences?.clusterName || cluster.contextName,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const hotbar of workspaceHotbars.values()) {
|
||||
if (hotbar.items.length === 0) {
|
||||
logger.info(`Skipping ${hotbar.name} due to it being empty`);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (hotbar.items.length < defaultHotbarCells) {
|
||||
hotbar.items.push(null);
|
||||
}
|
||||
|
||||
hotbars.push(hotbar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally, make sure that the catalog entity hotbar item is in place.
|
||||
* Just in case something else removed it.
|
||||
*
|
||||
* if every hotbar has elements that all not the `catalog-entity` item
|
||||
*/
|
||||
if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) {
|
||||
// note, we will add a new whole hotbar here called "default" if that was previously removed
|
||||
const defaultHotbarIndex = hotbars.findIndex(hotbar => hotbar.name === "default");
|
||||
|
||||
if (defaultHotbarIndex >= 0) {
|
||||
const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]);
|
||||
|
||||
if (defaultHotbar.isFull()) {
|
||||
// making a new hotbar is less destructive if the first hotbar
|
||||
// called "default" is full than overriding a hotbar item
|
||||
const hotbar = createHotbar({ name: "initial" });
|
||||
|
||||
hotbar.addEntity(catalogCatalogEntity);
|
||||
hotbars.unshift(hotbar.toJSON());
|
||||
} else {
|
||||
defaultHotbar.addEntity(catalogCatalogEntity);
|
||||
hotbars[defaultHotbarIndex] = defaultHotbar.toJSON();
|
||||
}
|
||||
} else {
|
||||
const hotbar = createHotbar({ name: "default" });
|
||||
|
||||
hotbar.addEntity(catalogCatalogEntity);
|
||||
hotbars.unshift(hotbar.toJSON());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// ignore files being missing
|
||||
if (isErrnoException(error) && error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
store.set("hotbars", hotbars);
|
||||
},
|
||||
}),
|
||||
injectionToken: hotbarStoreMigrationInjectionToken,
|
||||
});
|
||||
|
||||
export default v500Beta10HotbarStoreMigrationInjectable;
|
||||
|
||||
@@ -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 catalogEntityRegistryInjectable from "../../../../main/catalog/entity-registry.injectable";
|
||||
import type { HotbarData } from "../common/hotbar";
|
||||
import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token";
|
||||
|
||||
const v500Beta5HotbarStoreMigrationInjectable = getInjectable({
|
||||
id: "v500-beta5-hotbar-store-migration",
|
||||
instantiate: (di) => ({
|
||||
version: "5.0.0-beta.5",
|
||||
run(store) {
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const rawHotbars = store.get("hotbars");
|
||||
const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars : [];
|
||||
|
||||
for (const hotbar of hotbars) {
|
||||
for (let i = 0; i < hotbar.items.length; i += 1) {
|
||||
const item = hotbar.items[i];
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entity = catalogEntityRegistry.findById(item.entity.uid);
|
||||
|
||||
if (!entity) {
|
||||
// Clear disabled item
|
||||
hotbar.items[i] = null;
|
||||
} else {
|
||||
// Save additional data
|
||||
item.entity = {
|
||||
...item.entity,
|
||||
name: entity.metadata.name,
|
||||
source: entity.metadata.source,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.set("hotbars", hotbars);
|
||||
},
|
||||
}),
|
||||
injectionToken: hotbarStoreMigrationInjectionToken,
|
||||
});
|
||||
|
||||
export default v500Beta5HotbarStoreMigrationInjectable;
|
||||
|
||||
+6
-6
@@ -3,21 +3,21 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "@k8slens/application";
|
||||
import setupSyncingOfGeneralCatalogEntitiesInjectable from "../../../../main/start-main-application/runnables/setup-syncing-of-general-catalog-entities.injectable";
|
||||
import hotbarsPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const initHotbarStoreInjectable = getInjectable({
|
||||
id: "init-hotbar-store",
|
||||
const loadHotbarStorageInjectable = getInjectable({
|
||||
id: "load-hotbar-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const hotbarStore = di.inject(hotbarStoreInjectable);
|
||||
const storage = di.inject(hotbarsPersistentStorageInjectable);
|
||||
|
||||
hotbarStore.load();
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
runAfter: setupSyncingOfGeneralCatalogEntitiesInjectable,
|
||||
}),
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default initHotbarStoreInjectable;
|
||||
export default loadHotbarStorageInjectable;
|
||||
+7
-7
@@ -3,21 +3,21 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
|
||||
import initClusterStoreInjectable from "../../../cluster/store/renderer/init.injectable";
|
||||
import initClusterStoreInjectable from "../../../cluster/storage/renderer/init.injectable";
|
||||
import hotbarsPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const initHotbarStoreInjectable = getInjectable({
|
||||
id: "init-hotbar-store",
|
||||
const loadHotbarStorageInjectable = getInjectable({
|
||||
id: "load-hotbar-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const hotbarStore = di.inject(hotbarStoreInjectable);
|
||||
const storage = di.inject(hotbarsPersistentStorageInjectable);
|
||||
|
||||
hotbarStore.load();
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
runAfter: initClusterStoreInjectable,
|
||||
}),
|
||||
injectionToken: beforeFrameStartsSecondInjectionToken,
|
||||
});
|
||||
|
||||
export default initHotbarStoreInjectable;
|
||||
export default loadHotbarStorageInjectable;
|
||||
@@ -0,0 +1,373 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { anyObject } from "jest-mock-extended";
|
||||
import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../../../common/catalog";
|
||||
import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import catalogEntityRegistryInjectable from "../../../main/catalog/entity-registry.injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { computed } from "mobx";
|
||||
import hasCategoryForEntityInjectable from "../../../common/catalog/has-category-for-entity.injectable";
|
||||
import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import type { Logger } from "../../../common/logger";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable";
|
||||
import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable";
|
||||
import type { SetAsActiveHotbar } from "./common/set-as-active.injectable";
|
||||
import setAsActiveHotbarInjectable from "./common/set-as-active.injectable";
|
||||
import hotbarsPersistentStorageInjectable from "./common/storage.injectable";
|
||||
import type { Hotbar } from "./common/hotbar";
|
||||
import hotbarsInjectable from "./common/hotbars.injectable";
|
||||
import activeHotbarInjectable from "./common/active.injectable";
|
||||
import type { AddHotbar } from "./common/add.injectable";
|
||||
import type { GetHotbarById } from "./common/get-by-id.injectable";
|
||||
import getHotbarByIdInjectable from "./common/get-by-id.injectable";
|
||||
import addHotbarInjectable from "./common/add.injectable";
|
||||
import { defaultHotbarCells } from "./common/types";
|
||||
|
||||
function getMockCatalogEntity(data: Partial<CatalogEntityData> & CatalogEntityKindData): CatalogEntity {
|
||||
return {
|
||||
getName: jest.fn(() => data.metadata?.name),
|
||||
getId: jest.fn(() => data.metadata?.uid),
|
||||
getSource: jest.fn(() => data.metadata?.source ?? "unknown"),
|
||||
isEnabled: jest.fn(() => data.status?.enabled ?? true),
|
||||
onContextMenuOpen: jest.fn(),
|
||||
onSettingsOpen: jest.fn(),
|
||||
metadata: {},
|
||||
spec: {},
|
||||
status: {},
|
||||
...data,
|
||||
} as CatalogEntity;
|
||||
}
|
||||
|
||||
describe("Hotbars technical tests", () => {
|
||||
let di: DiContainer;
|
||||
let testCluster: CatalogEntity;
|
||||
let minikubeCluster: CatalogEntity;
|
||||
let awsCluster: CatalogEntity;
|
||||
let loggerMock: jest.Mocked<Logger>;
|
||||
let setAsActiveHotbar: SetAsActiveHotbar;
|
||||
let hotbars: IComputedValue<Hotbar[]>;
|
||||
let activeHotbar: IComputedValue<Hotbar | undefined>;
|
||||
let addHotbar: AddHotbar;
|
||||
let getHotbarById: GetHotbarById;
|
||||
|
||||
beforeEach(async () => {
|
||||
di = getDiForUnitTesting();
|
||||
|
||||
testCluster = getMockCatalogEntity({
|
||||
apiVersion: "v1",
|
||||
kind: "Cluster",
|
||||
status: {
|
||||
phase: "Running",
|
||||
},
|
||||
metadata: {
|
||||
uid: "some-test-id",
|
||||
name: "my-test-cluster",
|
||||
source: "local",
|
||||
labels: {},
|
||||
},
|
||||
});
|
||||
minikubeCluster = getMockCatalogEntity({
|
||||
apiVersion: "v1",
|
||||
kind: "Cluster",
|
||||
status: {
|
||||
phase: "Running",
|
||||
},
|
||||
metadata: {
|
||||
uid: "some-minikube-id",
|
||||
name: "my-minikube-cluster",
|
||||
source: "local",
|
||||
labels: {},
|
||||
},
|
||||
});
|
||||
awsCluster = getMockCatalogEntity({
|
||||
apiVersion: "v1",
|
||||
kind: "Cluster",
|
||||
status: {
|
||||
phase: "Running",
|
||||
},
|
||||
metadata: {
|
||||
uid: "some-aws-id",
|
||||
name: "my-aws-cluster",
|
||||
source: "local",
|
||||
labels: {},
|
||||
},
|
||||
});
|
||||
|
||||
di.override(hasCategoryForEntityInjectable, () => () => true);
|
||||
|
||||
loggerMock = {
|
||||
warn: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
error: jest.fn(),
|
||||
info: jest.fn(),
|
||||
silly: jest.fn(),
|
||||
};
|
||||
|
||||
di.override(loggerInjectable, () => loggerMock);
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
|
||||
catalogEntityRegistry.addComputedSource("some-id", computed(() => [
|
||||
testCluster,
|
||||
minikubeCluster,
|
||||
awsCluster,
|
||||
catalogCatalogEntity,
|
||||
]));
|
||||
|
||||
setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable);
|
||||
hotbars = di.inject(hotbarsInjectable);
|
||||
activeHotbar = di.inject(activeHotbarInjectable);
|
||||
addHotbar = di.inject(addHotbarInjectable);
|
||||
getHotbarById = di.inject(getHotbarByIdInjectable);
|
||||
});
|
||||
|
||||
describe("given no previous data in store, running all migrations", () => {
|
||||
beforeEach(() => {
|
||||
di.override(storeMigrationVersionInjectable, () => "9999.0.0");
|
||||
di.inject(hotbarsPersistentStorageInjectable).loadAndStartSyncing();
|
||||
});
|
||||
|
||||
describe("load", () => {
|
||||
it("loads one hotbar by default", () => {
|
||||
expect(hotbars.get().length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("add", () => {
|
||||
it("adds a hotbar", () => {
|
||||
addHotbar({ name: "hottest" });
|
||||
expect(hotbars.get().length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hotbar items", () => {
|
||||
it("initially creates default number of empty cells", () => {
|
||||
expect(activeHotbar.get()?.items?.length).toEqual(defaultHotbarCells);
|
||||
});
|
||||
|
||||
it("initially adds catalog entity as first item", () => {
|
||||
expect(activeHotbar.get()?.items[0]?.entity.name).toEqual("Catalog");
|
||||
});
|
||||
|
||||
it("adds items", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
const items = activeHotbar.get()?.items.filter(Boolean);
|
||||
|
||||
expect(items?.length).toEqual(2);
|
||||
});
|
||||
|
||||
it("removes items", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.removeEntity("some-test-id");
|
||||
activeHotbar.get()?.removeEntity("catalog-entity");
|
||||
const items = activeHotbar.get()?.items.filter(Boolean);
|
||||
|
||||
expect(items).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("does nothing if removing with invalid uid", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.removeEntity("invalid uid");
|
||||
const items = activeHotbar.get()?.items.filter(Boolean);
|
||||
|
||||
expect(items?.length).toEqual(2);
|
||||
});
|
||||
|
||||
it("moves item to empty cell", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.addEntity(minikubeCluster);
|
||||
activeHotbar.get()?.addEntity(awsCluster);
|
||||
|
||||
expect(activeHotbar.get()?.items[6]).toBeNull();
|
||||
|
||||
activeHotbar.get()?.restack(1, 5);
|
||||
|
||||
expect(activeHotbar.get()?.items[5]).toBeTruthy();
|
||||
expect(activeHotbar.get()?.items[5]?.entity.uid).toEqual("some-test-id");
|
||||
});
|
||||
|
||||
it("moves items down", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.addEntity(minikubeCluster);
|
||||
activeHotbar.get()?.addEntity(awsCluster);
|
||||
|
||||
// aws -> catalog
|
||||
activeHotbar.get()?.restack(3, 0);
|
||||
|
||||
const items = activeHotbar.get()?.items.map(item => item?.entity.uid || null);
|
||||
|
||||
expect(items?.slice(0, 4)).toEqual(["some-aws-id", "catalog-entity", "some-test-id", "some-minikube-id"]);
|
||||
});
|
||||
|
||||
it("moves items up", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.addEntity(minikubeCluster);
|
||||
activeHotbar.get()?.addEntity(awsCluster);
|
||||
|
||||
// test -> aws
|
||||
activeHotbar.get()?.restack(1, 3);
|
||||
|
||||
const items = activeHotbar.get()?.items.map(item => item?.entity.uid || null);
|
||||
|
||||
expect(items?.slice(0, 4)).toEqual(["catalog-entity", "some-minikube-id", "some-aws-id", "some-test-id"]);
|
||||
});
|
||||
|
||||
it("logs an error if cellIndex is out of bounds", () => {
|
||||
addHotbar({ name: "hottest", id: "hottest" });
|
||||
setAsActiveHotbar("hottest");
|
||||
|
||||
activeHotbar.get()?.addEntity(testCluster, -1);
|
||||
expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
|
||||
activeHotbar.get()?.addEntity(testCluster, 12);
|
||||
expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
|
||||
activeHotbar.get()?.addEntity(testCluster, 13);
|
||||
expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
});
|
||||
|
||||
it("throws an error if getId is invalid or returns not a string", () => {
|
||||
expect(() => activeHotbar.get()?.addEntity({} as any)).toThrowError(TypeError);
|
||||
expect(() => activeHotbar.get()?.addEntity({ getId: () => true } as any)).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it("throws an error if getName is invalid or returns not a string", () => {
|
||||
expect(() => activeHotbar.get()?.addEntity({ getId: () => "" } as any)).toThrowError(TypeError);
|
||||
expect(() => activeHotbar.get()?.addEntity({ getId: () => "", getName: () => 4 } as any)).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it("does nothing when item moved to same cell", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.restack(1, 1);
|
||||
|
||||
expect(activeHotbar.get()?.items[1]?.entity.uid).toEqual("some-test-id");
|
||||
});
|
||||
|
||||
it("new items takes first empty cell", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
activeHotbar.get()?.addEntity(awsCluster);
|
||||
activeHotbar.get()?.restack(0, 3);
|
||||
activeHotbar.get()?.addEntity(minikubeCluster);
|
||||
|
||||
expect(activeHotbar.get()?.items[0]?.entity.uid).toEqual("some-minikube-id");
|
||||
});
|
||||
|
||||
it("throws if invalid arguments provided", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
|
||||
expect(() => activeHotbar.get()?.restack(-5, 0)).toThrow();
|
||||
expect(() => activeHotbar.get()?.restack(2, -1)).toThrow();
|
||||
expect(() => activeHotbar.get()?.restack(14, 1)).toThrow();
|
||||
expect(() => activeHotbar.get()?.restack(11, 112)).toThrow();
|
||||
});
|
||||
|
||||
it("checks if entity already pinned to hotbar", () => {
|
||||
activeHotbar.get()?.addEntity(testCluster);
|
||||
|
||||
expect(activeHotbar.get()?.hasEntity(testCluster.getId())).toBeTruthy();
|
||||
expect(activeHotbar.get()?.hasEntity(awsCluster.getId())).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => {
|
||||
beforeEach(() => {
|
||||
const writeJsonSync = di.inject(writeJsonSyncInjectable);
|
||||
|
||||
writeJsonSync("/some-directory-for-user-data/lens-hotbar-store.json", {
|
||||
__internal__: {
|
||||
migrations: {
|
||||
version: "5.0.0-beta.3",
|
||||
},
|
||||
},
|
||||
hotbars: [
|
||||
{
|
||||
id: "3caac17f-aec2-4723-9694-ad204465d935",
|
||||
name: "myhotbar",
|
||||
items: [
|
||||
{
|
||||
entity: {
|
||||
uid: "some-aws-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
uid: "55b42c3c7ba3b04193416cda405269a5",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
uid: "176fd331968660832f62283219d7eb6e",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
uid: "61c4fb45528840ebad1badc25da41d14",
|
||||
name: "user1-context",
|
||||
source: "local",
|
||||
},
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
uid: "27d6f99fe9e7548a6e306760bfe19969",
|
||||
name: "foo2",
|
||||
source: "local",
|
||||
},
|
||||
},
|
||||
null,
|
||||
{
|
||||
entity: {
|
||||
uid: "c0b20040646849bb4dcf773e43a0bf27",
|
||||
name: "multinode-demo",
|
||||
source: "local",
|
||||
},
|
||||
},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
di.override(storeMigrationVersionInjectable, () => "5.0.0-beta.10");
|
||||
|
||||
di.inject(hotbarsPersistentStorageInjectable).loadAndStartSyncing();
|
||||
});
|
||||
|
||||
it("allows to retrieve a hotbar", () => {
|
||||
const hotbar = getHotbarById("3caac17f-aec2-4723-9694-ad204465d935");
|
||||
|
||||
expect(hotbar?.id).toBe("3caac17f-aec2-4723-9694-ad204465d935");
|
||||
});
|
||||
|
||||
it("clears cells without entity", () => {
|
||||
const items = hotbars.get()[0].items;
|
||||
|
||||
expect(items[2]).toBeNull();
|
||||
});
|
||||
|
||||
it("adds extra data to cells with according entity", () => {
|
||||
const items = hotbars.get()[0].items;
|
||||
|
||||
expect(items[0]).toEqual({
|
||||
entity: {
|
||||
name: "my-aws-cluster",
|
||||
source: "local",
|
||||
uid: "some-aws-id",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+8
-8
@@ -709,7 +709,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1057,7 +1057,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1263,7 +1263,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1469,7 +1469,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2231,7 +2231,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2579,7 +2579,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2785,7 +2785,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2991,7 +2991,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+1
-1
@@ -722,7 +722,7 @@ exports[`preferences: extension adding preference tabs given in preferences, whe
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+3
-3
@@ -697,7 +697,7 @@ exports[`preferences - hiding-of-empty-branches, given in preferences page given
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1475,7 +1475,7 @@ exports[`preferences - hiding-of-empty-branches, given in preferences page given
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2265,7 +2265,7 @@ exports[`preferences - hiding-of-empty-branches, given in preferences page given
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+5
-5
@@ -697,7 +697,7 @@ exports[`preferences - navigation to application preferences given in preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1478,7 +1478,7 @@ exports[`preferences - navigation to application preferences given in preference
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1884,7 +1884,7 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2634,7 +2634,7 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3385,7 +3385,7 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -697,7 +697,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1336,7 +1336,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+9
-9
@@ -710,7 +710,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1090,7 +1090,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1481,7 +1481,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1872,7 +1872,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2289,7 +2289,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3039,7 +3039,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -3827,7 +3827,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4232,7 +4232,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -4568,7 +4568,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -697,7 +697,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1374,7 +1374,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -697,7 +697,7 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1103,7 +1103,7 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+5
-5
@@ -337,7 +337,7 @@ exports[`preferences - navigation to telemetry preferences given URL for Sentry
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1087,7 +1087,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1849,7 +1849,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2228,7 +2228,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -2567,7 +2567,7 @@ exports[`preferences - navigation to telemetry preferences given no URL for Sent
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -697,7 +697,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1310,7 +1310,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -230,7 +230,7 @@ exports[`preferences - navigation using application menu renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -980,7 +980,7 @@ exports[`preferences - navigation using application menu when navigating to pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+2
-2
@@ -231,7 +231,7 @@ exports[`show-about-using-tray renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -983,7 +983,7 @@ exports[`show-about-using-tray when navigating using tray renders 1`] = `
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+5
-5
@@ -375,7 +375,7 @@ exports[`preferences: URLs of legacy extensions given extension with both custom
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -804,7 +804,7 @@ exports[`preferences: URLs of legacy extensions given extension with both custom
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1195,7 +1195,7 @@ exports[`preferences: URLs of legacy extensions given extension with custom pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1560,7 +1560,7 @@ exports[`preferences: URLs of legacy extensions given extension with custom pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@@ -1965,7 +1965,7 @@ exports[`preferences: URLs of legacy extensions given extension with custom pref
|
||||
class="HotbarSelector"
|
||||
>
|
||||
<i
|
||||
class="Icon Icon previous material interactive focusable"
|
||||
class="Icon material interactive focusable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
+17
-21
@@ -6,16 +6,16 @@ import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { defaultExtensionRegistryUrl, defaultExtensionRegistryUrlLocation } from "../../../../../../common/user-store/preferences-helpers";
|
||||
import { Input } from "../../../../../../renderer/components/input";
|
||||
import { isUrl } from "../../../../../../renderer/components/input/input_validators";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import { runInAction } from "mobx";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { observer } from "mobx-react";
|
||||
import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable";
|
||||
import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable";
|
||||
import { defaultExtensionRegistryUrlLocation, defaultExtensionRegistryUrl } from "../../../../../user-preferences/common/preferences-helpers";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
state: UserPreferencesState;
|
||||
}
|
||||
|
||||
const extensionInstallRegistryOptions = [
|
||||
@@ -33,8 +33,8 @@ const extensionInstallRegistryOptions = [
|
||||
},
|
||||
] as const;
|
||||
|
||||
const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencies) => {
|
||||
const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || "");
|
||||
const NonInjectedExtensionInstallRegistry = observer(({ state }: Dependencies) => {
|
||||
const [customUrl, setCustomUrl] = React.useState(state.extensionRegistryUrl.customUrl || "");
|
||||
|
||||
return (
|
||||
<section id="extensionRegistryUrl">
|
||||
@@ -42,14 +42,14 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie
|
||||
<Select
|
||||
id="extension-install-registry-input"
|
||||
options={extensionInstallRegistryOptions}
|
||||
value={userStore.extensionRegistryUrl.location}
|
||||
value={state.extensionRegistryUrl.location}
|
||||
onChange={(value) =>
|
||||
runInAction(() => {
|
||||
userStore.extensionRegistryUrl.location =
|
||||
state.extensionRegistryUrl.location =
|
||||
value?.value ?? defaultExtensionRegistryUrlLocation;
|
||||
|
||||
if (userStore.extensionRegistryUrl.location === "custom") {
|
||||
userStore.extensionRegistryUrl.customUrl = "";
|
||||
if (state.extensionRegistryUrl.location === "custom") {
|
||||
state.extensionRegistryUrl.customUrl = "";
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -69,20 +69,16 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie
|
||||
validators={isUrl}
|
||||
value={customUrl}
|
||||
onChange={setCustomUrl}
|
||||
onBlur={() => (userStore.extensionRegistryUrl.customUrl = customUrl)}
|
||||
onBlur={() => (state.extensionRegistryUrl.customUrl = customUrl)}
|
||||
placeholder="Custom Extension Registry URL..."
|
||||
disabled={userStore.extensionRegistryUrl.location !== "custom"}
|
||||
disabled={state.extensionRegistryUrl.location !== "custom"}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
});
|
||||
|
||||
export const ExtensionInstallRegistry = withInjectables<Dependencies>(
|
||||
NonInjectedExtensionInstallRegistry,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const ExtensionInstallRegistry = withInjectables<Dependencies>(NonInjectedExtensionInstallRegistry, {
|
||||
getProps: (di) => ({
|
||||
state: di.inject(userPreferencesStateInjectable),
|
||||
}),
|
||||
});
|
||||
+11
-15
@@ -5,33 +5,29 @@
|
||||
import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { Switch } from "../../../../../../renderer/components/switch";
|
||||
import { observer } from "mobx-react";
|
||||
import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable";
|
||||
import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
state: UserPreferencesState;
|
||||
}
|
||||
|
||||
const NonInjectedStartUp = observer(({ userStore }: Dependencies) => (
|
||||
const NonInjectedStartUp = observer(({ state }: Dependencies) => (
|
||||
<section id="other">
|
||||
<SubTitle title="Start-up" />
|
||||
<Switch
|
||||
checked={userStore.openAtLogin}
|
||||
onChange={() => (userStore.openAtLogin = !userStore.openAtLogin)}
|
||||
checked={state.openAtLogin}
|
||||
onChange={() => (state.openAtLogin = !state.openAtLogin)}
|
||||
>
|
||||
Automatically start Lens on login
|
||||
</Switch>
|
||||
</section>
|
||||
));
|
||||
|
||||
export const StartUp = withInjectables<Dependencies>(
|
||||
NonInjectedStartUp,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const StartUp = withInjectables<Dependencies>(NonInjectedStartUp, {
|
||||
getProps: (di) => ({
|
||||
state: di.inject(userPreferencesStateInjectable),
|
||||
}),
|
||||
});
|
||||
+8
-8
@@ -7,26 +7,26 @@ import { SubTitle } from "../../../../../../renderer/components/layout/sub-title
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import type { LensTheme } from "../../../../../../renderer/themes/lens-theme";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import defaultLensThemeInjectable from "../../../../../../renderer/themes/default-theme.injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "../../../../../../renderer/themes/declaration";
|
||||
import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable";
|
||||
import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
state: UserPreferencesState;
|
||||
defaultTheme: LensTheme;
|
||||
themes: LensTheme[];
|
||||
}
|
||||
|
||||
const NonInjectedTheme = observer(({
|
||||
userStore,
|
||||
state,
|
||||
themes,
|
||||
defaultTheme,
|
||||
}: Dependencies) => {
|
||||
const themeOptions = [
|
||||
{
|
||||
value: "system", // TODO: replace with a sentinal value that isn't string (and serialize it differently)
|
||||
value: "system", // TODO: replace with a sentinel value that isn't string (and serialize it differently)
|
||||
label: "Sync with computer",
|
||||
},
|
||||
...themes.map(theme => ({
|
||||
@@ -41,9 +41,9 @@ const NonInjectedTheme = observer(({
|
||||
<Select
|
||||
id="theme-input"
|
||||
options={themeOptions}
|
||||
value={userStore.colorTheme}
|
||||
value={state.colorTheme}
|
||||
onChange={(value) =>
|
||||
(userStore.colorTheme = value?.value ?? defaultTheme.name)
|
||||
(state.colorTheme = value?.value ?? defaultTheme.name)
|
||||
}
|
||||
themeName="lens"
|
||||
/>
|
||||
@@ -53,7 +53,7 @@ const NonInjectedTheme = observer(({
|
||||
|
||||
export const Theme = withInjectables<Dependencies>(NonInjectedTheme, {
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
state: di.inject(userPreferencesStateInjectable),
|
||||
defaultTheme: di.inject(defaultLensThemeInjectable),
|
||||
themes: di.injectMany(lensThemeDeclarationInjectionToken),
|
||||
}),
|
||||
|
||||
+8
-10
@@ -5,15 +5,15 @@
|
||||
import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import moment from "moment-timezone";
|
||||
import { observer } from "mobx-react";
|
||||
import currentTimezoneInjectable from "../../../../../../common/user-store/current-timezone.injectable";
|
||||
import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable";
|
||||
import currentTimezoneInjectable from "../../../../../../common/vars/current-timezone.injectable";
|
||||
import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
state: UserPreferencesState;
|
||||
currentTimezone: string;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,8 @@ const timezoneOptions = moment.tz.names()
|
||||
label: timezone.replace("_", " "),
|
||||
}));
|
||||
|
||||
|
||||
const NonInjectedTimezone = observer(({
|
||||
userStore,
|
||||
state,
|
||||
currentTimezone,
|
||||
}: Dependencies) => (
|
||||
<section id="locale">
|
||||
@@ -33,17 +32,16 @@ const NonInjectedTimezone = observer(({
|
||||
<Select
|
||||
id="timezone-input"
|
||||
options={timezoneOptions}
|
||||
value={userStore.localeTimezone}
|
||||
onChange={value => userStore.localeTimezone = value?.value ?? currentTimezone}
|
||||
value={state.localeTimezone}
|
||||
onChange={value => state.localeTimezone = value?.value ?? currentTimezone}
|
||||
themeName="lens"
|
||||
/>
|
||||
</section>
|
||||
|
||||
));
|
||||
|
||||
export const Timezone = withInjectables<Dependencies>(NonInjectedTimezone, {
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
state: di.inject(userPreferencesStateInjectable),
|
||||
currentTimezone: di.inject(currentTimezoneInjectable),
|
||||
}),
|
||||
});
|
||||
+9
-13
@@ -5,16 +5,16 @@
|
||||
import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { Input } from "../../../../../../renderer/components/input";
|
||||
import { observer } from "mobx-react";
|
||||
import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable";
|
||||
import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
state: UserPreferencesState;
|
||||
}
|
||||
|
||||
const NonInjectedEditorFontFamily = observer(({ userStore: { editorConfiguration }}: Dependencies) => (
|
||||
const NonInjectedEditorFontFamily = observer(({ state: { editorConfiguration }}: Dependencies) => (
|
||||
<section>
|
||||
<SubTitle title="Font family" />
|
||||
<Input
|
||||
@@ -26,12 +26,8 @@ const NonInjectedEditorFontFamily = observer(({ userStore: { editorConfiguration
|
||||
</section>
|
||||
));
|
||||
|
||||
export const EditorFontFamily = withInjectables<Dependencies>(
|
||||
NonInjectedEditorFontFamily,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const EditorFontFamily = withInjectables<Dependencies>(NonInjectedEditorFontFamily, {
|
||||
getProps: (di) => ({
|
||||
state: di.inject(userPreferencesStateInjectable),
|
||||
}),
|
||||
});
|
||||
Loaded 100 of 365 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user