From 993c3746b11fb3ee97fd2890abf337c7b7ddd1a7 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Mon, 17 May 2021 15:06:26 +0300 Subject: [PATCH] Making extension components observable Signed-off-by: Alex Andreev --- src/extensions/extension-loader.ts | 6 +- .../components/+extensions/extensions.tsx | 111 ++++-------------- .../components/+extensions/install.tsx | 8 +- .../installed-extensions.module.css | 4 + .../+extensions/installed-extensions.tsx | 16 ++- 5 files changed, 44 insertions(+), 101 deletions(-) diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index bbb62aec87..c86e4f1bee 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -61,7 +61,7 @@ export class ExtensionLoader extends Singleton { whenLoaded = when(() => this.isLoaded); @computed get userExtensions(): Map { - const extensions = this.extensions.toJS(); + const extensions = this.toJSON(); extensions.forEach((ext, extId) => { if (ext.isBundled) { @@ -86,6 +86,10 @@ export class ExtensionLoader extends Singleton { return extensions; } + @computed get userExtensionList() { + return Array.from(this.userExtensions.values()); + } + getExtensionByName(name: string): LensExtension | null { for (const [, val] of this.instances) { if (val.name === name) { diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index 267728d435..8f9585165b 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -24,7 +24,7 @@ import "./extensions.scss"; import { remote, shell } from "electron"; import fse from "fs-extra"; import _ from "lodash"; -import { computed, observable, reaction, when } from "mobx"; +import { observable, reaction, when } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import os from "os"; import path from "path"; @@ -33,7 +33,6 @@ import { SemVer } from "semver"; import URLParse from "url-parse"; import { - autobind, Disposer, disposer, downloadFile, @@ -55,11 +54,9 @@ import { import logger from "../../../main/logger"; import { Button } from "../button"; import { ConfirmDialog } from "../confirm-dialog"; -import { Icon } from "../icon"; import { DropFileInput, InputValidators } from "../input"; import { PageLayout } from "../layout/page-layout"; import { Notifications } from "../notifications"; -import { Spinner } from "../spinner/spinner"; import { ExtensionInstallationState, ExtensionInstallationStateStore } from "./extension-install.store"; import { Install } from "./install"; import { InstalledExtensions } from "./installed-extensions"; @@ -106,6 +103,22 @@ interface InstallRequestValidated { tempFile: string; // temp system path to packed extension for unpacking } +function setExtensionEnabled(id: LensExtensionId, isEnabled: boolean): void { + const extension = ExtensionLoader.getInstance().getExtension(id); + + if (extension) { + extension.isEnabled = isEnabled; + } +} + +function enableExtension(id: LensExtensionId) { + setExtensionEnabled(id, true); +} + +function disableExtension(id: LensExtensionId) { + setExtensionEnabled(id, false); +} + async function uninstallExtension(extensionId: LensExtensionId): Promise { const loader = ExtensionLoader.getInstance(); const { manifest } = loader.getExtension(extensionId); @@ -482,19 +495,8 @@ async function installFromSelectFileDialog() { @observer export class Extensions extends React.Component { - @observable search = ""; @observable installPath = ""; - @computed get searchedForExtensions() { - const searchText = this.search.toLowerCase(); - - return Array.from(ExtensionLoader.getInstance().userExtensions.values()) - .filter(({ manifest: { name, description }}) => ( - name.toLowerCase().includes(searchText) - || description?.toLowerCase().includes(searchText) - )); - } - componentDidMount() { // TODO: change this after upgrading to mobx6 as that versions' reactions have this functionality let prevSize = ExtensionLoader.getInstance().userExtensions.size; @@ -513,83 +515,8 @@ export class Extensions extends React.Component { ]); } - renderNoExtensionsHelpText() { - if (this.search) { - return

No search results found

; - } - - return ( -

- There are no installed extensions. - See list of available extensions. -

- ); - } - - renderNoExtensions() { - return ( -
- -
- {this.renderNoExtensionsHelpText()} -
-
- ); - } - - @autobind() - renderExtension(extension: InstalledExtension) { - const { id, isEnabled, manifest } = extension; - const { name, description, version } = manifest; - const isUninstalling = ExtensionInstallationStateStore.isExtensionUninstalling(id); - - return ( -
-
-
{name}
-
{version}
-

{description}

-
-
- { - isEnabled - ? - : - } - -
-
- ); - } - - renderExtensions() { - if (!ExtensionDiscovery.getInstance().isLoaded) { - return
; - } - - const { searchedForExtensions } = this; - - if (!searchedForExtensions.length) { - return this.renderNoExtensions(); - } - - return ( - <> - {...searchedForExtensions.map(this.renderExtension)} - - ); - } - render() { - const extensions = Array.from(ExtensionLoader.getInstance().userExtensions.values()); + const extensions = ExtensionLoader.getInstance().userExtensionList; return ( @@ -611,6 +538,8 @@ export class Extensions extends React.Component { diff --git a/src/renderer/components/+extensions/install.tsx b/src/renderer/components/+extensions/install.tsx index 0f87fb8d83..d32aa14d0b 100644 --- a/src/renderer/components/+extensions/install.tsx +++ b/src/renderer/components/+extensions/install.tsx @@ -7,6 +7,7 @@ import { Input, InputValidator, InputValidators } from "../input"; import { SubTitle } from "../layout/sub-title"; import { TooltipPosition } from "../tooltip"; import { ExtensionInstallationStateStore } from "./extension-install.store"; +import { observer } from "mobx-react"; interface Props { installPath: string; @@ -29,7 +30,7 @@ const installInputValidator: InputValidator = { ), }; -export function Install(props: Props) { +export const Install = observer((props: Props) => { const { installPath, supportedFormats, onChange, installFromInput, installFromSelectFileDialog } = props; return ( @@ -63,7 +64,7 @@ export function Install(props: Props) { primary label="Install" className="w-80 h-full" - // disabled={ExtensionInstallationStateStore.anyPreInstallingOrInstalling || !installInputValidator.validate(installPath)} + disabled={ExtensionInstallationStateStore.anyPreInstallingOrInstalling} waiting={ExtensionInstallationStateStore.anyPreInstallingOrInstalling} onClick={installFromInput} /> @@ -74,4 +75,5 @@ export function Install(props: Props) { ); -} +}); + diff --git a/src/renderer/components/+extensions/installed-extensions.module.css b/src/renderer/components/+extensions/installed-extensions.module.css index 4b0357a062..831ece9024 100644 --- a/src/renderer/components/+extensions/installed-extensions.module.css +++ b/src/renderer/components/+extensions/installed-extensions.module.css @@ -18,4 +18,8 @@ .noItemsIcon { @apply opacity-10; --size: 180px; +} + +.frozenRow { + @apply opacity-30 pointer-events-none; } \ No newline at end of file diff --git a/src/renderer/components/+extensions/installed-extensions.tsx b/src/renderer/components/+extensions/installed-extensions.tsx index 46a020cedb..b45c39d6fd 100644 --- a/src/renderer/components/+extensions/installed-extensions.tsx +++ b/src/renderer/components/+extensions/installed-extensions.tsx @@ -7,9 +7,13 @@ import { MenuActions, MenuItem } from "../menu"; import { Spinner } from "../spinner"; import { ExtensionInstallationStateStore } from "./extension-install.store"; import { cssNames } from "../../utils"; +import { observer } from "mobx-react"; +import type { LensExtensionId } from "../../../extensions/lens-extension"; interface Props { extensions: InstalledExtension[]; + enable: (id: LensExtensionId) => void; + disable: (id: LensExtensionId) => void; uninstall: (extension: InstalledExtension) => void; } @@ -17,7 +21,7 @@ function getStatus(isEnabled: boolean) { return isEnabled ? "Enabled" : "Disabled"; } -export function InstalledExtensions({ extensions, uninstall }: Props) { +export const InstalledExtensions = observer(({ extensions, uninstall, enable, disable }: Props) => { if (!ExtensionDiscovery.getInstance().isLoaded) { return
; } @@ -43,7 +47,7 @@ export function InstalledExtensions({ extensions, uninstall }: Props) { const columns = useMemo( () => [ { - Header: "Extension", + Header: "Name", accessor: "extension", width: 200 }, @@ -74,7 +78,7 @@ export function InstalledExtensions({ extensions, uninstall }: Props) { return { extension: ( -
+
{name}
{description}
@@ -92,7 +96,7 @@ export function InstalledExtensions({ extensions, uninstall }: Props) { {isEnabled ? ( extension.isEnabled = false} + onClick={() => disable(id)} > Disable @@ -100,7 +104,7 @@ export function InstalledExtensions({ extensions, uninstall }: Props) { ) : ( extension.isEnabled = true} + onClick={() => enable(id)} > Enable @@ -131,4 +135,4 @@ export function InstalledExtensions({ extensions, uninstall }: Props) { /> ); -} +});