1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

using the update syncBox injectables directly for status bar notifications

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
Jim Ehrismann 2022-06-22 19:43:33 -04:00
parent 7cbcc184a0
commit 041141fe39
8 changed files with 86 additions and 128 deletions

View File

@ -10,7 +10,8 @@ export type ApplicationUpdateStatusEventId =
| "checking-for-updates" | "checking-for-updates"
| "no-updates-available" | "no-updates-available"
| "download-for-update-started" | "download-for-update-started"
| "download-for-update-failed"; | "download-for-update-failed"
| "download-for-update-succeeded";
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type ApplicationUpdateStatusChannelMessage = { eventId: ApplicationUpdateStatusEventId; version?: string }; export type ApplicationUpdateStatusChannelMessage = { eventId: ApplicationUpdateStatusEventId; version?: string };

View File

@ -5,21 +5,21 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable"; import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { UpdateChannel } from "../update-channels"; import type { UpdateChannel } from "../update-channels";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token"; import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type DiscoveredUpdateVersion = SyncBox<{ version: string; updateChannel: UpdateChannel } | null>;
const discoveredUpdateVersionInjectable = getInjectable({ const discoveredUpdateVersionInjectable = getInjectable({
id: "discovered-update-version", id: "discovered-update-version",
instantiate: (di) => { instantiate: (di) => {
const createSyncBox = di.inject(createSyncBoxInjectable); const createSyncBox = di.inject(createSyncBoxInjectable);
return createSyncBox< return createSyncBox(
| { version: string; updateChannel: UpdateChannel } "discovered-update-version",
| null null,
>( ) as DiscoveredUpdateVersion;
"discovered-update-version",
null,
);
}, },
injectionToken: syncBoxInjectionToken, injectionToken: syncBoxInjectionToken,

View File

@ -4,12 +4,15 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable"; import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token"; import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export interface ProgressOfDownload { export interface ProgressOfDownload {
percentage: number; percentage: number;
} }
export type ProgressOfUpdateDownload = SyncBox<ProgressOfDownload>;
const progressOfUpdateDownloadInjectable = getInjectable({ const progressOfUpdateDownloadInjectable = getInjectable({
id: "progress-of-update-download-state", id: "progress-of-update-download-state",

View File

@ -4,8 +4,11 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable"; import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token"; import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type UpdateIsBeingDownloaded = SyncBox<boolean>;
const updateIsBeingDownloadedInjectable = getInjectable({ const updateIsBeingDownloadedInjectable = getInjectable({
id: "update-is-being-downloaded", id: "update-is-being-downloaded",

View File

@ -4,8 +4,11 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable"; import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
import type { SyncBox } from "../../utils/sync-box/sync-box-injection-token";
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token"; import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
export type UpdatesAreBeingDiscovered = SyncBox<boolean>;
const updatesAreBeingDiscoveredInjectable = getInjectable({ const updatesAreBeingDiscoveredInjectable = getInjectable({
id: "updates-are-being-discovered", id: "updates-are-being-discovered",

View File

@ -1,67 +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 { makeObservable, observable } from "mobx";
export type AutoUpdateStateName = "checking" | "available" | "not-available" | "done" | "downloading" | "download-failed" | "download-succeeded" | "idle";
let timerId: NodeJS.Timeout;
export class AutoUpdateState {
@observable private _state: AutoUpdateStateName;
@observable private _version: string | undefined = undefined;
constructor(state: AutoUpdateStateName = "idle") {
makeObservable(this);
this._state = state;
}
get name(): AutoUpdateStateName {
return this._state;
}
set name(state: AutoUpdateStateName) {
this._state = state;
this.triggerIdle();
}
get version(): string | undefined {
return this._version;
}
set version(version: string | undefined) {
this._version = version;
this.triggerIdle();
}
private triggerIdle(): void {
clearTimeout(timerId);
switch (this.name) {
case "checking":
case "available":
case "downloading":
case "idle":
break;
case "done":
case "not-available":
case "download-failed":
case "download-succeeded":
timerId = setTimeout(() => this.name = "idle", 5000);
break;
}
}
}
const AutoUpdateStateInjectable = getInjectable({
id: "auto-update-state",
instantiate: () => new AutoUpdateState("idle"),
});
export default AutoUpdateStateInjectable;

View File

@ -8,7 +8,6 @@ import applicationUpdateStatusChannelInjectable from "../../common/application-u
//import showInfoNotificationInjectable from "../components/notifications/show-info-notification.injectable"; //import showInfoNotificationInjectable from "../components/notifications/show-info-notification.injectable";
import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token"; import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token";
import { messageChannelListenerInjectionToken } from "../../common/utils/channel/message-channel-listener-injection-token"; import { messageChannelListenerInjectionToken } from "../../common/utils/channel/message-channel-listener-injection-token";
import AutoUpdateStateInjectable from "../../common/auto-update/auto-update-state.injectable";
const applicationUpdateStatusListenerInjectable = getInjectable({ const applicationUpdateStatusListenerInjectable = getInjectable({
id: "application-update-status-listener", id: "application-update-status-listener",
@ -16,35 +15,34 @@ const applicationUpdateStatusListenerInjectable = getInjectable({
instantiate: (di): MessageChannelListener<ApplicationUpdateStatusChannel> => { instantiate: (di): MessageChannelListener<ApplicationUpdateStatusChannel> => {
const channel = di.inject(applicationUpdateStatusChannelInjectable); const channel = di.inject(applicationUpdateStatusChannelInjectable);
//const showInfoNotification = di.inject(showInfoNotificationInjectable); //const showInfoNotification = di.inject(showInfoNotificationInjectable);
const autoUpdateState = di.inject(AutoUpdateStateInjectable);
const eventHandlers: Record<ApplicationUpdateStatusEventId, { handle: (version?: string) => void }> = { const eventHandlers: Record<ApplicationUpdateStatusEventId, { handle: (version?: string) => void }> = {
"checking-for-updates": { "checking-for-updates": {
handle: () => { handle: () => {
//showInfoNotification("Checking for updates..."); //showInfoNotification("Checking for updates...");
autoUpdateState.name = "checking";
}, },
}, },
"no-updates-available": { "no-updates-available": {
handle: () => { handle: () => {
//showInfoNotification("No new updates available"); //showInfoNotification("No new updates available");
autoUpdateState.name = "not-available";
}, },
}, },
"download-for-update-started": { "download-for-update-started": {
handle: (version) => { handle: (/*version*/) => {
//showInfoNotification(`Download for version ${version} started...`); //showInfoNotification(`Download for version ${version} started...`);
autoUpdateState.name = "downloading";
autoUpdateState.version = version;
}, },
}, },
"download-for-update-failed": { "download-for-update-failed": {
handle: () => { handle: () => {
//showInfoNotification("Download of update failed"); //showInfoNotification("Download of update failed");
autoUpdateState.name = "download-failed"; },
},
"download-for-update-succeeded": {
handle: () => {
}, },
}, },
}; };

View File

@ -4,30 +4,58 @@
*/ */
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import assert from "assert";
import AutoUpdateStateInjectable from "../../../common/auto-update/auto-update-state.injectable"; import React, { useEffect, useState } from "react";
import type { AutoUpdateState } from "../../../common/auto-update/auto-update-state.injectable";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
import type { ProgressOfUpdateDownload } from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
import progressOfUpdateDownloadInjectable from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable"; import progressOfUpdateDownloadInjectable from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
import type { ProgressOfDownload } from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable"; import type { DiscoveredUpdateVersion } from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import type { SyncBox } from "../../../common/utils/sync-box/sync-box-injection-token"; import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import type { UpdateIsBeingDownloaded } from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
import updateIsBeingDownloadedInjectable from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
import type { UpdatesAreBeingDiscovered } from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable";
import updatesAreBeingDiscoveredInjectable from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable";
interface Dependencies { interface Dependencies {
state: AutoUpdateState; progressOfUpdateDownload: ProgressOfUpdateDownload;
progressOfUpdateDownload: SyncBox<ProgressOfDownload>; discoveredVersionState: DiscoveredUpdateVersion;
downloadingUpdateState: UpdateIsBeingDownloaded;
checkingForUpdatesState: UpdatesAreBeingDiscovered;
} }
interface EndNoteProps {
version?: string;
note: (version: string) => JSX.Element;
}
const EndNote = ({ version, note }: EndNoteProps) => {
const [idling, setIdling] = useState(false);
useEffect(() => {
const timerId = setTimeout(() => setIdling(true), 5000);
return () => clearTimeout(timerId);
});
if (idling) {
return idle();
}
return note(version ?? "");
};
const checking = () => ( const checking = () => (
<> <>
<Spinner/> <Spinner/>
<div>{"Checking for updates..."}</div> <div>{"Checking for updates..."}</div>
</> </>
); );
const available = () => <div>{"Update is available"}</div>;
const notAvailable = () => <div>{"No new updates available"}</div>;
const downloading = (state: AutoUpdateState, percentDone: number) => {
const { version } = state;
const available = (version: string) => <div>{`${version ?? "Update"} is available`}</div>;
const notAvailable = () => <div>{"No new updates available"}</div>;
const downloading = (version: string, percentDone: number) => {
if ( percentDone === 0 ) { if ( percentDone === 0 ) {
return ( return (
<> <>
@ -37,57 +65,46 @@ const downloading = (state: AutoUpdateState, percentDone: number) => {
); );
} }
if ( percentDone < 100 ) { return <div>{`Download for version ${version} ${percentDone}%...`}</div>;
return <div>{`Download for version ${version} ${percentDone}%...`}</div>;
}
state.name = "download-succeeded";
return null;
}; };
const done = () => <div>{"Done checking for updates"}</div>; const downloadSucceeded = (version: string) => <div>{`Download for version ${version} complete`}</div>;
const downloadFailed = (version: string | undefined) => <div>{`Download for version ${version} failed`}</div>;
const downloadSucceeded = (version: string | undefined) => <div>{`Download for version ${version} complete`}</div>;
const idle = () => <></>; const idle = () => <></>;
export const NonInjectedAutoUpdateComponent = observer(({ state, progressOfUpdateDownload }: Dependencies) => { export const NonInjectedAutoUpdateComponent = observer(({ progressOfUpdateDownload, discoveredVersionState, downloadingUpdateState, checkingForUpdatesState }: Dependencies) => {
const discoveredVersion = discoveredVersionState.value.get();
switch(state.name) { if (downloadingUpdateState.value.get()) {
case "checking":
return checking();
case "available": assert(discoveredVersion);
return available();
case "not-available": const roundedPercentage = Math.round(progressOfUpdateDownload.value.get().percentage);
return notAvailable();
case "downloading": { if ( roundedPercentage > 99 ) {
const roundedPercentage = Math.round(progressOfUpdateDownload.value.get().percentage); return <EndNote note={downloadSucceeded} version={discoveredVersion.version} />;
return downloading(state, roundedPercentage);
} }
case "done": return downloading(discoveredVersion.version, roundedPercentage);
return done();
case "download-failed":
return downloadFailed(state.version);
case "download-succeeded":
return downloadSucceeded(state.version);
case "idle":
return idle();
} }
if (checkingForUpdatesState.value.get()) {
return checking();
}
if ( discoveredVersion) {
return <EndNote note={available} version={discoveredVersion.version} />;
}
return <EndNote note={notAvailable} />;
}); });
export const AutoUpdateComponent = withInjectables<Dependencies>(NonInjectedAutoUpdateComponent, { export const AutoUpdateComponent = withInjectables<Dependencies>(NonInjectedAutoUpdateComponent, {
getProps: (di, props) => ({ getProps: (di, props) => ({
state: di.inject(AutoUpdateStateInjectable),
progressOfUpdateDownload: di.inject(progressOfUpdateDownloadInjectable), progressOfUpdateDownload: di.inject(progressOfUpdateDownloadInjectable),
discoveredVersionState: di.inject(discoveredUpdateVersionInjectable),
downloadingUpdateState: di.inject(updateIsBeingDownloadedInjectable),
checkingForUpdatesState: di.inject(updatesAreBeingDiscoveredInjectable),
...props, ...props,
}), }),
}); });