mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce a tray item for updating application
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
8d3bc40aa9
commit
84ac22904d
@ -0,0 +1,25 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`trigger updating using tray given no update available, when started renders 1`] = `
|
||||
<body>
|
||||
<div />
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`trigger updating using tray given no update available, when started when an update becomes available renders 1`] = `
|
||||
<body>
|
||||
<div />
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`trigger updating using tray given no update available, when started when an update becomes available when triggering installation of the update renders 1`] = `
|
||||
<body>
|
||||
<div />
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`trigger updating using tray given no update available, when started when an update becomes available when update becomes unavailable renders 1`] = `
|
||||
<body>
|
||||
<div />
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
|
||||
import quitAndInstallUpdateInjectable from "../../main/electron-app/features/quit-and-install-update.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
|
||||
describe("trigger updating using tray", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let quitAndInstallUpdateMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
quitAndInstallUpdateMock = jest.fn();
|
||||
|
||||
mainDi.override(quitAndInstallUpdateInjectable, () => quitAndInstallUpdateMock);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no update available, when started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not quit and install update yet", () => {
|
||||
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not have possibility to trigger installation of an update", () => {
|
||||
const trayItem = applicationBuilder.tray.get("trigger-application-update");
|
||||
|
||||
expect(trayItem).toBe(undefined);
|
||||
});
|
||||
|
||||
describe("when an update becomes available", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.applicationUpdater.makeUpdateAvailable(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not quit and install update yet", () => {
|
||||
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("has possibility to trigger installation of the update", () => {
|
||||
const trayItem = applicationBuilder.tray.get("trigger-application-update");
|
||||
|
||||
expect(trayItem).not.toBe(undefined);
|
||||
});
|
||||
|
||||
describe("when triggering installation of the update", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.tray.click("trigger-application-update");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("quits application and installs update", () => {
|
||||
expect(quitAndInstallUpdateMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when update becomes unavailable", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.applicationUpdater.makeUpdateAvailable(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not have possibility to trigger installation of the update", () => {
|
||||
const trayItem = applicationBuilder.tray.get("trigger-application-update");
|
||||
|
||||
expect(trayItem).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
|
||||
const electronUpdaterInjectable = getInjectable({
|
||||
id: "electron-updater",
|
||||
instantiate: () => autoUpdater,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default electronUpdaterInjectable;
|
||||
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
|
||||
const quitAndInstallUpdateInjectable = getInjectable({
|
||||
id: "quit-and-install-update",
|
||||
|
||||
instantiate: () => () => {
|
||||
autoUpdater.quitAndInstall(true, true);
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default quitAndInstallUpdateInjectable;
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import synchronizeUpdateIsAvailableStateInjectable from "./synchronize-update-is-available-state.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
|
||||
const startSynchronizingUpdateIsAvailableStateInjectable = getInjectable({
|
||||
id: "start-synchronizing-update-is-available-state",
|
||||
|
||||
instantiate: (di) => {
|
||||
const synchronizeUpdateIsAvailableState = di.inject(synchronizeUpdateIsAvailableStateInjectable);
|
||||
|
||||
return {
|
||||
run: () => {
|
||||
synchronizeUpdateIsAvailableState.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default startSynchronizingUpdateIsAvailableStateInjectable;
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import synchronizeUpdateIsAvailableStateInjectable from "./synchronize-update-is-available-state.injectable";
|
||||
import { beforeQuitOfBackEndInjectionToken } from "../../../start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
|
||||
|
||||
const stopSynchronizingUpdateIsAvailableStateInjectable = getInjectable({
|
||||
id: "stop-synchronizing-update-is-available-state",
|
||||
|
||||
instantiate: (di) => {
|
||||
const synchronizeUpdateIsAvailableState = di.inject(synchronizeUpdateIsAvailableStateInjectable);
|
||||
|
||||
return {
|
||||
run: () => {
|
||||
synchronizeUpdateIsAvailableState.stop();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
});
|
||||
|
||||
export default stopSynchronizingUpdateIsAvailableStateInjectable;
|
||||
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 { getStartableStoppable } from "../../../../common/utils/get-startable-stoppable";
|
||||
import electronUpdaterInjectable from "../../features/electron-updater.injectable";
|
||||
import updateIsAvailableStateInjectable from "../../../update-app/update-is-available-state.injectable";
|
||||
|
||||
const synchronizeUpdateIsAvailableStateInjectable = getInjectable({
|
||||
id: "synchronize-update-is-available-state",
|
||||
|
||||
instantiate: (di) => {
|
||||
const electronUpdater = di.inject(electronUpdaterInjectable);
|
||||
const updateIsAvailableState = di.inject(updateIsAvailableStateInjectable);
|
||||
|
||||
const makeUpdateAvailableFor = (available: boolean) => () => {
|
||||
updateIsAvailableState.set(available);
|
||||
};
|
||||
|
||||
return getStartableStoppable(
|
||||
"synchronize-update-is-available-state",
|
||||
() => {
|
||||
|
||||
const makeUpdateAvailable = makeUpdateAvailableFor(true);
|
||||
const makeUpdateUnavailable = makeUpdateAvailableFor(false);
|
||||
|
||||
electronUpdater.on("update-downloaded", makeUpdateAvailable);
|
||||
electronUpdater.on("update-not-available", makeUpdateUnavailable);
|
||||
|
||||
return () => {
|
||||
electronUpdater.off("update-downloaded", makeUpdateAvailable);
|
||||
electronUpdater.off("update-not-available", makeUpdateUnavailable);
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default synchronizeUpdateIsAvailableStateInjectable;
|
||||
@ -78,6 +78,8 @@ import getElectronThemeInjectable from "./electron-app/features/get-electron-the
|
||||
import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable";
|
||||
import platformInjectable from "../common/vars/platform.injectable";
|
||||
import productNameInjectable from "./app-paths/app-name/product-name.injectable";
|
||||
import synchronizeUpdateIsAvailableStateInjectable from "./electron-app/runnables/update-application/synchronize-update-is-available-state.injectable";
|
||||
import quitAndInstallUpdateInjectable from "./electron-app/features/quit-and-install-update.injectable";
|
||||
|
||||
export function getDiForUnitTesting(opts: GetDiForUnitTestingOptions = {}) {
|
||||
const {
|
||||
@ -220,6 +222,8 @@ const overrideElectronFeatures = (di: DiContainer) => {
|
||||
di.override(ipcMainInjectable, () => ({}));
|
||||
di.override(getElectronThemeInjectable, () => () => "dark");
|
||||
di.override(syncThemeFromOperatingSystemInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
di.override(synchronizeUpdateIsAvailableStateInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
di.override(quitAndInstallUpdateInjectable, () => () => {});
|
||||
|
||||
di.override(createElectronWindowForInjectable, () => () => async () => ({
|
||||
show: () => {},
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import { trayMenuItemInjectionToken } from "../tray/tray-menu-item/tray-menu-item-injection-token";
|
||||
import updateIsAvailableInjectable from "./update-is-available.injectable";
|
||||
import triggerApplicationUpdateInjectable from "./trigger-application-update.injectable";
|
||||
|
||||
const triggerApplicationUpdateTrayItemInjectable = getInjectable({
|
||||
id: "trigger-application-update-tray-item",
|
||||
|
||||
instantiate: (di) => {
|
||||
const updateIsAvailable = di.inject(updateIsAvailableInjectable);
|
||||
const triggerApplicationUpdate = di.inject(triggerApplicationUpdateInjectable);
|
||||
|
||||
return {
|
||||
id: "trigger-application-update",
|
||||
parentId: null,
|
||||
orderNumber: 50,
|
||||
label: "Trigger update",
|
||||
enabled: computed(() => true),
|
||||
visible: computed(() => updateIsAvailable.get()),
|
||||
|
||||
click: () => {
|
||||
triggerApplicationUpdate();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: trayMenuItemInjectionToken,
|
||||
});
|
||||
|
||||
export default triggerApplicationUpdateTrayItemInjectable;
|
||||
20
src/main/update-app/trigger-application-update.injectable.ts
Normal file
20
src/main/update-app/trigger-application-update.injectable.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import quitAndInstallUpdateInjectable from "../electron-app/features/quit-and-install-update.injectable";
|
||||
|
||||
const triggerApplicationUpdateInjectable = getInjectable({
|
||||
id: "trigger-application-update",
|
||||
|
||||
instantiate: (di) => {
|
||||
const quitAndInstallUpdate = di.inject(quitAndInstallUpdateInjectable);
|
||||
|
||||
return () => {
|
||||
quitAndInstallUpdate();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default triggerApplicationUpdateInjectable;
|
||||
13
src/main/update-app/update-is-available-state.injectable.ts
Normal file
13
src/main/update-app/update-is-available-state.injectable.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
|
||||
const updateIsAvailableState = getInjectable({
|
||||
id: "update-is-available-state",
|
||||
instantiate: () => observable.box<boolean>(false),
|
||||
});
|
||||
|
||||
export default updateIsAvailableState;
|
||||
19
src/main/update-app/update-is-available.injectable.ts
Normal file
19
src/main/update-app/update-is-available.injectable.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import updateIsAvailableStateInjectable from "./update-is-available-state.injectable";
|
||||
|
||||
const updateIsAvailableInjectable = getInjectable({
|
||||
id: "update-is-available",
|
||||
|
||||
instantiate: (di) => {
|
||||
const updateIsAvailableState = di.inject(updateIsAvailableStateInjectable);
|
||||
|
||||
return computed(() => updateIsAvailableState.get());
|
||||
},
|
||||
});
|
||||
|
||||
export default updateIsAvailableInjectable;
|
||||
@ -7,7 +7,7 @@ import rendererExtensionsInjectable from "../../../extensions/renderer-extension
|
||||
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
||||
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { IObservableArray } from "mobx";
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import { action, computed, observable, runInAction } from "mobx";
|
||||
import { renderFor } from "./renderFor";
|
||||
import React from "react";
|
||||
import { Router } from "react-router";
|
||||
@ -25,7 +25,7 @@ import type { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
|
||||
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { flatMap, compact, join, get, filter, find, map } from "lodash/fp";
|
||||
import { flatMap, compact, join, get, filter, find, map, matches } from "lodash/fp";
|
||||
import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable";
|
||||
import navigateToPreferencesInjectable from "../../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable";
|
||||
import type { MenuItemOpts } from "../../../main/menu/application-menu-items.injectable";
|
||||
@ -45,6 +45,8 @@ import type { NamespaceStore } from "../+namespaces/store";
|
||||
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
||||
import historyInjectable from "../../navigation/history.injectable";
|
||||
import trayMenuItemsInjectable from "../../../main/tray/tray-menu-item/tray-menu-items.injectable";
|
||||
import type { TrayMenuItem } from "../../../main/tray/tray-menu-item/tray-menu-item-injection-token";
|
||||
import updateIsAvailableStateInjectable from "../../../main/update-app/update-is-available-state.injectable";
|
||||
|
||||
type Callback = (dis: DiContainers) => void | Promise<void>;
|
||||
|
||||
@ -57,8 +59,13 @@ export interface ApplicationBuilder {
|
||||
beforeRender: (callback: Callback) => ApplicationBuilder;
|
||||
render: () => Promise<RenderResult>;
|
||||
|
||||
applicationUpdater: {
|
||||
makeUpdateAvailable: (available: boolean) => void;
|
||||
};
|
||||
|
||||
tray: {
|
||||
click: (id: string) => Promise<void>;
|
||||
get: (id: string) => TrayMenuItem | undefined;
|
||||
};
|
||||
|
||||
applicationMenu: {
|
||||
@ -149,6 +156,14 @@ export const getApplicationBuilder = () => {
|
||||
const builder: ApplicationBuilder = {
|
||||
dis,
|
||||
|
||||
applicationUpdater: {
|
||||
makeUpdateAvailable: action((available: boolean) => {
|
||||
const updateIsAvailableState = mainDi.inject(updateIsAvailableStateInjectable);
|
||||
|
||||
updateIsAvailableState.set(available);
|
||||
}),
|
||||
},
|
||||
|
||||
applicationMenu: {
|
||||
click: async (path: string) => {
|
||||
const applicationMenuItems = mainDi.inject(
|
||||
@ -186,6 +201,14 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
tray: {
|
||||
get: (id: string) => {
|
||||
const trayMenuItems = mainDi.inject(
|
||||
trayMenuItemsInjectable,
|
||||
);
|
||||
|
||||
return trayMenuItems.get().find(matches({ id }));
|
||||
},
|
||||
|
||||
click: async (id: string) => {
|
||||
const trayMenuItems = mainDi.inject(
|
||||
trayMenuItemsInjectable,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user