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

add confirm to internal install extension route

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2020-12-10 15:59:37 -05:00
parent dc6623ec65
commit 30f59655f0
3 changed files with 40 additions and 12 deletions

View File

@ -13,7 +13,7 @@ export async function installExtension(params: RouteParams): Promise<void> {
try { try {
navigate(extensionsURL()); navigate(extensionsURL());
await installFromNpm(name); await installFromNpm(name, true);
} catch (error) { } catch (error) {
logger.error("[PH - Install Extension]: failed to install from NPM", error); logger.error("[PH - Install Extension]: failed to install from NPM", error);
} }

View File

@ -30,6 +30,7 @@ interface InstallRequest {
fileName: string; fileName: string;
filePath?: string; filePath?: string;
data?: Buffer; data?: Buffer;
confirmInstall?: boolean;
} }
interface InstallRequestPreloaded extends InstallRequest { interface InstallRequestPreloaded extends InstallRequest {
@ -164,6 +165,10 @@ async function requestInstall(init: InstallRequest | InstallRequest[]) {
const folderExists = await fse.pathExists(extensionFolder); const folderExists = await fse.pathExists(extensionFolder);
if (!folderExists) { if (!folderExists) {
if (install.confirmInstall && !(await confirmInstallExtension(install.manifest))) {
continue;
}
// auto-install extension if not yet exists // auto-install extension if not yet exists
return unpackExtension(install); return unpackExtension(install);
} else { } else {
@ -309,6 +314,20 @@ async function uninstallExtension(extension: InstalledExtension) {
} }
} }
function confirmInstallExtension({name, version}: LensExtensionManifest): Promise<boolean> {
const displayName = extensionDisplayName(name, version);
return new Promise(resolve => {
ConfirmDialog.open({
message: <p>Are you sure you want to install extension <b>{displayName}</b>?</p>,
labelOk: <Trans>Yes</Trans>,
labelCancel: <Trans>No</Trans>,
ok: () => resolve(true),
cancel: () => resolve(false),
});
});
}
function confirmUninstallExtension(extension: InstalledExtension) { function confirmUninstallExtension(extension: InstalledExtension) {
const displayName = extensionDisplayName(extension.manifest.name, extension.manifest.version); const displayName = extensionDisplayName(extension.manifest.name, extension.manifest.version);
@ -357,15 +376,15 @@ async function installFromSelectFileDialog() {
* Start extension install using a package name, which is resolved to a tarball url using the npm registry. * Start extension install using a package name, which is resolved to a tarball url using the npm registry.
* @param packageName e.g. "@publisher/extension-name" * @param packageName e.g. "@publisher/extension-name"
*/ */
export async function installFromNpm(packageName: string) { export async function installFromNpm(packageName: string, confirm = false) {
const tarballUrl = await extensionLoader.getNpmPackageTarballUrl(packageName, "@hackweek"); const tarballUrl = await extensionLoader.getNpmPackageTarballUrl(packageName, "@hackweek");
Notifications.info(`Installing ${packageName}`); Notifications.info(`Installing ${packageName}`);
return installFromUrlOrPath(tarballUrl); return installFromUrlOrPath(tarballUrl, confirm);
} }
async function installFromUrlOrPath(installPath: string) { async function installFromUrlOrPath(installPath: string, confirmInstall = false) {
ExtensionStateStore.getInstance<ExtensionStateStore>().startingInstall = true; ExtensionStateStore.getInstance<ExtensionStateStore>().startingInstall = true;
const fileName = path.basename(installPath); const fileName = path.basename(installPath);
@ -376,11 +395,11 @@ async function installFromUrlOrPath(installPath: string) {
const { promise: filePromise } = downloadFile({ url: installPath, timeout: 60000 /*1m*/ }); const { promise: filePromise } = downloadFile({ url: installPath, timeout: 60000 /*1m*/ });
const data = await filePromise; const data = await filePromise;
await requestInstall({ fileName, data }); await requestInstall({ fileName, data, confirmInstall });
} }
// otherwise installing from system path // otherwise installing from system path
else if (InputValidators.isPath.validate(installPath)) { else if (InputValidators.isPath.validate(installPath)) {
await requestInstall({ fileName, filePath: installPath }); await requestInstall({ fileName, filePath: installPath, confirmInstall });
} }
} catch (error) { } catch (error) {
ExtensionStateStore.getInstance<ExtensionStateStore>().startingInstall = false; ExtensionStateStore.getInstance<ExtensionStateStore>().startingInstall = false;

View File

@ -4,7 +4,7 @@ import React, { ReactNode } from "react";
import { observable } from "mobx"; import { observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Trans } from "@lingui/macro"; import { Trans } from "@lingui/macro";
import { cssNames, noop, prevDefault } from "../../utils"; import { cssNames, prevDefault } from "../../utils";
import { Button, ButtonProps } from "../button"; import { Button, ButtonProps } from "../button";
import { Dialog, DialogProps } from "../dialog"; import { Dialog, DialogProps } from "../dialog";
import { Icon } from "../icon"; import { Icon } from "../icon";
@ -13,7 +13,8 @@ export interface ConfirmDialogProps extends Partial<DialogProps> {
} }
export interface ConfirmDialogParams { export interface ConfirmDialogParams {
ok?: () => void; ok?: () => void | Promise<void> | Promise<any>;
cancel?: () => void | Promise<void> | Promise<any>;
labelOk?: ReactNode; labelOk?: ReactNode;
labelCancel?: ReactNode; labelCancel?: ReactNode;
message?: ReactNode; message?: ReactNode;
@ -39,7 +40,6 @@ export class ConfirmDialog extends React.Component<ConfirmDialogProps> {
} }
public defaultParams: ConfirmDialogParams = { public defaultParams: ConfirmDialogParams = {
ok: noop,
labelOk: <Trans>Ok</Trans>, labelOk: <Trans>Ok</Trans>,
labelCancel: <Trans>Cancel</Trans>, labelCancel: <Trans>Cancel</Trans>,
icon: <Icon big material="warning"/>, icon: <Icon big material="warning"/>,
@ -52,18 +52,27 @@ export class ConfirmDialog extends React.Component<ConfirmDialogProps> {
ok = async () => { ok = async () => {
try { try {
this.isSaving = true; this.isSaving = true;
await Promise.resolve(this.params.ok()).catch(noop); await this.params.ok?.();
} catch {
// ignore
} finally { } finally {
this.isSaving = false; this.isSaving = false;
} }
this.close(); ConfirmDialog.close();
}; };
onClose = () => { onClose = () => {
this.isSaving = false; this.isSaving = false;
}; };
close = () => { close = async () => {
try {
await this.params.cancel?.();
} catch {
// ignore
} finally {
this.isSaving = false;
}
ConfirmDialog.close(); ConfirmDialog.close();
}; };