mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add ability to hide KubeObjectMenu Edit and Remove buttons in extensions (#5107)
This commit is contained in:
1 parent
e532b90b72
commit
dbdde19222
51 files changed
+1245
-765
No files matched your search
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ExtendableDisposer } from "../../../common/utils";
|
||||
import { downloadFile, downloadJson } from "../../../common/utils";
|
||||
import { Notifications } from "../notifications";
|
||||
import React from "react";
|
||||
import path from "path";
|
||||
import { SemVer } from "semver";
|
||||
import URLParse from "url-parse";
|
||||
import type { InstallRequest } from "./attempt-install/install-request";
|
||||
import { reduce } from "lodash";
|
||||
import type { ExtensionInstallationStateStore } from "../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
||||
import type { Confirm } from "../confirm-dialog/confirm.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import attemptInstallInjectable from "./attempt-install/attempt-install.injectable";
|
||||
import getBaseRegistryUrlInjectable from "./get-base-registry-url/get-base-registry-url.injectable";
|
||||
import extensionInstallationStateStoreInjectable from "../../../extensions/extension-installation-state-store/extension-installation-state-store.injectable";
|
||||
import confirmInjectable from "../confirm-dialog/confirm.injectable";
|
||||
|
||||
export interface ExtensionInfo {
|
||||
name: string;
|
||||
version?: string;
|
||||
requireConfirmation?: boolean;
|
||||
}
|
||||
|
||||
export type AttemptInstallByInfo = (info: ExtensionInfo) => Promise<void>;
|
||||
|
||||
interface Dependencies {
|
||||
attemptInstall: (request: InstallRequest, d: ExtendableDisposer) => Promise<void>;
|
||||
getBaseRegistryUrl: () => Promise<string>;
|
||||
extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||
confirm: Confirm;
|
||||
}
|
||||
|
||||
const attemptInstallByInfo = ({
|
||||
attemptInstall,
|
||||
getBaseRegistryUrl,
|
||||
extensionInstallationStateStore,
|
||||
confirm,
|
||||
}: Dependencies): AttemptInstallByInfo => (
|
||||
async (info) => {
|
||||
const { name, version, requireConfirmation = false } = info;
|
||||
const disposer = extensionInstallationStateStore.startPreInstall();
|
||||
const baseUrl = await getBaseRegistryUrl();
|
||||
const registryUrl = new URLParse(baseUrl).set("pathname", name).toString();
|
||||
let json: any;
|
||||
let finalVersion = version;
|
||||
|
||||
try {
|
||||
json = await downloadJson({ url: registryUrl }).promise;
|
||||
|
||||
if (!json || json.error || typeof json.versions !== "object" || !json.versions) {
|
||||
const message = json?.error ? `: ${json.error}` : "";
|
||||
|
||||
Notifications.error(`Failed to get registry information for that extension${message}`);
|
||||
|
||||
return disposer();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof SyntaxError) {
|
||||
// assume invalid JSON
|
||||
console.warn("Set registry has invalid json", { url: baseUrl }, error);
|
||||
Notifications.error("Failed to get valid registry information for that extension. Registry did not return valid JSON");
|
||||
} else {
|
||||
console.error("Failed to download registry information", error);
|
||||
Notifications.error(`Failed to get valid registry information for that extension. ${error}`);
|
||||
}
|
||||
|
||||
return disposer();
|
||||
}
|
||||
|
||||
if (version) {
|
||||
if (!json.versions[version]) {
|
||||
if (json["dist-tags"][version]) {
|
||||
finalVersion = json["dist-tags"][version];
|
||||
} else {
|
||||
Notifications.error((
|
||||
<p>
|
||||
The <em>{name}</em> extension does not have a version or tag <code>{version}</code>.
|
||||
</p>
|
||||
));
|
||||
|
||||
return disposer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const versions = Object.keys(json.versions)
|
||||
.map(version => new SemVer(version, { loose: true, includePrerelease: true }))
|
||||
// ignore pre-releases for auto picking the version
|
||||
.filter(version => version.prerelease.length === 0);
|
||||
|
||||
finalVersion = reduce(
|
||||
versions,
|
||||
(prev, curr) => prev.compareMain(curr) === -1 ? curr : prev,
|
||||
).format();
|
||||
}
|
||||
|
||||
if (requireConfirmation) {
|
||||
const proceed = await confirm({
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to install{" "}
|
||||
<b>
|
||||
{name}@{finalVersion}
|
||||
</b>
|
||||
?
|
||||
</p>
|
||||
),
|
||||
labelCancel: "Cancel",
|
||||
labelOk: "Install",
|
||||
});
|
||||
|
||||
if (!proceed) {
|
||||
return disposer();
|
||||
}
|
||||
}
|
||||
|
||||
const url = json.versions[finalVersion].dist.tarball;
|
||||
const fileName = path.basename(url);
|
||||
const { promise: dataP } = downloadFile({ url, timeout: 10 * 60 * 1000 });
|
||||
|
||||
return attemptInstall({ fileName, dataP }, disposer);
|
||||
}
|
||||
);
|
||||
|
||||
const attemptInstallByInfoInjectable = getInjectable({
|
||||
id: "attempt-install-by-info",
|
||||
instantiate: (di) => attemptInstallByInfo({
|
||||
attemptInstall: di.inject(attemptInstallInjectable),
|
||||
getBaseRegistryUrl: di.inject(getBaseRegistryUrlInjectable),
|
||||
extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable),
|
||||
confirm: di.inject(confirmInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default attemptInstallByInfoInjectable;
|
||||
-23
@@ -1,23 +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 { attemptInstallByInfo } from "./attempt-install-by-info";
|
||||
import attemptInstallInjectable from "../attempt-install/attempt-install.injectable";
|
||||
import getBaseRegistryUrlInjectable from "../get-base-registry-url/get-base-registry-url.injectable";
|
||||
import extensionInstallationStateStoreInjectable
|
||||
from "../../../../extensions/extension-installation-state-store/extension-installation-state-store.injectable";
|
||||
|
||||
const attemptInstallByInfoInjectable = getInjectable({
|
||||
id: "attempt-install-by-info",
|
||||
|
||||
instantiate: (di) =>
|
||||
attemptInstallByInfo({
|
||||
attemptInstall: di.inject(attemptInstallInjectable),
|
||||
getBaseRegistryUrl: di.inject(getBaseRegistryUrlInjectable),
|
||||
extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default attemptInstallByInfoInjectable;
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ExtendableDisposer } from "../../../../common/utils";
|
||||
import { downloadFile, downloadJson } from "../../../../common/utils";
|
||||
import { Notifications } from "../../notifications";
|
||||
import { ConfirmDialog } from "../../confirm-dialog";
|
||||
import React from "react";
|
||||
import path from "path";
|
||||
import { SemVer } from "semver";
|
||||
import URLParse from "url-parse";
|
||||
import type { InstallRequest } from "../attempt-install/install-request";
|
||||
import lodash from "lodash";
|
||||
import type { ExtensionInstallationStateStore } from "../../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
||||
|
||||
export interface ExtensionInfo {
|
||||
name: string;
|
||||
version?: string;
|
||||
requireConfirmation?: boolean;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
attemptInstall: (request: InstallRequest, d: ExtendableDisposer) => Promise<void>;
|
||||
getBaseRegistryUrl: () => Promise<string>;
|
||||
extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||
}
|
||||
|
||||
export const attemptInstallByInfo = ({ attemptInstall, getBaseRegistryUrl, extensionInstallationStateStore }: Dependencies) => async ({
|
||||
name,
|
||||
version,
|
||||
requireConfirmation = false,
|
||||
}: ExtensionInfo) => {
|
||||
const disposer = extensionInstallationStateStore.startPreInstall();
|
||||
const baseUrl = await getBaseRegistryUrl();
|
||||
const registryUrl = new URLParse(baseUrl).set("pathname", name).toString();
|
||||
let json: any;
|
||||
|
||||
try {
|
||||
json = await downloadJson({ url: registryUrl }).promise;
|
||||
|
||||
if (!json || json.error || typeof json.versions !== "object" || !json.versions) {
|
||||
const message = json?.error ? `: ${json.error}` : "";
|
||||
|
||||
Notifications.error(`Failed to get registry information for that extension${message}`);
|
||||
|
||||
return disposer();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof SyntaxError) {
|
||||
// assume invalid JSON
|
||||
console.warn("Set registry has invalid json", { url: baseUrl }, error);
|
||||
Notifications.error("Failed to get valid registry information for that extension. Registry did not return valid JSON");
|
||||
} else {
|
||||
console.error("Failed to download registry information", error);
|
||||
Notifications.error(`Failed to get valid registry information for that extension. ${error}`);
|
||||
}
|
||||
|
||||
return disposer();
|
||||
}
|
||||
|
||||
if (version) {
|
||||
if (!json.versions[version]) {
|
||||
if (json["dist-tags"][version]) {
|
||||
version = json["dist-tags"][version];
|
||||
} else {
|
||||
Notifications.error(
|
||||
<p>
|
||||
The <em>{name}</em> extension does not have a version or tag{" "}
|
||||
<code>{version}</code>.
|
||||
</p>,
|
||||
);
|
||||
|
||||
return disposer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const versions = Object.keys(json.versions)
|
||||
.map(
|
||||
version =>
|
||||
new SemVer(version, { loose: true, includePrerelease: true }),
|
||||
)
|
||||
// ignore pre-releases for auto picking the version
|
||||
.filter(version => version.prerelease.length === 0);
|
||||
|
||||
version = lodash.reduce(versions, (prev, curr) =>
|
||||
prev.compareMain(curr) === -1 ? curr : prev,
|
||||
).format();
|
||||
}
|
||||
|
||||
if (requireConfirmation) {
|
||||
const proceed = await ConfirmDialog.confirm({
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to install{" "}
|
||||
<b>
|
||||
{name}@{version}
|
||||
</b>
|
||||
?
|
||||
</p>
|
||||
),
|
||||
labelCancel: "Cancel",
|
||||
labelOk: "Install",
|
||||
});
|
||||
|
||||
if (!proceed) {
|
||||
return disposer();
|
||||
}
|
||||
}
|
||||
|
||||
const url = json.versions[version].dist.tarball;
|
||||
const fileName = path.basename(url);
|
||||
const { promise: dataP } = downloadFile({ url, timeout: 10 * 60 * 1000 });
|
||||
|
||||
return attemptInstall({ fileName, dataP }, disposer);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 React from "react";
|
||||
import type { InstalledExtension } from "../../../extensions/extension-discovery/extension-discovery";
|
||||
import type { LensExtensionId } from "../../../extensions/lens-extension";
|
||||
import { extensionDisplayName } from "../../../extensions/lens-extension";
|
||||
import type { Confirm } from "../confirm-dialog/confirm.injectable";
|
||||
import confirmInjectable from "../confirm-dialog/confirm.injectable";
|
||||
import uninstallExtensionInjectable from "./uninstall-extension/uninstall-extension.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
uninstallExtension: (id: LensExtensionId) => Promise<boolean>;
|
||||
confirm: Confirm;
|
||||
}
|
||||
|
||||
export type ConfirmUninstallExtension = (ext: InstalledExtension) => Promise<void>;
|
||||
|
||||
const confirmUninstallExtension = ({
|
||||
uninstallExtension,
|
||||
confirm,
|
||||
}: Dependencies): ConfirmUninstallExtension => (
|
||||
async (extension) => {
|
||||
const displayName = extensionDisplayName(
|
||||
extension.manifest.name,
|
||||
extension.manifest.version,
|
||||
);
|
||||
const confirmed = await confirm({
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to uninstall extension <b>{displayName}</b>?
|
||||
</p>
|
||||
),
|
||||
labelOk: "Yes",
|
||||
labelCancel: "No",
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
await uninstallExtension(extension.id);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const confirmUninstallExtensionInjectable = getInjectable({
|
||||
id: "confirm-uninstall-extension",
|
||||
instantiate: (di) => confirmUninstallExtension({
|
||||
uninstallExtension: di.inject(uninstallExtensionInjectable),
|
||||
confirm: di.inject(confirmInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default confirmUninstallExtensionInjectable;
|
||||
-18
@@ -1,18 +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 { confirmUninstallExtension } from "./confirm-uninstall-extension";
|
||||
import uninstallExtensionInjectable from "../uninstall-extension/uninstall-extension.injectable";
|
||||
|
||||
const confirmUninstallExtensionInjectable = getInjectable({
|
||||
id: "confirm-uninstall-extension",
|
||||
|
||||
instantiate: (di) =>
|
||||
confirmUninstallExtension({
|
||||
uninstallExtension: di.inject(uninstallExtensionInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default confirmUninstallExtensionInjectable;
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { InstalledExtension } from "../../../../extensions/extension-discovery/extension-discovery";
|
||||
import type { LensExtensionId } from "../../../../extensions/lens-extension";
|
||||
import { extensionDisplayName } from "../../../../extensions/lens-extension";
|
||||
import { ConfirmDialog } from "../../confirm-dialog";
|
||||
|
||||
interface Dependencies {
|
||||
uninstallExtension: (id: LensExtensionId) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const confirmUninstallExtension =
|
||||
({ uninstallExtension }: Dependencies) =>
|
||||
async (extension: InstalledExtension): Promise<void> => {
|
||||
const displayName = extensionDisplayName(
|
||||
extension.manifest.name,
|
||||
extension.manifest.version,
|
||||
);
|
||||
const confirmed = await ConfirmDialog.confirm({
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to uninstall extension <b>{displayName}</b>?
|
||||
</p>
|
||||
),
|
||||
labelOk: "Yes",
|
||||
labelCancel: "No",
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
await uninstallExtension(extension.id);
|
||||
}
|
||||
};
|
||||
@@ -26,7 +26,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import userExtensionsInjectable from "./user-extensions/user-extensions.injectable";
|
||||
import enableExtensionInjectable from "./enable-extension/enable-extension.injectable";
|
||||
import disableExtensionInjectable from "./disable-extension/disable-extension.injectable";
|
||||
import confirmUninstallExtensionInjectable from "./confirm-uninstall-extension/confirm-uninstall-extension.injectable";
|
||||
import type { ConfirmUninstallExtension } from "./confirm-uninstall-extension.injectable";
|
||||
import confirmUninstallExtensionInjectable from "./confirm-uninstall-extension.injectable";
|
||||
import installFromInputInjectable from "./install-from-input/install-from-input.injectable";
|
||||
import installFromSelectFileDialogInjectable from "./install-from-select-file-dialog.injectable";
|
||||
import type { LensExtensionId } from "../../../extensions/lens-extension";
|
||||
@@ -39,7 +40,7 @@ interface Dependencies {
|
||||
userExtensions: IComputedValue<InstalledExtension[]>;
|
||||
enableExtension: (id: LensExtensionId) => void;
|
||||
disableExtension: (id: LensExtensionId) => void;
|
||||
confirmUninstallExtension: (extension: InstalledExtension) => Promise<void>;
|
||||
confirmUninstallExtension: ConfirmUninstallExtension;
|
||||
installFromInput: (input: string) => Promise<void>;
|
||||
installFromSelectFileDialog: () => Promise<void>;
|
||||
installOnDrop: (files: File[]) => Promise<void>;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import attemptInstallInjectable from "../attempt-install/attempt-install.injectable";
|
||||
import { installFromInput } from "./install-from-input";
|
||||
import attemptInstallByInfoInjectable from "../attempt-install-by-info/attempt-install-by-info.injectable";
|
||||
import attemptInstallByInfoInjectable from "../attempt-install-by-info.injectable";
|
||||
import extensionInstallationStateStoreInjectable
|
||||
from "../../../../extensions/extension-installation-state-store/extension-installation-state-store.injectable";
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import path from "path";
|
||||
import React from "react";
|
||||
import { readFileNotify } from "../read-file-notify/read-file-notify";
|
||||
import type { InstallRequest } from "../attempt-install/install-request";
|
||||
import type { ExtensionInfo } from "../attempt-install-by-info/attempt-install-by-info";
|
||||
import type { ExtensionInfo } from "../attempt-install-by-info.injectable";
|
||||
import type { ExtensionInstallationStateStore } from "../../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
||||
|
||||
interface Dependencies {
|
||||
|
||||
Reference in new issue
Block a user