mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add confirmation dialog to extension uninstall (#1547)
Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
This commit is contained in:
parent
168385385b
commit
77c8617b79
@ -7,8 +7,6 @@ import { workspaceStore } from "../workspace-store";
|
|||||||
|
|
||||||
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png");
|
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png");
|
||||||
|
|
||||||
console.log(""); // fix bug
|
|
||||||
|
|
||||||
let clusterStore: ClusterStore;
|
let clusterStore: ClusterStore;
|
||||||
|
|
||||||
describe("empty config", () => {
|
describe("empty config", () => {
|
||||||
|
|||||||
@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
export function defineGlobal(propName: string, descriptor: PropertyDescriptor) {
|
export function defineGlobal(propName: string, descriptor: PropertyDescriptor) {
|
||||||
const scope = typeof global !== "undefined" ? global : window;
|
const scope = typeof global !== "undefined" ? global : window;
|
||||||
|
|
||||||
if (scope.hasOwnProperty(propName)) {
|
if (scope.hasOwnProperty(propName)) {
|
||||||
console.info(`Global variable "${propName}" already exists. Skipping.`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(scope, propName, descriptor);
|
Object.defineProperty(scope, propName, descriptor);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,15 @@ import '@testing-library/jest-dom/extend-expect';
|
|||||||
import { fireEvent, render, screen } from '@testing-library/react';
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { extensionDiscovery } from "../../../../extensions/extension-discovery";
|
import { extensionDiscovery } from "../../../../extensions/extension-discovery";
|
||||||
|
import { ConfirmDialog } from "../../confirm-dialog";
|
||||||
|
import { Notifications } from "../../notifications";
|
||||||
import { Extensions } from "../extensions";
|
import { Extensions } from "../extensions";
|
||||||
|
|
||||||
jest.mock("../../../../extensions/extension-discovery", () => ({
|
jest.mock("../../../../extensions/extension-discovery", () => ({
|
||||||
...jest.requireActual("../../../../extensions/extension-discovery"),
|
...jest.requireActual("../../../../extensions/extension-discovery"),
|
||||||
extensionDiscovery: {
|
extensionDiscovery: {
|
||||||
localFolderPath: "/fake/path",
|
localFolderPath: "/fake/path",
|
||||||
uninstallExtension: jest.fn()
|
uninstallExtension: jest.fn(() => Promise.resolve())
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -31,14 +33,47 @@ jest.mock("../../../../extensions/extension-loader", () => ({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock("../../notifications", () => ({
|
||||||
|
ok: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
info: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
describe("Extensions", () => {
|
describe("Extensions", () => {
|
||||||
it("disables uninstall and disable buttons while uninstalling", () => {
|
it("disables uninstall and disable buttons while uninstalling", async () => {
|
||||||
render(<Extensions />);
|
render(<><Extensions /><ConfirmDialog/></>);
|
||||||
|
|
||||||
|
expect(screen.getByText("Disable").closest("button")).not.toBeDisabled();
|
||||||
|
expect(screen.getByText("Uninstall").closest("button")).not.toBeDisabled();
|
||||||
|
|
||||||
fireEvent.click(screen.getByText("Uninstall"));
|
fireEvent.click(screen.getByText("Uninstall"));
|
||||||
|
|
||||||
|
// Approve confirm dialog
|
||||||
|
fireEvent.click(screen.getByText("Yes"));
|
||||||
|
|
||||||
expect(extensionDiscovery.uninstallExtension).toHaveBeenCalledWith("/absolute/path");
|
expect(extensionDiscovery.uninstallExtension).toHaveBeenCalledWith("/absolute/path");
|
||||||
expect(screen.getByText("Disable").closest("button")).toBeDisabled();
|
expect(screen.getByText("Disable").closest("button")).toBeDisabled();
|
||||||
expect(screen.getByText("Uninstall").closest("button")).toBeDisabled();
|
expect(screen.getByText("Uninstall").closest("button")).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("displays error notification on uninstall error", () => {
|
||||||
|
(extensionDiscovery.uninstallExtension as any).mockImplementationOnce(() =>
|
||||||
|
Promise.reject()
|
||||||
|
);
|
||||||
|
render(<><Extensions /><ConfirmDialog/></>);
|
||||||
|
|
||||||
|
expect(screen.getByText("Disable").closest("button")).not.toBeDisabled();
|
||||||
|
expect(screen.getByText("Uninstall").closest("button")).not.toBeDisabled();
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText("Uninstall"));
|
||||||
|
|
||||||
|
// Approve confirm dialog
|
||||||
|
fireEvent.click(screen.getByText("Yes"));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(screen.getByText("Disable").closest("button")).not.toBeDisabled();
|
||||||
|
expect(screen.getByText("Uninstall").closest("button")).not.toBeDisabled();
|
||||||
|
expect(Notifications.error).toHaveBeenCalledTimes(1);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { t, Trans } from "@lingui/macro";
|
import { t, Trans } from "@lingui/macro";
|
||||||
import { remote, shell } from "electron";
|
import { remote, shell } from "electron";
|
||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { map, omit } from "lodash";
|
import { computed, observable, reaction } from "mobx";
|
||||||
import { computed, observable, ObservableMap, reaction } from "mobx";
|
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@ -16,6 +15,7 @@ import logger from "../../../main/logger";
|
|||||||
import { _i18n } from "../../i18n";
|
import { _i18n } from "../../i18n";
|
||||||
import { prevDefault } from "../../utils";
|
import { prevDefault } from "../../utils";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
|
import { ConfirmDialog } from "../confirm-dialog";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { DropFileInput, Input, InputValidator, InputValidators, SearchInput } from "../input";
|
import { DropFileInput, Input, InputValidator, InputValidators, SearchInput } from "../input";
|
||||||
import { PageLayout } from "../layout/page-layout";
|
import { PageLayout } from "../layout/page-layout";
|
||||||
@ -314,6 +314,17 @@ export class Extensions extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmUninstallExtension = (extension: InstalledExtension) => {
|
||||||
|
const displayName = extensionDisplayName(extension.manifest.name, extension.manifest.version);
|
||||||
|
|
||||||
|
ConfirmDialog.open({
|
||||||
|
message: <p>Are you sure you want to uninstall extension <b>{displayName}</b>?</p>,
|
||||||
|
labelOk: <Trans>Yes</Trans>,
|
||||||
|
labelCancel: <Trans>No</Trans>,
|
||||||
|
ok: () => this.uninstallExtension(extension)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
async uninstallExtension(extension: InstalledExtension) {
|
async uninstallExtension(extension: InstalledExtension) {
|
||||||
const displayName = extensionDisplayName(extension.manifest.name, extension.manifest.version);
|
const displayName = extensionDisplayName(extension.manifest.name, extension.manifest.version);
|
||||||
|
|
||||||
@ -348,8 +359,8 @@ export class Extensions extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensions.map(ext => {
|
return extensions.map(extension => {
|
||||||
const { id, isEnabled, manifest } = ext;
|
const { id, isEnabled, manifest } = extension;
|
||||||
const { name, description } = manifest;
|
const { name, description } = manifest;
|
||||||
const isUninstalling = this.extensionState.get(id)?.state === "uninstalling";
|
const isUninstalling = this.extensionState.get(id)?.state === "uninstalling";
|
||||||
|
|
||||||
@ -365,13 +376,17 @@ export class Extensions extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
{!isEnabled && (
|
{!isEnabled && (
|
||||||
<Button plain active disabled={isUninstalling} onClick={() => ext.isEnabled = true}>Enable</Button>
|
<Button plain active disabled={isUninstalling} onClick={() => {
|
||||||
|
extension.isEnabled = true;
|
||||||
|
}}>Enable</Button>
|
||||||
)}
|
)}
|
||||||
{isEnabled && (
|
{isEnabled && (
|
||||||
<Button accent disabled={isUninstalling} onClick={() => ext.isEnabled = false}>Disable</Button>
|
<Button accent disabled={isUninstalling} onClick={() => {
|
||||||
|
extension.isEnabled = false;
|
||||||
|
}}>Disable</Button>
|
||||||
)}
|
)}
|
||||||
<Button plain active disabled={isUninstalling} waiting={isUninstalling} onClick={() => {
|
<Button plain active disabled={isUninstalling} waiting={isUninstalling} onClick={() => {
|
||||||
this.uninstallExtension(ext);
|
this.confirmUninstallExtension(extension);
|
||||||
}}>Uninstall</Button>
|
}}>Uninstall</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user