mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor runnables (#6528)
* Convert runManyFor to use composite Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert runManySyncFor to use composite and to enfore sync-ness Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove dead code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert getStartableStoppable to be always sync as it is never used in an async fashion Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all sync runnables to comply with new checks for sync-ness Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
82ab60d544
commit
b498f12186
@ -223,7 +223,7 @@ describe("runManyFor", () => {
|
||||
);
|
||||
|
||||
return expect(() => runMany()).rejects.toThrow(
|
||||
'Tried to run runnable "some-runnable-1" after the runnable "some-runnable-2" which does not share the "some-injection-token" injection token.',
|
||||
/Tried to get a composite but encountered missing parent ids: "some-runnable-2".\n\nAvailable parent ids are:\n"[0-9a-z-]+",\n"some-runnable-1"/,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -2,13 +2,10 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import type {
|
||||
DiContainerForInjection,
|
||||
InjectionToken,
|
||||
} from "@ogre-tools/injectable";
|
||||
import { filter, forEach, map, tap } from "lodash/fp";
|
||||
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for";
|
||||
import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Composite } from "../utils/composite/get-composite/get-composite";
|
||||
import { getCompositeFor } from "../utils/composite/get-composite/get-composite";
|
||||
import * as uuid from "uuid";
|
||||
|
||||
export interface Runnable<TParameter = void> {
|
||||
id: string;
|
||||
@ -18,35 +15,34 @@ export interface Runnable<TParameter = void> {
|
||||
|
||||
type Run<Param> = (parameter: Param) => Promise<void> | void;
|
||||
|
||||
export type RunMany = <Param>(
|
||||
injectionToken: InjectionToken<Runnable<Param>, void>
|
||||
) => Run<Param>;
|
||||
export type RunMany = <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => Run<Param>;
|
||||
|
||||
async function runCompositeRunnables<Param>(param: Param, composite: Composite<Runnable<Param>>) {
|
||||
await composite.value.run(param);
|
||||
await Promise.all(composite.children.map(composite => runCompositeRunnables(param, composite)));
|
||||
}
|
||||
|
||||
export function runManyFor(di: DiContainerForInjection): RunMany {
|
||||
return (injectionToken) => async (parameter) => {
|
||||
return <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => async (param: Param) => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
const rootId = uuid.v4();
|
||||
const getCompositeRunnables = getCompositeFor<Runnable<Param>>({
|
||||
getId: (runnable) => runnable.id,
|
||||
getParentId: (runnable) => (
|
||||
runnable.id === rootId
|
||||
? undefined
|
||||
: runnable.runAfter?.id ?? rootId
|
||||
),
|
||||
});
|
||||
const composite = getCompositeRunnables([
|
||||
// This is a dummy runnable to conform to the requirements of `getCompositeFor` to only have one root
|
||||
{
|
||||
id: rootId,
|
||||
run: () => {},
|
||||
},
|
||||
...allRunnables,
|
||||
]);
|
||||
|
||||
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor((injectionToken as any).id, allRunnables);
|
||||
|
||||
const recursedRun = async (
|
||||
runAfterRunnable: Runnable<any> | undefined = undefined,
|
||||
) =>
|
||||
await pipeline(
|
||||
allRunnables,
|
||||
|
||||
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
|
||||
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
|
||||
map(async (runnable) => {
|
||||
await runnable.run(parameter);
|
||||
|
||||
await recursedRun(runnable);
|
||||
}),
|
||||
|
||||
(promises) => Promise.all(promises),
|
||||
);
|
||||
|
||||
await recursedRun();
|
||||
await runCompositeRunnables(param, composite);
|
||||
};
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ describe("runManySyncFor", () => {
|
||||
|
||||
instantiate: (di) => ({
|
||||
id: "some-injectable-1",
|
||||
run: () => runMock("third-level-run"),
|
||||
run: () => void runMock("third-level-run"),
|
||||
runAfter: di.inject(someInjectable2),
|
||||
}),
|
||||
|
||||
@ -81,7 +81,7 @@ describe("runManySyncFor", () => {
|
||||
|
||||
instantiate: (di) => ({
|
||||
id: "some-injectable-2",
|
||||
run: () => runMock("second-level-run"),
|
||||
run: () => void runMock("second-level-run"),
|
||||
runAfter: di.inject(someInjectable3),
|
||||
}),
|
||||
|
||||
@ -92,7 +92,7 @@ describe("runManySyncFor", () => {
|
||||
id: "some-injectable-3",
|
||||
instantiate: () => ({
|
||||
id: "some-injectable-3",
|
||||
run: () => runMock("first-level-run"),
|
||||
run: () => void runMock("first-level-run"),
|
||||
}),
|
||||
injectionToken: someInjectionTokenForRunnables,
|
||||
});
|
||||
@ -151,13 +151,13 @@ describe("runManySyncFor", () => {
|
||||
someInjectionToken,
|
||||
);
|
||||
|
||||
return expect(() => runMany()).rejects.toThrow(
|
||||
'Tried to run runnable "some-runnable-1" after the runnable "some-runnable-2" which does not share the "some-injection-token" injection token.',
|
||||
return expect(() => runMany()).toThrow(
|
||||
/Tried to get a composite but encountered missing parent ids: "some-runnable-2".\n\nAvailable parent ids are:\n"[0-9a-z-]+",\n"some-runnable-1"/,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when running many with parameter", () => {
|
||||
let runMock: jest.Mock<(arg: string, arg2: string) => void>;
|
||||
let runMock: jest.Mock<(arg: string, arg2: string) => undefined>;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer("irrelevant");
|
||||
@ -175,7 +175,7 @@ describe("runManySyncFor", () => {
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-runnable-1",
|
||||
run: (parameter) => runMock("run-of-some-runnable-1", parameter),
|
||||
run: (parameter) => void runMock("run-of-some-runnable-1", parameter),
|
||||
}),
|
||||
|
||||
injectionToken: someInjectionTokenForRunnablesWithParameter,
|
||||
@ -186,7 +186,7 @@ describe("runManySyncFor", () => {
|
||||
|
||||
instantiate: () => ({
|
||||
id: "some-runnable-2",
|
||||
run: (parameter) => runMock("run-of-some-runnable-2", parameter),
|
||||
run: (parameter) => void runMock("run-of-some-runnable-2", parameter),
|
||||
}),
|
||||
|
||||
injectionToken: someInjectionTokenForRunnablesWithParameter,
|
||||
|
||||
@ -2,11 +2,10 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
|
||||
import { filter, forEach, map, tap } from "lodash/fp";
|
||||
import type { Runnable } from "./run-many-for";
|
||||
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for";
|
||||
import type { Composite } from "../utils/composite/get-composite/get-composite";
|
||||
import { getCompositeFor } from "../utils/composite/get-composite/get-composite";
|
||||
import * as uuid from "uuid";
|
||||
|
||||
export interface RunnableSync<TParameter = void> {
|
||||
id: string;
|
||||
@ -14,35 +13,43 @@ export interface RunnableSync<TParameter = void> {
|
||||
runAfter?: RunnableSync<TParameter>;
|
||||
}
|
||||
|
||||
type RunSync<Param> = (parameter: Param) => void;
|
||||
/**
|
||||
* NOTE: this is the worse of two evils. This makes sure that `RunnableSync` always is sync.
|
||||
* If the return type is `void` instead then async functions (those return `Promise<T>`) can
|
||||
* coerce to it.
|
||||
*/
|
||||
type RunSync<Param> = (parameter: Param) => undefined;
|
||||
|
||||
export type RunManySync = <Param>(
|
||||
injectionToken: InjectionToken<Runnable<Param>, void>
|
||||
) => RunSync<Param>;
|
||||
export type RunManySync = <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => RunSync<Param>;
|
||||
|
||||
function runCompositeRunnableSyncs<Param>(param: Param, composite: Composite<RunnableSync<Param>>): undefined {
|
||||
composite.value.run(param);
|
||||
composite.children.map(composite => runCompositeRunnableSyncs(param, composite));
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function runManySyncFor(di: DiContainerForInjection): RunManySync {
|
||||
return (injectionToken) => async (parameter) => {
|
||||
return <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => (param: Param): undefined => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
const rootId = uuid.v4();
|
||||
const getCompositeRunnables = getCompositeFor<RunnableSync<Param>>({
|
||||
getId: (runnable) => runnable.id,
|
||||
getParentId: (runnable) => (
|
||||
runnable.id === rootId
|
||||
? undefined
|
||||
: runnable.runAfter?.id ?? rootId
|
||||
),
|
||||
});
|
||||
const composite = getCompositeRunnables([
|
||||
// This is a dummy runnable to conform to the requirements of `getCompositeFor` to only have one root
|
||||
{
|
||||
id: rootId,
|
||||
run: () => undefined,
|
||||
},
|
||||
...allRunnables,
|
||||
]);
|
||||
|
||||
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor((injectionToken as any).id, allRunnables);
|
||||
|
||||
const recursedRun = (
|
||||
runAfterRunnable: RunnableSync<any> | undefined = undefined,
|
||||
) =>
|
||||
pipeline(
|
||||
allRunnables,
|
||||
|
||||
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
|
||||
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
|
||||
map((runnable) => {
|
||||
runnable.run(parameter);
|
||||
|
||||
recursedRun(runnable);
|
||||
}),
|
||||
);
|
||||
|
||||
recursedRun();
|
||||
return runCompositeRunnableSyncs(param, composite);
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Runnable } from "./run-many-for";
|
||||
import type { RunnableSync } from "./run-many-sync-for";
|
||||
|
||||
export const throwWithIncorrectHierarchyFor = (injectionTokenId: string, allRunnables: Runnable<any>[] | RunnableSync<any>[]) => (
|
||||
(runnable: Runnable<any> | RunnableSync<any>) => {
|
||||
if (runnable.runAfter && !allRunnables.includes(runnable.runAfter)) {
|
||||
throw new Error(`Tried to run runnable "${runnable.id}" after the runnable "${runnable.runAfter.id}" which does not share the "${injectionTokenId}" injection token.`);
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -2,21 +2,17 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { StartableStoppable } from "./get-startable-stoppable";
|
||||
import { getStartableStoppable } from "./get-startable-stoppable";
|
||||
import { getPromiseStatus } from "../test-utils/get-promise-status";
|
||||
import { flushPromises } from "../test-utils/flush-promises";
|
||||
|
||||
describe("getStartableStoppable", () => {
|
||||
let stopMock: AsyncFnMock<() => Promise<void>>;
|
||||
let startMock: AsyncFnMock<() => Promise<() => Promise<void>>>;
|
||||
let actual: { stop: () => Promise<void>; start: () => Promise<void>; started: boolean };
|
||||
let stopMock: jest.MockedFunction<() => void>;
|
||||
let startMock: jest.MockedFunction<() => () => void>;
|
||||
let actual: StartableStoppable;
|
||||
|
||||
beforeEach(() => {
|
||||
stopMock = asyncFn();
|
||||
startMock = asyncFn();
|
||||
|
||||
stopMock = jest.fn();
|
||||
startMock = jest.fn().mockImplementation(() => stopMock);
|
||||
actual = getStartableStoppable("some-id", startMock);
|
||||
});
|
||||
|
||||
@ -29,7 +25,7 @@ describe("getStartableStoppable", () => {
|
||||
});
|
||||
|
||||
it("when stopping before ever starting, throws", () => {
|
||||
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has not started yet.");
|
||||
expect(() => actual.stop()).toThrow("Tried to stop \"some-id\", but it is already stopped.");
|
||||
});
|
||||
|
||||
it("is not started", () => {
|
||||
@ -37,199 +33,30 @@ describe("getStartableStoppable", () => {
|
||||
});
|
||||
|
||||
describe("when started", () => {
|
||||
let startPromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
startPromise = actual.start();
|
||||
});
|
||||
|
||||
it("starts starting", () => {
|
||||
expect(startMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("starting does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(startPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("is not started yet", () => {
|
||||
expect(actual.started).toBe(false);
|
||||
});
|
||||
|
||||
describe("when started again before the start has finished", () => {
|
||||
let error: Error;
|
||||
|
||||
beforeEach(() => {
|
||||
startMock.mockClear();
|
||||
|
||||
actual.start().catch((e) => { error = e; });
|
||||
});
|
||||
|
||||
it("does not start starting again", () => {
|
||||
expect(startMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws", () => {
|
||||
expect(error.message).toBe("Tried to start \"some-id\", but it is already being started.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when starting finishes", () => {
|
||||
beforeEach(async () => {
|
||||
await startMock.resolve(stopMock);
|
||||
});
|
||||
|
||||
it("is started", () => {
|
||||
expect(actual.started).toBe(true);
|
||||
});
|
||||
|
||||
it("starting resolves", async () => {
|
||||
const promiseStatus = await getPromiseStatus(startPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(true);
|
||||
});
|
||||
|
||||
it("when started again, throws", () => {
|
||||
expect(actual.start).rejects.toThrow("Tried to start \"some-id\", but it has already started.");
|
||||
});
|
||||
|
||||
it("does not stop yet", () => {
|
||||
expect(stopMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when stopped", () => {
|
||||
let stopPromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
stopPromise = actual.stop();
|
||||
});
|
||||
|
||||
it("starts stopping", () => {
|
||||
expect(stopMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("stopping does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(stopPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("is not stopped yet", () => {
|
||||
expect(actual.started).toBe(true);
|
||||
});
|
||||
|
||||
describe("when stopping finishes", () => {
|
||||
beforeEach(async () => {
|
||||
await stopMock.resolve();
|
||||
});
|
||||
|
||||
it("is not started", () => {
|
||||
expect(actual.started).toBe(false);
|
||||
});
|
||||
|
||||
it("stopping resolves", async () => {
|
||||
const promiseStatus = await getPromiseStatus(stopPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(true);
|
||||
});
|
||||
|
||||
it("when stopped again, throws", () => {
|
||||
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has already stopped.");
|
||||
});
|
||||
|
||||
describe("when started again", () => {
|
||||
beforeEach(
|
||||
() => {
|
||||
startMock.mockClear();
|
||||
|
||||
actual.start();
|
||||
});
|
||||
|
||||
it("starts", () => {
|
||||
it("calls start function", () => {
|
||||
expect(startMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("is not started yet", () => {
|
||||
expect(actual.started).toBe(false);
|
||||
});
|
||||
|
||||
describe("when starting finishes", () => {
|
||||
beforeEach(async () => {
|
||||
await startMock.resolve(stopMock);
|
||||
});
|
||||
|
||||
it("is started", () => {
|
||||
expect(actual.started).toBe(true);
|
||||
});
|
||||
|
||||
it("when stopped again, starts stopping again", async () => {
|
||||
stopMock.mockClear();
|
||||
|
||||
actual.stop();
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(stopMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when stopped before starting finishes", () => {
|
||||
let stopPromise: Promise<void>;
|
||||
|
||||
describe("when stopped", () => {
|
||||
beforeEach(() => {
|
||||
stopPromise = actual.stop();
|
||||
actual.stop();
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(stopPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("is not started yet", () => {
|
||||
expect(actual.started).toBe(false);
|
||||
});
|
||||
|
||||
describe("when starting finishes", () => {
|
||||
beforeEach(async () => {
|
||||
await startMock.resolve(stopMock);
|
||||
});
|
||||
|
||||
it("starts stopping", () => {
|
||||
expect(stopMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("is not stopped yet", () => {
|
||||
expect(actual.started).toBe(true);
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(stopPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
describe("when stopping finishes", () => {
|
||||
beforeEach(async () => {
|
||||
await stopMock.resolve();
|
||||
it("calls stop function", () => {
|
||||
expect(stopMock).toBeCalled();
|
||||
});
|
||||
|
||||
it("is stopped", () => {
|
||||
expect(actual.started).toBe(false);
|
||||
});
|
||||
|
||||
it("resolves", async () => {
|
||||
const promiseStatus = await getPromiseStatus(stopPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,58 +3,43 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
type Stopper = () => Promise<void> | void;
|
||||
type Starter = () => Promise<Stopper> | Stopper;
|
||||
export type Stopper = () => void;
|
||||
export type Starter = () => Stopper;
|
||||
|
||||
export const getStartableStoppable = (
|
||||
id: string,
|
||||
startAndGetStopCallback: Starter,
|
||||
) => {
|
||||
export interface StartableStoppable {
|
||||
readonly started: boolean;
|
||||
start: () => void;
|
||||
stop: () => void;
|
||||
}
|
||||
|
||||
type StartableStoppableState = "stopped" | "started" | "starting";
|
||||
|
||||
export function getStartableStoppable(id: string, startAndGetStopper: Starter): StartableStoppable {
|
||||
let stop: Stopper;
|
||||
let stopped = false;
|
||||
let started = false;
|
||||
let starting = false;
|
||||
let startingPromise: Promise<Stopper> | Stopper;
|
||||
let state: StartableStoppableState = "stopped";
|
||||
|
||||
return {
|
||||
get started() {
|
||||
return started;
|
||||
return state === "started";
|
||||
},
|
||||
|
||||
start: async () => {
|
||||
if (starting) {
|
||||
throw new Error(`Tried to start "${id}", but it is already being started.`);
|
||||
start: () => {
|
||||
if (state !== "stopped") {
|
||||
throw new Error(`Tried to start "${id}", but it is already ${state}.`);
|
||||
}
|
||||
|
||||
starting = true;
|
||||
|
||||
if (started) {
|
||||
throw new Error(`Tried to start "${id}", but it has already started.`);
|
||||
}
|
||||
|
||||
startingPromise = startAndGetStopCallback();
|
||||
stop = await startingPromise;
|
||||
|
||||
stopped = false;
|
||||
started = true;
|
||||
starting = false;
|
||||
state = "starting";
|
||||
stop = startAndGetStopper();
|
||||
state = "started";
|
||||
},
|
||||
|
||||
stop: async () => {
|
||||
await startingPromise;
|
||||
|
||||
if (stopped) {
|
||||
throw new Error(`Tried to stop "${id}", but it has already stopped.`);
|
||||
stop: () => {
|
||||
if (state !== "started") {
|
||||
throw new Error(`Tried to stop "${id}", but it is already ${state}.`);
|
||||
}
|
||||
|
||||
if (!started) {
|
||||
throw new Error(`Tried to stop "${id}", but it has not started yet.`);
|
||||
}
|
||||
|
||||
await stop();
|
||||
|
||||
started = false;
|
||||
stopped = true;
|
||||
stop();
|
||||
state = "stopped";
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -15,8 +15,9 @@ const applicationMenuReactivityInjectable = getInjectable({
|
||||
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
|
||||
const populateApplicationMenu = di.inject(populateApplicationMenuInjectable);
|
||||
|
||||
return getStartableStoppable("application-menu-reactivity", () =>
|
||||
autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), {
|
||||
return getStartableStoppable(
|
||||
"application-menu-reactivity",
|
||||
() => autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), {
|
||||
delay: 100,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -10,15 +10,11 @@ const stopApplicationMenuInjectable = getInjectable({
|
||||
id: "stop-application-menu",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationMenu = di.inject(
|
||||
applicationMenuReactivityInjectable,
|
||||
);
|
||||
const applicationMenu = di.inject(applicationMenuReactivityInjectable);
|
||||
|
||||
return {
|
||||
id: "stop-application-menu",
|
||||
run: async () => {
|
||||
await applicationMenu.stop();
|
||||
},
|
||||
run: () => void applicationMenu.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import { getStartableStoppable } from "../../../../../common/utils/get-startable
|
||||
import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable";
|
||||
import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable";
|
||||
|
||||
const TWO_HOURS = 1000 * 60 * 60 * 2;
|
||||
|
||||
const periodicalCheckForUpdatesInjectable = getInjectable({
|
||||
id: "periodical-check-for-updates",
|
||||
|
||||
@ -15,12 +17,9 @@ const periodicalCheckForUpdatesInjectable = getInjectable({
|
||||
const processCheckingForUpdates = withOrphanPromise(di.inject(processCheckingForUpdatesInjectable));
|
||||
|
||||
return getStartableStoppable("periodical-check-for-updates", () => {
|
||||
const TWO_HOURS = 1000 * 60 * 60 * 2;
|
||||
|
||||
processCheckingForUpdates("periodic");
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
|
||||
processCheckingForUpdates("periodic");
|
||||
}, TWO_HOURS);
|
||||
|
||||
|
||||
@ -14,10 +14,12 @@ const stopCheckingForUpdatesInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-checking-for-updates",
|
||||
run: async () => {
|
||||
run: () => {
|
||||
if (periodicalCheckForUpdates.started) {
|
||||
await periodicalCheckForUpdates.stop();
|
||||
periodicalCheckForUpdates.stop();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -14,9 +14,7 @@ const stopWatchingIfUpdateShouldHappenOnQuitInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-watching-if-update-should-happen-on-quit",
|
||||
run: () => {
|
||||
watchIfUpdateShouldHappenOnQuit.stop();
|
||||
},
|
||||
run: () => void watchIfUpdateShouldHappenOnQuit.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -44,6 +44,9 @@ const setupAppPathsInjectable = getInjectable({
|
||||
) as AppPaths;
|
||||
|
||||
appPathsState.set(appPaths);
|
||||
|
||||
// NOTE: this is the worse of two evils. This makes sure that `RunnableSync` always is sync
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -13,8 +13,9 @@ const catalogSyncToRendererInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
|
||||
return getStartableStoppable("catalog-sync", () =>
|
||||
startCatalogSyncToRenderer(catalogEntityRegistry),
|
||||
return getStartableStoppable(
|
||||
"catalog-sync",
|
||||
() => startCatalogSyncToRenderer(catalogEntityRegistry),
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@ -14,10 +14,12 @@ const stopCatalogSyncInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-catalog-sync",
|
||||
run: async () => {
|
||||
run: () => {
|
||||
if (catalogSyncToRenderer.started) {
|
||||
await catalogSyncToRenderer.stop();
|
||||
catalogSyncToRenderer.stop();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -18,9 +18,7 @@ const syncThemeFromOperatingSystemInjectable = getInjectable({
|
||||
|
||||
return getStartableStoppable("sync-theme-from-operating-system", () => {
|
||||
const updateThemeState = () => {
|
||||
const newTheme = getElectronTheme();
|
||||
|
||||
currentThemeState.set(newTheme);
|
||||
currentThemeState.set(getElectronTheme());
|
||||
};
|
||||
|
||||
nativeTheme.on("updated", updateThemeState);
|
||||
|
||||
@ -14,9 +14,7 @@ const cleanUpDeepLinkingInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "clean-up-deep-linking",
|
||||
run: () => {
|
||||
lensProtocolRouterMain.cleanup();
|
||||
},
|
||||
run: () => void lensProtocolRouterMain.cleanup(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -23,6 +23,8 @@ const hideDockForLastClosedWindowInjectable = getInjectable({
|
||||
if (isEmpty(visibleWindows)) {
|
||||
app.dock?.hide();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -20,6 +20,8 @@ const enforceSingleApplicationInstanceInjectable = getInjectable({
|
||||
if (!requestSingleInstanceLock()) {
|
||||
exitApp();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -18,6 +18,8 @@ const setupApplicationNameInjectable = getInjectable({
|
||||
id: "setup-application-name",
|
||||
run: () => {
|
||||
app.setName(appName);
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -13,15 +13,14 @@ const setupRunnablesAfterWindowIsOpenedInjectable = getInjectable({
|
||||
|
||||
instantiate: (di) => {
|
||||
const afterWindowIsOpened = runManyFor(di)(afterWindowIsOpenedInjectionToken);
|
||||
const app = di.inject(electronAppInjectable);
|
||||
|
||||
return {
|
||||
id: "setup-runnables-after-window-is-opened",
|
||||
run: () => {
|
||||
const app = di.inject(electronAppInjectable);
|
||||
app.on("browser-window-created", () => afterWindowIsOpened);
|
||||
|
||||
app.on("browser-window-created", async () => {
|
||||
await afterWindowIsOpened();
|
||||
});
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -15,24 +15,16 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({
|
||||
id: "setup-closing-of-application",
|
||||
|
||||
instantiate: (di) => {
|
||||
const runMany = runManySyncFor(di);
|
||||
|
||||
const runRunnablesBeforeQuitOfFrontEnd = runMany(
|
||||
beforeQuitOfFrontEndInjectionToken,
|
||||
);
|
||||
|
||||
const runRunnablesBeforeQuitOfBackEnd = runMany(
|
||||
beforeQuitOfBackEndInjectionToken,
|
||||
);
|
||||
const runManySync = runManySyncFor(di);
|
||||
const runRunnablesBeforeQuitOfFrontEnd = runManySync(beforeQuitOfFrontEndInjectionToken);
|
||||
const runRunnablesBeforeQuitOfBackEnd = runManySync(beforeQuitOfBackEndInjectionToken);
|
||||
const app = di.inject(electronAppInjectable);
|
||||
const isIntegrationTesting = di.inject(isIntegrationTestingInjectable);
|
||||
const autoUpdater = di.inject(autoUpdaterInjectable);
|
||||
|
||||
return {
|
||||
id: "setup-closing-of-application",
|
||||
run: () => {
|
||||
const app = di.inject(electronAppInjectable);
|
||||
|
||||
const isIntegrationTesting = di.inject(isIntegrationTestingInjectable);
|
||||
const autoUpdater = di.inject(autoUpdaterInjectable);
|
||||
|
||||
let isAutoUpdating = false;
|
||||
|
||||
autoUpdater.on("before-quit-for-update", () => {
|
||||
@ -51,6 +43,8 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
|
||||
|
||||
export const beforeElectronIsReadyInjectionToken =
|
||||
getInjectionToken<RunnableSync>({
|
||||
export const beforeElectronIsReadyInjectionToken = getInjectionToken<RunnableSync>({
|
||||
id: "before-electron-is-ready",
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
|
||||
|
||||
export const beforeQuitOfBackEndInjectionToken =
|
||||
getInjectionToken<RunnableSync>({
|
||||
export const beforeQuitOfBackEndInjectionToken = getInjectionToken<RunnableSync>({
|
||||
id: "before-quit-of-back-end",
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
|
||||
|
||||
export const beforeQuitOfFrontEndInjectionToken =
|
||||
getInjectionToken<RunnableSync>({
|
||||
export const beforeQuitOfFrontEndInjectionToken = getInjectionToken<RunnableSync>({
|
||||
id: "before-quit-of-front-end",
|
||||
});
|
||||
});
|
||||
|
||||
@ -11,9 +11,7 @@ const cleanUpShellSessionsInjectable = getInjectable({
|
||||
|
||||
instantiate: () => ({
|
||||
id: "clean-up-shell-sessions",
|
||||
run: () => {
|
||||
ShellSession.cleanup();
|
||||
},
|
||||
run: () => void ShellSession.cleanup(),
|
||||
}),
|
||||
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
|
||||
@ -16,6 +16,8 @@ const emitCloseToEventBusInjectable = getInjectable({
|
||||
id: "emit-close-to-event-bus",
|
||||
run: () => {
|
||||
emitAppEvent({ name: "app", action: "close" });
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -20,6 +20,8 @@ const flagRendererAsNotLoadedInjectable = getInjectable({
|
||||
// Todo: remove this kludge which enables out-of-place temporal dependency.
|
||||
lensProtocolRouterMain.rendererLoaded = false;
|
||||
});
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -14,9 +14,7 @@ const stopKubeConfigSyncInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-kube-config-sync",
|
||||
run: () => {
|
||||
kubeConfigSyncManager.stopSync();
|
||||
},
|
||||
run: () => void kubeConfigSyncManager.stopSync(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ const setupSentryInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "setup-sentry",
|
||||
run: () => initializeSentryReportingWith(initializeSentryOnMain),
|
||||
run: () => void initializeSentryReportingWith(initializeSentryOnMain),
|
||||
};
|
||||
},
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
|
||||
@ -20,6 +20,8 @@ const setupHardwareAccelerationInjectable = getInjectable({
|
||||
if (hardwareAccelerationShouldBeDisabled) {
|
||||
disableHardwareAcceleration();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -16,6 +16,8 @@ const setupImmerInjectable = getInjectable({
|
||||
// Required in `utils/storage-helper.ts`
|
||||
Immer.setAutoFreeze(false); // allow to merge mobx observables
|
||||
Immer.enableMapSet(); // allow to merge maps and sets
|
||||
|
||||
return undefined;
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -21,6 +21,8 @@ const setupMobxInjectable = getInjectable({
|
||||
// reactionRequiresObservable: true,
|
||||
// observableRequiresReaction: true,
|
||||
});
|
||||
|
||||
return undefined;
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@ const setupProxyEnvInjectable = getInjectable({
|
||||
if (getCommandLineSwitch("proxy-server") !== "") {
|
||||
process.env.HTTPS_PROXY = getCommandLineSwitch("proxy-server");
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -16,13 +16,13 @@ const stopClusterManagerInjectable = getInjectable({
|
||||
id: "stop-cluster-manager",
|
||||
run: () => {
|
||||
clusterManager.stop();
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeQuitOfFrontEndInjectionToken,
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default stopClusterManagerInjectable;
|
||||
|
||||
@ -14,9 +14,7 @@ const stopBroadcastingThemeChangeInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-broadcasting-theme-change",
|
||||
run: async () => {
|
||||
await broadcastThemeChange.stop();
|
||||
},
|
||||
run: () => void broadcastThemeChange.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -14,9 +14,7 @@ const stopSyncingThemeFromOperatingSystemInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-syncing-theme-from-operating-system",
|
||||
run: async () => {
|
||||
await syncTheme.stop();
|
||||
},
|
||||
run: () => void syncTheme.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -15,10 +15,7 @@ const stopTrayInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-tray",
|
||||
run: () => {
|
||||
electronTray.stop();
|
||||
},
|
||||
|
||||
run: () => void electronTray.stop(),
|
||||
runAfter: di.inject(stopReactiveTrayMenuItemsInjectable),
|
||||
};
|
||||
},
|
||||
|
||||
@ -14,9 +14,7 @@ const stopReactiveTrayMenuIconInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-reactive-tray-menu-icon",
|
||||
run: async () => {
|
||||
await reactiveTrayMenuIcon.stop();
|
||||
},
|
||||
run: () => void reactiveTrayMenuIcon.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -19,10 +19,8 @@ const reactiveTrayMenuItemsInjectable = getInjectable({
|
||||
|
||||
return getStartableStoppable("reactive-tray-menu-items", () =>
|
||||
reaction(
|
||||
(): MinimalTrayMenuItem[] => reactiveItems.get().map(toNonReactiveItem),
|
||||
|
||||
() => reactiveItems.get().map(toNonReactiveItem),
|
||||
(nonReactiveItems) => electronTray.setMenuItems(nonReactiveItems),
|
||||
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
|
||||
@ -14,9 +14,7 @@ const stopReactiveTrayMenuItemsInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "stop-reactive-tray-menu-items",
|
||||
run: async () => {
|
||||
await reactiveTrayMenuItems.stop();
|
||||
},
|
||||
run: () => void reactiveTrayMenuItems.stop(),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -16,9 +16,9 @@ const startListeningOnChannelsInjectable = getInjectable({
|
||||
|
||||
return {
|
||||
id: "start-listening-on-channels-main",
|
||||
run: async () => {
|
||||
await listeningOnMessageChannels.start();
|
||||
await listeningOnRequestChannels.start();
|
||||
run: () => {
|
||||
listeningOnMessageChannels.start();
|
||||
listeningOnRequestChannels.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user