Fix hotbar migration of workspaces (#3178)

This commit is contained in:
Sebastian Malton authored and GitHub committed 2021-06-25 09:55:25 -04:00
1 parent b9dfd20a93
commit 51655884c7
39 files changed
+333 -446

No files matched your search

+12 -1
View File
@@ -42,6 +42,11 @@ import { ExtensionInstallationStateStore } from "./components/+extensions/extens
import { DefaultProps } from "./mui-base-theme";
import configurePackages from "../common/configure-packages";
import * as initializers from "./initializers";
import { HotbarStore } from "../common/hotbar-store";
import { WeblinkStore } from "../common/weblink-store";
import { ExtensionsStore } from "../extensions/extensions-store";
import { FilesystemProvisionerStore } from "../main/extension-filesystem";
import { ThemeStore } from "./theme.store";
configurePackages();
@@ -79,7 +84,13 @@ export async function bootstrap(App: AppComponent) {
ExtensionLoader.createInstance().init();
ExtensionDiscovery.createInstance().init();
await initializers.initStores();
UserStore.createInstance();
await ClusterStore.createInstance().loadInitialOnRenderer();
HotbarStore.createInstance();
ExtensionsStore.createInstance();
FilesystemProvisionerStore.createInstance();
ThemeStore.createInstance();
WeblinkStore.createInstance();
ExtensionInstallationStateStore.bindIpcListeners();
HelmRepoManager.createInstance(); // initialize the manager
@@ -30,6 +30,7 @@ import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
import { HotbarIcon } from "../hotbar/hotbar-icon";
import type { CatalogEntityItem } from "./catalog-entity.store";
import { isDevelopment } from "../../../common/vars";
interface Props<T extends CatalogEntity> {
item: CatalogEntityItem<T> | null | undefined;
@@ -91,6 +92,11 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Pro
<DrawerItem name="Labels">
{...item.getLabelBadges(this.props.hideDetails)}
</DrawerItem>
{isDevelopment && (
<DrawerItem name="Id">
{item.getId()}
</DrawerItem>
)}
</div>
</div>
)}
@@ -61,7 +61,7 @@ describe("Extensions", () => {
ExtensionInstallationStateStore.reset();
UserStore.resetInstance();
await UserStore.createInstance().load();
UserStore.createInstance();
ExtensionDiscovery.resetInstance();
ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve());
@@ -30,10 +30,11 @@ import type { LogTabData } from "../log-tab.store";
import { dockerPod, deploymentPod1 } from "./pod.mock";
import { ThemeStore } from "../../../theme.store";
import { UserStore } from "../../../../common/user-store";
import mockFs from "mock-fs";
jest.mock("electron", () => ({
app: {
getPath: () => "/foo",
getPath: () => "tmp",
},
}));
@@ -71,6 +72,9 @@ const getFewPodsTabData = (): LogTabData => {
describe("<LogResourceSelector />", () => {
beforeEach(() => {
mockFs({
"tmp": {}
});
UserStore.createInstance();
ThemeStore.createInstance();
});
@@ -78,6 +82,7 @@ describe("<LogResourceSelector />", () => {
afterEach(() => {
UserStore.resetInstance();
ThemeStore.resetInstance();
mockFs.restore();
});
it("renders w/o errors", () => {
@@ -26,6 +26,14 @@ import React from "react";
import { ThemeStore } from "../../../theme.store";
import { UserStore } from "../../../../common/user-store";
import { Notifications } from "../../notifications";
import mockFs from "mock-fs";
jest.mock("electron", () => ({
app: {
getPath: () => "tmp",
setLoginItemSettings: jest.fn(),
},
}));
const mockHotbars: {[id: string]: any} = {
"1": {
@@ -48,6 +56,9 @@ jest.mock("../../../../common/hotbar-store", () => ({
describe("<HotbarRemoveCommand />", () => {
beforeEach(() => {
mockFs({
"tmp": {}
});
UserStore.createInstance();
ThemeStore.createInstance();
});
@@ -55,11 +66,12 @@ describe("<HotbarRemoveCommand />", () => {
afterEach(() => {
UserStore.resetInstance();
ThemeStore.resetInstance();
mockFs.restore();
});
it("renders w/o errors", () => {
const { container } = render(<HotbarRemoveCommand/>);
expect(container).toBeInstanceOf(HTMLElement);
});
@@ -73,4 +85,3 @@ describe("<HotbarRemoveCommand />", () => {
spy.mockRestore();
});
});
@@ -33,22 +33,14 @@ const uniqueHotbarName: InputValidator = {
@observer
export class HotbarAddCommand extends React.Component {
onSubmit(name: string) {
onSubmit = (name: string) => {
if (!name.trim()) {
return;
}
const hotbarStore = HotbarStore.getInstance();
const hotbar = hotbarStore.add({
name
});
hotbarStore.activeHotbarId = hotbar.id;
HotbarStore.getInstance().add({ name }, { setActive: true });
CommandOverlay.close();
}
};
render() {
return (
@@ -58,10 +50,11 @@ export class HotbarAddCommand extends React.Component {
autoFocus={true}
theme="round-black"
data-test-id="command-palette-hotbar-add-name"
validators={[uniqueHotbarName]}
onSubmit={(v) => this.onSubmit(v)}
validators={uniqueHotbarName}
onSubmit={this.onSubmit}
dirty={true}
showValidationLine={true} />
showValidationLine={true}
/>
<small className="hint">
Please provide a new hotbar name (Press &quot;Enter&quot; to confirm or &quot;Escape&quot; to cancel)
</small>
-1
View File
@@ -27,5 +27,4 @@ export * from "./registries";
export * from "./welcome-menu-registry";
export * from "./workloads-overview-detail-registry";
export * from "./catalog";
export * from "./stores";
export * from "./ipc";
-50
View File
@@ -1,50 +0,0 @@
/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { HotbarStore } from "../../common/hotbar-store";
import { ClusterStore } from "../../common/cluster-store";
import { UserStore } from "../../common/user-store";
import { ExtensionsStore } from "../../extensions/extensions-store";
import { FilesystemProvisionerStore } from "../../main/extension-filesystem";
import { ThemeStore } from "../theme.store";
import { WeblinkStore } from "../../common/weblink-store";
export async function initStores() {
const userStore = UserStore.createInstance();
const clusterStore = ClusterStore.createInstance();
const extensionsStore = ExtensionsStore.createInstance();
const filesystemStore = FilesystemProvisionerStore.createInstance();
const themeStore = ThemeStore.createInstance();
const hotbarStore = HotbarStore.createInstance();
const weblinkStore = WeblinkStore.createInstance();
// preload common stores
await Promise.all([
userStore.load(),
hotbarStore.load(),
clusterStore.load(),
extensionsStore.load(),
filesystemStore.load(),
themeStore.init(),
weblinkStore.load()
]);
}
+18 -50
View File
@@ -20,9 +20,11 @@
*/
import { computed, observable, reaction, makeObservable } from "mobx";
import { autoBind, boundMethod, Singleton } from "./utils";
import { autoBind, iter, Singleton } from "./utils";
import { UserStore } from "../common/user-store";
import logger from "../main/logger";
import darkTheme from "./themes/lens-dark.json";
import lightTheme from "./themes/lens-light.json";
export type ThemeId = string;
@@ -32,12 +34,15 @@ export enum ThemeType {
}
export interface Theme {
id: ThemeId; // filename without .json-extension
type: ThemeType;
name?: string;
colors?: Record<string, string>;
description?: string;
author?: string;
name: string;
colors: Record<string, string>;
description: string;
author: string;
}
export interface ThemeItems extends Theme {
id: string;
}
export class ThemeStore extends Singleton {
@@ -45,16 +50,12 @@ export class ThemeStore extends Singleton {
// bundled themes from `themes/${themeId}.json`
private allThemes = observable.map<string, Theme>([
["lens-dark", { id: "lens-dark", type: ThemeType.DARK }],
["lens-light", { id: "lens-light", type: ThemeType.LIGHT }],
["lens-dark", { ...darkTheme, type: ThemeType.DARK }],
["lens-light", { ...lightTheme, type: ThemeType.LIGHT }],
]);
@computed get themeIds(): string[] {
return Array.from(this.allThemes.keys());
}
@computed get themes(): Theme[] {
return Array.from(this.allThemes.values());
@computed get themes(): ThemeItems[] {
return Array.from(iter.map(this.allThemes, ([id, theme]) => ({ id, ...theme })));
}
@computed get activeThemeId(): string {
@@ -62,12 +63,7 @@ export class ThemeStore extends Singleton {
}
@computed get activeTheme(): Theme {
const activeTheme = this.allThemes.get(this.activeThemeId) ?? this.allThemes.get("lens-dark");
return {
colors: {},
...activeTheme,
};
return this.allThemes.get(this.activeThemeId) ?? this.allThemes.get("lens-dark");
}
constructor() {
@@ -77,9 +73,9 @@ export class ThemeStore extends Singleton {
autoBind(this);
// auto-apply active theme
reaction(() => this.activeThemeId, async themeId => {
reaction(() => this.activeThemeId, themeId => {
try {
this.applyTheme(await this.loadTheme(themeId));
this.applyTheme(this.getThemeById(themeId));
} catch (err) {
logger.error(err);
UserStore.getInstance().resetTheme();
@@ -89,38 +85,10 @@ export class ThemeStore extends Singleton {
});
}
async init() {
// preload all themes
await Promise.all(this.themeIds.map(this.loadTheme));
}
getThemeById(themeId: ThemeId): Theme {
return this.allThemes.get(themeId);
}
@boundMethod
protected async loadTheme(themeId: ThemeId): Promise<Theme> {
try {
const existingTheme = this.getThemeById(themeId);
if (existingTheme) {
const theme = await import(
/* webpackChunkName: "themes/[name]" */
`./themes/${themeId}.json`
);
existingTheme.author = theme.author;
existingTheme.colors = theme.colors;
existingTheme.description = theme.description;
existingTheme.name = theme.name;
}
return existingTheme;
} catch (err) {
throw new Error(`Can't load theme "${themeId}": ${err}`);
}
}
protected applyTheme(theme: Theme) {
if (!this.styles) {
this.styles = document.createElement("style");