mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Make ThemeStore non-singleton and fix navigation-to-terminal-preferences.test.ts
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
48d5aeb18c
commit
955aa28bc8
@ -105,7 +105,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Theme
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
@ -190,7 +190,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Extension Install Registry
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
@ -270,16 +270,11 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="mt-4 mb-5 leading-relaxed"
|
||||
>
|
||||
This setting is to change the registry URL for installing extensions by name.
|
||||
|
||||
If you are unable to access the default registry (
|
||||
https://registry.npmjs.org
|
||||
)
|
||||
|
||||
you can change it in your
|
||||
If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
|
||||
<b>
|
||||
.npmrc
|
||||
</b>
|
||||
file or in the input below.
|
||||
file or in the input below.
|
||||
</p>
|
||||
<div
|
||||
class="Input theme round black disabled invalid"
|
||||
@ -309,7 +304,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Start-up
|
||||
|
||||
|
||||
</div>
|
||||
<label
|
||||
class="Switch"
|
||||
@ -330,7 +325,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Update Channel
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
@ -415,7 +410,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Locale Timezone
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
@ -634,7 +629,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Terminal Shell Path
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Input theme round black"
|
||||
@ -662,7 +657,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Terminal copy & paste
|
||||
|
||||
|
||||
</div>
|
||||
<label
|
||||
class="Switch"
|
||||
@ -682,7 +677,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Terminal theme
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
@ -764,7 +759,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Font size
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Input theme round black"
|
||||
@ -791,7 +786,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="SubTitle"
|
||||
>
|
||||
Font family
|
||||
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Input theme round black"
|
||||
|
||||
@ -12,8 +12,8 @@ import { routeInjectionToken } from "../../common/front-end-routing/route-inject
|
||||
import { computed } from "mobx";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import { preferenceNavigationItemInjectionToken } from "../../renderer/components/+preferences/preferences-navigation/preference-navigation-items.injectable";
|
||||
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
|
||||
import { Preferences } from "../../renderer/components/+preferences";
|
||||
|
||||
@ -7,8 +7,8 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import navigateToProxyPreferencesInjectable
|
||||
from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable";
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
|
||||
describe("preferences - navigation to editor preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
@ -7,9 +7,9 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||
import React from "react";
|
||||
import { getRendererExtensionFake } from "../../renderer/components/test-utils/get-renderer-extension-fake";
|
||||
|
||||
@ -107,10 +107,8 @@ describe("preferences - navigation to extension specific preferences", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const extensionStubWithExtensionSpecificPreferenceItems: Partial<LensRendererExtension> = {
|
||||
id: "some-test-extension-id",
|
||||
|
||||
appPreferences: [
|
||||
const extensionStubWithExtensionSpecificPreferenceItems = new (class extends LensRendererExtension{
|
||||
appPreferences = [
|
||||
{
|
||||
title: "Some preference item",
|
||||
id: "some-preference-item-id",
|
||||
@ -131,6 +129,17 @@ const extensionStubWithExtensionSpecificPreferenceItems: Partial<LensRendererExt
|
||||
Input: () => <div />,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
];
|
||||
})({
|
||||
absolutePath: "/some/absolute/path",
|
||||
id: "some-extension-id",
|
||||
isBundled: true,
|
||||
isCompatible: true,
|
||||
isEnabled: true,
|
||||
manifest: {
|
||||
name: "some-extension-name",
|
||||
version: "1.0.0",
|
||||
},
|
||||
manifestPath: "/some/manifest/path",
|
||||
});
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import { observable } from "mobx";
|
||||
|
||||
describe("preferences - navigation to kubernetes preferences", () => {
|
||||
|
||||
@ -7,8 +7,8 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
|
||||
describe("preferences - navigation to proxy preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
@ -9,8 +9,8 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
|
||||
import { getRendererExtensionFake } from "../../renderer/components/test-utils/get-renderer-extension-fake";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable";
|
||||
import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable";
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import { observable } from "mobx";
|
||||
import defaultShellInjectable from "../../renderer/components/+preferences/default-shell.injectable";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
|
||||
describe("preferences - navigation to terminal preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
@ -26,12 +26,12 @@ describe("preferences - navigation to terminal preferences", () => {
|
||||
} as unknown as UserStore;
|
||||
|
||||
rendererDi.override(userStoreInjectable, () => userStoreStub);
|
||||
|
||||
rendererDi.override(defaultShellInjectable, () => "some-default-shell");
|
||||
|
||||
const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
|
||||
|
||||
rendererDi.override(themeStoreInjectable, () => themeStoreStub);
|
||||
rendererDi.permitSideEffects(themeStoreInjectable);
|
||||
rendererDi.override(ipcRendererInjectable, () => ({
|
||||
on: jest.fn(),
|
||||
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
|
||||
} as never));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -9,8 +9,8 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
|
||||
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
||||
import type { UserStore } from "../../common/user-store";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/theme-store.injectable";
|
||||
import type { ThemeStore } from "../../renderer/themes/store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
|
||||
describe("preferences - navigation using application menu", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
@ -30,7 +30,7 @@ import userStoreInjectable from "../user-store/user-store.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import type { ClusterStoreModel } from "../cluster-store/cluster-store";
|
||||
import { defaultTheme } from "../vars";
|
||||
import { defaultThemeId } from "../vars";
|
||||
import writeFileInjectable from "../fs/write-file.injectable";
|
||||
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
|
||||
import getConfigurationFileModelInjectable
|
||||
@ -80,7 +80,7 @@ describe("user store tests", () => {
|
||||
userStore.httpsProxy = "abcd://defg";
|
||||
|
||||
expect(userStore.httpsProxy).toBe("abcd://defg");
|
||||
expect(userStore.colorTheme).toBe(defaultTheme);
|
||||
expect(userStore.colorTheme).toBe(defaultThemeId);
|
||||
|
||||
userStore.colorTheme = "light";
|
||||
expect(userStore.colorTheme).toBe("light");
|
||||
@ -89,7 +89,7 @@ describe("user store tests", () => {
|
||||
it("correctly resets theme to default value", async () => {
|
||||
userStore.colorTheme = "some other theme";
|
||||
userStore.resetTheme();
|
||||
expect(userStore.colorTheme).toBe(defaultTheme);
|
||||
expect(userStore.colorTheme).toBe(defaultThemeId);
|
||||
});
|
||||
|
||||
it("correctly calculates if the last seen version is an old release", () => {
|
||||
|
||||
@ -10,7 +10,7 @@ import { getAppVersion } from "../utils";
|
||||
import type { editor } from "monaco-editor";
|
||||
import merge from "lodash/merge";
|
||||
import { SemVer } from "semver";
|
||||
import { defaultTheme, defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars";
|
||||
import { defaultThemeId, defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars";
|
||||
import type { ObservableMap } from "mobx";
|
||||
import { observable } from "mobx";
|
||||
import { readonly } from "../utils/readonly";
|
||||
@ -77,10 +77,10 @@ const shell: PreferenceDescription<string | undefined> = {
|
||||
|
||||
const colorTheme: PreferenceDescription<string> = {
|
||||
fromStore(val) {
|
||||
return val || defaultTheme;
|
||||
return val || defaultThemeId;
|
||||
},
|
||||
toStore(val) {
|
||||
if (!val || val === defaultTheme) {
|
||||
if (!val || val === defaultThemeId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
import path from "path";
|
||||
import { SemVer } from "semver";
|
||||
import packageInfo from "../../package.json";
|
||||
import type { ThemeId } from "../renderer/themes/store";
|
||||
import { lazyInitialized } from "./utils/lazy-initialized";
|
||||
|
||||
export const isMac = process.platform === "darwin";
|
||||
@ -25,7 +26,7 @@ export const isIntegrationTesting = process.argv.includes(integrationTestingArg)
|
||||
export const productName = packageInfo.productName;
|
||||
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
||||
export const publicPath = "/build/" as string;
|
||||
export const defaultTheme = "lens-dark" as string;
|
||||
export const defaultThemeId: ThemeId = "lens-dark";
|
||||
export const defaultFontSize = 12;
|
||||
export const defaultTerminalFontFamily = "RobotoMono";
|
||||
export const defaultEditorFontFamily = "RobotoMono";
|
||||
|
||||
@ -3,8 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { ThemeStore } from "../../renderer/theme.store";
|
||||
import themeStoreInjectable from "../../renderer/themes/store.injectable";
|
||||
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||
|
||||
const themeStore = asLegacyGlobalForExtensionApi(themeStoreInjectable);
|
||||
|
||||
export function getActiveTheme() {
|
||||
return ThemeStore.getInstance().activeTheme;
|
||||
return themeStore.activeTheme;
|
||||
}
|
||||
|
||||
@ -5,12 +5,16 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import ipcRendererInjectable from "./ipc-renderer/ipc-renderer.injectable";
|
||||
import { getValueFromRegisteredChannel } from "./get-value-from-registered-channel";
|
||||
import type { Channel } from "../../../common/ipc-channel/channel";
|
||||
|
||||
export type GetValueFromRegisteredChannel = <TChannel extends Channel<TInstance>, TInstance>(channel: TChannel) => Promise<TChannel["_template"]>;
|
||||
|
||||
const getValueFromRegisteredChannelInjectable = getInjectable({
|
||||
id: "get-value-from-registered-channel",
|
||||
|
||||
instantiate: (di) =>
|
||||
getValueFromRegisteredChannel({ ipcRenderer: di.inject(ipcRendererInjectable) }),
|
||||
instantiate: (di) => getValueFromRegisteredChannel({
|
||||
ipcRenderer: di.inject(ipcRendererInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default getValueFromRegisteredChannelInjectable;
|
||||
|
||||
@ -9,9 +9,8 @@ interface Dependencies {
|
||||
ipcRenderer: IpcRenderer;
|
||||
}
|
||||
|
||||
export const getValueFromRegisteredChannel =
|
||||
({ ipcRenderer }: Dependencies) =>
|
||||
export const getValueFromRegisteredChannel = ({ ipcRenderer }: Dependencies) =>
|
||||
<TChannel extends Channel<TInstance>, TInstance>(
|
||||
channel: TChannel,
|
||||
): Promise<TChannel["_template"]> =>
|
||||
ipcRenderer.invoke(channel.name);
|
||||
channel: TChannel,
|
||||
): Promise<TChannel["_template"]> =>
|
||||
ipcRenderer.invoke(channel.name);
|
||||
|
||||
@ -37,7 +37,7 @@ import initClusterFrameInjectable from "./frames/cluster-frame/init-cluster-fram
|
||||
import commandOverlayInjectable from "./components/command-palette/command-overlay.injectable";
|
||||
import { Router } from "react-router";
|
||||
import historyInjectable from "./navigation/history.injectable";
|
||||
import themeStoreInjectable from "./theme-store.injectable";
|
||||
import themeStoreInjectable from "./themes/store.injectable";
|
||||
import navigateToAddClusterInjectable from "../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
|
||||
import addSyncEntriesInjectable from "./initializers/add-sync-entries.injectable";
|
||||
import hotbarStoreInjectable from "../common/hotbars/store.injectable";
|
||||
|
||||
@ -19,8 +19,6 @@ import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-
|
||||
import catalogEntityRegistryInjectable from "../../api/catalog-entity-registry/catalog-entity-registry.injectable";
|
||||
import type { DiRender } from "../test-utils/renderFor";
|
||||
import { renderFor } from "../test-utils/renderFor";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import mockFs from "mock-fs";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
||||
@ -98,8 +96,6 @@ describe("<Catalog />", () => {
|
||||
await di.runSetups();
|
||||
|
||||
mockFs();
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
CatalogEntityDetailRegistry.createInstance();
|
||||
|
||||
render = renderFor(di);
|
||||
@ -125,8 +121,6 @@ describe("<Catalog />", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
UserStore.resetInstance();
|
||||
ThemeStore.resetInstance();
|
||||
CatalogEntityDetailRegistry.resetInstance();
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
|
||||
@ -11,15 +11,20 @@ import { computed, makeObservable } from "mobx";
|
||||
import { Icon } from "../icon";
|
||||
import { SubHeader } from "../layout/sub-header";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
||||
import { nodeStore } from "../+nodes/legacy-store";
|
||||
import { eventStore } from "../+events/legacy-store";
|
||||
import { cssNames, prevDefault } from "../../utils";
|
||||
import type { ItemObject } from "../../../common/item.store";
|
||||
import { Spinner } from "../spinner";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { kubeSelectedUrlParam, toggleDetails } from "../kube-detail-params";
|
||||
import { apiManager } from "../../../common/k8s-api/api-manager";
|
||||
import type { ApiManager } from "../../../common/k8s-api/api-manager";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
import type { NodeStore } from "../+nodes/store";
|
||||
import type { EventStore } from "../+events/store";
|
||||
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import eventStoreInjectable from "../+events/store.injectable";
|
||||
import nodeStoreInjectable from "../+nodes/store.injectable";
|
||||
|
||||
export interface ClusterIssuesProps {
|
||||
className?: string;
|
||||
@ -39,16 +44,23 @@ enum sortBy {
|
||||
age = "age",
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
nodeStore: NodeStore;
|
||||
eventStore: EventStore;
|
||||
apiManager: ApiManager;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ClusterIssues extends React.Component<ClusterIssuesProps> {
|
||||
constructor(props: ClusterIssuesProps) {
|
||||
class NonInjectedClusterIssues extends React.Component<ClusterIssuesProps & Dependencies> {
|
||||
constructor(props: ClusterIssuesProps & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@computed get warnings(): Warning[] {
|
||||
return [
|
||||
...nodeStore.items.flatMap(node => (
|
||||
...this.props.nodeStore.items.flatMap(node => (
|
||||
node.getWarningConditions()
|
||||
.map(({ message }) => ({
|
||||
selfLink: node.selfLink,
|
||||
@ -60,14 +72,14 @@ export class ClusterIssues extends React.Component<ClusterIssuesProps> {
|
||||
ageMs: -node.getCreationTimestamp(),
|
||||
}))
|
||||
)),
|
||||
...eventStore.getWarnings().map(warning => ({
|
||||
...this.props.eventStore.getWarnings().map(warning => ({
|
||||
getId: () => warning.involvedObject.uid,
|
||||
getName: () => warning.involvedObject.name,
|
||||
renderAge: () => <KubeObjectAge key="age" object={warning} />,
|
||||
ageMs: -warning.getCreationTimestamp(),
|
||||
message: warning.message,
|
||||
kind: warning.kind,
|
||||
selfLink: apiManager.lookupApiLink(warning.involvedObject, warning),
|
||||
selfLink: this.props.apiManager.lookupApiLink(warning.involvedObject, warning),
|
||||
})),
|
||||
];
|
||||
}
|
||||
@ -108,7 +120,7 @@ export class ClusterIssues extends React.Component<ClusterIssuesProps> {
|
||||
renderContent() {
|
||||
const { warnings } = this;
|
||||
|
||||
if (!eventStore.isLoaded) {
|
||||
if (!this.props.eventStore.isLoaded) {
|
||||
return (
|
||||
<Spinner center/>
|
||||
);
|
||||
@ -148,7 +160,7 @@ export class ClusterIssues extends React.Component<ClusterIssuesProps> {
|
||||
sortByDefault={{ sortBy: sortBy.object, orderBy: "asc" }}
|
||||
sortSyncWithUrl={false}
|
||||
getTableRow={this.getTableRow}
|
||||
className={cssNames("box grow", ThemeStore.getInstance().activeTheme.type)}
|
||||
className={cssNames("box grow", this.props.themeStore.activeTheme.type)}
|
||||
>
|
||||
<TableHead nowrap>
|
||||
<TableCell className="message">Message</TableCell>
|
||||
@ -169,3 +181,13 @@ export class ClusterIssues extends React.Component<ClusterIssuesProps> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ClusterIssues = withInjectables<Dependencies, ClusterIssuesProps>(NonInjectedClusterIssues, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
apiManager: di.inject(apiManagerInjectable),
|
||||
eventStore: di.inject(eventStoreInjectable),
|
||||
nodeStore: di.inject(nodeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -16,11 +16,12 @@ import type { PieChartData } from "../chart";
|
||||
import { PieChart } from "../chart";
|
||||
import { ClusterNoMetrics } from "./cluster-no-metrics";
|
||||
import { bytesToUnits, cssNames } from "../../utils";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
|
||||
import nodeStoreInjectable from "../+nodes/store.injectable";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
function createLabels(rawLabelData: [string, number | undefined][]): string[] {
|
||||
return rawLabelData.map(([key, value]) => `${key}: ${value?.toFixed(2) || "N/A"}`);
|
||||
@ -29,11 +30,13 @@ function createLabels(rawLabelData: [string, number | undefined][]): string[] {
|
||||
interface Dependencies {
|
||||
clusterOverviewStore: ClusterOverviewStore;
|
||||
nodeStore: NodeStore;
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedClusterPieCharts = observer(({
|
||||
clusterOverviewStore,
|
||||
nodeStore,
|
||||
themeStore,
|
||||
}: Dependencies) => {
|
||||
const renderLimitWarning = () => {
|
||||
return (
|
||||
@ -51,7 +54,7 @@ const NonInjectedClusterPieCharts = observer(({
|
||||
const { podUsage, podAllocatableCapacity, podCapacity } = data;
|
||||
const cpuLimitsOverload = cpuLimits > cpuAllocatableCapacity;
|
||||
const memoryLimitsOverload = memoryLimits > memoryAllocatableCapacity;
|
||||
const defaultColor = ThemeStore.getInstance().activeTheme.colors.pieChartDefaultColor;
|
||||
const defaultColor = themeStore.activeTheme.colors.pieChartDefaultColor;
|
||||
|
||||
if (!memoryCapacity || !cpuCapacity || !podCapacity || !memoryAllocatableCapacity || !cpuAllocatableCapacity || !podAllocatableCapacity) return null;
|
||||
const cpuData: PieChartData = {
|
||||
@ -258,5 +261,6 @@ export const ClusterPieCharts = withInjectables<Dependencies>(NonInjectedCluster
|
||||
getProps: (di) => ({
|
||||
clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
|
||||
nodeStore: di.inject(nodeStoreInjectable),
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -21,7 +21,7 @@ import { Spinner } from "../../spinner";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../../table";
|
||||
import { Button } from "../../button";
|
||||
import { Notifications } from "../../notifications";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import type { ThemeStore } from "../../../themes/store";
|
||||
import { apiManager } from "../../../../common/k8s-api/api-manager";
|
||||
import { SubTitle } from "../../layout/sub-title";
|
||||
import { getDetailsUrl } from "../../kube-detail-params";
|
||||
@ -38,6 +38,7 @@ import userSuppliedValuesAreShownInjectable from "./user-supplied-values-are-sho
|
||||
import { KubeObjectAge } from "../../kube-object/age";
|
||||
import type { KubeJsonApiData } from "../../../../common/k8s-api/kube-json-api";
|
||||
import { entries } from "../../../../common/utils/objects";
|
||||
import themeStoreInjectable from "../../../themes/store.injectable";
|
||||
|
||||
export interface ReleaseDetailsProps {
|
||||
hideDetails(): void;
|
||||
@ -50,6 +51,7 @@ interface Dependencies {
|
||||
updateRelease: (name: string, namespace: string, payload: HelmReleaseUpdatePayload) => Promise<HelmReleaseUpdateDetails>;
|
||||
createUpgradeChartTab: (release: HelmRelease) => void;
|
||||
userSuppliedValuesAreShown: { toggle: () => void; value: boolean };
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
@ -252,12 +254,12 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
|
||||
}
|
||||
|
||||
render() {
|
||||
const { hideDetails } = this.props;
|
||||
const { hideDetails, themeStore } = this.props;
|
||||
const release = this.props.release.get();
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
className={cssNames("ReleaseDetails", ThemeStore.getInstance().activeTheme.type)}
|
||||
className={cssNames("ReleaseDetails", themeStore.activeTheme.type)}
|
||||
usePortal={true}
|
||||
open={Boolean(release)}
|
||||
title={release ? `Release: ${release.getName()}` : ""}
|
||||
@ -285,5 +287,6 @@ export const ReleaseDetails = withInjectables<Dependencies, ReleaseDetailsProps>
|
||||
userSuppliedValuesAreShown: di.inject(userSuppliedValuesAreShownInjectable),
|
||||
updateRelease: di.inject(updateReleaseInjectable),
|
||||
createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable),
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -12,16 +12,26 @@ import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import { observer } from "mobx-react";
|
||||
import { mapValues } from "lodash";
|
||||
import { type MetricsTab, metricTabOptions } from "../chart/options";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export const NodeCharts = observer(() => {
|
||||
export interface NodeChartsProps {}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedNodeCharts = observer(({
|
||||
themeStore,
|
||||
}: Dependencies & NodeChartsProps) => {
|
||||
const { metrics, tab, object } = useContext(ResourceMetricsContext) ?? {};
|
||||
|
||||
if (!metrics || !object || !tab) return null;
|
||||
if (isMetricsEmpty(metrics)) return <NoMetrics/>;
|
||||
|
||||
const id = object.getId();
|
||||
const { chartCapacityColor } = ThemeStore.getInstance().activeTheme.colors;
|
||||
const { chartCapacityColor } = themeStore.activeTheme.colors;
|
||||
const {
|
||||
memoryUsage,
|
||||
workloadMemoryUsage,
|
||||
@ -148,3 +158,10 @@ export const NodeCharts = observer(() => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const NodeCharts = withInjectables<Dependencies, NodeChartsProps>(NonInjectedNodeCharts, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -7,7 +7,7 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { SubTitle } from "../layout/sub-title";
|
||||
import { Select } from "../select";
|
||||
import type { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import type { UserStore } from "../../../common/user-store";
|
||||
import { Input } from "../input";
|
||||
import { Switch } from "../switch";
|
||||
@ -22,8 +22,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import appPreferencesInjectable from "./app-preferences/app-preferences.injectable";
|
||||
import { Preferences } from "./preferences";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
import themeStoreInjectable from "../../theme-store.injectable";
|
||||
import { defaultTheme } from "../../../common/vars";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
import { defaultThemeId } from "../../../common/vars";
|
||||
|
||||
interface Dependencies {
|
||||
appPreferenceItems: IComputedValue<RegisteredAppPreference[]>;
|
||||
@ -57,8 +57,6 @@ const extensionInstallRegistryOptions = [
|
||||
|
||||
const NonInjectedApplication: React.FC<Dependencies> = ({ appPreferenceItems, userStore, themeStore }) => {
|
||||
const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || "");
|
||||
const extensionSettings = appPreferenceItems.get()
|
||||
.filter((preference) => preference.showInPreferencesTab === "application");
|
||||
const themeOptions = [
|
||||
{
|
||||
value: "system", // TODO: replace with a sentinal value that isn't string (and serialize it differently)
|
||||
@ -69,6 +67,8 @@ const NonInjectedApplication: React.FC<Dependencies> = ({ appPreferenceItems, us
|
||||
label: name,
|
||||
})),
|
||||
];
|
||||
const extensionSettings = appPreferenceItems.get()
|
||||
.filter((preference) => preference.showInPreferencesTab === "application");
|
||||
|
||||
return (
|
||||
<Preferences data-testid="application-preferences-page">
|
||||
@ -79,7 +79,7 @@ const NonInjectedApplication: React.FC<Dependencies> = ({ appPreferenceItems, us
|
||||
<Select
|
||||
options={themeOptions}
|
||||
value={userStore.colorTheme}
|
||||
onChange={value => userStore.colorTheme = value?.value ?? defaultTheme}
|
||||
onChange={value => userStore.colorTheme = value?.value ?? defaultThemeId}
|
||||
themeName="lens"
|
||||
/>
|
||||
</section>
|
||||
|
||||
@ -10,11 +10,11 @@ import { SubTitle } from "../layout/sub-title";
|
||||
import { Input, InputValidators } from "../input";
|
||||
import { Switch } from "../switch";
|
||||
import { Select } from "../select";
|
||||
import type { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { Preferences } from "./preferences";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
import themeStoreInjectable from "../../theme-store.injectable";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
import defaultShellInjectable from "./default-shell.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
|
||||
@ -10,16 +10,26 @@ import { BarChart, memoryOptions } from "../chart";
|
||||
import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export const VolumeClaimDiskChart = observer(() => {
|
||||
export interface VolumeClaimDiskChartProps {}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedVolumeClaimDiskChart = observer(({
|
||||
themeStore,
|
||||
}: Dependencies & VolumeClaimDiskChartProps) => {
|
||||
const { metrics, tab, object } = useContext(ResourceMetricsContext) ?? {};
|
||||
|
||||
if (!metrics || !object || !tab) return null;
|
||||
if (isMetricsEmpty(metrics)) return <NoMetrics/>;
|
||||
|
||||
const id = object.getId();
|
||||
const { chartCapacityColor } = ThemeStore.getInstance().activeTheme.colors;
|
||||
const { chartCapacityColor } = themeStore.activeTheme.colors;
|
||||
const { diskUsage, diskCapacity } = metrics;
|
||||
const usage = normalizeMetrics(diskUsage).data.result[0].values;
|
||||
const capacity = normalizeMetrics(diskCapacity).data.result[0].values;
|
||||
@ -51,3 +61,10 @@ export const VolumeClaimDiskChart = observer(() => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const VolumeClaimDiskChart = withInjectables<Dependencies, VolumeClaimDiskChartProps>(NonInjectedVolumeClaimDiskChart, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -11,14 +11,20 @@ import { observer } from "mobx-react";
|
||||
import type { DatasetTooltipLabel, PieChartData } from "../chart";
|
||||
import { PieChart } from "../chart";
|
||||
import { cssVar, object } from "../../utils";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export interface OverviewWorkloadStatusProps {
|
||||
status: Partial<Record<string, number>>;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class OverviewWorkloadStatus extends React.Component<OverviewWorkloadStatusProps> {
|
||||
class NonInjectedOverviewWorkloadStatus extends React.Component<OverviewWorkloadStatusProps & Dependencies> {
|
||||
private elem: HTMLElement | null = null;
|
||||
|
||||
renderChart() {
|
||||
@ -37,7 +43,7 @@ export class OverviewWorkloadStatus extends React.Component<OverviewWorkloadStat
|
||||
if (statuses.length === 0) {
|
||||
chartData.datasets.push({
|
||||
data: [1],
|
||||
backgroundColor: [ThemeStore.getInstance().activeTheme.colors.pieChartDefaultColor],
|
||||
backgroundColor: [this.props.themeStore.activeTheme.colors.pieChartDefaultColor],
|
||||
label: "Empty",
|
||||
});
|
||||
} else {
|
||||
@ -84,3 +90,10 @@ export class OverviewWorkloadStatus extends React.Component<OverviewWorkloadStat
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const OverviewWorkloadStatus = withInjectables<Dependencies, OverviewWorkloadStatusProps>(NonInjectedOverviewWorkloadStatus, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -10,17 +10,27 @@ import { BarChart } from "../chart";
|
||||
import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { mapValues } from "lodash";
|
||||
import { type MetricsTab, metricTabOptions } from "../chart/options";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export const ContainerCharts = observer(() => {
|
||||
export interface ContainerChartsProps {}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedContainerCharts = observer(({
|
||||
themeStore,
|
||||
}: Dependencies & ContainerChartsProps) => {
|
||||
const { metrics, tab, object } = useContext(ResourceMetricsContext) ?? {};
|
||||
|
||||
if (!metrics || !object || !tab) return null;
|
||||
if (isMetricsEmpty(metrics)) return <NoMetrics/>;
|
||||
|
||||
const { chartCapacityColor } = ThemeStore.getInstance().activeTheme.colors;
|
||||
const { chartCapacityColor } = themeStore.activeTheme.colors;
|
||||
const {
|
||||
cpuUsage,
|
||||
cpuRequests,
|
||||
@ -113,3 +123,10 @@ export const ContainerCharts = observer(() => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const ContainerCharts = withInjectables<Dependencies, ContainerChartsProps>(NonInjectedContainerCharts, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -13,9 +13,11 @@ import type { ChartProps } from "./chart";
|
||||
import { Chart, ChartKind } from "./chart";
|
||||
import { bytesToUnits, cssNames, isObject } from "../../utils";
|
||||
import { ZebraStripesPlugin } from "./zebra-stripes.plugin";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import assert from "assert";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export interface BarChartProps extends ChartProps {
|
||||
name?: string;
|
||||
@ -24,7 +26,12 @@ export interface BarChartProps extends ChartProps {
|
||||
|
||||
const getBarColor: Scriptable<string> = ({ dataset }) => Color(dataset?.borderColor).alpha(0.2).string();
|
||||
|
||||
export const BarChart = observer(({
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedBarChart = observer(({
|
||||
themeStore,
|
||||
name,
|
||||
data,
|
||||
className,
|
||||
@ -32,8 +39,8 @@ export const BarChart = observer(({
|
||||
plugins,
|
||||
options: customOptions,
|
||||
...settings
|
||||
}: BarChartProps) => {
|
||||
const { textColorPrimary, borderFaintColor, chartStripesColor } = ThemeStore.getInstance().activeTheme.colors;
|
||||
}: Dependencies & BarChartProps) => {
|
||||
const { textColorPrimary, borderFaintColor, chartStripesColor } = themeStore.activeTheme.colors;
|
||||
const { datasets: rawDatasets = [], ...rest } = data;
|
||||
const datasets = rawDatasets
|
||||
.filter(set => set.data?.length)
|
||||
@ -158,6 +165,13 @@ export const BarChart = observer(({
|
||||
);
|
||||
});
|
||||
|
||||
export const BarChart = withInjectables<Dependencies, BarChartProps>(NonInjectedBarChart, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
const tooltipCallbackWith = (precision: number): ChartTooltipCallback["label"] => (
|
||||
({ datasetIndex, index }, { datasets = [] }) => {
|
||||
if (typeof datasetIndex !== "number" || typeof index !== "number") {
|
||||
|
||||
@ -11,7 +11,9 @@ import ChartJS from "chart.js";
|
||||
import type { ChartProps } from "./chart";
|
||||
import { Chart } from "./chart";
|
||||
import { cssNames } from "../../utils";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export interface PieChartProps extends ChartProps {
|
||||
}
|
||||
@ -41,9 +43,19 @@ function getCutout(length: number | undefined): number {
|
||||
}
|
||||
}
|
||||
|
||||
export const PieChart = observer((props: PieChartProps) => {
|
||||
const { data, className, options, ...chartProps } = props;
|
||||
const { contentColor } = ThemeStore.getInstance().activeTheme.colors;
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
const NonInjectedPieChart = observer(({
|
||||
themeStore,
|
||||
data,
|
||||
className,
|
||||
options,
|
||||
showChart,
|
||||
...chartProps
|
||||
}: Dependencies & PieChartProps) => {
|
||||
const { contentColor } = themeStore.activeTheme.colors;
|
||||
const opts: ChartOptions = {
|
||||
maintainAspectRatio: false,
|
||||
tooltips: {
|
||||
@ -98,12 +110,20 @@ export const PieChart = observer((props: PieChartProps) => {
|
||||
<Chart
|
||||
className={cssNames("PieChart flex column align-center", className)}
|
||||
data={data}
|
||||
options={props.showChart ? {} : opts}
|
||||
options={showChart ? {} : opts}
|
||||
showChart={showChart}
|
||||
{...chartProps}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const PieChart = withInjectables<Dependencies, PieChartProps>(NonInjectedPieChart, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
ChartJS.Tooltip.positioners.cursor = function (elements: any, position: { x: number; y: number }) {
|
||||
return position;
|
||||
};
|
||||
|
||||
@ -11,8 +11,6 @@ import { DockTabs } from "../dock-tabs";
|
||||
import type { DockStore, DockTab } from "../dock/store";
|
||||
import { TabKind } from "../dock/store";
|
||||
import { noop } from "../../../utils";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import dockStoreInjectable from "../dock/store.injectable";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
@ -92,16 +90,11 @@ describe("<DockTabs />", () => {
|
||||
|
||||
dockStore = di.inject(dockStoreInjectable);
|
||||
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
await dockStore.whenReady;
|
||||
dockStore.tabs = initialTabs;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ThemeStore.resetInstance();
|
||||
UserStore.resetInstance();
|
||||
|
||||
// TODO: A unit test may not cause side effects. Here accessing file system is a side effect.
|
||||
fse.remove("some-test-suite-specific-directory-for-user-data");
|
||||
});
|
||||
|
||||
@ -8,8 +8,6 @@ import "@testing-library/jest-dom/extend-expect";
|
||||
import * as selectEvent from "react-select-event";
|
||||
import { LogResourceSelector } from "../resource-selector";
|
||||
import { dockerPod, deploymentPod1, deploymentPod2 } from "./pod.mock";
|
||||
import { ThemeStore } from "../../../../theme.store";
|
||||
import { UserStore } from "../../../../../common/user-store";
|
||||
import mockFs from "mock-fs";
|
||||
import { getDiForUnitTesting } from "../../../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../../test-utils/renderFor";
|
||||
@ -144,14 +142,9 @@ describe("<LogResourceSelector />", () => {
|
||||
mockFs({
|
||||
"tmp": {},
|
||||
});
|
||||
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
UserStore.resetInstance();
|
||||
ThemeStore.resetInstance();
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import type { TerminalApi } from "../../../api/terminal-api";
|
||||
import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable";
|
||||
import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable";
|
||||
import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable";
|
||||
import themeStoreInjectable from "../../../themes/store.injectable";
|
||||
|
||||
export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal;
|
||||
|
||||
@ -20,6 +21,7 @@ const createTerminalInjectable = getInjectable({
|
||||
spawningPool: di.inject(terminalSpawningPoolInjectable),
|
||||
terminalConfig: di.inject(terminalConfigInjectable),
|
||||
terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable),
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
};
|
||||
|
||||
return (tabId, api) => new Terminal(dependencies, { tabId, api });
|
||||
|
||||
@ -11,7 +11,7 @@ import { FitAddon } from "xterm-addon-fit";
|
||||
import type { TabId } from "../dock/store";
|
||||
import type { TerminalApi } from "../../../api/terminal-api";
|
||||
import { TerminalChannels } from "../../../api/terminal-api";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import type { ThemeStore } from "../../../themes/store";
|
||||
import { disposer } from "../../../utils";
|
||||
import { isMac } from "../../../../common/vars";
|
||||
import { once } from "lodash";
|
||||
@ -24,6 +24,7 @@ export interface TerminalDependencies {
|
||||
readonly spawningPool: HTMLElement;
|
||||
readonly terminalConfig: IComputedValue<TerminalConfig>;
|
||||
readonly terminalCopyOnSelect: IComputedValue<boolean>;
|
||||
readonly themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
export interface TerminalArguments {
|
||||
@ -94,7 +95,7 @@ export class Terminal {
|
||||
window.addEventListener("resize", this.onResize);
|
||||
|
||||
this.disposer.push(
|
||||
reaction(() => ThemeStore.getInstance().xtermColors, colors => {
|
||||
reaction(() => this.dependencies.themeStore.xtermColors, colors => {
|
||||
this.xterm?.setOption("theme", colors);
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
|
||||
@ -10,12 +10,13 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { cssNames } from "../../../utils";
|
||||
import type { Terminal } from "./terminal";
|
||||
import type { TerminalStore } from "./store";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import type { ThemeStore } from "../../../themes/store";
|
||||
import type { DockTab, DockStore } from "../dock/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import dockStoreInjectable from "../dock/store.injectable";
|
||||
import terminalStoreInjectable from "./store.injectable";
|
||||
import assert from "assert";
|
||||
import themeStoreInjectable from "../../../themes/store.injectable";
|
||||
|
||||
export interface TerminalWindowProps {
|
||||
tab: DockTab;
|
||||
@ -24,6 +25,7 @@ export interface TerminalWindowProps {
|
||||
interface Dependencies {
|
||||
dockStore: DockStore;
|
||||
terminalStore: TerminalStore;
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
@ -66,7 +68,7 @@ class NonInjectedTerminalWindow extends React.Component<TerminalWindowProps & De
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
className={cssNames("TerminalWindow", ThemeStore.getInstance().activeTheme.type)}
|
||||
className={cssNames("TerminalWindow", this.props.themeStore.activeTheme.type)}
|
||||
ref={elem => this.elem = elem}
|
||||
/>
|
||||
);
|
||||
@ -75,9 +77,10 @@ class NonInjectedTerminalWindow extends React.Component<TerminalWindowProps & De
|
||||
|
||||
export const TerminalWindow = withInjectables<Dependencies, TerminalWindowProps>(NonInjectedTerminalWindow, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
dockStore: di.inject(dockStoreInjectable),
|
||||
terminalStore: di.inject(terminalStoreInjectable),
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -12,9 +12,7 @@ import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import { ConfirmDialog } from "../../confirm-dialog";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
import mockFs from "mock-fs";
|
||||
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getConfigurationFileModelInjectable from "../../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
||||
@ -54,15 +52,10 @@ describe("<HotbarRemoveCommand />", () => {
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
ThemeStore.resetInstance();
|
||||
UserStore.resetInstance();
|
||||
});
|
||||
|
||||
it("renders w/o errors", async () => {
|
||||
|
||||
@ -22,39 +22,41 @@ import { Spinner } from "../spinner";
|
||||
import type { ItemObject } from "../../../common/item.store";
|
||||
import type { Filter } from "./page-filters.store";
|
||||
import { pageFilters } from "./page-filters.store";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { MenuActions } from "../menu/menu-actions";
|
||||
import { MenuItem } from "../menu";
|
||||
import { Checkbox } from "../checkbox";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import type { ItemListStore } from "./list-layout";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
export interface ItemListLayoutContentProps<I extends ItemObject, PreLoadStores extends boolean> {
|
||||
export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStores extends boolean> {
|
||||
getFilters: () => Filter[];
|
||||
tableId?: string;
|
||||
className: IClassName;
|
||||
getItems: () => I[];
|
||||
store: ItemListStore<I, PreLoadStores>;
|
||||
getItems: () => Item[];
|
||||
store: ItemListStore<Item, PreLoadStores>;
|
||||
getIsReady: () => boolean; // show loading indicator while not ready
|
||||
isSelectable?: boolean; // show checkbox in rows for selecting items
|
||||
isConfigurable?: boolean;
|
||||
copyClassNameFromHeadCells?: boolean;
|
||||
sortingCallbacks?: TableSortCallbacks<I>;
|
||||
tableProps?: Partial<TableProps<I>>; // low-level table configuration
|
||||
sortingCallbacks?: TableSortCallbacks<Item>;
|
||||
tableProps?: Partial<TableProps<Item>>; // low-level table configuration
|
||||
renderTableHeader?: (TableCellProps | undefined | null)[];
|
||||
renderTableContents: (item: I) => (ReactNode | TableCellProps)[];
|
||||
renderItemMenu?: (item: I, store: ItemListStore<I, PreLoadStores>) => ReactNode;
|
||||
customizeTableRowProps?: (item: I) => Partial<TableRowProps<I>>;
|
||||
renderTableContents: (item: Item) => (ReactNode | TableCellProps)[];
|
||||
renderItemMenu?: (item: Item, store: ItemListStore<Item, PreLoadStores>) => ReactNode;
|
||||
customizeTableRowProps?: (item: Item) => Partial<TableRowProps<Item>>;
|
||||
addRemoveButtons?: Partial<AddRemoveButtonsProps>;
|
||||
virtual?: boolean;
|
||||
|
||||
// item details view
|
||||
hasDetailsView?: boolean;
|
||||
detailsItem?: I;
|
||||
onDetails?: (item: I) => void;
|
||||
detailsItem?: Item;
|
||||
onDetails?: (item: Item) => void;
|
||||
|
||||
// other
|
||||
customizeRemoveDialog?: (selectedItems: I[]) => Partial<ConfirmDialogParams>;
|
||||
customizeRemoveDialog?: (selectedItems: Item[]) => Partial<ConfirmDialogParams>;
|
||||
|
||||
/**
|
||||
* Message to display when a store failed to load
|
||||
@ -64,9 +66,13 @@ export interface ItemListLayoutContentProps<I extends ItemObject, PreLoadStores
|
||||
failedToLoadMessage?: React.ReactNode;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ItemListLayoutContent<I extends ItemObject, PreLoadStores extends boolean> extends React.Component<ItemListLayoutContentProps<I, PreLoadStores>> {
|
||||
constructor(props: ItemListLayoutContentProps<I, PreLoadStores>) {
|
||||
class NonInjectedItemListLayoutContent<Item extends ItemObject, PreLoadStores extends boolean> extends React.Component<ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies> {
|
||||
constructor(props: ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
@ -76,11 +82,11 @@ export class ItemListLayoutContent<I extends ItemObject, PreLoadStores extends b
|
||||
return this.props.store.failedLoading;
|
||||
}
|
||||
|
||||
renderRow(item: I) {
|
||||
renderRow(item: Item) {
|
||||
return this.getTableRow(item);
|
||||
}
|
||||
|
||||
getTableRow(item: I) {
|
||||
getTableRow(item: Item) {
|
||||
const {
|
||||
isSelectable, renderTableHeader, renderTableContents, renderItemMenu,
|
||||
store, hasDetailsView, onDetails,
|
||||
@ -150,7 +156,7 @@ export class ItemListLayoutContent<I extends ItemObject, PreLoadStores extends b
|
||||
);
|
||||
}
|
||||
|
||||
removeItemsDialog(selectedItems: I[]) {
|
||||
removeItemsDialog(selectedItems: Item[]) {
|
||||
const { customizeRemoveDialog, store } = this.props;
|
||||
const visibleMaxNamesCount = 5;
|
||||
const selectedNames = selectedItems.map(ns => ns.getName()).slice(0, visibleMaxNamesCount).join(", ");
|
||||
@ -275,10 +281,10 @@ export class ItemListLayoutContent<I extends ItemObject, PreLoadStores extends b
|
||||
render() {
|
||||
const {
|
||||
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks,
|
||||
detailsItem, className, tableProps = {}, tableId, getItems,
|
||||
detailsItem, className, tableProps = {}, tableId, getItems, themeStore,
|
||||
} = this.props;
|
||||
const selectedItemId = detailsItem && detailsItem.getId();
|
||||
const classNames = cssNames(className, "box", "grow", ThemeStore.getInstance().activeTheme.type);
|
||||
const classNames = cssNames(className, "box", "grow", themeStore.activeTheme.type);
|
||||
const items = getItems();
|
||||
const selectedItems = store.pickOnlySelected(items);
|
||||
|
||||
@ -356,3 +362,10 @@ export class ItemListLayoutContent<I extends ItemObject, PreLoadStores extends b
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ItemListLayoutContent = withInjectables<Dependencies, ItemListLayoutContentProps<ItemObject, boolean>>(NonInjectedItemListLayoutContent, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
}) as <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;
|
||||
|
||||
@ -13,7 +13,9 @@ import { type MonacoValidator, monacoValidators } from "./monaco-validators";
|
||||
import { debounce, merge } from "lodash";
|
||||
import { autoBind, cssNames, disposer } from "../../utils";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
import logger from "../../../main/logger";
|
||||
|
||||
export type MonacoEditorId = string;
|
||||
@ -35,22 +37,21 @@ export interface MonacoEditorProps {
|
||||
onModelChange?(model: editor.ITextModel, prev?: editor.ITextModel): void;
|
||||
}
|
||||
|
||||
export const defaultEditorProps: Partial<MonacoEditorProps> = {
|
||||
language: "yaml",
|
||||
get theme(): MonacoTheme {
|
||||
// theme for monaco-editor defined in `src/renderer/themes/lens-*.json`
|
||||
return ThemeStore.getInstance().activeTheme.monacoTheme;
|
||||
},
|
||||
};
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
export function createMonacoUri(id: MonacoEditorId): Uri {
|
||||
return Uri.file(`/monaco-editor/${id}`);
|
||||
}
|
||||
|
||||
const monacoViewStates = new WeakMap<Uri, editor.ICodeEditorViewState>();
|
||||
|
||||
@observer
|
||||
export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
static readonly defaultProps = defaultEditorProps as object;
|
||||
static readonly viewStates = new WeakMap<Uri, editor.ICodeEditorViewState>();
|
||||
|
||||
static createUri(id: MonacoEditorId): Uri {
|
||||
return Uri.file(`/monaco-editor/${id}`);
|
||||
}
|
||||
class NonInjectedMonacoEditor extends React.Component<MonacoEditorProps & Dependencies> {
|
||||
static defaultProps = {
|
||||
language: "yaml" as const,
|
||||
};
|
||||
|
||||
private staticId = `editor-id#${Math.round(1e7 * Math.random())}`;
|
||||
private dispose = disposer();
|
||||
@ -60,7 +61,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
@observable readonly dimensions: { width?: number; height?: number } = {};
|
||||
@observable unmounting = false;
|
||||
|
||||
constructor(props: MonacoEditorProps) {
|
||||
constructor(props: MonacoEditorProps & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
@ -70,8 +71,12 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
return this.props.id ?? this.staticId;
|
||||
}
|
||||
|
||||
@computed get theme() {
|
||||
return this.props.theme ?? this.props.themeStore.activeTheme.monacoTheme;
|
||||
}
|
||||
|
||||
@computed get model(): editor.ITextModel {
|
||||
const uri = MonacoEditor.createUri(this.id);
|
||||
const uri = createMonacoUri(this.id);
|
||||
const model = editor.getModel(uri);
|
||||
|
||||
if (model) {
|
||||
@ -141,12 +146,12 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
const viewState = this.editor?.saveViewState();
|
||||
|
||||
if (viewState) {
|
||||
MonacoEditor.viewStates.set(model.uri, viewState);
|
||||
monacoViewStates.set(model.uri, viewState);
|
||||
}
|
||||
}
|
||||
|
||||
protected restoreViewState(model: editor.ITextModel) {
|
||||
const viewState = MonacoEditor.viewStates.get(model.uri);
|
||||
const viewState = monacoViewStates.get(model.uri);
|
||||
|
||||
if (viewState) {
|
||||
this.editor?.restoreViewState(viewState);
|
||||
@ -177,7 +182,8 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
if (!this.containerElem || this.editor || this.unmounting) {
|
||||
return;
|
||||
}
|
||||
const { language, theme, readOnly, value: defaultValue } = this.props;
|
||||
const { language, readOnly, value: defaultValue } = this.props;
|
||||
const { theme } = this;
|
||||
|
||||
this.editor = editor.create(this.containerElem, {
|
||||
model: this.model,
|
||||
@ -214,7 +220,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
|
||||
this.dispose.push(
|
||||
reaction(() => this.model, this.onModelChange),
|
||||
reaction(() => this.props.theme, theme => {
|
||||
reaction(() => this.theme, theme => {
|
||||
if (theme) {
|
||||
editor.setTheme(theme);
|
||||
}
|
||||
@ -283,3 +289,10 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const MonacoEditor = withInjectables<Dependencies, MonacoEditorProps>(NonInjectedMonacoEditor, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -6,8 +6,6 @@ import React from "react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import type { SelectOption } from "./select";
|
||||
import { Select } from "./select";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { DiRender } from "../test-utils/renderFor";
|
||||
@ -42,15 +40,9 @@ describe("<Select />", () => {
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ThemeStore.resetInstance();
|
||||
UserStore.resetInstance();
|
||||
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
|
||||
@ -12,9 +12,11 @@ import { action, computed, makeObservable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import ReactSelect, { components, createFilter } from "react-select";
|
||||
import type { Props as ReactSelectProps, GroupBase, MultiValue, OptionsOrGroups, PropsValue, SingleValue } from "react-select";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import type { ThemeStore } from "../../themes/store";
|
||||
import { autoBind, cssNames } from "../../utils";
|
||||
import type { SetRequired } from "type-fest";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import themeStoreInjectable from "../../themes/store.injectable";
|
||||
|
||||
const { Menu } = components;
|
||||
|
||||
@ -60,26 +62,30 @@ const defaultFilter = createFilter({
|
||||
},
|
||||
});
|
||||
|
||||
interface Dependencies {
|
||||
themeStore: ThemeStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class Select<
|
||||
class NonInjectedSelect<
|
||||
Value,
|
||||
Option extends SelectOption<Value>,
|
||||
IsMulti extends boolean = false,
|
||||
Group extends GroupBase<Option> = GroupBase<Option>,
|
||||
> extends React.Component<SelectProps<Value, Option, IsMulti, Group>> {
|
||||
> extends React.Component<SelectProps<Value, Option, IsMulti, Group> & Dependencies> {
|
||||
static defaultProps = {
|
||||
menuPortalTarget: document.body,
|
||||
menuPlacement: "auto",
|
||||
menuPlacement: "auto" as const,
|
||||
};
|
||||
|
||||
constructor(props: SelectProps<Value, Option, IsMulti, Group>) {
|
||||
constructor(props: SelectProps<Value, Option, IsMulti, Group> & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
@computed get themeClass() {
|
||||
const themeName = this.props.themeName || ThemeStore.getInstance().activeTheme.type;
|
||||
const themeName = this.props.themeName || this.props.themeStore.activeTheme.type;
|
||||
|
||||
return `theme-${themeName}`;
|
||||
}
|
||||
@ -183,3 +189,15 @@ export class Select<
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Select = withInjectables<Dependencies, SelectProps<unknown, SelectOption<unknown>, boolean>>(NonInjectedSelect, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
}),
|
||||
}) as <
|
||||
Value,
|
||||
Option extends SelectOption<Value>,
|
||||
IsMulti extends boolean = false,
|
||||
Group extends GroupBase<Option> = GroupBase<Option>,
|
||||
>(props: SelectProps<Value, Option, IsMulti, Group>) => React.ReactElement;
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ThemeStore } from "./theme.store";
|
||||
|
||||
const themeStoreInjectable = getInjectable({
|
||||
id: "theme-store",
|
||||
|
||||
instantiate: () => {
|
||||
ThemeStore.resetInstance();
|
||||
|
||||
return ThemeStore.createInstance();
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default themeStoreInjectable;
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Theme } from "../theme.store";
|
||||
import type { Theme } from "./store";
|
||||
|
||||
const lensDarkTheme: Theme = {
|
||||
"name": "Dark",
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Theme } from "../theme.store";
|
||||
import type { Theme } from "./store";
|
||||
|
||||
const lensLightTheme: Theme = {
|
||||
"name": "Light",
|
||||
|
||||
21
src/renderer/themes/store.injectable.ts
Normal file
21
src/renderer/themes/store.injectable.ts
Normal file
@ -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 userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import ipcRendererInjectable from "../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
import { ThemeStore } from "./store";
|
||||
|
||||
const themeStoreInjectable = getInjectable({
|
||||
id: "theme-store",
|
||||
|
||||
instantiate: (di) => new ThemeStore({
|
||||
ipcRenderer: di.inject(ipcRendererInjectable),
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default themeStoreInjectable;
|
||||
@ -4,17 +4,17 @@
|
||||
*/
|
||||
|
||||
import { comparer, computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { autoBind, Singleton } from "./utils";
|
||||
import { UserStore } from "../common/user-store";
|
||||
import logger from "../main/logger";
|
||||
import lensDarkTheme from "./themes/lens-dark";
|
||||
import lensLightTheme from "./themes/lens-light";
|
||||
import type { MonacoTheme } from "./components/monaco-editor";
|
||||
import { defaultTheme } from "../common/vars";
|
||||
import { autoBind } from "../utils";
|
||||
import logger from "../../main/logger";
|
||||
import lensDarkTheme from "./lens-dark";
|
||||
import lensLightTheme from "./lens-light";
|
||||
import type { MonacoTheme } from "../components/monaco-editor";
|
||||
import { defaultThemeId } from "../../common/vars";
|
||||
import { camelCase } from "lodash";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { getNativeThemeChannel, setNativeThemeChannel } from "../common/ipc/native-theme";
|
||||
import type { IpcRenderer } from "electron";
|
||||
import { getNativeThemeChannel, setNativeThemeChannel } from "../../common/ipc/native-theme";
|
||||
import type { ReadonlyDeep } from "type-fest/source/readonly-deep";
|
||||
import assert from "assert";
|
||||
|
||||
export type ThemeId = string;
|
||||
|
||||
@ -27,7 +27,16 @@ export interface Theme {
|
||||
monacoTheme: MonacoTheme;
|
||||
}
|
||||
|
||||
export class ThemeStore extends Singleton {
|
||||
interface Dependencies {
|
||||
readonly userStore: {
|
||||
colorTheme: string;
|
||||
terminalTheme: ThemeId;
|
||||
resetTheme(): void;
|
||||
};
|
||||
readonly ipcRenderer: IpcRenderer;
|
||||
}
|
||||
|
||||
export class ThemeStore {
|
||||
private terminalColorPrefix = "terminal";
|
||||
|
||||
#themes = observable.map<ThemeId, Theme>({
|
||||
@ -38,18 +47,19 @@ export class ThemeStore extends Singleton {
|
||||
@observable osNativeTheme: "dark" | "light" | undefined;
|
||||
|
||||
@computed get activeThemeId(): ThemeId {
|
||||
return UserStore.getInstance().colorTheme;
|
||||
return this.dependencies.userStore.colorTheme;
|
||||
}
|
||||
|
||||
@computed get terminalThemeId(): ThemeId | undefined {
|
||||
return UserStore.getInstance().terminalTheme;
|
||||
@computed get terminalThemeId(): ThemeId {
|
||||
return this.dependencies.userStore.terminalTheme;
|
||||
}
|
||||
|
||||
private readonly defaultTheme: Theme;
|
||||
|
||||
@computed get activeTheme(): Theme {
|
||||
return this.systemTheme
|
||||
?? this.#themes.get(this.activeThemeId)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
?? this.#themes.get(defaultTheme)!;
|
||||
?? this.defaultTheme;
|
||||
}
|
||||
|
||||
@computed get terminalColors(): [string, string][] {
|
||||
@ -85,12 +95,16 @@ export class ThemeStore extends Singleton {
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
constructor(protected readonly dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
this.init();
|
||||
|
||||
const defaultTheme = this.#themes.get(defaultThemeId);
|
||||
|
||||
assert(defaultTheme, `${defaultThemeId} is invalid as there is no corresponding theme`);
|
||||
|
||||
this.defaultTheme = defaultTheme;
|
||||
}
|
||||
|
||||
async init() {
|
||||
@ -106,7 +120,7 @@ export class ThemeStore extends Singleton {
|
||||
this.applyActiveTheme();
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
UserStore.getInstance().resetTheme();
|
||||
this.dependencies.userStore.resetTheme();
|
||||
}
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
@ -115,14 +129,14 @@ export class ThemeStore extends Singleton {
|
||||
}
|
||||
|
||||
bindNativeThemeUpdateEvent() {
|
||||
ipcRenderer.on(setNativeThemeChannel, (event, theme: "dark" | "light") => {
|
||||
this.dependencies.ipcRenderer.on(setNativeThemeChannel, (event, theme: "dark" | "light") => {
|
||||
this.osNativeTheme = theme;
|
||||
this.applyActiveTheme();
|
||||
});
|
||||
}
|
||||
|
||||
async setNativeTheme() {
|
||||
const theme: "dark" | "light" = await ipcRenderer.invoke(getNativeThemeChannel);
|
||||
const theme: "dark" | "light" = await this.dependencies.ipcRenderer.invoke(getNativeThemeChannel);
|
||||
|
||||
this.osNativeTheme = theme;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user