mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Only create TerminalStore after ThemeStore (#3359)
- Use Proxy for backwards compatability - Fix a bunch of unit tests that needed all the Singleton's created - Add comments on the order required for the store migrations Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
9e363b8d5f
commit
c335b0f054
12 files changed
+634
-566
No files matched your search
@@ -48,6 +48,7 @@ import { ExtensionsStore } from "../extensions/extensions-store";
|
||||
import { FilesystemProvisionerStore } from "../main/extension-filesystem";
|
||||
import { ThemeStore } from "./theme.store";
|
||||
import { SentryInit } from "../common/sentry";
|
||||
import { TerminalStore } from "./components/dock/terminal.store";
|
||||
|
||||
configurePackages();
|
||||
|
||||
@@ -89,18 +90,28 @@ export async function bootstrap(App: AppComponent) {
|
||||
|
||||
SentryInit();
|
||||
|
||||
await ClusterStore.createInstance().loadInitialOnRenderer();
|
||||
// ClusterStore depends on: UserStore
|
||||
const cs = ClusterStore.createInstance();
|
||||
|
||||
await cs.loadInitialOnRenderer();
|
||||
|
||||
// HotbarStore depends on: ClusterStore
|
||||
HotbarStore.createInstance();
|
||||
ExtensionsStore.createInstance();
|
||||
FilesystemProvisionerStore.createInstance();
|
||||
|
||||
// ThemeStore depends on: UserStore
|
||||
ThemeStore.createInstance();
|
||||
|
||||
// TerminalStore depends on: ThemeStore
|
||||
TerminalStore.createInstance();
|
||||
WeblinkStore.createInstance();
|
||||
|
||||
ExtensionInstallationStateStore.bindIpcListeners();
|
||||
HelmRepoManager.createInstance(); // initialize the manager
|
||||
|
||||
// Register additional store listeners
|
||||
ClusterStore.getInstance().registerIpcListener();
|
||||
cs.registerIpcListener();
|
||||
|
||||
// init app's dependencies if any
|
||||
if (App.init) {
|
||||
|
||||
@@ -22,14 +22,18 @@
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import fse from "fs-extra";
|
||||
|
||||
import { DockTabs } from "../dock-tabs";
|
||||
import { dockStore, DockTab, TabKind } from "../dock.store";
|
||||
import { noop } from "../../../utils";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import { TerminalStore } from "../terminal.store";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
getPath: () => "/foo",
|
||||
getPath: () => "tmp",
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -55,10 +59,20 @@ const getTabKinds = () => dockStore.tabs.map(tab => tab.kind);
|
||||
|
||||
describe("<DockTabs />", () => {
|
||||
beforeEach(async () => {
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
TerminalStore.createInstance();
|
||||
await dockStore.whenReady;
|
||||
dockStore.tabs = initialTabs;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ThemeStore.resetInstance();
|
||||
TerminalStore.resetInstance();
|
||||
UserStore.resetInstance();
|
||||
fse.remove("tmp");
|
||||
});
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = renderTabs();
|
||||
|
||||
|
||||
@@ -20,14 +20,18 @@
|
||||
*/
|
||||
|
||||
import { podsStore } from "../../+workloads-pods/pods.store";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
import { Pod } from "../../../api/endpoints";
|
||||
import { ThemeStore } from "../../../theme.store";
|
||||
import { dockStore } from "../dock.store";
|
||||
import { logTabStore } from "../log-tab.store";
|
||||
import { TerminalStore } from "../terminal.store";
|
||||
import { deploymentPod1, deploymentPod2, deploymentPod3, dockerPod } from "./pod.mock";
|
||||
import fse from "fs-extra";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
getPath: () => "/foo",
|
||||
getPath: () => "tmp",
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -36,9 +40,19 @@ podsStore.items.push(new Pod(deploymentPod1));
|
||||
podsStore.items.push(new Pod(deploymentPod2));
|
||||
|
||||
describe("log tab store", () => {
|
||||
beforeEach(() => {
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
TerminalStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
logTabStore.reset();
|
||||
dockStore.reset();
|
||||
UserStore.resetInstance();
|
||||
ThemeStore.resetInstance();
|
||||
TerminalStore.resetInstance();
|
||||
fse.remove("tmp");
|
||||
});
|
||||
|
||||
it("creates log tab without sibling pods", () => {
|
||||
|
||||
@@ -136,7 +136,12 @@ export class DockStore implements DockStorageState {
|
||||
}
|
||||
|
||||
get selectedTabId(): TabId | undefined {
|
||||
return this.storage.get().selectedTabId || this.tabs[0]?.id;
|
||||
return this.storage.get().selectedTabId
|
||||
|| (
|
||||
this.tabs.length > 0
|
||||
? this.tabs[0]?.id
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
|
||||
set selectedTabId(tabId: TabId) {
|
||||
@@ -277,9 +282,9 @@ export class DockStore implements DockStorageState {
|
||||
|
||||
if (newTab?.kind === TabKind.TERMINAL) {
|
||||
// close the dock when selected sibling inactive terminal tab
|
||||
const { terminalStore } = await import("./terminal.store");
|
||||
const { TerminalStore } = await import("./terminal.store");
|
||||
|
||||
if (!terminalStore.isConnected(newTab.id)) this.close();
|
||||
if (!TerminalStore.getInstance(false)?.isConnected(newTab.id)) this.close();
|
||||
}
|
||||
this.selectTab(newTab.id);
|
||||
} else {
|
||||
|
||||
@@ -108,8 +108,10 @@ export class LogTabStore extends DockTabStore<LogTabData> {
|
||||
});
|
||||
}
|
||||
|
||||
private updateTabsData() {
|
||||
this.data.forEach((tabData, tabId) => {
|
||||
private async updateTabsData() {
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (const [tabId, tabData] of this.data) {
|
||||
const pod = new Pod(tabData.selectedPod);
|
||||
const pods = podsStore.getPodsByOwnerId(pod.getOwnerRefs()[0]?.uid);
|
||||
const isSelectedPodInList = pods.find(item => item.getId() == pod.getId());
|
||||
@@ -126,14 +128,16 @@ export class LogTabStore extends DockTabStore<LogTabData> {
|
||||
|
||||
this.renameTab(tabId);
|
||||
} else {
|
||||
this.closeTab(tabId);
|
||||
promises.push(this.closeTab(tabId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
private closeTab(tabId: string) {
|
||||
private async closeTab(tabId: string) {
|
||||
this.clearData(tabId);
|
||||
dockStore.closeTab(tabId);
|
||||
await dockStore.closeTab(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import { autorun, observable } from "mobx";
|
||||
import { autoBind } from "../../utils";
|
||||
import { autoBind, Singleton } from "../../utils";
|
||||
import { Terminal } from "./terminal";
|
||||
import { TerminalApi } from "../../api/terminal-api";
|
||||
import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store";
|
||||
@@ -38,11 +38,12 @@ export function createTerminalTab(tabParams: DockTabCreateSpecific = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
export class TerminalStore {
|
||||
export class TerminalStore extends Singleton {
|
||||
protected terminals = new Map<TabId, Terminal>();
|
||||
protected connections = observable.map<TabId, TerminalApi>();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
autoBind(this);
|
||||
|
||||
// connect active tab
|
||||
@@ -129,4 +130,24 @@ export class TerminalStore {
|
||||
}
|
||||
}
|
||||
|
||||
export const terminalStore = new TerminalStore();
|
||||
/**
|
||||
* @deprecated use `TerminalStore.getInstance()` instead
|
||||
*/
|
||||
export const terminalStore = new Proxy({}, {
|
||||
get(target, p) {
|
||||
if (p === "$$typeof") {
|
||||
return "TerminalStore";
|
||||
}
|
||||
|
||||
const ts = TerminalStore.getInstance();
|
||||
const res = (ts as any)?.[p];
|
||||
|
||||
if (typeof res === "function") {
|
||||
return function(...args: any[]) {
|
||||
return res.apply(ts, args);
|
||||
};
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
}) as TerminalStore;
|
||||
@@ -84,7 +84,7 @@ export interface TabProps<D = any> extends DOMAttributes<HTMLElement> {
|
||||
export class Tab extends React.PureComponent<TabProps> {
|
||||
static contextType = TabsContext;
|
||||
declare context: TabsContextValue;
|
||||
public elem: HTMLElement;
|
||||
public ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
get isActive() {
|
||||
const { active, value } = this.props;
|
||||
@@ -93,11 +93,11 @@ export class Tab extends React.PureComponent<TabProps> {
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.elem.focus();
|
||||
this.ref.current?.focus();
|
||||
}
|
||||
|
||||
scrollIntoView() {
|
||||
this.elem.scrollIntoView({
|
||||
this.ref.current?.scrollIntoView?.({
|
||||
behavior: "smooth",
|
||||
inline: "center",
|
||||
});
|
||||
@@ -106,30 +106,28 @@ export class Tab extends React.PureComponent<TabProps> {
|
||||
@boundMethod
|
||||
onClick(evt: React.MouseEvent<HTMLElement>) {
|
||||
const { value, active, disabled, onClick } = this.props;
|
||||
const { onChange } = this.context;
|
||||
|
||||
if (disabled || active) return;
|
||||
if (onClick) onClick(evt);
|
||||
if (onChange) onChange(value);
|
||||
if (disabled || active) {
|
||||
return;
|
||||
}
|
||||
|
||||
onClick?.(evt);
|
||||
this.context.onChange?.(value);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onFocus(evt: React.FocusEvent<HTMLElement>) {
|
||||
const { onFocus } = this.props;
|
||||
|
||||
if (onFocus) onFocus(evt);
|
||||
this.props.onFocus?.(evt);
|
||||
this.scrollIntoView();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onKeyDown(evt: React.KeyboardEvent<HTMLElement>) {
|
||||
const ENTER_KEY = evt.keyCode === 13;
|
||||
const SPACE_KEY = evt.keyCode === 32;
|
||||
if (evt.key === " " || evt.key === "Enter") {
|
||||
this.ref.current?.click();
|
||||
}
|
||||
|
||||
if (SPACE_KEY || ENTER_KEY) this.elem.click();
|
||||
const { onKeyDown } = this.props;
|
||||
|
||||
if (onKeyDown) onKeyDown(evt);
|
||||
this.props?.onKeyDown(evt);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -138,11 +136,6 @@ export class Tab extends React.PureComponent<TabProps> {
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
protected bindRef(elem: HTMLElement) {
|
||||
this.elem = elem;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { active, disabled, icon, label, value, ...elemProps } = this.props;
|
||||
let { className } = this.props;
|
||||
@@ -160,7 +153,7 @@ export class Tab extends React.PureComponent<TabProps> {
|
||||
onClick={this.onClick}
|
||||
onFocus={this.onFocus}
|
||||
onKeyDown={this.onKeyDown}
|
||||
ref={this.bindRef}
|
||||
ref={this.ref}
|
||||
>
|
||||
{typeof icon === "string" ? <Icon small material={icon}/> : icon}
|
||||
<div className="label">
|
||||
|
||||
Reference in new issue
Block a user