diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 3c928430ed..307032e036 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -94,9 +94,25 @@ jobs:
GH_TOKEN: $(LENS_IDE_GH_TOKEN)
displayName: Customize config
- - script: make build
+ - bash: |
+ set -e
+
+ echo "Importing codesign certificate ..."
+ echo $CSC_LINK | base64 -D > certificate.p12
+ security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
+ security set-keychain-settings -lut 21600 build.keychain
+ security default-keychain -s build.keychain
+ security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
+ security import certificate.p12 -k build.keychain -P $CSC_KEY_PASSWORD -T /usr/bin/codesign -T /usr/bin/security -A
+ security set-key-partition-list -S apple-tool:,apple: -k $KEYCHAIN_PASSWORD build.keychain
+
+ rm certificate.p12
+ echo "Codesign certificate imported!"
+
+ make build
condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))"
env:
+ KEYCHAIN_PASSWORD: secretz
APPLEID: $(APPLEID)
APPLEIDPASS: $(APPLEIDPASS)
CSC_LINK: $(CSC_LINK)
diff --git a/.eslintrc.js b/.eslintrc.js
index 8cd6fd26fa..733f644615 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -22,15 +22,16 @@ module.exports = {
{
files: [
"**/*.js",
+ "**/*.mjs",
],
extends: [
"eslint:recommended",
],
env: {
node: true,
+ es2022: true,
},
parserOptions: {
- ecmaVersion: 2018,
sourceType: "module",
},
plugins: [
@@ -129,6 +130,14 @@ module.exports = {
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off",
+ "no-restricted-imports": ["error", {
+ "paths": [
+ {
+ "name": ".",
+ "message": "No importing from local index.ts(x?) file. A common way to make circular dependencies.",
+ },
+ ],
+ }],
"@typescript-eslint/member-delimiter-style": ["error", {
"multiline": {
"delimiter": "semi",
@@ -139,6 +148,28 @@ module.exports = {
"requireLast": false,
},
}],
+ "react/jsx-max-props-per-line": ["error", {
+ "maximum": {
+ "single": 2,
+ "multi": 1,
+ },
+ }],
+ "react/jsx-first-prop-new-line": ["error", "multiline"],
+ "react/jsx-one-expression-per-line": ["error", {
+ "allow": "single-child",
+ }],
+ "react/jsx-indent": ["error", 2],
+ "react/jsx-indent-props": ["error", 2],
+ "react/jsx-closing-tag-location": "error",
+ "react/jsx-wrap-multilines": ["error", {
+ "declaration": "parens-new-line",
+ "assignment": "parens-new-line",
+ "return": "parens-new-line",
+ "arrow": "parens-new-line",
+ "condition": "parens-new-line",
+ "logical": "parens-new-line",
+ "prop": "parens-new-line",
+ }],
"react/display-name": "off",
"space-before-function-paren": "off",
"@typescript-eslint/space-before-function-paren": ["error", {
@@ -217,5 +248,35 @@ module.exports = {
"@typescript-eslint/consistent-type-imports": "error",
},
},
+ {
+ files: [
+ "src/{common,main,renderer}/**/*.ts",
+ "src/{common,main,renderer}/**/*.tsx",
+ ],
+ rules: {
+ "no-restricted-imports": ["error", {
+ "paths": [
+ {
+ "name": ".",
+ "message": "No importing from local index.ts(x?) file. A common way to make circular dependencies.",
+ },
+ {
+ "name": "..",
+ "message": "No importing from parent index.ts(x?) file. A common way to make circular dependencies.",
+ },
+ ],
+ "patterns": [
+ {
+ "group": [
+ "**/extensions/renderer-api/**/*",
+ "**/extensions/main-api/**/*",
+ "**/extensions/common-api/**/*",
+ ],
+ message: "No importing from the extension api definitions in application code",
+ },
+ ],
+ }],
+ },
+ },
],
};
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 94beca0de6..44967d192c 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -73,7 +73,9 @@ jobs:
- name: Install integration test dependencies
id: minikube
- uses: medyagh/setup-minikube@5a9a7104d7322fa40424de8855c84685e89cefd7
+ uses: medyagh/setup-minikube@master
+ with:
+ minikube-version: latest
if: runner.os == 'Linux'
- run: xvfb-run --auto-servernum --server-args='-screen 0, 1600x900x24' make integration
diff --git a/.gitignore b/.gitignore
index 4c9c3c8165..d018f3b251 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,6 @@ locales/**/**.js
lens.log
static/build
static/types
-build/tray/
binaries/client/
binaries/server/
src/extensions/*/*.js
diff --git a/Makefile b/Makefile
index 1199ee381d..48ce768766 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ compile-dev: node_modules
ci-validate-dev: binaries/client build-extensions compile-dev
.PHONY: dev
-dev: binaries/client build/tray/trayIconTemplate.png build-extensions
+dev: binaries/client build-extensions
rm -rf static/build/
yarn dev
@@ -53,7 +53,7 @@ integration: build
yarn integration
.PHONY: build
-build: node_modules binaries/client build/tray/trayIconTemplate.png
+build: node_modules binaries/client
yarn run npm:fix-build-version
$(MAKE) build-extensions -B
yarn run compile
@@ -63,6 +63,10 @@ ifeq "$(DETECTED_OS)" "Windows"
endif
yarn run electron-builder --publish onTag $(ELECTRON_BUILDER_EXTRA_ARGS)
+.PHONY: update-extension-locks
+update-extension-locks:
+ $(foreach dir, $(extensions), (cd $(dir) && rm package-lock.json && ../../node_modules/.bin/npm install --package-lock-only);)
+
.NOTPARALLEL: $(extension_node_modules)
$(extension_node_modules): node_modules
cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund --no-save
@@ -70,9 +74,6 @@ $(extension_node_modules): node_modules
$(extension_dists): src/extensions/npm/extensions/dist $(extension_node_modules)
cd $(@:/dist=) && ../../node_modules/.bin/npm run build
-build/tray/trayIconTemplate.png: node_modules
- yarn ts-node ./build/generate-tray-icons.ts
-
.PHONY: clean-old-extensions
clean-old-extensions:
find ./extensions -mindepth 1 -maxdepth 1 -type d '!' -exec test -e '{}/package.json' \; -exec rm -rf {} \;
@@ -84,19 +85,17 @@ build-extensions: node_modules clean-old-extensions $(extension_dists)
test-extensions: $(extension_node_modules)
$(foreach dir, $(extensions), (cd $(dir) && npm run test || exit $?);)
-.PHONY: copy-extension-themes
-copy-extension-themes:
- mkdir -p src/extensions/npm/extensions/dist/src/renderer/themes/
- cp $(wildcard src/renderer/themes/*.json) src/extensions/npm/extensions/dist/src/renderer/themes/
-
src/extensions/npm/extensions/__mocks__:
cp -r __mocks__ src/extensions/npm/extensions/
-src/extensions/npm/extensions/dist: node_modules
+src/extensions/npm/extensions/dist: src/extensions/npm/extensions/node_modules
yarn compile:extension-types
+src/extensions/npm/extensions/node_modules: src/extensions/npm/extensions/package.json
+ cd src/extensions/npm/extensions/ && ../../../../node_modules/.bin/npm install --no-audit --no-fund
+
.PHONY: build-npm
-build-npm: build-extension-types copy-extension-themes src/extensions/npm/extensions/__mocks__
+build-npm: build-extension-types src/extensions/npm/extensions/__mocks__
yarn npm:fix-package-version
.PHONY: build-extension-types
@@ -129,7 +128,6 @@ clean: clean-npm clean-extensions
rm -rf binaries/client
rm -rf dist
rm -rf static/build
- rm -rf build/tray
rm -rf node_modules
rm -rf site
rm -rf docs/extensions/api
diff --git a/README.md b/README.md
index 595def597b..cb9f44b35d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Lens Open Source Project (OpenLens)
[](https://github.com/lensapp/lens/actions/workflows/test.yml)
-[](https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI)
+[](https://join.slack.com/t/k8slens/shared_invite/zt-198iepl92-EPJsCckkJ~f887vWqJcgGA)
## The Repository
diff --git a/__mocks__/@sentry/electron/main.ts b/__mocks__/@sentry/electron/main.ts
new file mode 100644
index 0000000000..cbe02cb296
--- /dev/null
+++ b/__mocks__/@sentry/electron/main.ts
@@ -0,0 +1,5 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+export default {};
diff --git a/__mocks__/@sentry/electron/renderer.ts b/__mocks__/@sentry/electron/renderer.ts
new file mode 100644
index 0000000000..cbe02cb296
--- /dev/null
+++ b/__mocks__/@sentry/electron/renderer.ts
@@ -0,0 +1,5 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+export default {};
diff --git a/build/build_theme_vars.ts b/build/build_theme_vars.ts
index 44376712a7..dbade45847 100644
--- a/build/build_theme_vars.ts
+++ b/build/build_theme_vars.ts
@@ -5,11 +5,11 @@
import fs from "fs-extra";
import path from "path";
-import defaultBaseLensTheme from "../src/renderer/themes/lens-dark.json";
+import defaultBaseLensTheme from "../src/renderer/themes/lens-dark";
const outputCssFile = path.resolve("src/renderer/themes/theme-vars.css");
-const banner = `/*
+const banner = `/*
Generated Lens theme CSS-variables, don't edit manually.
To refresh file run $: yarn run ts-node build/${path.basename(__filename)}
*/`;
diff --git a/build/download_binaries.ts b/build/download_binaries.ts
index 73c9dff175..5b4f960c5e 100644
--- a/build/download_binaries.ts
+++ b/build/download_binaries.ts
@@ -3,9 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import packageInfo from "../package.json";
-import { type WriteStream } from "fs";
import type { FileHandle } from "fs/promises";
import { open } from "fs/promises";
+import type { WriteStream } from "fs-extra";
import { constants, ensureDir, unlink } from "fs-extra";
import path from "path";
import fetch from "node-fetch";
@@ -17,6 +17,7 @@ import AbortController from "abort-controller";
import { extract } from "tar-stream";
import gunzip from "gunzip-maybe";
import { getBinaryName, normalizedPlatform } from "../src/common/vars";
+import { isErrnoException } from "../src/common/utils";
const pipeline = promisify(_pipeline);
@@ -44,6 +45,10 @@ abstract class BinaryDownloader {
}
async ensureBinary(): Promise {
+ if (process.env.LENS_SKIP_DOWNLOAD_BINARIES === "true") {
+ return;
+ }
+
const controller = new AbortController();
const stream = await fetch(this.url, {
timeout: 15 * 60 * 1000, // 15min
@@ -51,7 +56,7 @@ abstract class BinaryDownloader {
});
const total = Number(stream.headers.get("content-length"));
const bar = this.bar;
- let fileHandle: FileHandle;
+ let fileHandle: FileHandle | undefined = undefined;
if (isNaN(total)) {
throw new Error("no content-length header was present");
@@ -66,7 +71,7 @@ abstract class BinaryDownloader {
* This is necessary because for some reason `createWriteStream({ flags: "wx" })`
* was throwing someplace else and not here
*/
- fileHandle = await open(this.target, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
+ const handle = fileHandle = await open(this.target, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
await pipeline(
stream.body,
@@ -79,7 +84,7 @@ abstract class BinaryDownloader {
}),
...this.getTransformStreams(new Writable({
write(chunk, encoding, cb) {
- fileHandle.write(chunk)
+ handle.write(chunk)
.then(() => cb())
.catch(cb);
},
@@ -90,7 +95,7 @@ abstract class BinaryDownloader {
} catch (error) {
await fileHandle?.close();
- if (error.code === "EEXIST") {
+ if (isErrnoException(error) && error.code === "EEXIST") {
bar.increment(total); // mark as finished
controller.abort(); // stop trying to download
} else {
diff --git a/build/generate-tray-icons.ts b/build/generate-tray-icons.ts
index c09ab6320d..a7ab3bd48b 100644
--- a/build/generate-tray-icons.ts
+++ b/build/generate-tray-icons.ts
@@ -28,23 +28,23 @@ console.log("Generating tray icon pngs");
ensureDirSync(outputFolder);
-Promise.allSettled([
- sharp(Buffer.from(darkTemplate))
+Promise.all([
+ sharp(Buffer.from(lightTemplate))
.resize({ width: size, height: size })
.png()
.toFile(path.join(outputFolder, "trayIconDarkTemplate.png")),
- sharp(Buffer.from(darkTemplate))
+ sharp(Buffer.from(lightTemplate))
.resize({ width: size*2, height: size*2 })
.png()
.toFile(path.join(outputFolder, "trayIconDarkTemplate@2x.png")),
- sharp(Buffer.from(lightTemplate))
+ sharp(Buffer.from(darkTemplate))
.resize({ width: size, height: size })
.png()
.toFile(path.join(outputFolder, "trayIconTemplate.png")),
- sharp(Buffer.from(lightTemplate))
+ sharp(Buffer.from(darkTemplate))
.resize({ width: size*2, height: size*2 })
.png()
.toFile(path.join(outputFolder, "trayIconTemplate@2x.png")),
])
- .then(console.log)
+ .then((resolutions) => console.log(`Generated ${resolutions.length} images`))
.catch(console.error);
diff --git a/build/tray/trayIconDarkTemplate.png b/build/tray/trayIconDarkTemplate.png
new file mode 100644
index 0000000000..63f2eb1895
Binary files /dev/null and b/build/tray/trayIconDarkTemplate.png differ
diff --git a/build/tray/trayIconDarkTemplate@2x.png b/build/tray/trayIconDarkTemplate@2x.png
new file mode 100644
index 0000000000..c5dcfa9e15
Binary files /dev/null and b/build/tray/trayIconDarkTemplate@2x.png differ
diff --git a/build/tray/trayIconTemplate.png b/build/tray/trayIconTemplate.png
new file mode 100644
index 0000000000..0e1c5d6e8e
Binary files /dev/null and b/build/tray/trayIconTemplate.png differ
diff --git a/build/tray/trayIconTemplate@2x.png b/build/tray/trayIconTemplate@2x.png
new file mode 100644
index 0000000000..553a8ec373
Binary files /dev/null and b/build/tray/trayIconTemplate@2x.png differ
diff --git a/build/tsconfig.json b/build/tsconfig.json
new file mode 100644
index 0000000000..7c6e822d2c
--- /dev/null
+++ b/build/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../tsconfig.json",
+ "include": [
+ "./**/*",
+ ]
+}
diff --git a/docs/extensions/get-started/anatomy.md b/docs/extensions/get-started/anatomy.md
index 481c18ac2c..8cfcd57076 100644
--- a/docs/extensions/get-started/anatomy.md
+++ b/docs/extensions/get-started/anatomy.md
@@ -79,7 +79,7 @@ Some of the most-important fields include:
}
```
-## Webpack configuation
+## Webpack configuration
The following webpack `externals` are provided by `Lens` and must be used (when available) to make sure that the versions used are in sync.
diff --git a/docs/extensions/guides/renderer-extension.md b/docs/extensions/guides/renderer-extension.md
index 5d41dff89d..d90a343692 100644
--- a/docs/extensions/guides/renderer-extension.md
+++ b/docs/extensions/guides/renderer-extension.md
@@ -224,7 +224,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
{
id: "bonjour",
components: {
- Page: () => ,
+ Page: () => ,
},
},
];
@@ -250,7 +250,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
target: { pageId: "bonjour" },
title: "Bonjour le monde",
components: {
- Icon: ExempleIcon,
+ Icon: ExampleIcon,
},
},
];
diff --git a/extensions/kube-object-event-status/package-lock.json b/extensions/kube-object-event-status/package-lock.json
deleted file mode 100644
index 0a541e307a..0000000000
--- a/extensions/kube-object-event-status/package-lock.json
+++ /dev/null
@@ -1,2374 +0,0 @@
-{
- "name": "kube-object-event-status",
- "version": "0.0.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@k8slens/extensions": {
- "version": "file:../../src/extensions/npm/extensions",
- "dev": true,
- "requires": {
- "@material-ui/core": "4.12.3",
- "@types/node": "14.17.14",
- "@types/react-select": "3.1.2",
- "conf": "^7.0.1",
- "typed-emitter": "^1.3.1"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.3",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
- "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@emotion/hash": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
- "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
- "dev": true
- },
- "@material-ui/core": {
- "version": "4.12.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
- "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.11.4",
- "@material-ui/system": "^4.12.1",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "@types/react-transition-group": "^4.2.0",
- "clsx": "^1.0.4",
- "hoist-non-react-statics": "^3.3.2",
- "popper.js": "1.16.1-lts",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0",
- "react-transition-group": "^4.4.0"
- }
- },
- "@material-ui/styles": {
- "version": "4.11.4",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
- "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@emotion/hash": "^0.8.0",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "clsx": "^1.0.4",
- "csstype": "^2.5.2",
- "hoist-non-react-statics": "^3.3.2",
- "jss": "^10.5.1",
- "jss-plugin-camel-case": "^10.5.1",
- "jss-plugin-default-unit": "^10.5.1",
- "jss-plugin-global": "^10.5.1",
- "jss-plugin-nested": "^10.5.1",
- "jss-plugin-props-sort": "^10.5.1",
- "jss-plugin-rule-value-function": "^10.5.1",
- "jss-plugin-vendor-prefixer": "^10.5.1",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/system": {
- "version": "4.12.1",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
- "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/utils": "^4.11.2",
- "csstype": "^2.5.2",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/types": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
- "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
- "dev": true
- },
- "@material-ui/utils": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
- "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0"
- }
- },
- "@types/node": {
- "version": "14.17.14",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.14.tgz",
- "integrity": "sha512-rsAj2u8Xkqfc332iXV12SqIsjVi07H479bOP4q94NAcjzmAvapumEhuVIt53koEf7JFrpjgNKjBga5Pnn/GL8A==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.4",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
- "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
- "dev": true
- },
- "@types/react": {
- "version": "17.0.35",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.35.tgz",
- "integrity": "sha512-r3C8/TJuri/SLZiiwwxQoLAoavaczARfT9up9b4Jr65+ErAUX3MIkU0oMOQnrpfgHme8zIqZLX7O5nnjm5Wayw==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "@types/react-dom": {
- "version": "17.0.11",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
- "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-select": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.2.tgz",
- "integrity": "sha512-ygvR/2FL87R2OLObEWFootYzkvm67LRA+URYEAcBuvKk7IXmdsnIwSGm60cVXGaqkJQHozb2Cy1t94tCYb6rJA==",
- "dev": true,
- "requires": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "@types/react-transition-group": "*"
- }
- },
- "@types/react-transition-group": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
- "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
- "dev": true
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "atomically": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
- "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
- "dev": true
- },
- "clsx": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
- "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
- "dev": true
- },
- "conf": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
- "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.2",
- "atomically": "^1.3.1",
- "debounce-fn": "^4.0.0",
- "dot-prop": "^5.2.0",
- "env-paths": "^2.2.0",
- "json-schema-typed": "^7.0.3",
- "make-dir": "^3.1.0",
- "onetime": "^5.1.0",
- "pkg-up": "^3.1.0",
- "semver": "^7.3.2"
- }
- },
- "css-vendor": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
- "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.3",
- "is-in-browser": "^1.0.2"
- }
- },
- "csstype": {
- "version": "2.6.18",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
- "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
- "dev": true
- },
- "debounce-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
- "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^3.0.0"
- }
- },
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "dev": true,
- "requires": {
- "is-obj": "^2.0.0"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
- "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dev": true,
- "requires": {
- "react-is": "^16.7.0"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "hyphenate-style-name": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
- "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
- "dev": true
- },
- "is-in-browser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
- "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
- "dev": true
- },
- "is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-schema-typed": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
- "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
- "dev": true
- },
- "jss": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz",
- "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "csstype": "^3.0.2",
- "is-in-browser": "^1.1.3",
- "tiny-warning": "^1.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "jss-plugin-camel-case": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz",
- "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "hyphenate-style-name": "^1.0.3",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-default-unit": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz",
- "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-global": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz",
- "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-nested": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz",
- "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-props-sort": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz",
- "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-rule-value-function": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz",
- "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-vendor-prefixer": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz",
- "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "css-vendor": "^2.0.8",
- "jss": "10.8.2"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- }
- }
- },
- "mimic-fn": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
- "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- },
- "dependencies": {
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- }
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
- "dev": true
- },
- "pkg-up": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
- "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0"
- }
- },
- "popper.js": {
- "version": "1.16.1-lts",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
- "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
- "dev": true
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "react-transition-group": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
- "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
- "dev": true
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
- "dev": true
- },
- "typed-emitter": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
- "integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
- "dev": true
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "npm": {
- "version": "8.5.3",
- "resolved": "https://registry.npmjs.org/npm/-/npm-8.5.3.tgz",
- "integrity": "sha512-O+1j66Alx7ZQgWnUSSTaz8rTqQrJnqNb8Num5uQw2vYvc2RrxLaX7cWtRkDhvkPIL8Nf2WU9gx1oSu268QConA==",
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/config": "^4.0.1",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.1",
- "abbrev": "~1.1.1",
- "ansicolors": "~0.3.2",
- "ansistyles": "~0.1.3",
- "archy": "~1.0.0",
- "cacache": "^15.3.0",
- "chalk": "^4.1.2",
- "chownr": "^2.0.0",
- "cli-columns": "^4.0.0",
- "cli-table3": "^0.6.1",
- "columnify": "^1.6.0",
- "fastest-levenshtein": "^1.0.12",
- "glob": "^7.2.0",
- "graceful-fs": "^4.2.9",
- "hosted-git-info": "^4.1.0",
- "ini": "^2.0.0",
- "init-package-json": "^3.0.0",
- "is-cidr": "^4.0.2",
- "json-parse-even-better-errors": "^2.3.1",
- "libnpmaccess": "^6.0.0",
- "libnpmdiff": "^4.0.0",
- "libnpmexec": "^4.0.0",
- "libnpmfund": "^3.0.0",
- "libnpmhook": "^8.0.0",
- "libnpmorg": "^4.0.0",
- "libnpmpack": "^4.0.0",
- "libnpmpublish": "^6.0.0",
- "libnpmsearch": "^5.0.0",
- "libnpmteam": "^4.0.0",
- "libnpmversion": "^3.0.0",
- "make-fetch-happen": "^10.0.4",
- "minipass": "^3.1.6",
- "minipass-pipeline": "^1.2.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "ms": "^2.1.2",
- "node-gyp": "^9.0.0",
- "nopt": "^5.0.0",
- "npm-audit-report": "^2.1.5",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-profile": "^6.0.2",
- "npm-registry-fetch": "^13.0.1",
- "npm-user-validate": "^1.0.1",
- "npmlog": "^6.0.1",
- "opener": "^1.5.2",
- "pacote": "^13.0.3",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "qrcode-terminal": "^0.12.0",
- "read": "~1.0.7",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "tar": "^6.1.11",
- "text-table": "~0.2.0",
- "tiny-relative-date": "^1.3.0",
- "treeverse": "^1.0.4",
- "validate-npm-package-name": "~3.0.0",
- "which": "^2.0.2",
- "write-file-atomic": "^4.0.1"
- },
- "dependencies": {
- "@gar/promisify": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "@isaacs/string-locale-compare": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/arborist": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/metavuln-calculator": "^3.0.0",
- "@npmcli/move-file": "^1.1.0",
- "@npmcli/name-from-folder": "^1.0.1",
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.0",
- "bin-links": "^3.0.0",
- "cacache": "^15.0.3",
- "common-ancestor-path": "^1.0.1",
- "json-parse-even-better-errors": "^2.3.1",
- "json-stringify-nice": "^1.1.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "promise-all-reject-late": "^1.0.0",
- "promise-call-limit": "^1.0.1",
- "read-package-json-fast": "^2.0.2",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "treeverse": "^1.0.4",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/ci-detect": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/config": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/map-workspaces": "^2.0.1",
- "ini": "^2.0.0",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "proc-log": "^2.0.0",
- "read-package-json-fast": "^2.0.3",
- "semver": "^7.3.5",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/disparity-colors": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.3.0"
- }
- },
- "@npmcli/fs": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@gar/promisify": "^1.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/git": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/promise-spawn": "^1.3.2",
- "lru-cache": "^7.3.1",
- "mkdirp": "^1.0.4",
- "npm-pick-manifest": "^7.0.0",
- "proc-log": "^2.0.0",
- "promise-inflight": "^1.0.1",
- "promise-retry": "^2.0.1",
- "semver": "^7.3.5",
- "which": "^2.0.2"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "@npmcli/installed-package-contents": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "@npmcli/map-workspaces": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/name-from-folder": "^1.0.1",
- "glob": "^7.2.0",
- "minimatch": "^5.0.0",
- "read-package-json-fast": "^2.0.3"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
- "@npmcli/metavuln-calculator": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cacache": "^15.3.0",
- "json-parse-even-better-errors": "^2.3.1",
- "pacote": "^13.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/move-file": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp": "^1.0.4",
- "rimraf": "^3.0.2"
- }
- },
- "@npmcli/name-from-folder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "@npmcli/node-gyp": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "@npmcli/package-json": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1"
- }
- },
- "@npmcli/promise-spawn": {
- "version": "1.3.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "infer-owner": "^1.0.4"
- }
- },
- "@npmcli/run-script": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/promise-spawn": "^1.3.2",
- "node-gyp": "^9.0.0",
- "read-package-json-fast": "^2.0.3"
- }
- },
- "@tootallnate/once": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "abbrev": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "agent-base": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "4"
- }
- },
- "agentkeepalive": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "^4.1.0",
- "depd": "^1.1.2",
- "humanize-ms": "^1.2.1"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "ansicolors": {
- "version": "0.3.2",
- "bundled": true,
- "dev": true
- },
- "ansistyles": {
- "version": "0.1.3",
- "bundled": true,
- "dev": true
- },
- "aproba": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "archy": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "are-we-there-yet": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^3.6.0"
- }
- },
- "asap": {
- "version": "2.0.6",
- "bundled": true,
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "bin-links": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cmd-shim": "^4.0.1",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-normalize-package-bin": "^1.0.0",
- "read-cmd-shim": "^2.0.0",
- "rimraf": "^3.0.0",
- "write-file-atomic": "^4.0.0"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "builtins": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "cacache": {
- "version": "15.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/fs": "^1.0.0",
- "@npmcli/move-file": "^1.0.1",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "glob": "^7.1.4",
- "infer-owner": "^1.0.4",
- "lru-cache": "^6.0.0",
- "minipass": "^3.1.1",
- "minipass-collect": "^1.0.2",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.2",
- "mkdirp": "^1.0.3",
- "p-map": "^4.0.0",
- "promise-inflight": "^1.0.1",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.0.2",
- "unique-filename": "^1.1.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "chownr": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "cidr-regex": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip-regex": "^4.1.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "cli-columns": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "cli-table3": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "colors": "1.4.0",
- "string-width": "^4.2.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "cmd-shim": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp-infer-owner": "^2.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "color-support": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "colors": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "columnify": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "strip-ansi": "^6.0.1",
- "wcwidth": "^1.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "common-ancestor-path": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "debug": {
- "version": "4.3.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true
- }
- }
- },
- "debuglog": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "defaults": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "depd": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true
- },
- "dezalgo": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "diff": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true
- },
- "encoding": {
- "version": "0.1.13",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "iconv-lite": "^0.6.2"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "bundled": true,
- "dev": true
- },
- "err-code": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true
- },
- "fastest-levenshtein": {
- "version": "1.0.12",
- "bundled": true,
- "dev": true
- },
- "fs-minipass": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "function-bind": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "gauge": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1",
- "aproba": "^1.0.3 || ^2.0.0",
- "color-support": "^1.1.3",
- "console-control-strings": "^1.1.0",
- "has-unicode": "^2.0.1",
- "signal-exit": "^3.0.7",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "wide-align": "^1.1.5"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "glob": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.9",
- "bundled": true,
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true
- },
- "hosted-git-info": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "http-cache-semantics": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "http-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "https-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "humanize-ms": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "^2.0.0"
- }
- },
- "iconv-lite": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- },
- "ignore-walk": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimatch": "^3.0.4"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "bundled": true,
- "dev": true
- },
- "indent-string": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "infer-owner": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "bundled": true,
- "dev": true
- },
- "ini": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "init-package-json": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-package-arg": "^9.0.0",
- "promzard": "^0.3.0",
- "read": "^1.0.7",
- "read-package-json": "^4.1.1",
- "semver": "^7.3.5",
- "validate-npm-package-license": "^3.0.4",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "ip": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true
- },
- "ip-regex": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true
- },
- "is-cidr": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "cidr-regex": "^3.1.1"
- }
- },
- "is-core-module": {
- "version": "2.8.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "is-lambda": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "bundled": true,
- "dev": true
- },
- "json-stringify-nice": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "jsonparse": {
- "version": "1.3.1",
- "bundled": true,
- "dev": true
- },
- "just-diff": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "just-diff-apply": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true
- },
- "libnpmaccess": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "minipass": "^3.1.1",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmdiff": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/disparity-colors": "^1.0.1",
- "@npmcli/installed-package-contents": "^1.0.7",
- "binary-extensions": "^2.2.0",
- "diff": "^5.0.0",
- "minimatch": "^3.0.4",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2",
- "tar": "^6.1.0"
- }
- },
- "libnpmexec": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/run-script": "^3.0.0",
- "chalk": "^4.1.0",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-package-arg": "^9.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "proc-log": "^2.0.0",
- "read": "^1.0.7",
- "read-package-json-fast": "^2.0.2",
- "walk-up-path": "^1.0.0"
- }
- },
- "libnpmfund": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0"
- }
- },
- "libnpmhook": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmorg": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmpack": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/run-script": "^3.0.0",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2"
- }
- },
- "libnpmpublish": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "normalize-package-data": "^3.0.2",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0",
- "semver": "^7.1.3",
- "ssri": "^8.0.1"
- }
- },
- "libnpmsearch": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmteam": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmversion": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/run-script": "^3.0.0",
- "json-parse-even-better-errors": "^2.3.1",
- "proc-log": "^2.0.0",
- "semver": "^7.3.5",
- "stringify-package": "^1.0.1"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-fetch-happen": {
- "version": "10.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "agentkeepalive": "^4.2.1",
- "cacache": "^15.3.0",
- "http-cache-semantics": "^4.1.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.0",
- "is-lambda": "^1.0.1",
- "lru-cache": "^7.4.0",
- "minipass": "^3.1.6",
- "minipass-collect": "^1.0.2",
- "minipass-fetch": "^2.0.1",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.4",
- "negotiator": "^0.6.3",
- "promise-retry": "^2.0.1",
- "socks-proxy-agent": "^6.1.1",
- "ssri": "^8.0.1"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minipass": {
- "version": "3.1.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "minipass-collect": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-fetch": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "encoding": "^0.1.13",
- "minipass": "^3.1.6",
- "minipass-sized": "^1.0.3",
- "minizlib": "^2.1.2"
- }
- },
- "minipass-flush": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-json-stream": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "jsonparse": "^1.3.1",
- "minipass": "^3.0.0"
- }
- },
- "minipass-pipeline": {
- "version": "1.2.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-sized": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "mkdirp-infer-owner": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "infer-owner": "^1.0.4",
- "mkdirp": "^1.0.3"
- }
- },
- "ms": {
- "version": "2.1.3",
- "bundled": true,
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true
- },
- "negotiator": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true
- },
- "node-gyp": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "env-paths": "^2.2.0",
- "glob": "^7.1.4",
- "graceful-fs": "^4.2.6",
- "make-fetch-happen": "^10.0.3",
- "nopt": "^5.0.0",
- "npmlog": "^6.0.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "tar": "^6.1.2",
- "which": "^2.0.2"
- }
- },
- "nopt": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-package-data": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "npm-audit-report": {
- "version": "2.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "npm-bundled": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-install-checks": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "semver": "^7.1.1"
- }
- },
- "npm-normalize-package-bin": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npm-package-arg": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.1.0",
- "semver": "^7.3.5",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "npm-packlist": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.6",
- "ignore-walk": "^4.0.1",
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-pick-manifest": {
- "version": "7.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-install-checks": "^4.0.0",
- "npm-normalize-package-bin": "^1.0.1",
- "npm-package-arg": "^9.0.0",
- "semver": "^7.3.5"
- }
- },
- "npm-profile": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-registry-fetch": {
- "version": "13.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "make-fetch-happen": "^10.0.3",
- "minipass": "^3.1.6",
- "minipass-fetch": "^2.0.1",
- "minipass-json-stream": "^1.0.1",
- "minizlib": "^2.1.2",
- "npm-package-arg": "^9.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-user-validate": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npmlog": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "are-we-there-yet": "^3.0.0",
- "console-control-strings": "^1.1.0",
- "gauge": "^4.0.0",
- "set-blocking": "^2.0.0"
- }
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "opener": {
- "version": "1.5.2",
- "bundled": true,
- "dev": true
- },
- "p-map": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "pacote": {
- "version": "13.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/promise-spawn": "^1.2.0",
- "@npmcli/run-script": "^3.0.0",
- "cacache": "^15.3.0",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.1.0",
- "infer-owner": "^1.0.4",
- "minipass": "^3.1.6",
- "mkdirp": "^1.0.4",
- "npm-package-arg": "^9.0.0",
- "npm-packlist": "^3.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0",
- "promise-retry": "^2.0.1",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.1.11"
- }
- },
- "parse-conflict-json": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1",
- "just-diff": "^5.0.1",
- "just-diff-apply": "^4.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "proc-log": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "promise-all-reject-late": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-call-limit": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-inflight": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-retry": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "err-code": "^2.0.2",
- "retry": "^0.12.0"
- }
- },
- "promzard": {
- "version": "0.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "read": "1"
- }
- },
- "qrcode-terminal": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "read": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "mute-stream": "~0.0.4"
- }
- },
- "read-cmd-shim": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "read-package-json": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.1",
- "json-parse-even-better-errors": "^2.3.0",
- "normalize-package-data": "^3.0.0",
- "npm-normalize-package-bin": "^1.0.0"
- }
- },
- "read-package-json-fast": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.0",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "readable-stream": {
- "version": "3.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "readdir-scoped-modules": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "debuglog": "^1.0.1",
- "dezalgo": "^1.0.0",
- "graceful-fs": "^4.1.2",
- "once": "^1.3.0"
- }
- },
- "retry": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "bundled": true,
- "dev": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "semver": {
- "version": "7.3.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.7",
- "bundled": true,
- "dev": true
- },
- "smart-buffer": {
- "version": "4.2.0",
- "bundled": true,
- "dev": true
- },
- "socks": {
- "version": "2.6.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip": "^1.1.5",
- "smart-buffer": "^4.2.0"
- }
- },
- "socks-proxy-agent": {
- "version": "6.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "^6.0.2",
- "debug": "^4.3.1",
- "socks": "^2.6.1"
- }
- },
- "spdx-correct": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true
- },
- "spdx-expression-parse": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.11",
- "bundled": true,
- "dev": true
- },
- "ssri": {
- "version": "8.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.1.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "string_decoder": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
- "stringify-package": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "tar": {
- "version": "6.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^3.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true
- },
- "tiny-relative-date": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true
- },
- "treeverse": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "unique-filename": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "unique-slug": "^2.0.0"
- }
- },
- "unique-slug": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "validate-npm-package-name": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "builtins": "^1.0.3"
- }
- },
- "walk-up-path": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "wcwidth": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
- "which": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "wide-align": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2 || 3 || 4"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "write-file-atomic": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- }
- }
- }
- }
-}
diff --git a/extensions/metrics-cluster-feature/package-lock.json b/extensions/metrics-cluster-feature/package-lock.json
deleted file mode 100644
index 7025687b2b..0000000000
--- a/extensions/metrics-cluster-feature/package-lock.json
+++ /dev/null
@@ -1,2380 +0,0 @@
-{
- "name": "lens-metrics-cluster-feature",
- "version": "0.0.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@k8slens/extensions": {
- "version": "file:../../src/extensions/npm/extensions",
- "dev": true,
- "requires": {
- "@material-ui/core": "4.12.3",
- "@types/node": "14.17.14",
- "@types/react-select": "3.1.2",
- "conf": "^7.0.1",
- "typed-emitter": "^1.3.1"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.3",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
- "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@emotion/hash": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
- "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
- "dev": true
- },
- "@material-ui/core": {
- "version": "4.12.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
- "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.11.4",
- "@material-ui/system": "^4.12.1",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "@types/react-transition-group": "^4.2.0",
- "clsx": "^1.0.4",
- "hoist-non-react-statics": "^3.3.2",
- "popper.js": "1.16.1-lts",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0",
- "react-transition-group": "^4.4.0"
- }
- },
- "@material-ui/styles": {
- "version": "4.11.4",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
- "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@emotion/hash": "^0.8.0",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "clsx": "^1.0.4",
- "csstype": "^2.5.2",
- "hoist-non-react-statics": "^3.3.2",
- "jss": "^10.5.1",
- "jss-plugin-camel-case": "^10.5.1",
- "jss-plugin-default-unit": "^10.5.1",
- "jss-plugin-global": "^10.5.1",
- "jss-plugin-nested": "^10.5.1",
- "jss-plugin-props-sort": "^10.5.1",
- "jss-plugin-rule-value-function": "^10.5.1",
- "jss-plugin-vendor-prefixer": "^10.5.1",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/system": {
- "version": "4.12.1",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
- "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/utils": "^4.11.2",
- "csstype": "^2.5.2",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/types": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
- "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
- "dev": true
- },
- "@material-ui/utils": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
- "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0"
- }
- },
- "@types/node": {
- "version": "14.17.14",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.14.tgz",
- "integrity": "sha512-rsAj2u8Xkqfc332iXV12SqIsjVi07H479bOP4q94NAcjzmAvapumEhuVIt53koEf7JFrpjgNKjBga5Pnn/GL8A==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.4",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
- "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
- "dev": true
- },
- "@types/react": {
- "version": "17.0.35",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.35.tgz",
- "integrity": "sha512-r3C8/TJuri/SLZiiwwxQoLAoavaczARfT9up9b4Jr65+ErAUX3MIkU0oMOQnrpfgHme8zIqZLX7O5nnjm5Wayw==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "@types/react-dom": {
- "version": "17.0.11",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
- "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-select": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.2.tgz",
- "integrity": "sha512-ygvR/2FL87R2OLObEWFootYzkvm67LRA+URYEAcBuvKk7IXmdsnIwSGm60cVXGaqkJQHozb2Cy1t94tCYb6rJA==",
- "dev": true,
- "requires": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "@types/react-transition-group": "*"
- }
- },
- "@types/react-transition-group": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
- "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
- "dev": true
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "atomically": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
- "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
- "dev": true
- },
- "clsx": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
- "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
- "dev": true
- },
- "conf": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
- "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.2",
- "atomically": "^1.3.1",
- "debounce-fn": "^4.0.0",
- "dot-prop": "^5.2.0",
- "env-paths": "^2.2.0",
- "json-schema-typed": "^7.0.3",
- "make-dir": "^3.1.0",
- "onetime": "^5.1.0",
- "pkg-up": "^3.1.0",
- "semver": "^7.3.2"
- }
- },
- "css-vendor": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
- "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.3",
- "is-in-browser": "^1.0.2"
- }
- },
- "csstype": {
- "version": "2.6.18",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
- "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
- "dev": true
- },
- "debounce-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
- "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^3.0.0"
- }
- },
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "dev": true,
- "requires": {
- "is-obj": "^2.0.0"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
- "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dev": true,
- "requires": {
- "react-is": "^16.7.0"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "hyphenate-style-name": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
- "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
- "dev": true
- },
- "is-in-browser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
- "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
- "dev": true
- },
- "is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-schema-typed": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
- "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
- "dev": true
- },
- "jss": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz",
- "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "csstype": "^3.0.2",
- "is-in-browser": "^1.1.3",
- "tiny-warning": "^1.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "jss-plugin-camel-case": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz",
- "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "hyphenate-style-name": "^1.0.3",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-default-unit": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz",
- "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-global": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz",
- "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-nested": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz",
- "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-props-sort": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz",
- "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-rule-value-function": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz",
- "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-vendor-prefixer": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz",
- "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "css-vendor": "^2.0.8",
- "jss": "10.8.2"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- }
- }
- },
- "mimic-fn": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
- "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- },
- "dependencies": {
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- }
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
- "dev": true
- },
- "pkg-up": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
- "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0"
- }
- },
- "popper.js": {
- "version": "1.16.1-lts",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
- "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
- "dev": true
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "react-transition-group": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
- "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
- "dev": true
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
- "dev": true
- },
- "typed-emitter": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
- "integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
- "dev": true
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "npm": {
- "version": "8.5.3",
- "resolved": "https://registry.npmjs.org/npm/-/npm-8.5.3.tgz",
- "integrity": "sha512-O+1j66Alx7ZQgWnUSSTaz8rTqQrJnqNb8Num5uQw2vYvc2RrxLaX7cWtRkDhvkPIL8Nf2WU9gx1oSu268QConA==",
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/config": "^4.0.1",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.1",
- "abbrev": "~1.1.1",
- "ansicolors": "~0.3.2",
- "ansistyles": "~0.1.3",
- "archy": "~1.0.0",
- "cacache": "^15.3.0",
- "chalk": "^4.1.2",
- "chownr": "^2.0.0",
- "cli-columns": "^4.0.0",
- "cli-table3": "^0.6.1",
- "columnify": "^1.6.0",
- "fastest-levenshtein": "^1.0.12",
- "glob": "^7.2.0",
- "graceful-fs": "^4.2.9",
- "hosted-git-info": "^4.1.0",
- "ini": "^2.0.0",
- "init-package-json": "^3.0.0",
- "is-cidr": "^4.0.2",
- "json-parse-even-better-errors": "^2.3.1",
- "libnpmaccess": "^6.0.0",
- "libnpmdiff": "^4.0.0",
- "libnpmexec": "^4.0.0",
- "libnpmfund": "^3.0.0",
- "libnpmhook": "^8.0.0",
- "libnpmorg": "^4.0.0",
- "libnpmpack": "^4.0.0",
- "libnpmpublish": "^6.0.0",
- "libnpmsearch": "^5.0.0",
- "libnpmteam": "^4.0.0",
- "libnpmversion": "^3.0.0",
- "make-fetch-happen": "^10.0.4",
- "minipass": "^3.1.6",
- "minipass-pipeline": "^1.2.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "ms": "^2.1.2",
- "node-gyp": "^9.0.0",
- "nopt": "^5.0.0",
- "npm-audit-report": "^2.1.5",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-profile": "^6.0.2",
- "npm-registry-fetch": "^13.0.1",
- "npm-user-validate": "^1.0.1",
- "npmlog": "^6.0.1",
- "opener": "^1.5.2",
- "pacote": "^13.0.3",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "qrcode-terminal": "^0.12.0",
- "read": "~1.0.7",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "tar": "^6.1.11",
- "text-table": "~0.2.0",
- "tiny-relative-date": "^1.3.0",
- "treeverse": "^1.0.4",
- "validate-npm-package-name": "~3.0.0",
- "which": "^2.0.2",
- "write-file-atomic": "^4.0.1"
- },
- "dependencies": {
- "@gar/promisify": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "@isaacs/string-locale-compare": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/arborist": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/metavuln-calculator": "^3.0.0",
- "@npmcli/move-file": "^1.1.0",
- "@npmcli/name-from-folder": "^1.0.1",
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.0",
- "bin-links": "^3.0.0",
- "cacache": "^15.0.3",
- "common-ancestor-path": "^1.0.1",
- "json-parse-even-better-errors": "^2.3.1",
- "json-stringify-nice": "^1.1.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "promise-all-reject-late": "^1.0.0",
- "promise-call-limit": "^1.0.1",
- "read-package-json-fast": "^2.0.2",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "treeverse": "^1.0.4",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/ci-detect": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/config": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/map-workspaces": "^2.0.1",
- "ini": "^2.0.0",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "proc-log": "^2.0.0",
- "read-package-json-fast": "^2.0.3",
- "semver": "^7.3.5",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/disparity-colors": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.3.0"
- }
- },
- "@npmcli/fs": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@gar/promisify": "^1.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/git": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/promise-spawn": "^1.3.2",
- "lru-cache": "^7.3.1",
- "mkdirp": "^1.0.4",
- "npm-pick-manifest": "^7.0.0",
- "proc-log": "^2.0.0",
- "promise-inflight": "^1.0.1",
- "promise-retry": "^2.0.1",
- "semver": "^7.3.5",
- "which": "^2.0.2"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "@npmcli/installed-package-contents": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "@npmcli/map-workspaces": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/name-from-folder": "^1.0.1",
- "glob": "^7.2.0",
- "minimatch": "^5.0.0",
- "read-package-json-fast": "^2.0.3"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
- "@npmcli/metavuln-calculator": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cacache": "^15.3.0",
- "json-parse-even-better-errors": "^2.3.1",
- "pacote": "^13.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/move-file": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp": "^1.0.4",
- "rimraf": "^3.0.2"
- }
- },
- "@npmcli/name-from-folder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "@npmcli/node-gyp": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "@npmcli/package-json": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1"
- }
- },
- "@npmcli/promise-spawn": {
- "version": "1.3.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "infer-owner": "^1.0.4"
- }
- },
- "@npmcli/run-script": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/promise-spawn": "^1.3.2",
- "node-gyp": "^9.0.0",
- "read-package-json-fast": "^2.0.3"
- }
- },
- "@tootallnate/once": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "abbrev": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "agent-base": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "4"
- }
- },
- "agentkeepalive": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "^4.1.0",
- "depd": "^1.1.2",
- "humanize-ms": "^1.2.1"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "ansicolors": {
- "version": "0.3.2",
- "bundled": true,
- "dev": true
- },
- "ansistyles": {
- "version": "0.1.3",
- "bundled": true,
- "dev": true
- },
- "aproba": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "archy": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "are-we-there-yet": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^3.6.0"
- }
- },
- "asap": {
- "version": "2.0.6",
- "bundled": true,
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "bin-links": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cmd-shim": "^4.0.1",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-normalize-package-bin": "^1.0.0",
- "read-cmd-shim": "^2.0.0",
- "rimraf": "^3.0.0",
- "write-file-atomic": "^4.0.0"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "builtins": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "cacache": {
- "version": "15.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/fs": "^1.0.0",
- "@npmcli/move-file": "^1.0.1",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "glob": "^7.1.4",
- "infer-owner": "^1.0.4",
- "lru-cache": "^6.0.0",
- "minipass": "^3.1.1",
- "minipass-collect": "^1.0.2",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.2",
- "mkdirp": "^1.0.3",
- "p-map": "^4.0.0",
- "promise-inflight": "^1.0.1",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.0.2",
- "unique-filename": "^1.1.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "chownr": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "cidr-regex": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip-regex": "^4.1.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "cli-columns": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "cli-table3": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "colors": "1.4.0",
- "string-width": "^4.2.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "cmd-shim": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp-infer-owner": "^2.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "color-support": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "colors": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "columnify": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "strip-ansi": "^6.0.1",
- "wcwidth": "^1.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "common-ancestor-path": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "debug": {
- "version": "4.3.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true
- }
- }
- },
- "debuglog": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "defaults": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "depd": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true
- },
- "dezalgo": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "diff": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true
- },
- "encoding": {
- "version": "0.1.13",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "iconv-lite": "^0.6.2"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "bundled": true,
- "dev": true
- },
- "err-code": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true
- },
- "fastest-levenshtein": {
- "version": "1.0.12",
- "bundled": true,
- "dev": true
- },
- "fs-minipass": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "function-bind": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "gauge": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1",
- "aproba": "^1.0.3 || ^2.0.0",
- "color-support": "^1.1.3",
- "console-control-strings": "^1.1.0",
- "has-unicode": "^2.0.1",
- "signal-exit": "^3.0.7",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "wide-align": "^1.1.5"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "glob": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.9",
- "bundled": true,
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true
- },
- "hosted-git-info": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "http-cache-semantics": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "http-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "https-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "humanize-ms": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "^2.0.0"
- }
- },
- "iconv-lite": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- },
- "ignore-walk": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimatch": "^3.0.4"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "bundled": true,
- "dev": true
- },
- "indent-string": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "infer-owner": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "bundled": true,
- "dev": true
- },
- "ini": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "init-package-json": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-package-arg": "^9.0.0",
- "promzard": "^0.3.0",
- "read": "^1.0.7",
- "read-package-json": "^4.1.1",
- "semver": "^7.3.5",
- "validate-npm-package-license": "^3.0.4",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "ip": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true
- },
- "ip-regex": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true
- },
- "is-cidr": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "cidr-regex": "^3.1.1"
- }
- },
- "is-core-module": {
- "version": "2.8.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "is-lambda": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "bundled": true,
- "dev": true
- },
- "json-stringify-nice": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "jsonparse": {
- "version": "1.3.1",
- "bundled": true,
- "dev": true
- },
- "just-diff": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "just-diff-apply": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true
- },
- "libnpmaccess": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "minipass": "^3.1.1",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmdiff": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/disparity-colors": "^1.0.1",
- "@npmcli/installed-package-contents": "^1.0.7",
- "binary-extensions": "^2.2.0",
- "diff": "^5.0.0",
- "minimatch": "^3.0.4",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2",
- "tar": "^6.1.0"
- }
- },
- "libnpmexec": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/run-script": "^3.0.0",
- "chalk": "^4.1.0",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-package-arg": "^9.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "proc-log": "^2.0.0",
- "read": "^1.0.7",
- "read-package-json-fast": "^2.0.2",
- "walk-up-path": "^1.0.0"
- }
- },
- "libnpmfund": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0"
- }
- },
- "libnpmhook": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmorg": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmpack": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/run-script": "^3.0.0",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2"
- }
- },
- "libnpmpublish": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "normalize-package-data": "^3.0.2",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0",
- "semver": "^7.1.3",
- "ssri": "^8.0.1"
- }
- },
- "libnpmsearch": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmteam": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmversion": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/run-script": "^3.0.0",
- "json-parse-even-better-errors": "^2.3.1",
- "proc-log": "^2.0.0",
- "semver": "^7.3.5",
- "stringify-package": "^1.0.1"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-fetch-happen": {
- "version": "10.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "agentkeepalive": "^4.2.1",
- "cacache": "^15.3.0",
- "http-cache-semantics": "^4.1.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.0",
- "is-lambda": "^1.0.1",
- "lru-cache": "^7.4.0",
- "minipass": "^3.1.6",
- "minipass-collect": "^1.0.2",
- "minipass-fetch": "^2.0.1",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.4",
- "negotiator": "^0.6.3",
- "promise-retry": "^2.0.1",
- "socks-proxy-agent": "^6.1.1",
- "ssri": "^8.0.1"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minipass": {
- "version": "3.1.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "minipass-collect": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-fetch": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "encoding": "^0.1.13",
- "minipass": "^3.1.6",
- "minipass-sized": "^1.0.3",
- "minizlib": "^2.1.2"
- }
- },
- "minipass-flush": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-json-stream": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "jsonparse": "^1.3.1",
- "minipass": "^3.0.0"
- }
- },
- "minipass-pipeline": {
- "version": "1.2.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-sized": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "mkdirp-infer-owner": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "infer-owner": "^1.0.4",
- "mkdirp": "^1.0.3"
- }
- },
- "ms": {
- "version": "2.1.3",
- "bundled": true,
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true
- },
- "negotiator": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true
- },
- "node-gyp": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "env-paths": "^2.2.0",
- "glob": "^7.1.4",
- "graceful-fs": "^4.2.6",
- "make-fetch-happen": "^10.0.3",
- "nopt": "^5.0.0",
- "npmlog": "^6.0.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "tar": "^6.1.2",
- "which": "^2.0.2"
- }
- },
- "nopt": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-package-data": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "npm-audit-report": {
- "version": "2.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "npm-bundled": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-install-checks": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "semver": "^7.1.1"
- }
- },
- "npm-normalize-package-bin": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npm-package-arg": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.1.0",
- "semver": "^7.3.5",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "npm-packlist": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.6",
- "ignore-walk": "^4.0.1",
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-pick-manifest": {
- "version": "7.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-install-checks": "^4.0.0",
- "npm-normalize-package-bin": "^1.0.1",
- "npm-package-arg": "^9.0.0",
- "semver": "^7.3.5"
- }
- },
- "npm-profile": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-registry-fetch": {
- "version": "13.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "make-fetch-happen": "^10.0.3",
- "minipass": "^3.1.6",
- "minipass-fetch": "^2.0.1",
- "minipass-json-stream": "^1.0.1",
- "minizlib": "^2.1.2",
- "npm-package-arg": "^9.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-user-validate": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npmlog": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "are-we-there-yet": "^3.0.0",
- "console-control-strings": "^1.1.0",
- "gauge": "^4.0.0",
- "set-blocking": "^2.0.0"
- }
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "opener": {
- "version": "1.5.2",
- "bundled": true,
- "dev": true
- },
- "p-map": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "pacote": {
- "version": "13.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/promise-spawn": "^1.2.0",
- "@npmcli/run-script": "^3.0.0",
- "cacache": "^15.3.0",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.1.0",
- "infer-owner": "^1.0.4",
- "minipass": "^3.1.6",
- "mkdirp": "^1.0.4",
- "npm-package-arg": "^9.0.0",
- "npm-packlist": "^3.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0",
- "promise-retry": "^2.0.1",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.1.11"
- }
- },
- "parse-conflict-json": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1",
- "just-diff": "^5.0.1",
- "just-diff-apply": "^4.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "proc-log": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "promise-all-reject-late": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-call-limit": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-inflight": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-retry": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "err-code": "^2.0.2",
- "retry": "^0.12.0"
- }
- },
- "promzard": {
- "version": "0.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "read": "1"
- }
- },
- "qrcode-terminal": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "read": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "mute-stream": "~0.0.4"
- }
- },
- "read-cmd-shim": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "read-package-json": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.1",
- "json-parse-even-better-errors": "^2.3.0",
- "normalize-package-data": "^3.0.0",
- "npm-normalize-package-bin": "^1.0.0"
- }
- },
- "read-package-json-fast": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.0",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "readable-stream": {
- "version": "3.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "readdir-scoped-modules": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "debuglog": "^1.0.1",
- "dezalgo": "^1.0.0",
- "graceful-fs": "^4.1.2",
- "once": "^1.3.0"
- }
- },
- "retry": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "bundled": true,
- "dev": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "semver": {
- "version": "7.3.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.7",
- "bundled": true,
- "dev": true
- },
- "smart-buffer": {
- "version": "4.2.0",
- "bundled": true,
- "dev": true
- },
- "socks": {
- "version": "2.6.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip": "^1.1.5",
- "smart-buffer": "^4.2.0"
- }
- },
- "socks-proxy-agent": {
- "version": "6.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "^6.0.2",
- "debug": "^4.3.1",
- "socks": "^2.6.1"
- }
- },
- "spdx-correct": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true
- },
- "spdx-expression-parse": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.11",
- "bundled": true,
- "dev": true
- },
- "ssri": {
- "version": "8.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.1.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "string_decoder": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
- "stringify-package": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "tar": {
- "version": "6.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^3.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true
- },
- "tiny-relative-date": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true
- },
- "treeverse": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "unique-filename": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "unique-slug": "^2.0.0"
- }
- },
- "unique-slug": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "validate-npm-package-name": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "builtins": "^1.0.3"
- }
- },
- "walk-up-path": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "wcwidth": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
- "which": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "wide-align": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2 || 3 || 4"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "write-file-atomic": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
- "dev": true
- }
- }
-}
diff --git a/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb b/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb
index cc177204a3..288cd553b1 100644
--- a/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb
+++ b/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb
@@ -24,11 +24,6 @@ spec:
operator: In
values:
- linux
- - matchExpressions:
- - key: beta.kubernetes.io/os
- operator: In
- values:
- - linux
# <%- if config.node_selector -%>
# nodeSelector:
# <%- node_selector.to_h.each do |key, value| -%>
diff --git a/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb b/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb
index 2ff46d8d0b..c02fb93321 100644
--- a/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb
+++ b/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb
@@ -30,11 +30,6 @@ spec:
operator: In
values:
- linux
- - matchExpressions:
- - key: beta.kubernetes.io/os
- operator: In
- values:
- - linux
securityContext:
runAsNonRoot: true
runAsUser: 65534
diff --git a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb
index 5eaefe2cf9..0174d5c8f4 100644
--- a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb
+++ b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb
@@ -23,11 +23,6 @@ spec:
operator: In
values:
- linux
- - matchExpressions:
- - key: beta.kubernetes.io/os
- operator: In
- values:
- - linux
serviceAccountName: kube-state-metrics
containers:
- name: kube-state-metrics
diff --git a/extensions/metrics-cluster-feature/src/metrics-settings.tsx b/extensions/metrics-cluster-feature/src/metrics-settings.tsx
index dfd943797e..3f20a80df1 100644
--- a/extensions/metrics-cluster-feature/src/metrics-settings.tsx
+++ b/extensions/metrics-cluster-feature/src/metrics-settings.tsx
@@ -208,14 +208,14 @@ export class MetricsSettings extends React.Component {
this.togglePrometheus(v.target.checked)}
name="prometheus"
/>
- }
+ )}
label="Enable bundled Prometheus metrics stack"
/>
@@ -226,14 +226,14 @@ export class MetricsSettings extends React.Component {
this.toggleKubeStateMetrics(v.target.checked)}
name="node-exporter"
/>
- }
+ )}
label="Enable bundled kube-state-metrics stack"
/>
@@ -245,14 +245,14 @@ export class MetricsSettings extends React.Component {
this.toggleNodeExporter(v.target.checked)}
name="node-exporter"
/>
- }
+ )}
label="Enable bundled node-exporter stack"
/>
@@ -271,9 +271,11 @@ export class MetricsSettings extends React.Component {
className="w-60 h-14"
/>
- {this.canUpgrade && (
- An update is available for enabled metrics components.
- )}
+ {this.canUpgrade && (
+
+ An update is available for enabled metrics components.
+
+ )}
>
);
diff --git a/extensions/node-menu/package-lock.json b/extensions/node-menu/package-lock.json
deleted file mode 100644
index 9885b4a885..0000000000
--- a/extensions/node-menu/package-lock.json
+++ /dev/null
@@ -1,2374 +0,0 @@
-{
- "name": "lens-node-menu",
- "version": "0.0.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@k8slens/extensions": {
- "version": "file:../../src/extensions/npm/extensions",
- "dev": true,
- "requires": {
- "@material-ui/core": "4.12.3",
- "@types/node": "14.17.14",
- "@types/react-select": "3.1.2",
- "conf": "^7.0.1",
- "typed-emitter": "^1.3.1"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.3",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
- "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@emotion/hash": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
- "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
- "dev": true
- },
- "@material-ui/core": {
- "version": "4.12.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
- "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.11.4",
- "@material-ui/system": "^4.12.1",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "@types/react-transition-group": "^4.2.0",
- "clsx": "^1.0.4",
- "hoist-non-react-statics": "^3.3.2",
- "popper.js": "1.16.1-lts",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0",
- "react-transition-group": "^4.4.0"
- }
- },
- "@material-ui/styles": {
- "version": "4.11.4",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
- "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@emotion/hash": "^0.8.0",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "clsx": "^1.0.4",
- "csstype": "^2.5.2",
- "hoist-non-react-statics": "^3.3.2",
- "jss": "^10.5.1",
- "jss-plugin-camel-case": "^10.5.1",
- "jss-plugin-default-unit": "^10.5.1",
- "jss-plugin-global": "^10.5.1",
- "jss-plugin-nested": "^10.5.1",
- "jss-plugin-props-sort": "^10.5.1",
- "jss-plugin-rule-value-function": "^10.5.1",
- "jss-plugin-vendor-prefixer": "^10.5.1",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/system": {
- "version": "4.12.1",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
- "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/utils": "^4.11.2",
- "csstype": "^2.5.2",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/types": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
- "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
- "dev": true
- },
- "@material-ui/utils": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
- "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0"
- }
- },
- "@types/node": {
- "version": "14.17.14",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.14.tgz",
- "integrity": "sha512-rsAj2u8Xkqfc332iXV12SqIsjVi07H479bOP4q94NAcjzmAvapumEhuVIt53koEf7JFrpjgNKjBga5Pnn/GL8A==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.4",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
- "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
- "dev": true
- },
- "@types/react": {
- "version": "17.0.35",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.35.tgz",
- "integrity": "sha512-r3C8/TJuri/SLZiiwwxQoLAoavaczARfT9up9b4Jr65+ErAUX3MIkU0oMOQnrpfgHme8zIqZLX7O5nnjm5Wayw==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "@types/react-dom": {
- "version": "17.0.11",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
- "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-select": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.2.tgz",
- "integrity": "sha512-ygvR/2FL87R2OLObEWFootYzkvm67LRA+URYEAcBuvKk7IXmdsnIwSGm60cVXGaqkJQHozb2Cy1t94tCYb6rJA==",
- "dev": true,
- "requires": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "@types/react-transition-group": "*"
- }
- },
- "@types/react-transition-group": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
- "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
- "dev": true
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "atomically": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
- "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
- "dev": true
- },
- "clsx": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
- "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
- "dev": true
- },
- "conf": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
- "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.2",
- "atomically": "^1.3.1",
- "debounce-fn": "^4.0.0",
- "dot-prop": "^5.2.0",
- "env-paths": "^2.2.0",
- "json-schema-typed": "^7.0.3",
- "make-dir": "^3.1.0",
- "onetime": "^5.1.0",
- "pkg-up": "^3.1.0",
- "semver": "^7.3.2"
- }
- },
- "css-vendor": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
- "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.3",
- "is-in-browser": "^1.0.2"
- }
- },
- "csstype": {
- "version": "2.6.18",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
- "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
- "dev": true
- },
- "debounce-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
- "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^3.0.0"
- }
- },
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "dev": true,
- "requires": {
- "is-obj": "^2.0.0"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
- "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dev": true,
- "requires": {
- "react-is": "^16.7.0"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "hyphenate-style-name": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
- "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
- "dev": true
- },
- "is-in-browser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
- "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
- "dev": true
- },
- "is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-schema-typed": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
- "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
- "dev": true
- },
- "jss": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz",
- "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "csstype": "^3.0.2",
- "is-in-browser": "^1.1.3",
- "tiny-warning": "^1.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "jss-plugin-camel-case": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz",
- "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "hyphenate-style-name": "^1.0.3",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-default-unit": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz",
- "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-global": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz",
- "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-nested": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz",
- "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-props-sort": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz",
- "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-rule-value-function": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz",
- "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-vendor-prefixer": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz",
- "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "css-vendor": "^2.0.8",
- "jss": "10.8.2"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- }
- }
- },
- "mimic-fn": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
- "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- },
- "dependencies": {
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- }
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
- "dev": true
- },
- "pkg-up": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
- "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0"
- }
- },
- "popper.js": {
- "version": "1.16.1-lts",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
- "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
- "dev": true
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "react-transition-group": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
- "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
- "dev": true
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
- "dev": true
- },
- "typed-emitter": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
- "integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
- "dev": true
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "npm": {
- "version": "8.5.3",
- "resolved": "https://registry.npmjs.org/npm/-/npm-8.5.3.tgz",
- "integrity": "sha512-O+1j66Alx7ZQgWnUSSTaz8rTqQrJnqNb8Num5uQw2vYvc2RrxLaX7cWtRkDhvkPIL8Nf2WU9gx1oSu268QConA==",
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/config": "^4.0.1",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.1",
- "abbrev": "~1.1.1",
- "ansicolors": "~0.3.2",
- "ansistyles": "~0.1.3",
- "archy": "~1.0.0",
- "cacache": "^15.3.0",
- "chalk": "^4.1.2",
- "chownr": "^2.0.0",
- "cli-columns": "^4.0.0",
- "cli-table3": "^0.6.1",
- "columnify": "^1.6.0",
- "fastest-levenshtein": "^1.0.12",
- "glob": "^7.2.0",
- "graceful-fs": "^4.2.9",
- "hosted-git-info": "^4.1.0",
- "ini": "^2.0.0",
- "init-package-json": "^3.0.0",
- "is-cidr": "^4.0.2",
- "json-parse-even-better-errors": "^2.3.1",
- "libnpmaccess": "^6.0.0",
- "libnpmdiff": "^4.0.0",
- "libnpmexec": "^4.0.0",
- "libnpmfund": "^3.0.0",
- "libnpmhook": "^8.0.0",
- "libnpmorg": "^4.0.0",
- "libnpmpack": "^4.0.0",
- "libnpmpublish": "^6.0.0",
- "libnpmsearch": "^5.0.0",
- "libnpmteam": "^4.0.0",
- "libnpmversion": "^3.0.0",
- "make-fetch-happen": "^10.0.4",
- "minipass": "^3.1.6",
- "minipass-pipeline": "^1.2.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "ms": "^2.1.2",
- "node-gyp": "^9.0.0",
- "nopt": "^5.0.0",
- "npm-audit-report": "^2.1.5",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-profile": "^6.0.2",
- "npm-registry-fetch": "^13.0.1",
- "npm-user-validate": "^1.0.1",
- "npmlog": "^6.0.1",
- "opener": "^1.5.2",
- "pacote": "^13.0.3",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "qrcode-terminal": "^0.12.0",
- "read": "~1.0.7",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "tar": "^6.1.11",
- "text-table": "~0.2.0",
- "tiny-relative-date": "^1.3.0",
- "treeverse": "^1.0.4",
- "validate-npm-package-name": "~3.0.0",
- "which": "^2.0.2",
- "write-file-atomic": "^4.0.1"
- },
- "dependencies": {
- "@gar/promisify": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "@isaacs/string-locale-compare": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/arborist": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/metavuln-calculator": "^3.0.0",
- "@npmcli/move-file": "^1.1.0",
- "@npmcli/name-from-folder": "^1.0.1",
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.0",
- "bin-links": "^3.0.0",
- "cacache": "^15.0.3",
- "common-ancestor-path": "^1.0.1",
- "json-parse-even-better-errors": "^2.3.1",
- "json-stringify-nice": "^1.1.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "promise-all-reject-late": "^1.0.0",
- "promise-call-limit": "^1.0.1",
- "read-package-json-fast": "^2.0.2",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "treeverse": "^1.0.4",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/ci-detect": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/config": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/map-workspaces": "^2.0.1",
- "ini": "^2.0.0",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "proc-log": "^2.0.0",
- "read-package-json-fast": "^2.0.3",
- "semver": "^7.3.5",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/disparity-colors": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.3.0"
- }
- },
- "@npmcli/fs": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@gar/promisify": "^1.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/git": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/promise-spawn": "^1.3.2",
- "lru-cache": "^7.3.1",
- "mkdirp": "^1.0.4",
- "npm-pick-manifest": "^7.0.0",
- "proc-log": "^2.0.0",
- "promise-inflight": "^1.0.1",
- "promise-retry": "^2.0.1",
- "semver": "^7.3.5",
- "which": "^2.0.2"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "@npmcli/installed-package-contents": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "@npmcli/map-workspaces": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/name-from-folder": "^1.0.1",
- "glob": "^7.2.0",
- "minimatch": "^5.0.0",
- "read-package-json-fast": "^2.0.3"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
- "@npmcli/metavuln-calculator": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cacache": "^15.3.0",
- "json-parse-even-better-errors": "^2.3.1",
- "pacote": "^13.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/move-file": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp": "^1.0.4",
- "rimraf": "^3.0.2"
- }
- },
- "@npmcli/name-from-folder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "@npmcli/node-gyp": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "@npmcli/package-json": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1"
- }
- },
- "@npmcli/promise-spawn": {
- "version": "1.3.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "infer-owner": "^1.0.4"
- }
- },
- "@npmcli/run-script": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/promise-spawn": "^1.3.2",
- "node-gyp": "^9.0.0",
- "read-package-json-fast": "^2.0.3"
- }
- },
- "@tootallnate/once": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "abbrev": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "agent-base": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "4"
- }
- },
- "agentkeepalive": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "^4.1.0",
- "depd": "^1.1.2",
- "humanize-ms": "^1.2.1"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "ansicolors": {
- "version": "0.3.2",
- "bundled": true,
- "dev": true
- },
- "ansistyles": {
- "version": "0.1.3",
- "bundled": true,
- "dev": true
- },
- "aproba": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "archy": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "are-we-there-yet": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^3.6.0"
- }
- },
- "asap": {
- "version": "2.0.6",
- "bundled": true,
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "bin-links": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cmd-shim": "^4.0.1",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-normalize-package-bin": "^1.0.0",
- "read-cmd-shim": "^2.0.0",
- "rimraf": "^3.0.0",
- "write-file-atomic": "^4.0.0"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "builtins": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "cacache": {
- "version": "15.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/fs": "^1.0.0",
- "@npmcli/move-file": "^1.0.1",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "glob": "^7.1.4",
- "infer-owner": "^1.0.4",
- "lru-cache": "^6.0.0",
- "minipass": "^3.1.1",
- "minipass-collect": "^1.0.2",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.2",
- "mkdirp": "^1.0.3",
- "p-map": "^4.0.0",
- "promise-inflight": "^1.0.1",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.0.2",
- "unique-filename": "^1.1.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "chownr": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "cidr-regex": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip-regex": "^4.1.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "cli-columns": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "cli-table3": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "colors": "1.4.0",
- "string-width": "^4.2.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "cmd-shim": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp-infer-owner": "^2.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "color-support": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "colors": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "columnify": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "strip-ansi": "^6.0.1",
- "wcwidth": "^1.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "common-ancestor-path": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "debug": {
- "version": "4.3.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true
- }
- }
- },
- "debuglog": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "defaults": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "depd": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true
- },
- "dezalgo": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "diff": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true
- },
- "encoding": {
- "version": "0.1.13",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "iconv-lite": "^0.6.2"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "bundled": true,
- "dev": true
- },
- "err-code": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true
- },
- "fastest-levenshtein": {
- "version": "1.0.12",
- "bundled": true,
- "dev": true
- },
- "fs-minipass": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "function-bind": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "gauge": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1",
- "aproba": "^1.0.3 || ^2.0.0",
- "color-support": "^1.1.3",
- "console-control-strings": "^1.1.0",
- "has-unicode": "^2.0.1",
- "signal-exit": "^3.0.7",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "wide-align": "^1.1.5"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "glob": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.9",
- "bundled": true,
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true
- },
- "hosted-git-info": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "http-cache-semantics": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "http-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "https-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "humanize-ms": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "^2.0.0"
- }
- },
- "iconv-lite": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- },
- "ignore-walk": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimatch": "^3.0.4"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "bundled": true,
- "dev": true
- },
- "indent-string": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "infer-owner": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "bundled": true,
- "dev": true
- },
- "ini": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "init-package-json": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-package-arg": "^9.0.0",
- "promzard": "^0.3.0",
- "read": "^1.0.7",
- "read-package-json": "^4.1.1",
- "semver": "^7.3.5",
- "validate-npm-package-license": "^3.0.4",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "ip": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true
- },
- "ip-regex": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true
- },
- "is-cidr": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "cidr-regex": "^3.1.1"
- }
- },
- "is-core-module": {
- "version": "2.8.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "is-lambda": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "bundled": true,
- "dev": true
- },
- "json-stringify-nice": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "jsonparse": {
- "version": "1.3.1",
- "bundled": true,
- "dev": true
- },
- "just-diff": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "just-diff-apply": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true
- },
- "libnpmaccess": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "minipass": "^3.1.1",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmdiff": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/disparity-colors": "^1.0.1",
- "@npmcli/installed-package-contents": "^1.0.7",
- "binary-extensions": "^2.2.0",
- "diff": "^5.0.0",
- "minimatch": "^3.0.4",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2",
- "tar": "^6.1.0"
- }
- },
- "libnpmexec": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/run-script": "^3.0.0",
- "chalk": "^4.1.0",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-package-arg": "^9.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "proc-log": "^2.0.0",
- "read": "^1.0.7",
- "read-package-json-fast": "^2.0.2",
- "walk-up-path": "^1.0.0"
- }
- },
- "libnpmfund": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0"
- }
- },
- "libnpmhook": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmorg": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmpack": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/run-script": "^3.0.0",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2"
- }
- },
- "libnpmpublish": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "normalize-package-data": "^3.0.2",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0",
- "semver": "^7.1.3",
- "ssri": "^8.0.1"
- }
- },
- "libnpmsearch": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmteam": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmversion": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/run-script": "^3.0.0",
- "json-parse-even-better-errors": "^2.3.1",
- "proc-log": "^2.0.0",
- "semver": "^7.3.5",
- "stringify-package": "^1.0.1"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-fetch-happen": {
- "version": "10.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "agentkeepalive": "^4.2.1",
- "cacache": "^15.3.0",
- "http-cache-semantics": "^4.1.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.0",
- "is-lambda": "^1.0.1",
- "lru-cache": "^7.4.0",
- "minipass": "^3.1.6",
- "minipass-collect": "^1.0.2",
- "minipass-fetch": "^2.0.1",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.4",
- "negotiator": "^0.6.3",
- "promise-retry": "^2.0.1",
- "socks-proxy-agent": "^6.1.1",
- "ssri": "^8.0.1"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minipass": {
- "version": "3.1.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "minipass-collect": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-fetch": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "encoding": "^0.1.13",
- "minipass": "^3.1.6",
- "minipass-sized": "^1.0.3",
- "minizlib": "^2.1.2"
- }
- },
- "minipass-flush": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-json-stream": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "jsonparse": "^1.3.1",
- "minipass": "^3.0.0"
- }
- },
- "minipass-pipeline": {
- "version": "1.2.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-sized": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "mkdirp-infer-owner": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "infer-owner": "^1.0.4",
- "mkdirp": "^1.0.3"
- }
- },
- "ms": {
- "version": "2.1.3",
- "bundled": true,
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true
- },
- "negotiator": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true
- },
- "node-gyp": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "env-paths": "^2.2.0",
- "glob": "^7.1.4",
- "graceful-fs": "^4.2.6",
- "make-fetch-happen": "^10.0.3",
- "nopt": "^5.0.0",
- "npmlog": "^6.0.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "tar": "^6.1.2",
- "which": "^2.0.2"
- }
- },
- "nopt": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-package-data": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "npm-audit-report": {
- "version": "2.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "npm-bundled": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-install-checks": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "semver": "^7.1.1"
- }
- },
- "npm-normalize-package-bin": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npm-package-arg": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.1.0",
- "semver": "^7.3.5",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "npm-packlist": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.6",
- "ignore-walk": "^4.0.1",
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-pick-manifest": {
- "version": "7.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-install-checks": "^4.0.0",
- "npm-normalize-package-bin": "^1.0.1",
- "npm-package-arg": "^9.0.0",
- "semver": "^7.3.5"
- }
- },
- "npm-profile": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-registry-fetch": {
- "version": "13.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "make-fetch-happen": "^10.0.3",
- "minipass": "^3.1.6",
- "minipass-fetch": "^2.0.1",
- "minipass-json-stream": "^1.0.1",
- "minizlib": "^2.1.2",
- "npm-package-arg": "^9.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-user-validate": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npmlog": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "are-we-there-yet": "^3.0.0",
- "console-control-strings": "^1.1.0",
- "gauge": "^4.0.0",
- "set-blocking": "^2.0.0"
- }
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "opener": {
- "version": "1.5.2",
- "bundled": true,
- "dev": true
- },
- "p-map": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "pacote": {
- "version": "13.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/promise-spawn": "^1.2.0",
- "@npmcli/run-script": "^3.0.0",
- "cacache": "^15.3.0",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.1.0",
- "infer-owner": "^1.0.4",
- "minipass": "^3.1.6",
- "mkdirp": "^1.0.4",
- "npm-package-arg": "^9.0.0",
- "npm-packlist": "^3.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0",
- "promise-retry": "^2.0.1",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.1.11"
- }
- },
- "parse-conflict-json": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1",
- "just-diff": "^5.0.1",
- "just-diff-apply": "^4.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "proc-log": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "promise-all-reject-late": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-call-limit": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-inflight": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-retry": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "err-code": "^2.0.2",
- "retry": "^0.12.0"
- }
- },
- "promzard": {
- "version": "0.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "read": "1"
- }
- },
- "qrcode-terminal": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "read": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "mute-stream": "~0.0.4"
- }
- },
- "read-cmd-shim": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "read-package-json": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.1",
- "json-parse-even-better-errors": "^2.3.0",
- "normalize-package-data": "^3.0.0",
- "npm-normalize-package-bin": "^1.0.0"
- }
- },
- "read-package-json-fast": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.0",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "readable-stream": {
- "version": "3.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "readdir-scoped-modules": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "debuglog": "^1.0.1",
- "dezalgo": "^1.0.0",
- "graceful-fs": "^4.1.2",
- "once": "^1.3.0"
- }
- },
- "retry": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "bundled": true,
- "dev": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "semver": {
- "version": "7.3.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.7",
- "bundled": true,
- "dev": true
- },
- "smart-buffer": {
- "version": "4.2.0",
- "bundled": true,
- "dev": true
- },
- "socks": {
- "version": "2.6.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip": "^1.1.5",
- "smart-buffer": "^4.2.0"
- }
- },
- "socks-proxy-agent": {
- "version": "6.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "^6.0.2",
- "debug": "^4.3.1",
- "socks": "^2.6.1"
- }
- },
- "spdx-correct": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true
- },
- "spdx-expression-parse": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.11",
- "bundled": true,
- "dev": true
- },
- "ssri": {
- "version": "8.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.1.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "string_decoder": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
- "stringify-package": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "tar": {
- "version": "6.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^3.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true
- },
- "tiny-relative-date": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true
- },
- "treeverse": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "unique-filename": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "unique-slug": "^2.0.0"
- }
- },
- "unique-slug": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "validate-npm-package-name": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "builtins": "^1.0.3"
- }
- },
- "walk-up-path": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "wcwidth": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
- "which": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "wide-align": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2 || 3 || 4"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "write-file-atomic": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- }
- }
- }
- }
-}
diff --git a/extensions/node-menu/src/node-menu.tsx b/extensions/node-menu/src/node-menu.tsx
index 9666ad36e0..adc7576206 100644
--- a/extensions/node-menu/src/node-menu.tsx
+++ b/extensions/node-menu/src/node-menu.tsx
@@ -68,7 +68,9 @@ export function NodeMenu(props: NodeMenuProps) {
labelOk: `Drain Node`,
message: (
- Are you sure you want to drain {nodeName} ?
+ {"Are you sure you want to drain "}
+ {nodeName}
+ ?
),
});
@@ -77,26 +79,42 @@ export function NodeMenu(props: NodeMenuProps) {
return (
<>
-
+
Shell
{
node.isUnschedulable()
? (
-
+
Uncordon
)
: (
-
+
Cordon
)
}
-
+
Drain
>
diff --git a/extensions/pod-menu/package-lock.json b/extensions/pod-menu/package-lock.json
deleted file mode 100644
index 8a7e5e4544..0000000000
--- a/extensions/pod-menu/package-lock.json
+++ /dev/null
@@ -1,2367 +0,0 @@
-{
- "name": "lens-pod-menu",
- "version": "0.0.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@k8slens/extensions": {
- "version": "file:../../src/extensions/npm/extensions",
- "dev": true,
- "requires": {
- "@material-ui/core": "4.12.3",
- "@types/node": "14.17.14",
- "@types/react-select": "3.1.2",
- "conf": "^7.0.1",
- "typed-emitter": "^1.3.1"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.3",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
- "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@emotion/hash": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
- "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
- "dev": true
- },
- "@material-ui/core": {
- "version": "4.12.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
- "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.11.4",
- "@material-ui/system": "^4.12.1",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "@types/react-transition-group": "^4.2.0",
- "clsx": "^1.0.4",
- "hoist-non-react-statics": "^3.3.2",
- "popper.js": "1.16.1-lts",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0",
- "react-transition-group": "^4.4.0"
- }
- },
- "@material-ui/styles": {
- "version": "4.11.4",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
- "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@emotion/hash": "^0.8.0",
- "@material-ui/types": "5.1.0",
- "@material-ui/utils": "^4.11.2",
- "clsx": "^1.0.4",
- "csstype": "^2.5.2",
- "hoist-non-react-statics": "^3.3.2",
- "jss": "^10.5.1",
- "jss-plugin-camel-case": "^10.5.1",
- "jss-plugin-default-unit": "^10.5.1",
- "jss-plugin-global": "^10.5.1",
- "jss-plugin-nested": "^10.5.1",
- "jss-plugin-props-sort": "^10.5.1",
- "jss-plugin-rule-value-function": "^10.5.1",
- "jss-plugin-vendor-prefixer": "^10.5.1",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/system": {
- "version": "4.12.1",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
- "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/utils": "^4.11.2",
- "csstype": "^2.5.2",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/types": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
- "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
- "dev": true
- },
- "@material-ui/utils": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
- "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.4.4",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0"
- }
- },
- "@types/node": {
- "version": "14.17.14",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.14.tgz",
- "integrity": "sha512-rsAj2u8Xkqfc332iXV12SqIsjVi07H479bOP4q94NAcjzmAvapumEhuVIt53koEf7JFrpjgNKjBga5Pnn/GL8A==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.3",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
- "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
- "dev": true
- },
- "@types/react": {
- "version": "17.0.0",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz",
- "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
- "integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==",
- "dev": true
- }
- }
- },
- "@types/react-dom": {
- "version": "17.0.0",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz",
- "integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-select": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.2.tgz",
- "integrity": "sha512-ygvR/2FL87R2OLObEWFootYzkvm67LRA+URYEAcBuvKk7IXmdsnIwSGm60cVXGaqkJQHozb2Cy1t94tCYb6rJA==",
- "dev": true,
- "requires": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "@types/react-transition-group": "*"
- }
- },
- "@types/react-transition-group": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz",
- "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "atomically": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
- "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
- "dev": true
- },
- "clsx": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
- "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
- "dev": true
- },
- "conf": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
- "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.2",
- "atomically": "^1.3.1",
- "debounce-fn": "^4.0.0",
- "dot-prop": "^5.2.0",
- "env-paths": "^2.2.0",
- "json-schema-typed": "^7.0.3",
- "make-dir": "^3.1.0",
- "onetime": "^5.1.0",
- "pkg-up": "^3.1.0",
- "semver": "^7.3.2"
- }
- },
- "css-vendor": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
- "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.3",
- "is-in-browser": "^1.0.2"
- }
- },
- "csstype": {
- "version": "2.6.18",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
- "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
- "dev": true
- },
- "debounce-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
- "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^3.0.0"
- }
- },
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "dev": true,
- "requires": {
- "is-obj": "^2.0.0"
- }
- },
- "env-paths": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
- "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dev": true,
- "requires": {
- "react-is": "^16.7.0"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "hyphenate-style-name": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
- "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
- "dev": true
- },
- "is-in-browser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
- "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
- "dev": true
- },
- "is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-schema-typed": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
- "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
- "dev": true
- },
- "jss": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz",
- "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "csstype": "^3.0.2",
- "is-in-browser": "^1.1.3",
- "tiny-warning": "^1.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
- "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
- "dev": true
- }
- }
- },
- "jss-plugin-camel-case": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz",
- "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "hyphenate-style-name": "^1.0.3",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-default-unit": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz",
- "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-global": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz",
- "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-nested": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz",
- "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-props-sort": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz",
- "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2"
- }
- },
- "jss-plugin-rule-value-function": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz",
- "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.8.2",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-vendor-prefixer": {
- "version": "10.8.2",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz",
- "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "css-vendor": "^2.0.8",
- "jss": "10.8.2"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- }
- }
- },
- "mimic-fn": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
- "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- },
- "dependencies": {
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- }
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
- "dev": true
- },
- "pkg-up": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
- "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0"
- }
- },
- "popper.js": {
- "version": "1.16.1-lts",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
- "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
- "dev": true
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- }
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "react-transition-group": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
- "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
- "dev": true
- },
- "semver": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
- "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
- "dev": true
- },
- "typed-emitter": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
- "integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
- "dev": true
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "npm": {
- "version": "8.5.3",
- "resolved": "https://registry.npmjs.org/npm/-/npm-8.5.3.tgz",
- "integrity": "sha512-O+1j66Alx7ZQgWnUSSTaz8rTqQrJnqNb8Num5uQw2vYvc2RrxLaX7cWtRkDhvkPIL8Nf2WU9gx1oSu268QConA==",
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/config": "^4.0.1",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.1",
- "abbrev": "~1.1.1",
- "ansicolors": "~0.3.2",
- "ansistyles": "~0.1.3",
- "archy": "~1.0.0",
- "cacache": "^15.3.0",
- "chalk": "^4.1.2",
- "chownr": "^2.0.0",
- "cli-columns": "^4.0.0",
- "cli-table3": "^0.6.1",
- "columnify": "^1.6.0",
- "fastest-levenshtein": "^1.0.12",
- "glob": "^7.2.0",
- "graceful-fs": "^4.2.9",
- "hosted-git-info": "^4.1.0",
- "ini": "^2.0.0",
- "init-package-json": "^3.0.0",
- "is-cidr": "^4.0.2",
- "json-parse-even-better-errors": "^2.3.1",
- "libnpmaccess": "^6.0.0",
- "libnpmdiff": "^4.0.0",
- "libnpmexec": "^4.0.0",
- "libnpmfund": "^3.0.0",
- "libnpmhook": "^8.0.0",
- "libnpmorg": "^4.0.0",
- "libnpmpack": "^4.0.0",
- "libnpmpublish": "^6.0.0",
- "libnpmsearch": "^5.0.0",
- "libnpmteam": "^4.0.0",
- "libnpmversion": "^3.0.0",
- "make-fetch-happen": "^10.0.4",
- "minipass": "^3.1.6",
- "minipass-pipeline": "^1.2.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "ms": "^2.1.2",
- "node-gyp": "^9.0.0",
- "nopt": "^5.0.0",
- "npm-audit-report": "^2.1.5",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-profile": "^6.0.2",
- "npm-registry-fetch": "^13.0.1",
- "npm-user-validate": "^1.0.1",
- "npmlog": "^6.0.1",
- "opener": "^1.5.2",
- "pacote": "^13.0.3",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "qrcode-terminal": "^0.12.0",
- "read": "~1.0.7",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "tar": "^6.1.11",
- "text-table": "~0.2.0",
- "tiny-relative-date": "^1.3.0",
- "treeverse": "^1.0.4",
- "validate-npm-package-name": "~3.0.0",
- "which": "^2.0.2",
- "write-file-atomic": "^4.0.1"
- },
- "dependencies": {
- "@gar/promisify": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "@isaacs/string-locale-compare": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/arborist": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/map-workspaces": "^2.0.0",
- "@npmcli/metavuln-calculator": "^3.0.0",
- "@npmcli/move-file": "^1.1.0",
- "@npmcli/name-from-folder": "^1.0.1",
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/package-json": "^1.0.1",
- "@npmcli/run-script": "^3.0.0",
- "bin-links": "^3.0.0",
- "cacache": "^15.0.3",
- "common-ancestor-path": "^1.0.1",
- "json-parse-even-better-errors": "^2.3.1",
- "json-stringify-nice": "^1.1.4",
- "mkdirp": "^1.0.4",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "npm-install-checks": "^4.0.0",
- "npm-package-arg": "^9.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "parse-conflict-json": "^2.0.1",
- "proc-log": "^2.0.0",
- "promise-all-reject-late": "^1.0.0",
- "promise-call-limit": "^1.0.1",
- "read-package-json-fast": "^2.0.2",
- "readdir-scoped-modules": "^1.1.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "ssri": "^8.0.1",
- "treeverse": "^1.0.4",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/ci-detect": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "@npmcli/config": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/map-workspaces": "^2.0.1",
- "ini": "^2.0.0",
- "mkdirp-infer-owner": "^2.0.0",
- "nopt": "^5.0.0",
- "proc-log": "^2.0.0",
- "read-package-json-fast": "^2.0.3",
- "semver": "^7.3.5",
- "walk-up-path": "^1.0.0"
- }
- },
- "@npmcli/disparity-colors": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.3.0"
- }
- },
- "@npmcli/fs": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@gar/promisify": "^1.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/git": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/promise-spawn": "^1.3.2",
- "lru-cache": "^7.3.1",
- "mkdirp": "^1.0.4",
- "npm-pick-manifest": "^7.0.0",
- "proc-log": "^2.0.0",
- "promise-inflight": "^1.0.1",
- "promise-retry": "^2.0.1",
- "semver": "^7.3.5",
- "which": "^2.0.2"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "@npmcli/installed-package-contents": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "@npmcli/map-workspaces": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/name-from-folder": "^1.0.1",
- "glob": "^7.2.0",
- "minimatch": "^5.0.0",
- "read-package-json-fast": "^2.0.3"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
- "@npmcli/metavuln-calculator": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cacache": "^15.3.0",
- "json-parse-even-better-errors": "^2.3.1",
- "pacote": "^13.0.1",
- "semver": "^7.3.5"
- }
- },
- "@npmcli/move-file": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp": "^1.0.4",
- "rimraf": "^3.0.2"
- }
- },
- "@npmcli/name-from-folder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "@npmcli/node-gyp": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "@npmcli/package-json": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1"
- }
- },
- "@npmcli/promise-spawn": {
- "version": "1.3.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "infer-owner": "^1.0.4"
- }
- },
- "@npmcli/run-script": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/node-gyp": "^1.0.3",
- "@npmcli/promise-spawn": "^1.3.2",
- "node-gyp": "^9.0.0",
- "read-package-json-fast": "^2.0.3"
- }
- },
- "@tootallnate/once": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "abbrev": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "agent-base": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "4"
- }
- },
- "agentkeepalive": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "debug": "^4.1.0",
- "depd": "^1.1.2",
- "humanize-ms": "^1.2.1"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "ansicolors": {
- "version": "0.3.2",
- "bundled": true,
- "dev": true
- },
- "ansistyles": {
- "version": "0.1.3",
- "bundled": true,
- "dev": true
- },
- "aproba": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "archy": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "are-we-there-yet": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^3.6.0"
- }
- },
- "asap": {
- "version": "2.0.6",
- "bundled": true,
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "bin-links": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "cmd-shim": "^4.0.1",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-normalize-package-bin": "^1.0.0",
- "read-cmd-shim": "^2.0.0",
- "rimraf": "^3.0.0",
- "write-file-atomic": "^4.0.0"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "builtins": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true
- },
- "cacache": {
- "version": "15.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/fs": "^1.0.0",
- "@npmcli/move-file": "^1.0.1",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "glob": "^7.1.4",
- "infer-owner": "^1.0.4",
- "lru-cache": "^6.0.0",
- "minipass": "^3.1.1",
- "minipass-collect": "^1.0.2",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.2",
- "mkdirp": "^1.0.3",
- "p-map": "^4.0.0",
- "promise-inflight": "^1.0.1",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.0.2",
- "unique-filename": "^1.1.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "chownr": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "cidr-regex": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip-regex": "^4.1.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "cli-columns": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "cli-table3": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "colors": "1.4.0",
- "string-width": "^4.2.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "cmd-shim": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "mkdirp-infer-owner": "^2.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "color-support": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "colors": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "columnify": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "strip-ansi": "^6.0.1",
- "wcwidth": "^1.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "common-ancestor-path": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "debug": {
- "version": "4.3.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true
- }
- }
- },
- "debuglog": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "defaults": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "depd": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true
- },
- "dezalgo": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "diff": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true
- },
- "encoding": {
- "version": "0.1.13",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "iconv-lite": "^0.6.2"
- }
- },
- "env-paths": {
- "version": "2.2.1",
- "bundled": true,
- "dev": true
- },
- "err-code": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true
- },
- "fastest-levenshtein": {
- "version": "1.0.12",
- "bundled": true,
- "dev": true
- },
- "fs-minipass": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "function-bind": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true
- },
- "gauge": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1",
- "aproba": "^1.0.3 || ^2.0.0",
- "color-support": "^1.1.3",
- "console-control-strings": "^1.1.0",
- "has-unicode": "^2.0.1",
- "signal-exit": "^3.0.7",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "wide-align": "^1.1.5"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "glob": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.9",
- "bundled": true,
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true
- },
- "hosted-git-info": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "http-cache-semantics": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "http-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "https-proxy-agent": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "humanize-ms": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "^2.0.0"
- }
- },
- "iconv-lite": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- },
- "ignore-walk": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimatch": "^3.0.4"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "bundled": true,
- "dev": true
- },
- "indent-string": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "infer-owner": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "bundled": true,
- "dev": true
- },
- "ini": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "init-package-json": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-package-arg": "^9.0.0",
- "promzard": "^0.3.0",
- "read": "^1.0.7",
- "read-package-json": "^4.1.1",
- "semver": "^7.3.5",
- "validate-npm-package-license": "^3.0.4",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "ip": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true
- },
- "ip-regex": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true
- },
- "is-cidr": {
- "version": "4.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "cidr-regex": "^3.1.1"
- }
- },
- "is-core-module": {
- "version": "2.8.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "is-lambda": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "bundled": true,
- "dev": true
- },
- "json-stringify-nice": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "jsonparse": {
- "version": "1.3.1",
- "bundled": true,
- "dev": true
- },
- "just-diff": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "just-diff-apply": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true
- },
- "libnpmaccess": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "minipass": "^3.1.1",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmdiff": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/disparity-colors": "^1.0.1",
- "@npmcli/installed-package-contents": "^1.0.7",
- "binary-extensions": "^2.2.0",
- "diff": "^5.0.0",
- "minimatch": "^3.0.4",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2",
- "tar": "^6.1.0"
- }
- },
- "libnpmexec": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0",
- "@npmcli/ci-detect": "^2.0.0",
- "@npmcli/run-script": "^3.0.0",
- "chalk": "^4.1.0",
- "mkdirp-infer-owner": "^2.0.0",
- "npm-package-arg": "^9.0.0",
- "npmlog": "^6.0.1",
- "pacote": "^13.0.2",
- "proc-log": "^2.0.0",
- "read": "^1.0.7",
- "read-package-json-fast": "^2.0.2",
- "walk-up-path": "^1.0.0"
- }
- },
- "libnpmfund": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/arborist": "^5.0.0"
- }
- },
- "libnpmhook": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmorg": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmpack": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/run-script": "^3.0.0",
- "npm-package-arg": "^9.0.0",
- "pacote": "^13.0.2"
- }
- },
- "libnpmpublish": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "normalize-package-data": "^3.0.2",
- "npm-package-arg": "^9.0.0",
- "npm-registry-fetch": "^13.0.0",
- "semver": "^7.1.3",
- "ssri": "^8.0.1"
- }
- },
- "libnpmsearch": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmteam": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aproba": "^2.0.0",
- "npm-registry-fetch": "^13.0.0"
- }
- },
- "libnpmversion": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/run-script": "^3.0.0",
- "json-parse-even-better-errors": "^2.3.1",
- "proc-log": "^2.0.0",
- "semver": "^7.3.5",
- "stringify-package": "^1.0.1"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-fetch-happen": {
- "version": "10.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "agentkeepalive": "^4.2.1",
- "cacache": "^15.3.0",
- "http-cache-semantics": "^4.1.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.0",
- "is-lambda": "^1.0.1",
- "lru-cache": "^7.4.0",
- "minipass": "^3.1.6",
- "minipass-collect": "^1.0.2",
- "minipass-fetch": "^2.0.1",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.4",
- "negotiator": "^0.6.3",
- "promise-retry": "^2.0.1",
- "socks-proxy-agent": "^6.1.1",
- "ssri": "^8.0.1"
- },
- "dependencies": {
- "lru-cache": {
- "version": "7.4.0",
- "bundled": true,
- "dev": true
- }
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minipass": {
- "version": "3.1.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "minipass-collect": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-fetch": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "encoding": "^0.1.13",
- "minipass": "^3.1.6",
- "minipass-sized": "^1.0.3",
- "minizlib": "^2.1.2"
- }
- },
- "minipass-flush": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-json-stream": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "jsonparse": "^1.3.1",
- "minipass": "^3.0.0"
- }
- },
- "minipass-pipeline": {
- "version": "1.2.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-sized": {
- "version": "1.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "mkdirp-infer-owner": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "infer-owner": "^1.0.4",
- "mkdirp": "^1.0.3"
- }
- },
- "ms": {
- "version": "2.1.3",
- "bundled": true,
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true
- },
- "negotiator": {
- "version": "0.6.3",
- "bundled": true,
- "dev": true
- },
- "node-gyp": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "env-paths": "^2.2.0",
- "glob": "^7.1.4",
- "graceful-fs": "^4.2.6",
- "make-fetch-happen": "^10.0.3",
- "nopt": "^5.0.0",
- "npmlog": "^6.0.0",
- "rimraf": "^3.0.2",
- "semver": "^7.3.5",
- "tar": "^6.1.2",
- "which": "^2.0.2"
- }
- },
- "nopt": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-package-data": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "npm-audit-report": {
- "version": "2.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "npm-bundled": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-install-checks": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "semver": "^7.1.1"
- }
- },
- "npm-normalize-package-bin": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npm-package-arg": {
- "version": "9.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "hosted-git-info": "^4.1.0",
- "semver": "^7.3.5",
- "validate-npm-package-name": "^3.0.0"
- }
- },
- "npm-packlist": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.6",
- "ignore-walk": "^4.0.1",
- "npm-bundled": "^1.1.1",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "npm-pick-manifest": {
- "version": "7.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-install-checks": "^4.0.0",
- "npm-normalize-package-bin": "^1.0.1",
- "npm-package-arg": "^9.0.0",
- "semver": "^7.3.5"
- }
- },
- "npm-profile": {
- "version": "6.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-registry-fetch": {
- "version": "13.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "make-fetch-happen": "^10.0.3",
- "minipass": "^3.1.6",
- "minipass-fetch": "^2.0.1",
- "minipass-json-stream": "^1.0.1",
- "minizlib": "^2.1.2",
- "npm-package-arg": "^9.0.0",
- "proc-log": "^2.0.0"
- }
- },
- "npm-user-validate": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "npmlog": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "are-we-there-yet": "^3.0.0",
- "console-control-strings": "^1.1.0",
- "gauge": "^4.0.0",
- "set-blocking": "^2.0.0"
- }
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "opener": {
- "version": "1.5.2",
- "bundled": true,
- "dev": true
- },
- "p-map": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "pacote": {
- "version": "13.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "@npmcli/git": "^3.0.0",
- "@npmcli/installed-package-contents": "^1.0.7",
- "@npmcli/promise-spawn": "^1.2.0",
- "@npmcli/run-script": "^3.0.0",
- "cacache": "^15.3.0",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.1.0",
- "infer-owner": "^1.0.4",
- "minipass": "^3.1.6",
- "mkdirp": "^1.0.4",
- "npm-package-arg": "^9.0.0",
- "npm-packlist": "^3.0.0",
- "npm-pick-manifest": "^7.0.0",
- "npm-registry-fetch": "^13.0.0",
- "proc-log": "^2.0.0",
- "promise-retry": "^2.0.1",
- "read-package-json": "^4.1.1",
- "read-package-json-fast": "^2.0.3",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.1",
- "tar": "^6.1.11"
- }
- },
- "parse-conflict-json": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.1",
- "just-diff": "^5.0.1",
- "just-diff-apply": "^4.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "proc-log": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "promise-all-reject-late": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-call-limit": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-inflight": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "promise-retry": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "err-code": "^2.0.2",
- "retry": "^0.12.0"
- }
- },
- "promzard": {
- "version": "0.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "read": "1"
- }
- },
- "qrcode-terminal": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "read": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "mute-stream": "~0.0.4"
- }
- },
- "read-cmd-shim": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "read-package-json": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.1",
- "json-parse-even-better-errors": "^2.3.0",
- "normalize-package-data": "^3.0.0",
- "npm-normalize-package-bin": "^1.0.0"
- }
- },
- "read-package-json-fast": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "json-parse-even-better-errors": "^2.3.0",
- "npm-normalize-package-bin": "^1.0.1"
- }
- },
- "readable-stream": {
- "version": "3.6.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "readdir-scoped-modules": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "debuglog": "^1.0.1",
- "dezalgo": "^1.0.0",
- "graceful-fs": "^4.1.2",
- "once": "^1.3.0"
- }
- },
- "retry": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "bundled": true,
- "dev": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "semver": {
- "version": "7.3.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.7",
- "bundled": true,
- "dev": true
- },
- "smart-buffer": {
- "version": "4.2.0",
- "bundled": true,
- "dev": true
- },
- "socks": {
- "version": "2.6.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ip": "^1.1.5",
- "smart-buffer": "^4.2.0"
- }
- },
- "socks-proxy-agent": {
- "version": "6.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "agent-base": "^6.0.2",
- "debug": "^4.3.1",
- "socks": "^2.6.1"
- }
- },
- "spdx-correct": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true
- },
- "spdx-expression-parse": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.11",
- "bundled": true,
- "dev": true
- },
- "ssri": {
- "version": "8.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minipass": "^3.1.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
- "string_decoder": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
- "stringify-package": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "tar": {
- "version": "6.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^3.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true
- },
- "tiny-relative-date": {
- "version": "1.3.0",
- "bundled": true,
- "dev": true
- },
- "treeverse": {
- "version": "1.0.4",
- "bundled": true,
- "dev": true
- },
- "unique-filename": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "unique-slug": "^2.0.0"
- }
- },
- "unique-slug": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "validate-npm-package-name": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "builtins": "^1.0.3"
- }
- },
- "walk-up-path": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "wcwidth": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
- "which": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "wide-align": {
- "version": "1.1.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2 || 3 || 4"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "write-file-atomic": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- }
- }
- }
- }
-}
diff --git a/extensions/pod-menu/src/attach-menu.tsx b/extensions/pod-menu/src/attach-menu.tsx
index de8035ed94..fd6250bd30 100644
--- a/extensions/pod-menu/src/attach-menu.tsx
+++ b/extensions/pod-menu/src/attach-menu.tsx
@@ -71,7 +71,11 @@ export class PodAttachMenu extends React.Component {
return (
this.attachToPod(containers[0].name))}>
-
+
Attach Pod
{containers.length > 1 && (
<>
@@ -82,7 +86,11 @@ export class PodAttachMenu extends React.Component {
const { name } = container;
return (
- this.attachToPod(name))} className="flex align-center">
+ this.attachToPod(name))}
+ className="flex align-center"
+ >
{name}
diff --git a/extensions/pod-menu/src/logs-menu.tsx b/extensions/pod-menu/src/logs-menu.tsx
index b7cc0851aa..e5c8496d3d 100644
--- a/extensions/pod-menu/src/logs-menu.tsx
+++ b/extensions/pod-menu/src/logs-menu.tsx
@@ -46,7 +46,11 @@ export class PodLogsMenu extends React.Component {
return (
this.showLogs(containers[0]))}>
-
+
Logs
{containers.length > 1 && (
<>
@@ -63,7 +67,11 @@ export class PodLogsMenu extends React.Component {
) : null;
return (
- this.showLogs(container))} className="flex align-center">
+ this.showLogs(container))}
+ className="flex align-center"
+ >
{brick}
{name}
diff --git a/extensions/pod-menu/src/shell-menu.tsx b/extensions/pod-menu/src/shell-menu.tsx
index 4e239d6fdf..36be7c470b 100644
--- a/extensions/pod-menu/src/shell-menu.tsx
+++ b/extensions/pod-menu/src/shell-menu.tsx
@@ -79,7 +79,11 @@ export class PodShellMenu extends React.Component {
return (
this.execShell(containers[0].name))}>
-
+
Shell
{containers.length > 1 && (
<>
@@ -90,7 +94,11 @@ export class PodShellMenu extends React.Component {
const { name } = container;
return (
- this.execShell(name))} className="flex align-center">
+ this.execShell(name))}
+ className="flex align-center"
+ >
{name}
diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts
index 981628b1ba..b56b999b2b 100644
--- a/integration/__tests__/cluster-pages.tests.ts
+++ b/integration/__tests__/cluster-pages.tests.ts
@@ -39,14 +39,14 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
await frame.waitForSelector(`.Menu >> text="Remove"`);
});
- it("opens cluster settings by clicking link in no-metrics area", async () => {
+ // FIXME: failed locally since metrics might already exist, cc @aleksfront
+ it.skip("opens cluster settings by clicking link in no-metrics area", async () => {
await frame.locator("text=Open cluster settings >> nth=0").click();
await window.waitForSelector(`[data-testid="metrics-header"]`);
});
it(
"should navigate around common cluster pages",
-
async () => {
const scenariosByParent = pipeline(
scenarios,
@@ -138,7 +138,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
);
it(
- `should create the ${TEST_NAMESPACE} and a pod in the namespace`,
+ `should create the ${TEST_NAMESPACE} and a pod in the namespace and then remove that pod via the context menu`,
async () => {
await navigateToNamespaces(frame);
await frame.click("button.add-button");
@@ -208,6 +208,10 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
await frame.click(".Dock .Button >> text='Create'");
await frame.waitForSelector(`.TableCell >> text=${testPodName}`);
+ await frame.click(".TableRow .TableCell.menu");
+ await frame.click(".MenuItem >> text=Delete");
+ await frame.click("button >> text=Remove");
+ await frame.waitForSelector(`.TableCell >> text=${testPodName}`, { state: "detached" });
},
10 * 60 * 1000,
);
diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts
index b1d43bcd2e..7073d1d4cc 100644
--- a/integration/__tests__/command-palette.tests.ts
+++ b/integration/__tests__/command-palette.tests.ts
@@ -24,9 +24,9 @@ describe("Lens command palette", () => {
utils.itIf(!isWindows)("opens command dialog from menu", async () => {
await app.evaluate(async ({ app }) => {
await app.applicationMenu
- .getMenuItemById("view")
- .submenu.getMenuItemById("command-palette")
- .click();
+ ?.getMenuItemById("view")
+ ?.submenu?.getMenuItemById("command-palette")
+ ?.click();
});
await window.waitForSelector(".Select__option >> text=Hotbar: Switch");
}, 10*60*1000);
diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts
index 33dabede04..f8eca46c26 100644
--- a/integration/helpers/utils.ts
+++ b/integration/helpers/utils.ts
@@ -108,6 +108,10 @@ export async function lauchMinikubeClusterFromCatalog(window: Page): Promise/integration/\"]; }; func",
"dist": "yarn run compile && electron-builder --publish onTag",
"dist:dir": "yarn run dist --dir -c.compression=store -c.mac.identity=null",
"download:binaries": "yarn run ts-node build/download_binaries.ts",
- "build:tray-icons": "yarn run ts-node build/build_tray_icon.ts",
+ "build:tray-icons": "yarn run ts-node build/generate-tray-icons.ts",
"build:theme-vars": "yarn run ts-node build/build_theme_vars.ts",
"lint": "PROD=true yarn run eslint --ext js,ts,tsx --max-warnings=0 .",
"lint:fix": "yarn run lint --fix",
@@ -72,6 +72,9 @@
"/src/jest.setup.ts",
"jest-canvas-mock"
],
+ "setupFilesAfterEnv": [
+ "/src/jest-after-env.setup.ts"
+ ],
"globals": {
"ts-jest": {
"isolatedModules": true
@@ -203,9 +206,11 @@
"@hapi/call": "^8.0.1",
"@hapi/subtext": "^7.0.3",
"@kubernetes/client-node": "^0.16.3",
- "@ogre-tools/fp": "5.2.0",
- "@ogre-tools/injectable": "5.2.0",
- "@ogre-tools/injectable-react": "5.2.0",
+ "@material-ui/styles": "^4.11.5",
+ "@ogre-tools/injectable": "7.0.0",
+ "@ogre-tools/injectable-react": "7.0.0",
+ "@ogre-tools/fp": "7.0.0",
+ "@ogre-tools/injectable-extension-for-auto-registration": "7.0.0",
"@sentry/electron": "^3.0.7",
"@sentry/integrations": "^6.19.3",
"@types/circular-dependency-plugin": "5.0.5",
@@ -222,21 +227,22 @@
"filehound": "^1.17.6",
"fs-extra": "^9.0.1",
"glob-to-regexp": "^0.4.1",
- "got": "^11.8.3",
+ "got": "^11.8.5",
"grapheme-splitter": "^1.0.4",
"handlebars": "^4.7.7",
+ "history": "^4.10.1",
"http-proxy": "^1.18.1",
- "immer": "^9.0.12",
+ "immer": "^9.0.14",
"joi": "^17.6.0",
"js-yaml": "^4.1.0",
"jsdom": "^16.7.0",
"lodash": "^4.17.15",
"mac-ca": "^1.0.6",
- "marked": "^4.0.15",
+ "marked": "^4.0.16",
"md5-file": "^5.0.0",
"mobx": "^6.5.0",
"mobx-observable-history": "^2.0.3",
- "mobx-react": "^7.3.0",
+ "mobx-react": "^7.5.0",
"mobx-utils": "^6.0.4",
"mock-fs": "^5.1.2",
"moment": "^2.29.3",
@@ -265,35 +271,38 @@
"tar": "^6.1.11",
"tcp-port-used": "^1.0.2",
"tempy": "1.0.1",
+ "typed-regex": "^0.0.8",
"url-parse": "^1.5.10",
"uuid": "^8.3.2",
"win-ca": "^3.5.0",
"winston": "^3.7.2",
"winston-console-format": "^1.0.8",
"winston-transport-browserconsole": "^1.0.5",
- "ws": "^7.5.7"
+ "ws": "^8.7.0"
},
"devDependencies": {
- "@async-fn/jest": "1.5.3",
+ "@async-fn/jest": "1.6.1",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
- "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@sentry/types": "^6.19.7",
+ "@testing-library/dom": "^7.31.2",
"@testing-library/jest-dom": "^5.16.4",
- "@testing-library/react": "^12.1.4",
+ "@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^13.5.0",
"@types/byline": "^4.2.33",
"@types/chart.js": "^2.9.36",
- "@types/cli-progress": "^3.9.2",
+ "@types/circular-dependency-plugin": "5.0.5",
+ "@types/cli-progress": "^3.11.0",
"@types/color": "^3.0.3",
+ "@types/command-line-args": "^5.2.0",
"@types/crypto-js": "^3.1.47",
"@types/dompurify": "^2.3.3",
"@types/electron-devtools-installer": "^2.2.1",
"@types/fs-extra": "^9.0.13",
"@types/glob-to-regexp": "^0.4.1",
"@types/gunzip-maybe": "^1.4.0",
- "@types/hoist-non-react-statics": "^3.3.1",
"@types/html-webpack-plugin": "^3.2.6",
"@types/http-proxy": "^1.17.9",
"@types/jest": "^26.0.24",
@@ -304,17 +313,17 @@
"@types/md5-file": "^4.0.2",
"@types/mini-css-extract-plugin": "^2.4.0",
"@types/mock-fs": "^4.13.1",
- "@types/node": "14.18.12",
+ "@types/node": "14.18.18",
"@types/node-fetch": "^2.6.1",
"@types/npm": "^2.0.32",
"@types/proper-lockfile": "^4.1.2",
"@types/randomcolor": "^0.5.6",
- "@types/react": "^17.0.44",
+ "@types/react": "^17.0.45",
"@types/react-beautiful-dnd": "^13.1.2",
- "@types/react-dom": "^17.0.14",
+ "@types/react-dom": "^17.0.16",
+ "@types/react-router": "^5.1.18",
"@types/react-router-dom": "^5.3.3",
- "@types/react-select": "3.1.2",
- "@types/react-table": "^7.7.11",
+ "@types/react-table": "^7.7.12",
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5",
"@types/readable-stream": "^2.3.13",
@@ -332,34 +341,34 @@
"@types/uuid": "^8.3.4",
"@types/webpack": "^5.28.0",
"@types/webpack-dev-server": "^4.7.2",
- "@types/webpack-env": "^1.16.3",
+ "@types/webpack-env": "^1.17.0",
"@types/webpack-node-externals": "^2.5.3",
- "@typescript-eslint/eslint-plugin": "^5.21.0",
- "@typescript-eslint/parser": "^5.17.0",
+ "@typescript-eslint/eslint-plugin": "^5.27.0",
+ "@typescript-eslint/parser": "^5.27.0",
"ansi_up": "^5.1.0",
"chart.js": "^2.9.4",
"circular-dependency-plugin": "^5.2.2",
- "cli-progress": "^3.11.0",
+ "cli-progress": "^3.11.1",
"color": "^3.2.1",
- "concurrently": "^7.1.0",
+ "command-line-args": "^5.2.1",
+ "concurrently": "^7.2.1",
"css-loader": "^6.7.1",
"deepdash": "^5.3.9",
- "dompurify": "^2.3.6",
+ "dompurify": "^2.3.8",
"electron": "^14.2.9",
"electron-builder": "^23.0.3",
"electron-notarize": "^0.3.0",
"esbuild": "^0.14.38",
- "esbuild-loader": "^2.18.0",
- "eslint": "^8.14.0",
+ "esbuild-loader": "^2.19.0",
+ "eslint": "^8.16.0",
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-import": "^2.26.0",
- "eslint-plugin-react": "^7.29.4",
- "eslint-plugin-react-hooks": "^4.4.0",
+ "eslint-plugin-react": "^7.30.0",
+ "eslint-plugin-react-hooks": "^4.5.0",
"eslint-plugin-unused-imports": "^2.0.0",
"flex.box": "^3.4.4",
- "fork-ts-checker-webpack-plugin": "^6.5.0",
+ "fork-ts-checker-webpack-plugin": "^6.5.2",
"gunzip-maybe": "^1.4.2",
- "hoist-non-react-statics": "^3.3.2",
"html-webpack-plugin": "^5.5.0",
"identity-obj-proxy": "^3.0.0",
"ignore-loader": "^0.1.2",
@@ -374,37 +383,36 @@
"node-gyp": "7.1.2",
"node-loader": "^2.0.0",
"nodemon": "^2.0.16",
- "playwright": "^1.20.2",
- "postcss": "^8.4.12",
+ "playwright": "^1.22.2",
+ "postcss": "^8.4.14",
"postcss-loader": "^6.2.1",
"randomcolor": "^0.6.2",
"react-beautiful-dnd": "^13.1.0",
- "react-refresh": "^0.12.0",
- "react-refresh-typescript": "^2.0.4",
- "react-router-dom": "^5.3.1",
- "react-select": "^5.3.0",
+ "react-refresh": "^0.13.0",
+ "react-refresh-typescript": "^2.0.5",
+ "react-router-dom": "^5.3.3",
+ "react-select": "^5.3.2",
"react-select-event": "^5.5.0",
- "react-table": "^7.7.0",
- "react-window": "^1.8.6",
- "sass": "^1.51.0",
+ "react-table": "^7.8.0",
+ "react-window": "^1.8.7",
+ "sass": "^1.52.2",
"sass-loader": "^12.6.0",
- "sharp": "^0.30.4",
+ "sharp": "^0.30.6",
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.23",
"tar-stream": "^2.2.0",
"ts-jest": "26.5.6",
"ts-loader": "^9.2.8",
"ts-node": "^10.7.0",
- "type-fest": "^2.12.2",
+ "type-fest": "^2.13.0",
"typed-emitter": "^1.4.0",
- "typedoc": "0.22.15",
+ "typedoc": "0.22.17",
"typedoc-plugin-markdown": "^3.11.12",
- "typeface-roboto": "^1.1.13",
"typescript": "^4.5.5",
"typescript-plugin-css-modules": "^3.4.0",
- "webpack": "^5.72.0",
+ "webpack": "^5.73.0",
"webpack-cli": "^4.9.2",
- "webpack-dev-server": "^4.8.1",
+ "webpack-dev-server": "^4.9.1",
"webpack-node-externals": "^3.0.0",
"xterm": "^4.18.0",
"xterm-addon-fit": "^0.5.0"
diff --git a/scripts/clear-release-pr.mjs b/scripts/clear-release-pr.mjs
new file mode 100755
index 0000000000..4b55384e61
--- /dev/null
+++ b/scripts/clear-release-pr.mjs
@@ -0,0 +1,210 @@
+#!/usr/bin/env node
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+// This script creates a release PR
+import { execSync, exec, spawn } from "child_process";
+import commandLineArgs from "command-line-args";
+import fse from "fs-extra";
+import { basename } from "path";
+import semver from "semver";
+import { promisify } from "util";
+
+const {
+ SemVer,
+ valid: semverValid,
+ rcompare: semverRcompare,
+ lte: semverLte,
+} = semver;
+const { readJsonSync } = fse;
+const execP = promisify(exec);
+
+const options = commandLineArgs([
+ {
+ name: "type",
+ defaultOption: true,
+ },
+ {
+ name: "preid",
+ },
+]);
+
+const validReleaseValues = [
+ "major",
+ "minor",
+ "patch",
+];
+const validPrereleaseValues = [
+ "premajor",
+ "preminor",
+ "prepatch",
+ "prerelease",
+];
+const validPreidValues = [
+ "alpha",
+ "beta",
+];
+
+const errorMessages = {
+ noReleaseType: `No release type provided. Valid options are: ${[...validReleaseValues, ...validPrereleaseValues].join(", ")}`,
+ invalidRelease: (invalid) => `Invalid release type was provided (value was "${invalid}"). Valid options are: ${[...validReleaseValues, ...validPrereleaseValues].join(", ")}`,
+ noPreid: `No preid was provided. Use '--preid' to specify. Valid options are: ${validPreidValues.join(", ")}`,
+ invalidPreid: (invalid) => `Invalid preid was provided (value was "${invalid}"). Valid options are: ${validPreidValues.join(", ")}`,
+ wrongCwd: "It looks like you are running this script from the 'scripts' directory. This script assumes it is run from the root of the git repo",
+};
+
+if (!options.type) {
+ console.error(errorMessages.noReleaseType);
+ process.exit(1);
+}
+
+if (validReleaseValues.includes(options.type)) {
+ // do nothing, is valid
+} else if (validPrereleaseValues.includes(options.type)) {
+ if (!options.preid) {
+ console.error(errorMessages.noPreid);
+ process.exit(1);
+ }
+
+ if (!validPreidValues.includes(options.preid)) {
+ console.error(errorMessages.invalidPreid(options.preid));
+ process.exit(1);
+ }
+} else {
+ console.error(errorMessages.invalidRelease(options.type));
+ process.exit(1);
+}
+
+if (basename(process.cwd()) === "scripts") {
+ console.error(errorMessages.wrongCwd);
+}
+
+
+const currentVersion = new SemVer(readJsonSync("./package.json").version);
+const currentVersionMilestone = `${currentVersion.major}.${currentVersion.minor}.${currentVersion.patch}`;
+
+console.log(`current version: ${currentVersion.format()}`);
+console.log("fetching tags...");
+execSync("git fetch --tags --force");
+
+const actualTags = execSync("git tag --list", { encoding: "utf-8" }).split(/\r?\n/).map(line => line.trim());
+const [previousReleasedVersion] = actualTags
+ .map(semverValid)
+ .filter(Boolean)
+ .sort(semverRcompare)
+ .filter(version => semverLte(version, currentVersion));
+
+const npmVersionArgs = [
+ "npm",
+ "version",
+ options.type,
+];
+
+if (options.preid) {
+ npmVersionArgs.push(`--preid=${options.preid}`);
+}
+
+npmVersionArgs.push("--git-tag-version false");
+
+execSync(npmVersionArgs.join(" "), { stdio: "ignore" });
+
+const newVersion = new SemVer(readJsonSync("./package.json").version);
+
+const getMergedPrsArgs = [
+ "gh",
+ "pr",
+ "list",
+ "--limit=500", // Should be big enough, if not we need to release more often ;)
+ "--state=merged",
+ "--base=master",
+ "--json mergeCommit,title,author,labels,number,milestone",
+];
+
+console.log("retreiving last 500 PRs to create release PR body...");
+const mergedPrs = JSON.parse(execSync(getMergedPrsArgs.join(" "), { encoding: "utf-8" }));
+const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone && pr.milestone.title === currentVersionMilestone);
+const relaventPrsQuery = await Promise.all(
+ milestoneRelevantPrs.map(async pr => ({
+ pr,
+ stdout: (await execP(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout,
+ })),
+);
+const relaventPrs = relaventPrsQuery
+ .filter(query => query.stdout)
+ .map(query => query.pr);
+
+const enhancementPrLabelName = "enhancement";
+const bugfixPrLabelName = "bug";
+
+const enhancementPrs = relaventPrs.filter(pr => pr.labels.some(label => label.name === enhancementPrLabelName));
+const bugfixPrs = relaventPrs.filter(pr => pr.labels.some(label => label.name === bugfixPrLabelName));
+const maintenencePrs = relaventPrs.filter(pr => pr.labels.every(label => label.name !== bugfixPrLabelName && label.name !== enhancementPrLabelName));
+
+console.log("Found:");
+console.log(`${enhancementPrs.length} enhancement PRs`);
+console.log(`${bugfixPrs.length} bug fix PRs`);
+console.log(`${maintenencePrs.length} maintenence PRs`);
+
+const prBodyLines = [
+ `## Changes since ${previousReleasedVersion}`,
+ "",
+];
+
+if (enhancementPrs.length > 0) {
+ prBodyLines.push(
+ "## 🚀 Features",
+ "",
+ ...enhancementPrs.map(pr => `- ${pr.title} (**#${pr.number}**) https://github.com/${pr.author.login}`),
+ "",
+ );
+}
+
+if (bugfixPrs.length > 0) {
+ prBodyLines.push(
+ "## 🐛 Bug Fixes",
+ "",
+ ...bugfixPrs.map(pr => `- ${pr.title} (**#${pr.number}**) https://github.com/${pr.author.login}`),
+ "",
+ );
+}
+
+if (maintenencePrs.length > 0) {
+ prBodyLines.push(
+ "## 🧰 Maintenance",
+ "",
+ ...maintenencePrs.map(pr => `- ${pr.title} (**#${pr.number}**) https://github.com/${pr.author.login}`),
+ "",
+ );
+}
+
+const prBody = prBodyLines.join("\n");
+const prBase = newVersion.patch === 0
+ ? "master"
+ : `release/v${newVersion.major}.${newVersion.minor}`;
+const createPrArgs = [
+ "pr",
+ "create",
+ "--base", prBase,
+ "--title", `release ${newVersion.format()}`,
+ "--label", "skip-changelog",
+ "--body-file", "-",
+];
+
+const createPrProcess = spawn("gh", createPrArgs, { stdio: "pipe" });
+let result = "";
+
+createPrProcess.stdout.on("data", (chunk) => result += chunk);
+
+createPrProcess.stdin.write(prBody);
+createPrProcess.stdin.end();
+
+await new Promise((resolve) => {
+ createPrProcess.on("close", () => {
+ createPrProcess.stdout.removeAllListeners();
+ resolve();
+ });
+});
+
+console.log(result);
diff --git a/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap b/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap
index 3b43a51f66..80b0028469 100644
--- a/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap
+++ b/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap
@@ -1,11 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`extension special characters in page registrations renders 1`] = `
`;
+exports[`extension special characters in page registrations renders 1`] = `
+
+`;
exports[`extension special characters in page registrations when navigating to route with ID having special characters renders 1`] = `
`;
diff --git a/src/behaviours/__snapshots__/navigate-to-extension-page.test.tsx.snap b/src/behaviours/__snapshots__/navigate-to-extension-page.test.tsx.snap
index edab04b903..c96763fe6e 100644
--- a/src/behaviours/__snapshots__/navigate-to-extension-page.test.tsx.snap
+++ b/src/behaviours/__snapshots__/navigate-to-extension-page.test.tsx.snap
@@ -1,12 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`navigate to extension page renders 1`] = `
`;
+exports[`navigate to extension page renders 1`] = `
+
+`;
exports[`navigate to extension page when extension navigates to child route renders 1`] = `
`;
@@ -31,6 +40,9 @@ exports[`navigate to extension page when extension navigates to route with param
Some button
+
`;
@@ -55,6 +67,9 @@ exports[`navigate to extension page when extension navigates to route without pa
Some button
+
`;
@@ -79,5 +94,8 @@ exports[`navigate to extension page when extension navigates to route without pa
Some button
+
`;
diff --git a/src/behaviours/__snapshots__/navigating-between-routes.test.tsx.snap b/src/behaviours/__snapshots__/navigating-between-routes.test.tsx.snap
index 90ff615b2b..10e9eb2d39 100644
--- a/src/behaviours/__snapshots__/navigating-between-routes.test.tsx.snap
+++ b/src/behaviours/__snapshots__/navigating-between-routes.test.tsx.snap
@@ -8,6 +8,9 @@ exports[`navigating between routes given route with optional path parameters whe
"someOtherParameter": "some-other-value"
}
+
`;
@@ -16,5 +19,8 @@ exports[`navigating between routes given route without path parameters when navi
Some component
+
`;
diff --git a/src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap
similarity index 88%
rename from src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.ts.snap
rename to src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap
index 4c1203829a..0fd00133aa 100644
--- a/src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.ts.snap
+++ b/src/behaviours/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap
@@ -1,6 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`add-cluster - navigation using application menu renders 1`] = `
`;
+exports[`add-cluster - navigation using application menu renders 1`] = `
+
+`;
exports[`add-cluster - navigation using application menu when navigating to add cluster using application menu renders 1`] = `
@@ -19,7 +25,7 @@ exports[`add-cluster - navigation using application menu when navigating to add
Add Clusters from Kubeconfig
- Clusters added here are
+ Clusters added here are
not
@@ -27,16 +33,14 @@ exports[`add-cluster - navigation using application menu when navigating to add
~/.kube/config
- file.
-
+ file.
- Read more about adding clusters
+ Read more about adding clusters.
- .
+
`;
diff --git a/src/behaviours/add-cluster/navigation-using-application-menu.test.ts b/src/behaviours/add-cluster/navigation-using-application-menu.test.tsx
similarity index 72%
rename from src/behaviours/add-cluster/navigation-using-application-menu.test.ts
rename to src/behaviours/add-cluster/navigation-using-application-menu.test.tsx
index cc7749a7e9..bb68918c1a 100644
--- a/src/behaviours/add-cluster/navigation-using-application-menu.test.ts
+++ b/src/behaviours/add-cluster/navigation-using-application-menu.test.tsx
@@ -6,20 +6,27 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
+import React from "react";
// TODO: Make components free of side effects by making them deterministic
-jest.mock("../../renderer/components/tooltip");
-jest.mock("../../renderer/components/monaco-editor/monaco-editor");
+jest.mock("../../renderer/components/tooltip/tooltip", () => ({
+ Tooltip: () => null,
+}));
+
+jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
+ withTooltip: (Target: any) => ({ tooltip, tooltipOverrideDisabled, ...props }: any) => ,
+}));
+
+jest.mock("../../renderer/components/monaco-editor/monaco-editor", () => ({
+ MonacoEditor: () => null,
+}));
describe("add-cluster - navigation using application menu", () => {
let applicationBuilder: ApplicationBuilder;
let rendered: RenderResult;
beforeEach(async () => {
- applicationBuilder = getApplicationBuilder().beforeSetups(({ mainDi }) => {
- mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
- });
+ applicationBuilder = getApplicationBuilder();
rendered = await applicationBuilder.render();
});
@@ -35,8 +42,8 @@ describe("add-cluster - navigation using application menu", () => {
});
describe("when navigating to add cluster using application menu", () => {
- beforeEach(() => {
- applicationBuilder.applicationMenu.click("file.add-cluster");
+ beforeEach(async () => {
+ await applicationBuilder.applicationMenu.click("file.add-cluster");
});
it("renders", () => {
diff --git a/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap b/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap
new file mode 100644
index 0000000000..32e6cb1cb1
--- /dev/null
+++ b/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap
@@ -0,0 +1,536 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`installing update using tray when started renders 1`] = `
+
+
+
+`;
+
+exports[`installing update using tray when started when user checks for updates using tray renders 1`] = `
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Checking for updates...
+
+
+
+
+ close
+
+
+
+
+
+
+
+`;
+
+exports[`installing update using tray when started when user checks for updates using tray when new update is discovered renders 1`] = `
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Checking for updates...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Download for version some-version started...
+
+
+
+
+ close
+
+
+
+
+
+
+
+`;
+
+exports[`installing update using tray when started when user checks for updates using tray when new update is discovered when download fails renders 1`] = `
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Checking for updates...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Download for version some-version started...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Download of update failed
+
+
+
+
+ close
+
+
+
+
+
+
+
+`;
+
+exports[`installing update using tray when started when user checks for updates using tray when new update is discovered when download succeeds renders 1`] = `
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Checking for updates...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Download for version some-version started...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+
+
+ Update Available
+
+
+ Version some-version of Lens IDE is available and ready to be installed. Would you like to update now?
+
+Lens should restart automatically, if it doesn't please restart manually. Installed extensions might require updating.
+
+
+
+ Yes
+
+
+ No
+
+
+
+
+
+
+
+ close
+
+
+
+
+
+
+
+`;
+
+exports[`installing update using tray when started when user checks for updates using tray when no new update is discovered renders 1`] = `
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ Checking for updates...
+
+
+
+
+ close
+
+
+
+
+
+
+
+
+ info_outline
+
+
+
+
+ No new updates available
+
+
+
+
+ close
+
+
+
+
+
+
+
+`;
diff --git a/src/behaviours/application-update/__snapshots__/installing-update.test.ts.snap b/src/behaviours/application-update/__snapshots__/installing-update.test.ts.snap
new file mode 100644
index 0000000000..7025289254
--- /dev/null
+++ b/src/behaviours/application-update/__snapshots__/installing-update.test.ts.snap
@@ -0,0 +1,81 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`installing update when started renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when new update is discovered renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when new update is discovered when download fails renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when new update is discovered when download succeeds renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when new update is discovered when download succeeds when user answers not to install the update renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when new update is discovered when download succeeds when user answers to install the update renders 1`] = `
+
+
+
+`;
+
+exports[`installing update when started when user checks for updates when no new update is discovered renders 1`] = `
+
+
+
+`;
diff --git a/src/behaviours/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap b/src/behaviours/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap
new file mode 100644
index 0000000000..84fa35ae04
--- /dev/null
+++ b/src/behaviours/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`periodical checking of updates given updater is enabled and configuration exists, when started renders 1`] = `
+
+
+
+`;
diff --git a/src/behaviours/application-update/__snapshots__/selection-of-update-stability.test.ts.snap b/src/behaviours/application-update/__snapshots__/selection-of-update-stability.test.ts.snap
new file mode 100644
index 0000000000..dc96c447b0
--- /dev/null
+++ b/src/behaviours/application-update/__snapshots__/selection-of-update-stability.test.ts.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`selection of update stability when started renders 1`] = `
+
+
+
+`;
diff --git a/src/behaviours/application-update/downgrading-version-update.test.ts b/src/behaviours/application-update/downgrading-version-update.test.ts
new file mode 100644
index 0000000000..e8e5635fb3
--- /dev/null
+++ b/src/behaviours/application-update/downgrading-version-update.test.ts
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
+import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
+import type { AsyncFnMock } from "@async-fn/jest";
+import asyncFn from "@async-fn/jest";
+import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
+import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
+import type { DiContainer } from "@ogre-tools/injectable";
+import appVersionInjectable from "../../common/get-configuration-file-model/app-version/app-version.injectable";
+import { updateChannels } from "../../common/application-update/update-channels";
+
+describe("downgrading version update", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let checkForPlatformUpdatesMock: AsyncFnMock;
+ let mainDi: DiContainer;
+
+ beforeEach(() => {
+ jest.useFakeTimers();
+
+ applicationBuilder = getApplicationBuilder();
+
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ checkForPlatformUpdatesMock = asyncFn();
+
+ mainDi.override(
+ checkForPlatformUpdatesInjectable,
+ () => checkForPlatformUpdatesMock,
+ );
+
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+
+ mainDi = applicationBuilder.dis.mainDi;
+ });
+
+ [
+ {
+ updateChannel: updateChannels.latest,
+ appVersion: "4.0.0-beta",
+ downgradeIsAllowed: true,
+ },
+ {
+ updateChannel: updateChannels.beta,
+ appVersion: "4.0.0-beta",
+ downgradeIsAllowed: false,
+ },
+ {
+ updateChannel: updateChannels.beta,
+ appVersion: "4.0.0-beta.1",
+ downgradeIsAllowed: false,
+ },
+ {
+ updateChannel: updateChannels.alpha,
+ appVersion: "4.0.0-beta",
+ downgradeIsAllowed: true,
+ },
+ {
+ updateChannel: updateChannels.alpha,
+ appVersion: "4.0.0-alpha",
+ downgradeIsAllowed: false,
+ },
+ ].forEach(({ appVersion, updateChannel, downgradeIsAllowed }) => {
+ it(`given application version "${appVersion}" and update channel "${updateChannel.id}", when checking for updates, can${downgradeIsAllowed ? "": "not"} downgrade`, async () => {
+ mainDi.override(appVersionInjectable, () => appVersion);
+
+ await applicationBuilder.render();
+
+ const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
+
+ selectedUpdateChannel.setValue(updateChannel.id);
+
+ const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(expect.any(Object), { allowDowngrade: downgradeIsAllowed });
+ });
+ });
+});
diff --git a/src/behaviours/application-update/installing-update-using-tray.test.ts b/src/behaviours/application-update/installing-update-using-tray.test.ts
new file mode 100644
index 0000000000..f6570bb8fa
--- /dev/null
+++ b/src/behaviours/application-update/installing-update-using-tray.test.ts
@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import type { RenderResult } from "@testing-library/react";
+import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
+import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
+import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import type { AsyncFnMock } from "@async-fn/jest";
+import asyncFn from "@async-fn/jest";
+import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import showApplicationWindowInjectable from "../../main/start-main-application/lens-window/show-application-window.injectable";
+import progressOfUpdateDownloadInjectable from "../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
+
+describe("installing update using tray", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let checkForPlatformUpdatesMock: AsyncFnMock;
+ let downloadPlatformUpdateMock: AsyncFnMock;
+ let showApplicationWindowMock: jest.Mock;
+
+ beforeEach(() => {
+ applicationBuilder = getApplicationBuilder();
+
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ checkForPlatformUpdatesMock = asyncFn();
+ downloadPlatformUpdateMock = asyncFn();
+ showApplicationWindowMock = jest.fn();
+
+ mainDi.override(showApplicationWindowInjectable, () => showApplicationWindowMock);
+
+ mainDi.override(
+ checkForPlatformUpdatesInjectable,
+ () => checkForPlatformUpdatesMock,
+ );
+
+ mainDi.override(
+ downloadPlatformUpdateInjectable,
+ () => downloadPlatformUpdateMock,
+ );
+
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+ });
+
+ describe("when started", () => {
+ let rendered: RenderResult;
+
+ beforeEach(async () => {
+ rendered = await applicationBuilder.render();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("user cannot install update yet", () => {
+ expect(applicationBuilder.tray.get("install-update")).toBeUndefined();
+ });
+
+ describe("when user checks for updates using tray", () => {
+ let processCheckingForUpdatesPromise: Promise;
+
+ beforeEach(async () => {
+ processCheckingForUpdatesPromise =
+ applicationBuilder.tray.click("check-for-updates");
+ });
+
+ it("does not show application window yet", () => {
+ expect(showApplicationWindowMock).not.toHaveBeenCalled();
+ });
+
+ it("user cannot check for updates again", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
+ ).toBe(false);
+ });
+
+ it("name of tray item for checking updates indicates that checking is happening", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Checking for updates...");
+ });
+
+ it("user cannot install update yet", () => {
+ expect(applicationBuilder.tray.get("install-update")).toBeUndefined();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe("when no new update is discovered", () => {
+ beforeEach(async () => {
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: false,
+ });
+
+ await processCheckingForUpdatesPromise;
+ });
+
+ it("shows application window", () => {
+ expect(showApplicationWindowMock).toHaveBeenCalled();
+ });
+
+ it("user cannot install update", () => {
+ expect(applicationBuilder.tray.get("install-update")).toBeUndefined();
+ });
+
+ it("user can check for updates again", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
+ ).toBe(true);
+ });
+
+ it("name of tray item for checking updates no longer indicates that checking is happening", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Check for updates");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+ });
+
+ describe("when new update is discovered", () => {
+ beforeEach(async () => {
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-version",
+ });
+
+ await processCheckingForUpdatesPromise;
+ });
+
+ it("shows application window", () => {
+ expect(showApplicationWindowMock).toHaveBeenCalled();
+ });
+
+ it("user cannot check for updates again yet", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
+ ).toBe(false);
+ });
+
+ it("name of tray item for checking updates indicates that downloading is happening", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Downloading update some-version (0%)...");
+ });
+
+ it("when download progresses with decimals, percentage increases as integers", () => {
+ const progressOfUpdateDownload = applicationBuilder.dis.mainDi.inject(
+ progressOfUpdateDownloadInjectable,
+ );
+
+ progressOfUpdateDownload.set({ percentage: 42.424242 });
+
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Downloading update some-version (42%)...");
+ });
+
+ it("user still cannot install update", () => {
+ expect(applicationBuilder.tray.get("install-update")).toBeUndefined();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe("when download fails", () => {
+ beforeEach(async () => {
+ await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false });
+ });
+
+ it("user cannot install update", () => {
+ expect(
+ applicationBuilder.tray.get("install-update"),
+ ).toBeUndefined();
+ });
+
+ it("user can check for updates again", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
+ ).toBe(true);
+ });
+
+ it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Check for updates");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+ });
+
+ describe("when download succeeds", () => {
+ beforeEach(async () => {
+ await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
+ });
+
+ it("user can install update", () => {
+ expect(
+ applicationBuilder.tray.get("install-update")?.label?.get(),
+ ).toBe("Install update some-version");
+ });
+
+ it("user can check for updates again", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
+ ).toBe(true);
+ });
+
+ it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
+ expect(
+ applicationBuilder.tray.get("check-for-updates")?.label?.get(),
+ ).toBe("Check for updates");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/src/behaviours/application-update/installing-update.test.ts b/src/behaviours/application-update/installing-update.test.ts
new file mode 100644
index 0000000000..3fec5f6d27
--- /dev/null
+++ b/src/behaviours/application-update/installing-update.test.ts
@@ -0,0 +1,225 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import quitAndInstallUpdateInjectable from "../../main/electron-app/features/quit-and-install-update.injectable";
+import type { RenderResult } from "@testing-library/react";
+import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
+import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
+import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import type { AsyncFnMock } from "@async-fn/jest";
+import asyncFn from "@async-fn/jest";
+import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
+import type { AskBoolean } from "../../main/ask-boolean/ask-boolean.injectable";
+import askBooleanInjectable from "../../main/ask-boolean/ask-boolean.injectable";
+import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
+import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
+
+describe("installing update", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let quitAndInstallUpdateMock: jest.Mock;
+ let checkForPlatformUpdatesMock: AsyncFnMock;
+ let downloadPlatformUpdateMock: AsyncFnMock;
+ let setUpdateOnQuitMock: jest.Mock;
+ let showInfoNotificationMock: jest.Mock;
+ let askBooleanMock: AsyncFnMock;
+
+ beforeEach(() => {
+ applicationBuilder = getApplicationBuilder();
+
+ applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
+ quitAndInstallUpdateMock = jest.fn();
+ checkForPlatformUpdatesMock = asyncFn();
+ downloadPlatformUpdateMock = asyncFn();
+ setUpdateOnQuitMock = jest.fn();
+ showInfoNotificationMock = jest.fn(() => () => {});
+ askBooleanMock = asyncFn();
+
+ rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
+
+ mainDi.override(askBooleanInjectable, () => askBooleanMock);
+ mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
+
+ mainDi.override(
+ checkForPlatformUpdatesInjectable,
+ () => checkForPlatformUpdatesMock,
+ );
+
+ mainDi.override(
+ downloadPlatformUpdateInjectable,
+ () => downloadPlatformUpdateMock,
+ );
+
+ mainDi.override(
+ quitAndInstallUpdateInjectable,
+ () => quitAndInstallUpdateMock,
+ );
+
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+ });
+
+ describe("when started", () => {
+ let rendered: RenderResult;
+ let processCheckingForUpdates: () => Promise;
+
+ beforeEach(async () => {
+ rendered = await applicationBuilder.render();
+
+ processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe("when user checks for updates", () => {
+ let processCheckingForUpdatesPromise: Promise;
+
+ beforeEach(async () => {
+ processCheckingForUpdatesPromise = processCheckingForUpdates();
+ });
+
+ it("checks for updates", () => {
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
+ expect.any(Object),
+ { allowDowngrade: true },
+ );
+ });
+
+ it("notifies the user that checking for updates is happening", () => {
+ expect(showInfoNotificationMock).toHaveBeenCalledWith("Checking for updates...");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe("when no new update is discovered", () => {
+ beforeEach(async () => {
+ showInfoNotificationMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: false,
+ });
+
+ await processCheckingForUpdatesPromise;
+ });
+
+ it("notifies the user", () => {
+ expect(showInfoNotificationMock).toHaveBeenCalledWith("No new updates available");
+ });
+
+ it("does not start downloading update", () => {
+ expect(downloadPlatformUpdateMock).not.toHaveBeenCalled();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+ });
+
+ describe("when new update is discovered", () => {
+ beforeEach(async () => {
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-version",
+ });
+
+ await processCheckingForUpdatesPromise;
+ });
+
+ it("starts downloading the update", () => {
+ expect(downloadPlatformUpdateMock).toHaveBeenCalled();
+ });
+
+ it("notifies the user that download is happening", () => {
+ expect(showInfoNotificationMock).toHaveBeenCalledWith("Download for version some-version started...");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe("when download fails", () => {
+ beforeEach(async () => {
+ await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false });
+ });
+
+ it("does not quit and install update yet", () => {
+ expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
+ });
+
+ it("notifies the user about failed download", () => {
+ expect(showInfoNotificationMock).toHaveBeenCalledWith("Download of update failed");
+ });
+
+ it("does not ask user to install update", () => {
+ expect(askBooleanMock).not.toHaveBeenCalled();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+ });
+
+ describe("when download succeeds", () => {
+ beforeEach(async () => {
+ await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
+ });
+
+ it("does not quit and install update yet", () => {
+ expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("asks user to install update immediately", () => {
+ expect(askBooleanMock).toHaveBeenCalledWith({
+ title: "Update Available",
+ question:
+ "Version some-version of Lens IDE is available and ready to be installed. Would you like to update now?\n\n" +
+ "Lens should restart automatically, if it doesn't please restart manually. Installed extensions might require updating.",
+ });
+ });
+
+ describe("when user answers to install the update", () => {
+ beforeEach(async () => {
+ await askBooleanMock.resolve(true);
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("quits application and installs the update", () => {
+ expect(quitAndInstallUpdateMock).toHaveBeenCalled();
+ });
+ });
+
+ describe("when user answers not to install the update", () => {
+ beforeEach(async () => {
+ await askBooleanMock.resolve(false);
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("does not quit application and install the update", () => {
+ expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/src/behaviours/application-update/periodical-checking-of-updates.test.ts b/src/behaviours/application-update/periodical-checking-of-updates.test.ts
new file mode 100644
index 0000000000..e81c002e34
--- /dev/null
+++ b/src/behaviours/application-update/periodical-checking-of-updates.test.ts
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import type { RenderResult } from "@testing-library/react";
+import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
+import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
+import type { AsyncFnMock } from "@async-fn/jest";
+import asyncFn from "@async-fn/jest";
+import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
+import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable";
+
+const ENOUGH_TIME = 1000 * 60 * 60 * 2;
+
+describe("periodical checking of updates", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let processCheckingForUpdatesMock: AsyncFnMock<() => Promise>;
+
+ beforeEach(() => {
+ jest.useFakeTimers();
+
+ applicationBuilder = getApplicationBuilder();
+
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.unoverride(periodicalCheckForUpdatesInjectable);
+ mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable);
+
+ processCheckingForUpdatesMock = asyncFn();
+
+ mainDi.override(
+ processCheckingForUpdatesInjectable,
+ () => processCheckingForUpdatesMock,
+ );
+ });
+ });
+
+ describe("given updater is enabled and configuration exists, when started", () => {
+ let rendered: RenderResult;
+
+ beforeEach(async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+
+ rendered = await applicationBuilder.render();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("checks for updates", () => {
+ expect(processCheckingForUpdatesMock).toHaveBeenCalled();
+ });
+
+ it("when just not enough time passes, does not check for updates again automatically yet", () => {
+ processCheckingForUpdatesMock.mockClear();
+
+ jest.advanceTimersByTime(ENOUGH_TIME - 1);
+
+ expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
+ });
+
+ it("when just enough time passes, checks for updates again automatically", () => {
+ processCheckingForUpdatesMock.mockClear();
+
+ jest.advanceTimersByTime(ENOUGH_TIME);
+
+ expect(processCheckingForUpdatesMock).toHaveBeenCalled();
+ });
+ });
+
+ describe("given updater is enabled but no configuration exist, when started", () => {
+ beforeEach(async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => false);
+ });
+
+ await applicationBuilder.render();
+ });
+
+ it("does not check for updates", () => {
+ expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
+ });
+
+ it("when time passes, never checks for updates", () => {
+ jest.runOnlyPendingTimers();
+
+ expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
+ });
+ });
+
+ describe("given updater is not enabled but and configuration exist, when started", () => {
+ beforeEach(async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(electronUpdaterIsActiveInjectable, () => false);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+
+ await applicationBuilder.render();
+ });
+
+ it("does not check for updates", () => {
+ expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
+ });
+
+ it("when time passes, never checks for updates", () => {
+ jest.runOnlyPendingTimers();
+
+ expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/src/behaviours/application-update/selection-of-update-stability.test.ts b/src/behaviours/application-update/selection-of-update-stability.test.ts
new file mode 100644
index 0000000000..1792fcd484
--- /dev/null
+++ b/src/behaviours/application-update/selection-of-update-stability.test.ts
@@ -0,0 +1,331 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import quitAndInstallUpdateInjectable from "../../main/electron-app/features/quit-and-install-update.injectable";
+import type { RenderResult } from "@testing-library/react";
+import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
+import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
+import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
+import type { AsyncFnMock } from "@async-fn/jest";
+import asyncFn from "@async-fn/jest";
+import type { UpdateChannel, UpdateChannelId } from "../../common/application-update/update-channels";
+import { updateChannels } from "../../common/application-update/update-channels";
+import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
+import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
+import type { IComputedValue } from "mobx";
+import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
+import type { AskBoolean } from "../../main/ask-boolean/ask-boolean.injectable";
+import askBooleanInjectable from "../../main/ask-boolean/ask-boolean.injectable";
+import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
+import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
+import appVersionInjectable from "../../common/get-configuration-file-model/app-version/app-version.injectable";
+
+describe("selection of update stability", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let quitAndInstallUpdateMock: jest.Mock;
+ let checkForPlatformUpdatesMock: AsyncFnMock;
+ let downloadPlatformUpdateMock: AsyncFnMock;
+ let setUpdateOnQuitMock: jest.Mock;
+ let showInfoNotificationMock: jest.Mock;
+ let askBooleanMock: AsyncFnMock;
+
+ beforeEach(() => {
+ applicationBuilder = getApplicationBuilder();
+
+ applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
+ quitAndInstallUpdateMock = jest.fn();
+ checkForPlatformUpdatesMock = asyncFn();
+ downloadPlatformUpdateMock = asyncFn();
+ setUpdateOnQuitMock = jest.fn();
+ showInfoNotificationMock = jest.fn(() => () => {});
+ askBooleanMock = asyncFn();
+
+ rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
+
+ mainDi.override(askBooleanInjectable, () => askBooleanMock);
+ mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
+
+ mainDi.override(
+ checkForPlatformUpdatesInjectable,
+ () => checkForPlatformUpdatesMock,
+ );
+
+ mainDi.override(
+ downloadPlatformUpdateInjectable,
+ () => downloadPlatformUpdateMock,
+ );
+
+ mainDi.override(
+ quitAndInstallUpdateInjectable,
+ () => quitAndInstallUpdateMock,
+ );
+
+ mainDi.override(electronUpdaterIsActiveInjectable, () => true);
+ mainDi.override(publishIsConfiguredInjectable, () => true);
+ });
+ });
+
+ describe("when started", () => {
+ let rendered: RenderResult;
+ let processCheckingForUpdates: () => Promise;
+
+ beforeEach(async () => {
+ rendered = await applicationBuilder.render();
+
+ processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ describe('given update channel "alpha" is selected, when checking for updates', () => {
+ let selectedUpdateChannel: {
+ value: IComputedValue;
+ setValue: (channelId: UpdateChannelId) => void;
+ };
+
+ beforeEach(() => {
+ selectedUpdateChannel = applicationBuilder.dis.mainDi.inject(
+ selectedUpdateChannelInjectable,
+ );
+
+ selectedUpdateChannel.setValue(updateChannels.alpha.id);
+
+ processCheckingForUpdates();
+ });
+
+ it('checks updates from update channel "alpha"', () => {
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
+ updateChannels.alpha,
+ { allowDowngrade: true },
+ );
+ });
+
+ it("when update is discovered, does not check update from other update channels", async () => {
+ checkForPlatformUpdatesMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-version",
+ });
+
+ expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
+ });
+
+ describe("when no update is discovered", () => {
+ beforeEach(async () => {
+ checkForPlatformUpdatesMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: false,
+ });
+ });
+
+ it('checks updates from update channel "beta"', () => {
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
+ updateChannels.beta,
+ { allowDowngrade: true },
+ );
+ });
+
+ it("when update is discovered, does not check update from other update channels", async () => {
+ checkForPlatformUpdatesMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-version",
+ });
+
+ expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
+ });
+
+ describe("when no update is discovered again", () => {
+ beforeEach(async () => {
+ checkForPlatformUpdatesMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: false,
+ });
+ });
+
+ it('finally checks updates from update channel "latest"', () => {
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
+ updateChannels.latest,
+ { allowDowngrade: true },
+ );
+ });
+
+ it("when update is discovered, does not check update from other update channels", async () => {
+ checkForPlatformUpdatesMock.mockClear();
+
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-version",
+ });
+
+ expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('given update channel "beta" is selected', () => {
+ let selectedUpdateChannel: {
+ value: IComputedValue;
+ setValue: (channelId: UpdateChannelId) => void;
+ };
+
+ beforeEach(() => {
+ selectedUpdateChannel = applicationBuilder.dis.mainDi.inject(
+ selectedUpdateChannelInjectable,
+ );
+
+ selectedUpdateChannel.setValue(updateChannels.beta.id);
+ });
+
+ describe("when checking for updates", () => {
+ beforeEach(() => {
+ processCheckingForUpdates();
+ });
+
+ describe('when update from "beta" channel is discovered', () => {
+ beforeEach(async () => {
+ await checkForPlatformUpdatesMock.resolve({
+ updateWasDiscovered: true,
+ version: "some-beta-version",
+ });
+ });
+
+ describe("when update is downloaded", () => {
+ beforeEach(async () => {
+ await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
+ });
+
+ it("when user would close the application, installs the update", () => {
+ expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(true);
+ });
+
+ it('given user changes update channel to "latest", when user would close the application, does not install the update for not being stable enough', () => {
+ selectedUpdateChannel.setValue(updateChannels.latest.id);
+
+ expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(false);
+ });
+
+ it('given user changes update channel to "alpha", when user would close the application, installs the update for being stable enough', () => {
+ selectedUpdateChannel.setValue(updateChannels.alpha.id);
+
+ expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(false);
+ });
+ });
+ });
+ });
+ });
+ });
+
+ it("given valid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ // TODO: Switch to more natural way of setting initial value
+ // TODO: UserStore is currently responsible for getting and setting initial value
+ const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
+
+ selectedUpdateChannel.setValue(updateChannels.beta.id);
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
+ });
+
+ it("given invalid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ // TODO: Switch to more natural way of setting initial value
+ // TODO: UserStore is currently responsible for getting and setting initial value
+ const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
+
+ selectedUpdateChannel.setValue("something-invalid" as UpdateChannelId);
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.latest, expect.any(Object));
+ });
+
+ it('given no update channel selection is stored and currently using stable release, when user checks for updates, checks for updates from "latest" update channel by default', async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(appVersionInjectable, () => "1.0.0");
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
+ updateChannels.latest,
+ { allowDowngrade: true },
+ );
+ });
+
+ it('given no update channel selection is stored and currently using alpha release, when checking for updates, checks for updates from "alpha" channel', async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.alpha, expect.any(Object));
+ });
+
+ it('given no update channel selection is stored and currently using beta release, when checking for updates, checks for updates from "beta" channel', async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(appVersionInjectable, () => "1.0.0-beta");
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
+ });
+
+ it("given update channel selection is stored and currently using prerelease, when checking for updates, checks for updates from stored channel", async () => {
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
+
+ // TODO: Switch to more natural way of setting initial value
+ // TODO: UserStore is currently responsible for getting and setting initial value
+ const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
+
+ selectedUpdateChannel.setValue(updateChannels.beta.id);
+ });
+
+ await applicationBuilder.render();
+
+ const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
+
+ processCheckingForUpdates();
+
+ expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
+ });
+});
diff --git a/src/behaviours/cluster/__snapshots__/order-of-sidebar-items.test.tsx.snap b/src/behaviours/cluster/__snapshots__/order-of-sidebar-items.test.tsx.snap
index 092337ec82..9af01f0969 100644
--- a/src/behaviours/cluster/__snapshots__/order-of-sidebar-items.test.tsx.snap
+++ b/src/behaviours/cluster/__snapshots__/order-of-sidebar-items.test.tsx.snap
@@ -328,6 +328,9 @@ exports[`cluster - order of sidebar items when rendered renders 1`] = `
+
`;
@@ -723,5 +726,8 @@ exports[`cluster - order of sidebar items when rendered when parent is expanded
+
`;
diff --git a/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-core.test.tsx.snap b/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-core.test.tsx.snap
index ad1f7a8d4c..06d1a1e210 100644
--- a/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-core.test.tsx.snap
+++ b/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-core.test.tsx.snap
@@ -293,6 +293,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -589,6 +592,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -909,6 +915,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -1234,6 +1243,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -1534,6 +1546,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -1854,6 +1869,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
@@ -2150,5 +2168,8 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
+
`;
diff --git a/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-extensions.test.tsx.snap b/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-extensions.test.tsx.snap
index 808ea1128f..19cb615cce 100644
--- a/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-extensions.test.tsx.snap
+++ b/src/behaviours/cluster/__snapshots__/sidebar-and-tab-navigation-for-extensions.test.tsx.snap
@@ -261,14 +261,14 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
+
`;
@@ -557,14 +560,14 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
+
`;
@@ -853,14 +859,14 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
`;
diff --git a/src/behaviours/cluster/__snapshots__/visibility-of-sidebar-items.test.tsx.snap b/src/behaviours/cluster/__snapshots__/visibility-of-sidebar-items.test.tsx.snap
index 4f28c6ecef..cc44f56496 100644
--- a/src/behaviours/cluster/__snapshots__/visibility-of-sidebar-items.test.tsx.snap
+++ b/src/behaviours/cluster/__snapshots__/visibility-of-sidebar-items.test.tsx.snap
@@ -261,6 +261,9 @@ exports[`cluster - visibility of sidebar items given kube resource for route is
+
`;
@@ -573,5 +576,8 @@ exports[`cluster - visibility of sidebar items given kube resource for route is
+
`;
diff --git a/src/behaviours/cluster/order-of-sidebar-items.test.tsx b/src/behaviours/cluster/order-of-sidebar-items.test.tsx
index 681752a28a..77bf395de7 100644
--- a/src/behaviours/cluster/order-of-sidebar-items.test.tsx
+++ b/src/behaviours/cluster/order-of-sidebar-items.test.tsx
@@ -19,7 +19,7 @@ describe("cluster - order of sidebar items", () => {
beforeEach(() => {
applicationBuilder = getApplicationBuilder().setEnvironmentToClusterFrame();
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(testSidebarItemsInjectable);
});
});
diff --git a/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx b/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx
index aad53c4fd9..f270b7d13e 100644
--- a/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx
+++ b/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx
@@ -21,6 +21,8 @@ import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
+import { getSidebarItem } from "../utils";
+import sidebarStorageInjectable from "../../renderer/components/layout/sidebar-storage/sidebar-storage.injectable";
describe("cluster - sidebar and tab navigation for core", () => {
let applicationBuilder: ApplicationBuilder;
@@ -35,7 +37,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
applicationBuilder.setEnvironmentToClusterFrame();
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(
directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage",
@@ -45,7 +47,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
describe("given core registrations", () => {
beforeEach(() => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(testRouteInjectable);
rendererDi.register(testRouteComponentInjectable);
rendererDi.register(testSidebarItemsInjectable);
@@ -72,13 +74,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent is highlighted", () => {
const parent = getSidebarItem(rendered, "some-parent-id");
- expect(parent.dataset.isActiveTest).toBe("true");
+ expect(parent?.dataset.isActiveTest).toBe("true");
});
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
it("child page is shown", () => {
@@ -102,6 +104,12 @@ describe("cluster - sidebar and tab navigation for core", () => {
);
});
+ applicationBuilder.beforeRender(async ({ rendererDi }) => {
+ const sidebarStorage = rendererDi.inject(sidebarStorageInjectable);
+
+ await sidebarStorage.whenReady;
+ });
+
rendered = await applicationBuilder.render();
});
@@ -112,13 +120,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(rendered, "some-parent-id");
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).not.toBe(null);
+ expect(child).not.toBeUndefined();
});
});
@@ -148,7 +156,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
});
@@ -175,7 +183,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
});
@@ -191,13 +199,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(rendered, "some-parent-id");
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
describe("when a parent sidebar item is expanded", () => {
@@ -216,13 +224,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(rendered, "some-parent-id");
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is expanded", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child).not.toBe(null);
+ expect(child).not.toBeUndefined();
});
describe("when a child of the parent is selected", () => {
@@ -241,13 +249,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("parent is highlighted", () => {
const parent = getSidebarItem(rendered, "some-parent-id");
- expect(parent.dataset.isActiveTest).toBe("true");
+ expect(parent?.dataset.isActiveTest).toBe("true");
});
it("child is highlighted", () => {
const child = getSidebarItem(rendered, "some-child-id");
- expect(child.dataset.isActiveTest).toBe("true");
+ expect(child?.dataset.isActiveTest).toBe("true");
});
it("child page is shown", () => {
@@ -288,11 +296,6 @@ describe("cluster - sidebar and tab navigation for core", () => {
});
});
-const getSidebarItem = (rendered: RenderResult, itemId: string) =>
- rendered
- .queryAllByTestId("sidebar-item")
- .find((x) => x.dataset.idTest === itemId) || null;
-
const testSidebarItemsInjectable = getInjectable({
id: "some-sidebar-items-injectable",
diff --git a/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx b/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx
index 273a19840c..eb7fd0bc05 100644
--- a/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx
+++ b/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx
@@ -5,8 +5,6 @@
import React from "react";
import type { RenderResult } from "@testing-library/react";
import { fireEvent } from "@testing-library/react";
-import { getRendererExtensionFake } from "../../renderer/components/test-utils/get-renderer-extension-fake";
-import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import directoryForLensLocalStorageInjectable from "../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
import routesInjectable from "../../renderer/routes/routes.injectable";
import { matches } from "lodash/fp";
@@ -17,6 +15,10 @@ import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
+import assert from "assert";
+import { getSidebarItem } from "../utils";
+import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
+import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder;
@@ -31,7 +33,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
applicationBuilder.setEnvironmentToClusterFrame();
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(
directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage",
@@ -41,9 +43,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("given extension with cluster pages and cluster page menus", () => {
beforeEach(async () => {
- const testExtension = getRendererExtensionFake(
- extensionStubWithSidebarItems,
- );
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
+ const testExtension = getRendererExtensionFake(extensionStubWithSidebarItems);
await applicationBuilder.addExtensions(testExtension);
});
@@ -51,19 +52,17 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
beforeEach(async () => {
applicationBuilder.beforeRender(({ rendererDi }) => {
- const navigateToRoute = rendererDi.inject(
- navigateToRouteInjectionToken,
- );
-
+ const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
const route = rendererDi
.inject(routesInjectable)
.get()
.find(
matches({
- path: "/extension/some-extension-id/some-child-page-id",
+ path: "/extension/some-extension-name/some-child-page-id",
}),
);
+ assert(route);
navigateToRoute(route);
});
@@ -77,19 +76,19 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent is highlighted", () => {
const parent = getSidebarItem(
rendered,
- "some-extension-id-some-parent-id",
+ "some-extension-name-some-parent-id",
);
- expect(parent.dataset.isActiveTest).toBe("true");
+ expect(parent?.dataset.isActiveTest).toBe("true");
});
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
it("child page is shown", () => {
@@ -106,7 +105,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
"/some-directory-for-lens-local-storage/app.json",
{
sidebar: {
- expanded: { "some-extension-id-some-parent-id": true },
+ expanded: { "some-extension-name-some-parent-id": true },
width: 200,
},
},
@@ -123,19 +122,19 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(
rendered,
- "some-extension-id-some-parent-id",
+ "some-extension-name-some-parent-id",
);
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).not.toBe(null);
+ expect(child).not.toBeUndefined();
});
});
@@ -148,7 +147,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
"/some-directory-for-lens-local-storage/app.json",
{
sidebar: {
- expanded: { "some-extension-id-some-unknown-parent-id": true },
+ expanded: { "some-extension-name-some-unknown-parent-id": true },
width: 200,
},
},
@@ -165,10 +164,10 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
});
@@ -195,10 +194,10 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
});
@@ -214,25 +213,25 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(
rendered,
- "some-extension-id-some-parent-id",
+ "some-extension-name-some-parent-id",
);
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is not expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).toBe(null);
+ expect(child).toBeUndefined();
});
describe("when a parent sidebar item is expanded", () => {
beforeEach(() => {
const parentLink = rendered.getByTestId(
- "sidebar-item-link-for-some-extension-id-some-parent-id",
+ "sidebar-item-link-for-some-extension-name-some-parent-id",
);
fireEvent.click(parentLink);
@@ -245,25 +244,25 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent sidebar item is not highlighted", () => {
const parent = getSidebarItem(
rendered,
- "some-extension-id-some-parent-id",
+ "some-extension-name-some-parent-id",
);
- expect(parent.dataset.isActiveTest).toBe("false");
+ expect(parent?.dataset.isActiveTest).toBe("false");
});
it("parent sidebar item is expanded", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child).not.toBe(null);
+ expect(child).not.toBeUndefined();
});
describe("when a child of the parent is selected", () => {
beforeEach(() => {
const childLink = rendered.getByTestId(
- "sidebar-item-link-for-some-extension-id-some-child-id",
+ "sidebar-item-link-for-some-extension-name-some-child-id",
);
fireEvent.click(childLink);
@@ -276,19 +275,19 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("parent is highlighted", () => {
const parent = getSidebarItem(
rendered,
- "some-extension-id-some-parent-id",
+ "some-extension-name-some-parent-id",
);
- expect(parent.dataset.isActiveTest).toBe("true");
+ expect(parent?.dataset.isActiveTest).toBe("true");
});
it("child is highlighted", () => {
const child = getSidebarItem(
rendered,
- "some-extension-id-some-child-id",
+ "some-extension-name-some-child-id",
);
- expect(child.dataset.isActiveTest).toBe("true");
+ expect(child?.dataset.isActiveTest).toBe("true");
});
it("child page is shown", () => {
@@ -301,7 +300,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("tab for child page is active", () => {
const tabLink = rendered.getByTestId(
- "tab-link-for-some-extension-id-some-child-id",
+ "tab-link-for-some-extension-name-some-child-id",
);
expect(tabLink.dataset.isActiveTest).toBe("true");
@@ -309,7 +308,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("tab for sibling page is not active", () => {
const tabLink = rendered.getByTestId(
- "tab-link-for-some-extension-id-some-other-child-id",
+ "tab-link-for-some-extension-name-some-other-child-id",
);
expect(tabLink.dataset.isActiveTest).toBe("false");
@@ -338,7 +337,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
expect(actual).toEqual({
sidebar: {
- expanded: { "some-extension-id-some-parent-id": true },
+ expanded: { "some-extension-name-some-parent-id": true },
width: 200,
},
});
@@ -347,7 +346,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("when selecting sibling tab", () => {
beforeEach(() => {
const childTabLink = rendered.getByTestId(
- "tab-link-for-some-extension-id-some-other-child-id",
+ "tab-link-for-some-extension-name-some-other-child-id",
);
fireEvent.click(childTabLink);
@@ -365,7 +364,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("tab for sibling page is active", () => {
const tabLink = rendered.getByTestId(
- "tab-link-for-some-extension-id-some-other-child-id",
+ "tab-link-for-some-extension-name-some-other-child-id",
);
expect(tabLink.dataset.isActiveTest).toBe("true");
@@ -373,7 +372,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("tab for previous page is not active", () => {
const tabLink = rendered.getByTestId(
- "tab-link-for-some-extension-id-some-child-id",
+ "tab-link-for-some-extension-name-some-child-id",
);
expect(tabLink.dataset.isActiveTest).toBe("false");
@@ -385,9 +384,9 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
});
});
-const extensionStubWithSidebarItems: Partial = {
+const extensionStubWithSidebarItems: FakeExtensionData = {
id: "some-extension-id",
-
+ name: "some-extension-name",
clusterPages: [
{
components: {
@@ -396,7 +395,6 @@ const extensionStubWithSidebarItems: Partial = {
},
},
},
-
{
id: "some-child-page-id",
@@ -404,7 +402,6 @@ const extensionStubWithSidebarItems: Partial = {
Page: () => Some child page
,
},
},
-
{
id: "some-other-child-page-id",
@@ -415,7 +412,6 @@ const extensionStubWithSidebarItems: Partial = {
},
},
],
-
clusterPageMenus: [
{
id: "some-parent-id",
@@ -433,7 +429,7 @@ const extensionStubWithSidebarItems: Partial = {
title: "Child 1",
components: {
- Icon: null,
+ Icon: null as never,
},
},
@@ -444,13 +440,8 @@ const extensionStubWithSidebarItems: Partial = {
title: "Child 2",
components: {
- Icon: null,
+ Icon: null as never,
},
},
],
};
-
-const getSidebarItem = (rendered: RenderResult, itemId: string) =>
- rendered
- .queryAllByTestId("sidebar-item")
- .find((x) => x.dataset.idTest === itemId) || null;
diff --git a/src/behaviours/cluster/visibility-of-sidebar-items.test.tsx b/src/behaviours/cluster/visibility-of-sidebar-items.test.tsx
index 14f575b493..aa73936470 100644
--- a/src/behaviours/cluster/visibility-of-sidebar-items.test.tsx
+++ b/src/behaviours/cluster/visibility-of-sidebar-items.test.tsx
@@ -14,6 +14,7 @@ import { routeInjectionToken } from "../../common/front-end-routing/route-inject
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
+import { getSidebarItem } from "../utils";
describe("cluster - visibility of sidebar items", () => {
let applicationBuilder: ApplicationBuilder;
@@ -24,7 +25,7 @@ describe("cluster - visibility of sidebar items", () => {
applicationBuilder.setEnvironmentToClusterFrame();
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(testRouteInjectable);
rendererDi.register(testRouteComponentInjectable);
rendererDi.register(testSidebarItemsInjectable);
@@ -43,7 +44,7 @@ describe("cluster - visibility of sidebar items", () => {
it("related sidebar item does not exist", () => {
const item = getSidebarItem(rendered, "some-item-id");
- expect(item).toBeNull();
+ expect(item).toBeUndefined();
});
describe("when kube resource becomes allowed", () => {
@@ -58,17 +59,12 @@ describe("cluster - visibility of sidebar items", () => {
it("related sidebar item exists", () => {
const item = getSidebarItem(rendered, "some-item-id");
- expect(item).not.toBeNull();
+ expect(item).not.toBeUndefined();
});
});
});
});
-const getSidebarItem = (rendered: RenderResult, itemId: string) =>
- rendered
- .queryAllByTestId("sidebar-item")
- .find((x) => x.dataset.idTest === itemId) || null;
-
const testRouteInjectable = getInjectable({
id: "some-route-injectable-id",
diff --git a/src/behaviours/extension-special-characters-in-page-registrations.test.tsx b/src/behaviours/extension-special-characters-in-page-registrations.test.tsx
index 3e84479f69..2320d28a1b 100644
--- a/src/behaviours/extension-special-characters-in-page-registrations.test.tsx
+++ b/src/behaviours/extension-special-characters-in-page-registrations.test.tsx
@@ -2,12 +2,11 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import type { TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
-import { getRendererExtensionFake } from "../renderer/components/test-utils/get-renderer-extension-fake";
+import type { FakeExtensionData, TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
+import { getRendererExtensionFakeFor } from "../renderer/components/test-utils/get-renderer-extension-fake";
import React from "react";
import type { RenderResult } from "@testing-library/react";
import currentPathInjectable from "../renderer/routes/current-path.injectable";
-import type { LensRendererExtension } from "../extensions/lens-renderer-extension";
import type { ApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
@@ -18,6 +17,7 @@ describe("extension special characters in page registrations", () => {
beforeEach(async () => {
applicationBuilder = getApplicationBuilder();
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
testExtension = getRendererExtensionFake(
extensionWithPagesHavingSpecialCharacters,
@@ -44,14 +44,14 @@ describe("extension special characters in page registrations", () => {
it("knows URL", () => {
const currentPath = applicationBuilder.dis.rendererDi.inject(currentPathInjectable);
- expect(currentPath.get()).toBe("/extension/some-extension-id--/some-page-id");
+ expect(currentPath.get()).toBe("/extension/some-extension-name--/some-page-id");
});
});
});
-const extensionWithPagesHavingSpecialCharacters: Partial = {
- id: "@some-extension-id/",
-
+const extensionWithPagesHavingSpecialCharacters: FakeExtensionData = {
+ id: "some-extension-id",
+ name: "@some-extension-name/",
globalPages: [
{
id: "/some-page-id/",
diff --git a/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap
index 4878bbb0b7..c14ccb6160 100644
--- a/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap
+++ b/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap
@@ -1,6 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`extensions - navigation using application menu renders 1`] = `
`;
+exports[`extensions - navigation using application menu renders 1`] = `
+
+`;
exports[`extensions - navigation using application menu when navigating to extensions using application menu renders 1`] = `
@@ -23,9 +29,7 @@ exports[`extensions - navigation using application menu when navigating to exten
class="notice mb-14 mt-3"
>
- Add new features via Lens Extensions.
-
- Check out
+ Add new features via Lens Extensions. Check out the
docs
-
- and list of
+ and list of
+
`;
diff --git a/src/behaviours/extensions/navigation-using-application-menu.test.ts b/src/behaviours/extensions/navigation-using-application-menu.test.ts
index ef714a75d3..5d05ec31c2 100644
--- a/src/behaviours/extensions/navigation-using-application-menu.test.ts
+++ b/src/behaviours/extensions/navigation-using-application-menu.test.ts
@@ -6,12 +6,7 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
-import extensionsStoreInjectable from "../../extensions/extensions-store/extensions-store.injectable";
-import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store";
-import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store.injectable";
-import type { FileSystemProvisionerStore } from "../../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store";
-import focusWindowInjectable from "../../renderer/ipc-channel-listeners/focus-window.injectable";
+import focusWindowInjectable from "../../renderer/navigation/focus-window.injectable";
// TODO: Make components free of side effects by making them deterministic
jest.mock("../../renderer/components/input/input");
@@ -22,11 +17,7 @@ describe("extensions - navigation using application menu", () => {
let focusWindowMock: jest.Mock;
beforeEach(async () => {
- applicationBuilder = getApplicationBuilder().beforeSetups(({ mainDi, rendererDi }) => {
- mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
- rendererDi.override(extensionsStoreInjectable, () => ({}) as unknown as ExtensionsStore);
- rendererDi.override(fileSystemProvisionerStoreInjectable, () => ({}) as unknown as FileSystemProvisionerStore);
-
+ applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ rendererDi }) => {
focusWindowMock = jest.fn();
rendererDi.override(focusWindowInjectable, () => focusWindowMock);
@@ -46,8 +37,8 @@ describe("extensions - navigation using application menu", () => {
});
describe("when navigating to extensions using application menu", () => {
- beforeEach(() => {
- applicationBuilder.applicationMenu.click("root.extensions");
+ beforeEach(async () => {
+ await applicationBuilder.applicationMenu.click("root.extensions");
});
it("focuses the window", () => {
diff --git a/src/behaviours/helm-charts/__snapshots__/navigation-to-helm-charts.test.ts.snap b/src/behaviours/helm-charts/__snapshots__/navigation-to-helm-charts.test.ts.snap
new file mode 100644
index 0000000000..e323205008
--- /dev/null
+++ b/src/behaviours/helm-charts/__snapshots__/navigation-to-helm-charts.test.ts.snap
@@ -0,0 +1,461 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`helm-charts - navigation to Helm charts when navigating to Helm charts renders 1`] = `
+
+`;
diff --git a/src/behaviours/helm-charts/navigation-to-helm-charts.test.ts b/src/behaviours/helm-charts/navigation-to-helm-charts.test.ts
new file mode 100644
index 0000000000..c539db173a
--- /dev/null
+++ b/src/behaviours/helm-charts/navigation-to-helm-charts.test.ts
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { RenderResult } from "@testing-library/react";
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+
+describe("helm-charts - navigation to Helm charts", () => {
+ let applicationBuilder: ApplicationBuilder;
+
+ beforeEach(() => {
+ applicationBuilder = getApplicationBuilder();
+ });
+
+ describe("when navigating to Helm charts", () => {
+ let rendered: RenderResult;
+
+ beforeEach(async () => {
+ applicationBuilder.setEnvironmentToClusterFrame();
+
+ rendered = await applicationBuilder.render();
+
+ applicationBuilder.helmCharts.navigate();
+ });
+
+ it("renders", () => {
+ expect(rendered.container).toMatchSnapshot();
+ });
+
+ it("shows page for Helm charts", () => {
+ const page = rendered.getByTestId("page-for-helm-charts");
+
+ expect(page).not.toBeNull();
+ });
+ });
+});
diff --git a/src/behaviours/navigate-to-extension-page.test.tsx b/src/behaviours/navigate-to-extension-page.test.tsx
index 915d3bab2b..35c47b9076 100644
--- a/src/behaviours/navigate-to-extension-page.test.tsx
+++ b/src/behaviours/navigate-to-extension-page.test.tsx
@@ -2,8 +2,8 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import type { TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
-import { getRendererExtensionFake } from "../renderer/components/test-utils/get-renderer-extension-fake";
+import type { FakeExtensionData, TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
+import { getRendererExtensionFakeFor } from "../renderer/components/test-utils/get-renderer-extension-fake";
import React from "react";
import type { RenderResult } from "@testing-library/react";
import { fireEvent } from "@testing-library/react";
@@ -11,7 +11,6 @@ import isEmpty from "lodash/isEmpty";
import queryParametersInjectable from "../renderer/routes/query-parameters.injectable";
import currentPathInjectable from "../renderer/routes/current-path.injectable";
import type { IComputedValue } from "mobx";
-import type { LensRendererExtension } from "../extensions/lens-renderer-extension";
import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
describe("navigate to extension page", () => {
@@ -22,6 +21,7 @@ describe("navigate to extension page", () => {
beforeEach(async () => {
const applicationBuilder = getApplicationBuilder();
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
testExtension = getRendererExtensionFake(
extensionWithPagesHavingParameters,
@@ -51,7 +51,7 @@ describe("navigate to extension page", () => {
});
it("URL is correct", () => {
- expect(currentPath.get()).toBe("/extension/some-extension-id");
+ expect(currentPath.get()).toBe("/extension/some-extension-name");
});
it("query parameters is empty", () => {
@@ -70,7 +70,7 @@ describe("navigate to extension page", () => {
});
it("URL is correct", () => {
- expect(currentPath.get()).toBe("/extension/some-extension-id");
+ expect(currentPath.get()).toBe("/extension/some-extension-name");
});
it("knows query parameters", () => {
@@ -98,7 +98,7 @@ describe("navigate to extension page", () => {
});
it("URL is correct", () => {
- expect(currentPath.get()).toBe("/extension/some-extension-id");
+ expect(currentPath.get()).toBe("/extension/some-extension-name");
});
it("knows query parameters", () => {
@@ -120,14 +120,14 @@ describe("navigate to extension page", () => {
});
it("URL is correct", () => {
- expect(currentPath.get()).toBe("/extension/some-extension-id/some-child-page-id");
+ expect(currentPath.get()).toBe("/extension/some-extension-name/some-child-page-id");
});
});
});
-const extensionWithPagesHavingParameters: Partial = {
+const extensionWithPagesHavingParameters: FakeExtensionData = {
id: "some-extension-id",
-
+ name: "some-extension-name",
globalPages: [
{
components: {
@@ -159,20 +159,14 @@ const extensionWithPagesHavingParameters: Partial = {
params: {
someStringParameter: "some-string-value",
-
someNumberParameter: {
defaultValue: 42,
-
stringify: (value) => value.toString(),
-
parse: (value) => (value ? Number(value) : undefined),
},
-
someArrayParameter: {
defaultValue: ["some-array-value", "some-other-array-value"],
-
stringify: (value) => value.join(","),
-
parse: (value: string[]) => (!isEmpty(value) ? value : undefined),
},
},
diff --git a/src/behaviours/navigating-between-routes.test.tsx b/src/behaviours/navigating-between-routes.test.tsx
index 4cb55cd290..4def9b383f 100644
--- a/src/behaviours/navigating-between-routes.test.tsx
+++ b/src/behaviours/navigating-between-routes.test.tsx
@@ -31,7 +31,7 @@ describe("navigating between routes", () => {
describe("given route without path parameters", () => {
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(testRouteWithoutPathParametersInjectable);
rendererDi.register(testRouteWithoutPathParametersComponentInjectable);
});
@@ -102,7 +102,7 @@ describe("navigating between routes", () => {
describe("given route with optional path parameters", () => {
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(routeWithOptionalPathParametersInjectable);
rendererDi.register(routeWithOptionalPathParametersComponentInjectable);
});
diff --git a/src/behaviours/preferences/__snapshots__/closing-preferences.test.tsx.snap b/src/behaviours/preferences/__snapshots__/closing-preferences.test.tsx.snap
index d0f2586641..5cdee87f39 100644
--- a/src/behaviours/preferences/__snapshots__/closing-preferences.test.tsx.snap
+++ b/src/behaviours/preferences/__snapshots__/closing-preferences.test.tsx.snap
@@ -124,7 +124,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
Select...
@@ -150,7 +150,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
Select...
@@ -235,7 +235,7 @@ exports[`preferences - closing-preferences given accessing preferences directly
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -684,6 +680,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
+
`;
@@ -692,6 +691,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
Some front page
+
`;
@@ -700,6 +702,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
Some front page
+
`;
@@ -827,7 +832,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
Select...
@@ -853,7 +858,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
Select...
@@ -938,7 +943,7 @@ exports[`preferences - closing-preferences given already in a page and then navi
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -1387,6 +1388,9 @@ exports[`preferences - closing-preferences given already in a page and then navi
+
`;
@@ -1529,6 +1533,9 @@ exports[`preferences - closing-preferences given already in a page and then navi
+
`;
@@ -1671,5 +1678,8 @@ exports[`preferences - closing-preferences given already in a page and then navi
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-application-preferences.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-to-application-preferences.test.ts.snap
index c1a12d60ba..7cd89769f5 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-application-preferences.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-application-preferences.test.ts.snap
@@ -199,6 +199,9 @@ exports[`preferences - navigation to application preferences given in some child
+
`;
@@ -314,7 +317,7 @@ exports[`preferences - navigation to application preferences given in some child
>
Select...
@@ -340,7 +343,7 @@ exports[`preferences - navigation to application preferences given in some child
>
Select...
@@ -425,7 +428,7 @@ exports[`preferences - navigation to application preferences given in some child
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-editor-preferences.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-to-editor-preferences.test.ts.snap
index 6d5284f7bb..9f99faceb3 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-editor-preferences.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-editor-preferences.test.ts.snap
@@ -112,7 +112,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
Select...
@@ -138,7 +138,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
Select...
@@ -223,7 +223,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -668,7 +664,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
Select...
@@ -694,7 +690,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
Select...
@@ -778,7 +774,7 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
>
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-extension-specific-preferences.test.tsx.snap b/src/behaviours/preferences/__snapshots__/navigation-to-extension-specific-preferences.test.tsx.snap
index e8914c3f5a..ec00c0e498 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-extension-specific-preferences.test.tsx.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-extension-specific-preferences.test.tsx.snap
@@ -1,778 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`preferences - navigation to extension specific preferences given in preferences, when rendered given extension with registered tab shows extension tab in general area 1`] = `
-
-`;
-
-exports[`preferences - navigation to extension specific preferences given in preferences, when rendered given extension with registered tab when navigating to specific extension tab renders 1`] = `
-
-
-
-
-
-
-
- registered-tab-page-id
- preferences
-
-
-
- License item
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`preferences - navigation to extension specific preferences given in preferences, when rendered given extensions with tabs having same id when navigating to first extension tab renders 1`] = `
-
-
-
-
-
-
-
- registered-tab-page-id
- preferences
-
-
-
- License item
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`preferences - navigation to extension specific preferences given in preferences, when rendered given extensions with tabs having same id when navigating to second extension tab renders 1`] = `
-
-
-
-
-
-
-
- duplicated-tab-page-id
- preferences
-
-
-
- Another metrics
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`preferences - navigation to extension specific preferences given in preferences, when rendered given multiple extensions with specific preferences, when navigating to extension specific preferences page renders 1`] = `
-
-
-
-
-
-
-
- some-test-extension-id
- preferences
-
-
-
- Some preference item
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
exports[`preferences - navigation to extension specific preferences given in preferences, when rendered renders 1`] = `
-
-
-
-
- some-test-extension-id
-
-
+ Extensions
@@ -1452,7 +653,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
Select...
@@ -1478,7 +679,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
Select...
@@ -1563,7 +764,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -1954,37 +1151,15 @@ exports[`preferences - navigation to extension specific preferences given in pre
-
-
-
-
- some-test-extension-id
-
-
+ Extensions
@@ -2001,8 +1176,7 @@ exports[`preferences - navigation to extension specific preferences given in pre
id="extensions"
>
- some-test-extension-id
- preferences
+ Extensions
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-kubernetes-preferences.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-to-kubernetes-preferences.test.ts.snap
index 7f8ad70c1a..8ab873fac4 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-kubernetes-preferences.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-kubernetes-preferences.test.ts.snap
@@ -112,7 +112,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
Select...
@@ -138,7 +138,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
Select...
@@ -223,7 +223,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -664,7 +660,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
Download mirror for kubectl
@@ -690,7 +686,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
>
Repositories
@@ -974,5 +983,8 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-proxy-preferences.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-to-proxy-preferences.test.ts.snap
index ec521a3ad5..4710bb1957 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-proxy-preferences.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-proxy-preferences.test.ts.snap
@@ -112,7 +112,7 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
>
Select...
@@ -138,7 +138,7 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
>
Select...
@@ -223,7 +223,7 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -732,5 +728,8 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-telemetry-preferences.test.tsx.snap b/src/behaviours/preferences/__snapshots__/navigation-to-telemetry-preferences.test.tsx.snap
index 278461e4b9..68901d7a4d 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-telemetry-preferences.test.tsx.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-telemetry-preferences.test.tsx.snap
@@ -185,6 +185,9 @@ exports[`preferences - navigation to telemetry preferences given URL for Sentry
+
`;
@@ -300,7 +303,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
Select...
@@ -326,7 +329,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
Select...
@@ -411,7 +414,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -845,7 +844,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
Select...
@@ -871,7 +870,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
Select...
@@ -956,7 +955,7 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -1439,6 +1434,9 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
+
`;
@@ -1578,5 +1576,8 @@ exports[`preferences - navigation to telemetry preferences given no URL for Sent
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-to-terminal-preferences.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-to-terminal-preferences.test.ts.snap
index 76064feb67..e0187e504b 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-to-terminal-preferences.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-to-terminal-preferences.test.ts.snap
@@ -112,7 +112,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
Select...
@@ -138,7 +138,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
Select...
@@ -223,7 +223,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
@@ -689,7 +685,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
Select...
@@ -715,7 +711,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
>
@@ -850,5 +903,8 @@ exports[`preferences - navigation to terminal preferences given in preferences,
+
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap
index e44a035cd0..367ac869ba 100644
--- a/src/behaviours/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap
+++ b/src/behaviours/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap
@@ -1,6 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`preferences - navigation using application menu renders 1`] = `
`;
+exports[`preferences - navigation using application menu renders 1`] = `
+
+`;
exports[`preferences - navigation using application menu when navigating to preferences using application menu renders 1`] = `
@@ -114,7 +120,7 @@ exports[`preferences - navigation using application menu when navigating to pref
>
Select...
@@ -140,7 +146,7 @@ exports[`preferences - navigation using application menu when navigating to pref
>
Select...
@@ -225,7 +231,7 @@ exports[`preferences - navigation using application menu when navigating to pref
>
- This setting is to change the registry URL for installing extensions by name.
-
- If you are unable to access the default registry (
- https://registry.npmjs.org
- )
-
- you can change it in your
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
.npmrc
- file or in the input below.
+ file or in the input below.
`;
diff --git a/src/behaviours/preferences/__snapshots__/navigation-using-tray.test.ts.snap b/src/behaviours/preferences/__snapshots__/navigation-using-tray.test.ts.snap
new file mode 100644
index 0000000000..57b42580d9
--- /dev/null
+++ b/src/behaviours/preferences/__snapshots__/navigation-using-tray.test.ts.snap
@@ -0,0 +1,542 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`show-about-using-tray renders 1`] = `
+
+
+
+`;
+
+exports[`show-about-using-tray when navigating using tray renders 1`] = `
+
+
+
+
+
+
+
+
+ Application
+
+
+
+
+
+ Extension Install Registry
+
+
+
+
+ This setting is to change the registry URL for installing extensions by name.
+ If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
+
+ .npmrc
+
+ file or in the input below.
+
+
+
+
+
+
+
+
+ Update Channel
+
+
+
+
+
+
+
+ Locale Timezone
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/src/behaviours/preferences/closing-preferences.test.tsx b/src/behaviours/preferences/closing-preferences.test.tsx
index 60ab5719b2..3d3eaa89dc 100644
--- a/src/behaviours/preferences/closing-preferences.test.tsx
+++ b/src/behaviours/preferences/closing-preferences.test.tsx
@@ -10,10 +10,6 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import currentPathInjectable from "../../renderer/routes/current-path.injectable";
import { routeInjectionToken } from "../../common/front-end-routing/route-injection-token";
import { computed } from "mobx";
-import type { UserStore } from "../../common/user-store";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
import { preferenceNavigationItemInjectionToken } from "../../renderer/components/+preferences/preferences-navigation/preference-navigation-items.injectable";
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
import { Preferences } from "../../renderer/components/+preferences";
@@ -33,23 +29,13 @@ describe("preferences - closing-preferences", () => {
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.register(testPreferencesRouteInjectable);
rendererDi.register(testPreferencesRouteComponentInjectable);
rendererDi.register(testFrontPageRouteInjectable);
rendererDi.register(testFrontPageRouteComponentInjectable);
rendererDi.register(testNavigationItemInjectable);
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = { themeOptions: [] } as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
-
rendererDi.override(navigateToFrontPageInjectable, (di) => {
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
const testFrontPage = di.inject(testFrontPageRouteInjectable);
@@ -66,7 +52,7 @@ describe("preferences - closing-preferences", () => {
let rendererDi: DiContainer;
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(observableHistoryInjectable, () => {
const historyFake = createMemoryHistory({
initialEntries: ["/some-test-path"],
@@ -139,7 +125,7 @@ describe("preferences - closing-preferences", () => {
let rendererDi: DiContainer;
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(observableHistoryInjectable, () => {
const historyFake = createMemoryHistory({
initialEntries: ["/preferences/app"],
diff --git a/src/behaviours/preferences/navigation-to-application-preferences.test.ts b/src/behaviours/preferences/navigation-to-application-preferences.test.ts
index 67d525cfb3..c91f091323 100644
--- a/src/behaviours/preferences/navigation-to-application-preferences.test.ts
+++ b/src/behaviours/preferences/navigation-to-application-preferences.test.ts
@@ -5,30 +5,13 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import navigateToProxyPreferencesInjectable
- from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable";
+import navigateToProxyPreferencesInjectable from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable";
describe("preferences - navigation to application preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in some child page of preferences, when rendered", () => {
diff --git a/src/behaviours/preferences/navigation-to-editor-preferences.test.ts b/src/behaviours/preferences/navigation-to-editor-preferences.test.ts
index 43824371eb..1b74b94eb4 100644
--- a/src/behaviours/preferences/navigation-to-editor-preferences.test.ts
+++ b/src/behaviours/preferences/navigation-to-editor-preferences.test.ts
@@ -5,29 +5,12 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
describe("preferences - navigation to editor preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
diff --git a/src/behaviours/preferences/navigation-to-extension-specific-preferences.test.tsx b/src/behaviours/preferences/navigation-to-extension-specific-preferences.test.tsx
index 23c8c5560a..c81d3e9ac1 100644
--- a/src/behaviours/preferences/navigation-to-extension-specific-preferences.test.tsx
+++ b/src/behaviours/preferences/navigation-to-extension-specific-preferences.test.tsx
@@ -5,32 +5,16 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import React from "react";
-import { getRendererExtensionFake } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import "@testing-library/jest-dom/extend-expect";
+import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
+import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
describe("preferences - navigation to extension specific preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = { themeOptions: [] } as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
@@ -62,6 +46,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("given multiple extensions with specific preferences, when navigating to extension specific preferences page", () => {
beforeEach(async () => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
const someOtherTestExtension = getRendererExtensionFake(someOtherExtensionStubWithExtensionSpecificPreferenceItems);
@@ -88,6 +73,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("given multiple extensions with and without specific preferences, when navigating to extension specific preferences page", () => {
beforeEach(async () => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
const extensionWithoutPreferences = getRendererExtensionFake(extensionStubWithoutPreferences);
const extensionWithSpecificTab = getRendererExtensionFake(extensionStubWithShowInPreferencesTab);
@@ -109,10 +95,11 @@ describe("preferences - navigation to extension specific preferences", () => {
});
describe("when extension with specific preferences is enabled", () => {
- beforeEach(async () => {
+ beforeEach(() => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const testExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems);
- await applicationBuilder.addExtensions(testExtension);
+ applicationBuilder.addExtensions(testExtension);
});
it("renders", () => {
@@ -168,6 +155,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("given extension with registered tab", () => {
beforeEach(async () => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
await applicationBuilder.addExtensions(extension);
@@ -207,6 +195,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("given extension with few registered tabs", () => {
beforeEach(async () => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTabs);
await applicationBuilder.addExtensions(extension);
@@ -223,6 +212,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("given extensions with tabs having same id", () => {
beforeEach(async () => {
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
const otherExtension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
@@ -288,9 +278,9 @@ describe("preferences - navigation to extension specific preferences", () => {
});
});
-const extensionStubWithExtensionSpecificPreferenceItems: Partial = {
- id: "some-test-extension-id",
-
+const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = {
+ id: "some-extension-id",
+ name: "some-extension-name",
appPreferences: [
{
title: "Some preference item",
@@ -315,8 +305,9 @@ const extensionStubWithExtensionSpecificPreferenceItems: Partial = {
+const someOtherExtensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = {
id: "some-other-test-extension-id",
+ name: "some-other-test-extension-name",
appPreferences: [
{
@@ -331,12 +322,14 @@ const someOtherExtensionStubWithExtensionSpecificPreferenceItems: Partial = {
+const extensionStubWithoutPreferences: FakeExtensionData = {
id: "without-preferences-id",
+ name: "without-preferences-name",
};
-const extensionStubWithShowInPreferencesTab: Partial = {
+const extensionStubWithShowInPreferencesTab: FakeExtensionData = {
id: "specified-preferences-page-id",
+ name: "specified-preferences-page-name",
appPreferences: [
{
@@ -352,8 +345,9 @@ const extensionStubWithShowInPreferencesTab: Partial = {
],
};
-const extensionStubWithWithRegisteredTab: Partial = {
+const extensionStubWithWithRegisteredTab: FakeExtensionData = {
id: "registered-tab-page-id",
+ name: "registered-tab-page-name",
appPreferences: [
{
@@ -395,8 +389,9 @@ const extensionStubWithWithRegisteredTab: Partial = {
}],
};
-const extensionStubWithWithRegisteredTabs: Partial = {
+const extensionStubWithWithRegisteredTabs: FakeExtensionData = {
id: "hello-world-tab-page-id",
+ name: "hello-world-tab-page-name",
appPreferences: [
{
@@ -432,8 +427,9 @@ const extensionStubWithWithRegisteredTabs: Partial = {
}],
};
-const extensionStubWithWithSameRegisteredTab: Partial = {
+const extensionStubWithWithSameRegisteredTab: FakeExtensionData = {
id: "duplicated-tab-page-id",
+ name: "duplicated-tab-page-name",
appPreferences: [
{
diff --git a/src/behaviours/preferences/navigation-to-kubernetes-preferences.test.ts b/src/behaviours/preferences/navigation-to-kubernetes-preferences.test.ts
index 31693a6883..e404e1f489 100644
--- a/src/behaviours/preferences/navigation-to-kubernetes-preferences.test.ts
+++ b/src/behaviours/preferences/navigation-to-kubernetes-preferences.test.ts
@@ -5,30 +5,12 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import { observable } from "mobx";
describe("preferences - navigation to kubernetes preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- syncKubeconfigEntries: observable.map(),
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
diff --git a/src/behaviours/preferences/navigation-to-proxy-preferences.test.ts b/src/behaviours/preferences/navigation-to-proxy-preferences.test.ts
index c0b5dc1f25..3d2c8d6d2c 100644
--- a/src/behaviours/preferences/navigation-to-proxy-preferences.test.ts
+++ b/src/behaviours/preferences/navigation-to-proxy-preferences.test.ts
@@ -5,28 +5,12 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
describe("preferences - navigation to proxy preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
diff --git a/src/behaviours/preferences/navigation-to-telemetry-preferences.test.tsx b/src/behaviours/preferences/navigation-to-telemetry-preferences.test.tsx
index bd972337c3..f16c2d809b 100644
--- a/src/behaviours/preferences/navigation-to-telemetry-preferences.test.tsx
+++ b/src/behaviours/preferences/navigation-to-telemetry-preferences.test.tsx
@@ -6,11 +6,8 @@ import type { RenderResult } from "@testing-library/react";
import React from "react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import { getRendererExtensionFake } from "../../renderer/components/test-utils/get-renderer-extension-fake";
-import type { UserStore } from "../../common/user-store";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
+import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
+import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable";
import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable";
@@ -19,18 +16,6 @@ describe("preferences - navigation to telemetry preferences", () => {
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = { themeOptions: [] } as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
@@ -62,8 +47,8 @@ describe("preferences - navigation to telemetry preferences", () => {
describe("when extension with telemetry preference items gets enabled", () => {
beforeEach(() => {
- const testExtensionWithTelemetryPreferenceItems =
- getRendererExtensionFake(extensionStubWithTelemetryPreferenceItems);
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
+ const testExtensionWithTelemetryPreferenceItems = getRendererExtensionFake(extensionStubWithTelemetryPreferenceItems);
applicationBuilder.addExtensions(
testExtensionWithTelemetryPreferenceItems,
@@ -106,18 +91,19 @@ describe("preferences - navigation to telemetry preferences", () => {
});
it("given extensions but no telemetry preference items, does not show link for telemetry preferences", () => {
- const testExtensionWithTelemetryPreferenceItems =
- getRendererExtensionFake({
- id: "some-test-extension-id",
- appPreferences: [
- {
- title: "irrelevant",
- id: "irrelevant",
- showInPreferencesTab: "not-telemetry",
- components: { Hint: () =>
, Input: () =>
},
- },
- ],
- });
+ const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
+ const testExtensionWithTelemetryPreferenceItems = getRendererExtensionFake({
+ id: "some-test-extension-id",
+ name: "some-test-extension-name",
+ appPreferences: [
+ {
+ title: "irrelevant",
+ id: "irrelevant",
+ showInPreferencesTab: "not-telemetry",
+ components: { Hint: () =>
, Input: () =>
},
+ },
+ ],
+ });
applicationBuilder.addExtensions(
testExtensionWithTelemetryPreferenceItems,
@@ -133,7 +119,7 @@ describe("preferences - navigation to telemetry preferences", () => {
let rendered: RenderResult;
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(sentryDnsUrlInjectable, () => "some-sentry-dns-url");
});
@@ -163,7 +149,7 @@ describe("preferences - navigation to telemetry preferences", () => {
let rendered: RenderResult;
beforeEach(async () => {
- applicationBuilder.beforeSetups(({ rendererDi }) => {
+ applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(sentryDnsUrlInjectable, () => null);
});
@@ -186,8 +172,9 @@ describe("preferences - navigation to telemetry preferences", () => {
});
});
-const extensionStubWithTelemetryPreferenceItems = {
+const extensionStubWithTelemetryPreferenceItems: FakeExtensionData = {
id: "some-test-extension-id",
+ name: "some-test-extension-name",
appPreferences: [
{
title: "Some telemetry-preference item",
diff --git a/src/behaviours/preferences/navigation-to-terminal-preferences.test.ts b/src/behaviours/preferences/navigation-to-terminal-preferences.test.ts
index 7b273ca8e6..73eff39006 100644
--- a/src/behaviours/preferences/navigation-to-terminal-preferences.test.ts
+++ b/src/behaviours/preferences/navigation-to-terminal-preferences.test.ts
@@ -5,34 +5,12 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { UserStore } from "../../common/user-store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import { observable } from "mobx";
-import defaultShellInjectable from "../../renderer/components/+preferences/default-shell.injectable";
describe("preferences - navigation to terminal preferences", () => {
let applicationBuilder: ApplicationBuilder;
beforeEach(() => {
applicationBuilder = getApplicationBuilder();
-
- applicationBuilder.beforeSetups(({ rendererDi }) => {
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- syncKubeconfigEntries: observable.map(),
- terminalConfig: { fontSize: 42 },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- rendererDi.override(defaultShellInjectable, () => "some-default-shell");
-
- const themeStoreStub = ({ themeOptions: [] }) as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
});
describe("given in preferences, when rendered", () => {
diff --git a/src/behaviours/preferences/navigation-using-application-menu.test.ts b/src/behaviours/preferences/navigation-using-application-menu.test.ts
index 42664dbfdf..e12aa85a44 100644
--- a/src/behaviours/preferences/navigation-using-application-menu.test.ts
+++ b/src/behaviours/preferences/navigation-using-application-menu.test.ts
@@ -6,11 +6,6 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
-import type { UserStore } from "../../common/user-store";
-import userStoreInjectable from "../../common/user-store/user-store.injectable";
-import type { ThemeStore } from "../../renderer/theme.store";
-import themeStoreInjectable from "../../renderer/theme-store.injectable";
describe("preferences - navigation using application menu", () => {
let applicationBuilder: ApplicationBuilder;
@@ -19,20 +14,6 @@ describe("preferences - navigation using application menu", () => {
beforeEach(async () => {
applicationBuilder = getApplicationBuilder();
- applicationBuilder.beforeSetups(({ rendererDi, mainDi }) => {
- mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
-
- const userStoreStub = {
- extensionRegistryUrl: { customUrl: "some-custom-url" },
- } as unknown as UserStore;
-
- rendererDi.override(userStoreInjectable, () => userStoreStub);
-
- const themeStoreStub = { themeOptions: [] } as unknown as ThemeStore;
-
- rendererDi.override(themeStoreInjectable, () => themeStoreStub);
- });
-
rendered = await applicationBuilder.render();
});
@@ -47,8 +28,8 @@ describe("preferences - navigation using application menu", () => {
});
describe("when navigating to preferences using application menu", () => {
- beforeEach(() => {
- applicationBuilder.applicationMenu.click("root.preferences");
+ beforeEach(async () => {
+ await applicationBuilder.applicationMenu.click("root.preferences");
});
it("renders", () => {
diff --git a/src/behaviours/preferences/navigation-using-tray.test.ts b/src/behaviours/preferences/navigation-using-tray.test.ts
new file mode 100644
index 0000000000..065cc54f4b
--- /dev/null
+++ b/src/behaviours/preferences/navigation-using-tray.test.ts
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { RenderResult } from "@testing-library/react";
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+
+describe("show-about-using-tray", () => {
+ let applicationBuilder: ApplicationBuilder;
+ let rendered: RenderResult;
+
+ beforeEach(async () => {
+ applicationBuilder = getApplicationBuilder();
+
+ rendered = await applicationBuilder.render();
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("does not show application preferences page yet", () => {
+ const actual = rendered.queryByTestId("application-preferences-page");
+
+ expect(actual).toBeNull();
+ });
+
+ describe("when navigating using tray", () => {
+ beforeEach(async () => {
+ await applicationBuilder.tray.click("open-preferences");
+ });
+
+ it("renders", () => {
+ expect(rendered.baseElement).toMatchSnapshot();
+ });
+
+ it("shows application preferences page", () => {
+ const actual = rendered.getByTestId("application-preferences-page");
+
+ expect(actual).not.toBeNull();
+ });
+ });
+});
diff --git a/src/behaviours/utils.ts b/src/behaviours/utils.ts
new file mode 100644
index 0000000000..1a20ab249b
--- /dev/null
+++ b/src/behaviours/utils.ts
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { RenderResult } from "@testing-library/react";
+
+export function getSidebarItem(rendered: RenderResult, itemId: string) {
+ return rendered
+ .queryAllByTestId("sidebar-item")
+ .find((x) => x.dataset.idTest === itemId);
+}
diff --git a/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap
index 368d132edb..05eee498bf 100644
--- a/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap
+++ b/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap
@@ -1,6 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`welcome - navigation using application menu renders 1`] = `
`;
+exports[`welcome - navigation using application menu renders 1`] = `
+
+`;
exports[`welcome - navigation using application menu when navigating to welcome using application menu renders 1`] = `
@@ -27,16 +33,17 @@ exports[`welcome - navigation using application menu when navigating to welcome
style="width: 320px;"
>
- Welcome to
- OpenLens
- 5!
+ Welcome to OpenLens 5!
- To get you started we have auto-detected your clusters in your kubeconfig file and added them to the catalog, your centralized view for managing all your cloud-native resources.
-
-
- If you have any questions or feedback, please join our
+ To get you started we have auto-detected your clusters in your
+ kubeconfig file and added them to the catalog, your centralized
+
+ view for managing all your cloud-native resources.
+
+
+ If you have any questions or feedback, please join our
+
`;
diff --git a/src/behaviours/welcome/navigation-using-application-menu.test.ts b/src/behaviours/welcome/navigation-using-application-menu.test.ts
index daab31c40e..a9f09c783c 100644
--- a/src/behaviours/welcome/navigation-using-application-menu.test.ts
+++ b/src/behaviours/welcome/navigation-using-application-menu.test.ts
@@ -6,16 +6,13 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
-import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
describe("welcome - navigation using application menu", () => {
let applicationBuilder: ApplicationBuilder;
let rendered: RenderResult;
beforeEach(async () => {
- applicationBuilder = getApplicationBuilder().beforeSetups(({ mainDi }) => {
- mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
- });
+ applicationBuilder = getApplicationBuilder();
rendered = await applicationBuilder.render();
});
@@ -31,8 +28,8 @@ describe("welcome - navigation using application menu", () => {
});
describe("when navigating to welcome using application menu", () => {
- beforeEach(() => {
- applicationBuilder.applicationMenu.click("help.welcome");
+ beforeEach(async () => {
+ await applicationBuilder.applicationMenu.click("help.welcome");
});
it("renders", () => {
diff --git a/src/common/__tests__/base-store.test.ts b/src/common/__tests__/base-store.test.ts
index 07cea7039e..e7eb952111 100644
--- a/src/common/__tests__/base-store.test.ts
+++ b/src/common/__tests__/base-store.test.ts
@@ -30,9 +30,9 @@ interface TestStoreModel {
}
class TestStore extends BaseStore {
- @observable a: string;
- @observable b: string;
- @observable c: string;
+ @observable a = "";
+ @observable b = "";
+ @observable c = "";
constructor() {
super({
@@ -81,16 +81,13 @@ class TestStore extends BaseStore {
describe("BaseStore", () => {
let store: TestStore;
- beforeEach(async () => {
+ beforeEach(() => {
const mainDi = getDiForUnitTesting({ doGeneralOverrides: true });
mainDi.override(directoryForUserDataInjectable, () => "some-user-data-directory");
mainDi.permitSideEffects(getConfigurationFileModelInjectable);
mainDi.permitSideEffects(appVersionInjectable);
- await mainDi.runSetups();
-
- store = undefined;
TestStore.resetInstance();
const mockOpts = {
diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts
index ccc2d897b9..ca52f6f1d2 100644
--- a/src/common/__tests__/cluster-store.test.ts
+++ b/src/common/__tests__/cluster-store.test.ts
@@ -8,22 +8,23 @@ import mockFs from "mock-fs";
import path from "path";
import fse from "fs-extra";
import type { Cluster } from "../cluster/cluster";
-import { ClusterStore } from "../cluster-store/cluster-store";
+import type { ClusterStore } from "../cluster-store/cluster-store";
import { Console } from "console";
import { stdout, stderr } from "process";
import getCustomKubeConfigDirectoryInjectable from "../app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
import clusterStoreInjectable from "../cluster-store/cluster-store.injectable";
import type { ClusterModel } from "../cluster-types";
-import type {
- DiContainer,
-} from "@ogre-tools/injectable";
-
+import type { DiContainer } from "@ogre-tools/injectable";
import { createClusterInjectionToken } from "../cluster/create-cluster-injection-token";
-
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
+import assert from "assert";
+import directoryForTempInjectable from "../app-paths/directory-for-temp/directory-for-temp.injectable";
+import kubectlBinaryNameInjectable from "../../main/kubectl/binary-name.injectable";
+import kubectlDownloadingNormalizedArchInjectable from "../../main/kubectl/normalized-arch.injectable";
+import normalizedPlatformInjectable from "../vars/normalized-platform.injectable";
console = new Console(stdout, stderr);
@@ -84,15 +85,17 @@ describe("cluster-store", () => {
mockFs();
- mainDi.override(clusterStoreInjectable, (di) => ClusterStore.createInstance({ createCluster: di.inject(createClusterInjectionToken) }));
mainDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
+ mainDi.override(directoryForTempInjectable, () => "some-temp-directory");
+ mainDi.override(kubectlBinaryNameInjectable, () => "kubectl");
+ mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
+ mainDi.override(normalizedPlatformInjectable, () => "darwin");
mainDi.permitSideEffects(getConfigurationFileModelInjectable);
mainDi.permitSideEffects(appVersionInjectable);
+ mainDi.permitSideEffects(clusterStoreInjectable);
- await mainDi.runSetups();
-
- createCluster = mainDi.inject(createClusterInjectionToken);
+ mainDi.unoverride(clusterStoreInjectable);
});
afterEach(() => {
@@ -107,10 +110,6 @@ describe("cluster-store", () => {
getCustomKubeConfigDirectoryInjectable,
);
- // TODO: Remove these by removing Singleton base-class from BaseStore
- ClusterStore.getInstance(false)?.unregisterIpcListener();
- ClusterStore.resetInstance();
-
const mockOpts = {
"some-directory-for-user-data": {
"lens-cluster-store.json": JSON.stringify({}),
@@ -119,7 +118,11 @@ describe("cluster-store", () => {
mockFs(mockOpts);
+ createCluster = mainDi.inject(createClusterInjectionToken);
+
clusterStore = mainDi.inject(clusterStoreInjectable);
+
+ clusterStore.unregisterIpcListener();
});
afterEach(() => {
@@ -148,6 +151,8 @@ describe("cluster-store", () => {
it("adds new cluster to store", async () => {
const storedCluster = clusterStore.getById("foo");
+ assert(storedCluster);
+
expect(storedCluster.id).toBe("foo");
expect(storedCluster.preferences.terminalCWD).toBe("/some-directory-for-user-data");
expect(storedCluster.preferences.icon).toBe(
@@ -199,8 +204,6 @@ describe("cluster-store", () => {
describe("config with existing clusters", () => {
beforeEach(() => {
- ClusterStore.resetInstance();
-
const mockOpts = {
"temp-kube-config": kubeconfig,
"some-directory-for-user-data": {
@@ -239,6 +242,8 @@ describe("cluster-store", () => {
mockFs(mockOpts);
+ createCluster = mainDi.inject(createClusterInjectionToken);
+
clusterStore = mainDi.inject(clusterStoreInjectable);
});
@@ -249,6 +254,8 @@ describe("cluster-store", () => {
it("allows to retrieve a cluster", () => {
const storedCluster = clusterStore.getById("cluster1");
+ assert(storedCluster);
+
expect(storedCluster.id).toBe("cluster1");
expect(storedCluster.preferences.terminalCWD).toBe("/foo");
});
@@ -287,8 +294,6 @@ users:
token: kubeconfig-user-q4lm4:xxxyyyy
`;
- ClusterStore.resetInstance();
-
const mockOpts = {
"invalid-kube-config": invalidKubeconfig,
"valid-kube-config": kubeconfig,
@@ -321,6 +326,8 @@ users:
mockFs(mockOpts);
+ createCluster = mainDi.inject(createClusterInjectionToken);
+
clusterStore = mainDi.inject(clusterStoreInjectable);
});
@@ -337,7 +344,6 @@ users:
describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
beforeEach(() => {
- ClusterStore.resetInstance();
const mockOpts = {
"some-directory-for-user-data": {
"lens-cluster-store.json": JSON.stringify({
@@ -363,6 +369,10 @@ users:
mockFs(mockOpts);
+ mainDi.override(appVersionInjectable, () => "3.6.0");
+
+ createCluster = mainDi.inject(createClusterInjectionToken);
+
clusterStore = mainDi.inject(clusterStoreInjectable);
});
@@ -379,6 +389,7 @@ users:
it("migrates to modern format with icon not in file", async () => {
const { icon } = clusterStore.clustersList[0].preferences;
+ assert(icon);
expect(icon.startsWith("data:;base64,")).toBe(true);
});
});
diff --git a/src/common/__tests__/event-bus.test.ts b/src/common/__tests__/event-bus.test.ts
index e7165aac92..f90381eb44 100644
--- a/src/common/__tests__/event-bus.test.ts
+++ b/src/common/__tests__/event-bus.test.ts
@@ -5,7 +5,7 @@
import type { AppEvent } from "../app-event-bus/event-bus";
import { appEventBus } from "../app-event-bus/event-bus";
-import { Console } from "console";
+import { assert, Console } from "console";
import { stdout, stderr } from "process";
console = new Console(stdout, stderr);
@@ -13,14 +13,15 @@ console = new Console(stdout, stderr);
describe("event bus tests", () => {
describe("emit", () => {
it("emits an event", () => {
- let event: AppEvent = null;
+ let event: AppEvent | undefined;
appEventBus.addListener((data) => {
event = data;
});
appEventBus.emit({ name: "foo", action: "bar" });
- expect(event.name).toBe("foo");
+ assert(event);
+ expect(event?.name).toBe("foo");
});
});
});
diff --git a/src/common/__tests__/event-emitter.test.ts b/src/common/__tests__/event-emitter.test.ts
index 5a0e49aad0..cc71922182 100644
--- a/src/common/__tests__/event-emitter.test.ts
+++ b/src/common/__tests__/event-emitter.test.ts
@@ -21,7 +21,7 @@ describe("EventEmitter", () => {
let called = false;
const e = new EventEmitter<[]>();
- e.addListener(() => 0 as any, {});
+ e.addListener(() => 0 as never, {});
e.addListener(() => { called = true; }, {});
e.emit();
diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts
index 9bc12d103d..cc8a4dc8fa 100644
--- a/src/common/__tests__/hotbar-store.test.ts
+++ b/src/common/__tests__/hotbar-store.test.ts
@@ -5,69 +5,20 @@
import { anyObject } from "jest-mock-extended";
import mockFs from "mock-fs";
-import logger from "../../main/logger";
import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../catalog";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
-import hotbarStoreInjectable from "../hotbar-store.injectable";
-import { HotbarStore } from "../hotbar-store";
+import hotbarStoreInjectable from "../hotbars/store.injectable";
+import type { HotbarStore } from "../hotbars/store";
+import catalogEntityRegistryInjectable from "../../main/catalog/entity-registry.injectable";
+import { computed } from "mobx";
+import hasCategoryForEntityInjectable from "../catalog/has-category-for-entity.injectable";
import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
-
-jest.mock("../../main/catalog/catalog-entity-registry", () => ({
- catalogEntityRegistry: {
- items: [
- getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
-
- status: {
- phase: "Running",
- },
-
- metadata: {
- uid: "1dfa26e2ebab15780a3547e9c7fa785c",
- name: "mycluster",
- source: "local",
- labels: {},
- },
- }),
-
- getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
-
- status: {
- phase: "Running",
- },
-
- metadata: {
- uid: "55b42c3c7ba3b04193416cda405269a5",
- name: "my_shiny_cluster",
- source: "remote",
- labels: {},
- },
- }),
-
- getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
-
- status: {
- phase: "Running",
- },
-
- metadata: {
- uid: "catalog-entity",
- name: "Catalog",
- source: "app",
- labels: {},
- },
- }),
- ],
- },
-}));
+import loggerInjectable from "../logger.injectable";
+import type { Logger } from "../logger";
+import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
function getMockCatalogEntity(data: Partial & CatalogEntityKindData): CatalogEntity {
return {
@@ -84,75 +35,99 @@ function getMockCatalogEntity(data: Partial & CatalogEntityKi
} as CatalogEntity;
}
-const testCluster = getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
- status: {
- phase: "Running",
- },
- metadata: {
- uid: "test",
- name: "test",
- labels: {},
- },
-});
-
-const minikubeCluster = getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
- status: {
- phase: "Running",
- },
- metadata: {
- uid: "minikube",
- name: "minikube",
- labels: {},
- },
-});
-
-const awsCluster = getMockCatalogEntity({
- apiVersion: "v1",
- kind: "Cluster",
- status: {
- phase: "Running",
- },
- metadata: {
- uid: "aws",
- name: "aws",
- labels: {},
- },
-});
-
describe("HotbarStore", () => {
let di: DiContainer;
let hotbarStore: HotbarStore;
+ let testCluster: CatalogEntity;
+ let minikubeCluster: CatalogEntity;
+ let awsCluster: CatalogEntity;
+ let loggerMock: jest.Mocked;
beforeEach(async () => {
di = getDiForUnitTesting({ doGeneralOverrides: true });
+ (di as any).unoverride(hotbarStoreInjectable);
+
+ testCluster = getMockCatalogEntity({
+ apiVersion: "v1",
+ kind: "Cluster",
+ status: {
+ phase: "Running",
+ },
+ metadata: {
+ uid: "some-test-id",
+ name: "my-test-cluster",
+ source: "local",
+ labels: {},
+ },
+ });
+ minikubeCluster = getMockCatalogEntity({
+ apiVersion: "v1",
+ kind: "Cluster",
+ status: {
+ phase: "Running",
+ },
+ metadata: {
+ uid: "some-minikube-id",
+ name: "my-minikube-cluster",
+ source: "local",
+ labels: {},
+ },
+ });
+ awsCluster = getMockCatalogEntity({
+ apiVersion: "v1",
+ kind: "Cluster",
+ status: {
+ phase: "Running",
+ },
+ metadata: {
+ uid: "some-aws-id",
+ name: "my-aws-cluster",
+ source: "local",
+ labels: {},
+ },
+ });
+
+ di.override(hasCategoryForEntityInjectable, () => () => true);
+
+ loggerMock = {
+ warn: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ info: jest.fn(),
+ silly: jest.fn(),
+ };
+
+ di.override(loggerInjectable, () => loggerMock);
+
+ di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
+
+ const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
+ const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
+
+ catalogEntityRegistry.addComputedSource("some-id", computed(() => [
+ testCluster,
+ minikubeCluster,
+ awsCluster,
+ catalogCatalogEntity,
+ ]));
+
di.permitSideEffects(getConfigurationFileModelInjectable);
di.permitSideEffects(appVersionInjectable);
-
- di.override(hotbarStoreInjectable, () => {
- HotbarStore.resetInstance();
-
- return HotbarStore.createInstance({
- catalogCatalogEntity: di.inject(catalogCatalogEntityInjectable),
- });
- });
+ di.permitSideEffects(hotbarStoreInjectable);
});
afterEach(() => {
mockFs.restore();
});
- describe("given no migrations", () => {
- beforeEach(async () => {
+ describe("given no previous data in store, running all migrations", () => {
+ beforeEach(() => {
mockFs();
- await di.runSetups();
-
hotbarStore = di.inject(hotbarStoreInjectable);
+
+ hotbarStore.load();
});
describe("load", () => {
@@ -174,7 +149,7 @@ describe("HotbarStore", () => {
});
it("initially adds catalog entity as first item", () => {
- expect(hotbarStore.getActive().items[0].entity.name).toEqual("Catalog");
+ expect(hotbarStore.getActive().items[0]?.entity.name).toEqual("Catalog");
});
it("adds items", () => {
@@ -186,7 +161,7 @@ describe("HotbarStore", () => {
it("removes items", () => {
hotbarStore.addToHotbar(testCluster);
- hotbarStore.removeFromHotbar("test");
+ hotbarStore.removeFromHotbar("some-test-id");
hotbarStore.removeFromHotbar("catalog-entity");
const items = hotbarStore.getActive().items.filter(Boolean);
@@ -211,7 +186,7 @@ describe("HotbarStore", () => {
hotbarStore.restackItems(1, 5);
expect(hotbarStore.getActive().items[5]).toBeTruthy();
- expect(hotbarStore.getActive().items[5].entity.uid).toEqual("test");
+ expect(hotbarStore.getActive().items[5]?.entity.uid).toEqual("some-test-id");
});
it("moves items down", () => {
@@ -224,7 +199,7 @@ describe("HotbarStore", () => {
const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null);
- expect(items.slice(0, 4)).toEqual(["aws", "catalog-entity", "test", "minikube"]);
+ expect(items.slice(0, 4)).toEqual(["some-aws-id", "catalog-entity", "some-test-id", "some-minikube-id"]);
});
it("moves items up", () => {
@@ -237,28 +212,21 @@ describe("HotbarStore", () => {
const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null);
- expect(items.slice(0, 4)).toEqual(["catalog-entity", "minikube", "aws", "test"]);
+ expect(items.slice(0, 4)).toEqual(["catalog-entity", "some-minikube-id", "some-aws-id", "some-test-id"]);
});
it("logs an error if cellIndex is out of bounds", () => {
hotbarStore.add({ name: "hottest", id: "hottest" });
hotbarStore.setActiveHotbar("hottest");
- const { error } = logger;
- const mocked = jest.fn();
-
- logger.error = mocked;
-
hotbarStore.addToHotbar(testCluster, -1);
- expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
+ expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
hotbarStore.addToHotbar(testCluster, 12);
- expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
+ expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
hotbarStore.addToHotbar(testCluster, 13);
- expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
-
- logger.error = error;
+ expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
});
it("throws an error if getId is invalid or returns not a string", () => {
@@ -275,7 +243,7 @@ describe("HotbarStore", () => {
hotbarStore.addToHotbar(testCluster);
hotbarStore.restackItems(1, 1);
- expect(hotbarStore.getActive().items[1].entity.uid).toEqual("test");
+ expect(hotbarStore.getActive().items[1]?.entity.uid).toEqual("some-test-id");
});
it("new items takes first empty cell", () => {
@@ -284,7 +252,7 @@ describe("HotbarStore", () => {
hotbarStore.restackItems(0, 3);
hotbarStore.addToHotbar(minikubeCluster);
- expect(hotbarStore.getActive().items[0].entity.uid).toEqual("minikube");
+ expect(hotbarStore.getActive().items[0]?.entity.uid).toEqual("some-minikube-id");
});
it("throws if invalid arguments provided", () => {
@@ -315,10 +283,10 @@ describe("HotbarStore", () => {
});
});
- describe("given pre beta-5 configurations", () => {
- beforeEach(async () => {
+ describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => {
+ beforeEach(() => {
const configurationToBeMigrated = {
- "some-electron-app-path-for-user-data": {
+ "some-directory-for-user-data": {
"lens-hotbar-store.json": JSON.stringify({
__internal__: {
migrations: {
@@ -332,7 +300,7 @@ describe("HotbarStore", () => {
items: [
{
entity: {
- uid: "1dfa26e2ebab15780a3547e9c7fa785c",
+ uid: "some-aws-id",
},
},
{
@@ -381,15 +349,17 @@ describe("HotbarStore", () => {
mockFs(configurationToBeMigrated);
- await di.runSetups();
+ di.override(appVersionInjectable, () => "5.0.0-beta.10");
hotbarStore = di.inject(hotbarStoreInjectable);
+
+ hotbarStore.load();
});
it("allows to retrieve a hotbar", () => {
- const hotbar = hotbarStore.getById("3caac17f-aec2-4723-9694-ad204465d935");
+ const hotbar = hotbarStore.findById("3caac17f-aec2-4723-9694-ad204465d935");
- expect(hotbar.id).toBe("3caac17f-aec2-4723-9694-ad204465d935");
+ expect(hotbar?.id).toBe("3caac17f-aec2-4723-9694-ad204465d935");
});
it("clears cells without entity", () => {
@@ -403,17 +373,9 @@ describe("HotbarStore", () => {
expect(items[0]).toEqual({
entity: {
- name: "mycluster",
+ name: "my-aws-cluster",
source: "local",
- uid: "1dfa26e2ebab15780a3547e9c7fa785c",
- },
- });
-
- expect(items[1]).toEqual({
- entity: {
- name: "my_shiny_cluster",
- source: "remote",
- uid: "55b42c3c7ba3b04193416cda405269a5",
+ uid: "some-aws-id",
},
});
});
diff --git a/src/common/__tests__/system-ca.test.ts b/src/common/__tests__/system-ca.test.ts
index 0d962ee368..473fe6ed57 100644
--- a/src/common/__tests__/system-ca.test.ts
+++ b/src/common/__tests__/system-ca.test.ts
@@ -6,13 +6,14 @@ import https from "https";
import os from "os";
import { getMacRootCA, getWinRootCA, injectCAs, DSTRootCAX3 } from "../system-ca";
import { dependencies, devDependencies } from "../../../package.json";
+import assert from "assert";
const deps = { ...dependencies, ...devDependencies };
// Skip the test if mac-ca is not installed, or os is not darwin
(deps["mac-ca"] && os.platform().includes("darwin") ? describe: describe.skip)("inject CA for Mac", () => {
// for reset https.globalAgent.options.ca after testing
- let _ca: string | Buffer | (string | Buffer)[];
+ let _ca: string | Buffer | (string | Buffer)[] | undefined;
beforeEach(() => {
_ca = https.globalAgent.options.ca;
@@ -44,6 +45,7 @@ const deps = { ...dependencies, ...devDependencies };
injectCAs(osxCAs);
const injected = https.globalAgent.options.ca;
+ assert(injected);
expect(injected.includes(DSTRootCAX3)).toBeFalsy();
});
});
@@ -51,7 +53,7 @@ const deps = { ...dependencies, ...devDependencies };
// Skip the test if win-ca is not installed, or os is not win32
(deps["win-ca"] && os.platform().includes("win32") ? describe: describe.skip)("inject CA for Windows", () => {
// for reset https.globalAgent.options.ca after testing
- let _ca: string | Buffer | (string | Buffer)[];
+ let _ca: string | Buffer | (string | Buffer)[] | undefined;
beforeEach(() => {
_ca = https.globalAgent.options.ca;
diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts
index 9fb3713be1..238fc5bce8 100644
--- a/src/common/__tests__/user-store.test.ts
+++ b/src/common/__tests__/user-store.test.ts
@@ -21,7 +21,7 @@ jest.mock("electron", () => ({
},
}));
-import { UserStore } from "../user-store";
+import type { UserStore } from "../user-store";
import { Console } from "console";
import { SemVer } from "semver";
import electron from "electron";
@@ -30,13 +30,11 @@ import userStoreInjectable from "../user-store/user-store.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
import type { ClusterStoreModel } from "../cluster-store/cluster-store";
-import { defaultTheme } from "../vars";
+import { defaultThemeId } from "../vars";
import writeFileInjectable from "../fs/write-file.injectable";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
-import getConfigurationFileModelInjectable
- from "../get-configuration-file-model/get-configuration-file-model.injectable";
-import appVersionInjectable
- from "../get-configuration-file-model/app-version/app-version.injectable";
+import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
+import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
console = new Console(stdout, stderr);
@@ -44,23 +42,22 @@ describe("user store tests", () => {
let userStore: UserStore;
let di: DiContainer;
- beforeEach(async () => {
+ beforeEach(() => {
di = getDiForUnitTesting({ doGeneralOverrides: true });
mockFs();
- di.override(writeFileInjectable, () => () => undefined);
+ di.override(writeFileInjectable, () => () => Promise.resolve());
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
- di.override(userStoreInjectable, () => UserStore.createInstance());
-
di.permitSideEffects(getConfigurationFileModelInjectable);
- di.permitSideEffects(appVersionInjectable);
- await di.runSetups();
+ di.permitSideEffects(appVersionInjectable);
+ di.permitSideEffects(userStoreInjectable);
+
+ di.unoverride(userStoreInjectable);
});
afterEach(() => {
- UserStore.resetInstance();
mockFs.restore();
});
@@ -80,7 +77,7 @@ describe("user store tests", () => {
userStore.httpsProxy = "abcd://defg";
expect(userStore.httpsProxy).toBe("abcd://defg");
- expect(userStore.colorTheme).toBe(defaultTheme);
+ expect(userStore.colorTheme).toBe(defaultThemeId);
userStore.colorTheme = "light";
expect(userStore.colorTheme).toBe("light");
@@ -89,7 +86,7 @@ describe("user store tests", () => {
it("correctly resets theme to default value", async () => {
userStore.colorTheme = "some other theme";
userStore.resetTheme();
- expect(userStore.colorTheme).toBe(defaultTheme);
+ expect(userStore.colorTheme).toBe(defaultThemeId);
});
it("correctly calculates if the last seen version is an old release", () => {
@@ -130,6 +127,8 @@ describe("user store tests", () => {
},
});
+ di.override(appVersionInjectable, () => "10.0.0");
+
userStore = di.inject(userStoreInjectable);
});
diff --git a/src/common/app-event-bus/app-event-bus.injectable.ts b/src/common/app-event-bus/app-event-bus.injectable.ts
index 8ba0412ba4..31ed3dd3a1 100644
--- a/src/common/app-event-bus/app-event-bus.injectable.ts
+++ b/src/common/app-event-bus/app-event-bus.injectable.ts
@@ -8,6 +8,7 @@ import { appEventBus } from "./event-bus";
const appEventBusInjectable = getInjectable({
id: "app-event-bus",
instantiate: () => appEventBus,
+ causesSideEffects: true,
});
export default appEventBusInjectable;
diff --git a/src/common/app-paths/app-path-injection-token.ts b/src/common/app-paths/app-path-injection-token.ts
index 3b03e44daf..e29bcdbebf 100644
--- a/src/common/app-paths/app-path-injection-token.ts
+++ b/src/common/app-paths/app-path-injection-token.ts
@@ -4,12 +4,9 @@
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { PathName } from "./app-path-names";
-import { createChannel } from "../ipc-channel/create-channel/create-channel";
export type AppPaths = Record;
export const appPathsInjectionToken = getInjectionToken({ id: "app-paths-token" });
-export const appPathsIpcChannel = createChannel("app-paths");
-
diff --git a/src/common/app-paths/app-paths-channel.injectable.ts b/src/common/app-paths/app-paths-channel.injectable.ts
new file mode 100644
index 0000000000..99fc738b41
--- /dev/null
+++ b/src/common/app-paths/app-paths-channel.injectable.ts
@@ -0,0 +1,22 @@
+/**
+ * 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 type { AppPaths } from "./app-path-injection-token";
+import type { RequestChannel } from "../utils/channel/request-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+export type AppPathsChannel = RequestChannel;
+
+const appPathsChannelInjectable = getInjectable({
+ id: "app-paths-channel",
+
+ instantiate: (): AppPathsChannel => ({
+ id: "app-paths",
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default appPathsChannelInjectable;
diff --git a/src/common/app-paths/app-paths-state.injectable.ts b/src/common/app-paths/app-paths-state.injectable.ts
new file mode 100644
index 0000000000..5487d428b2
--- /dev/null
+++ b/src/common/app-paths/app-paths-state.injectable.ts
@@ -0,0 +1,34 @@
+/**
+ * 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 type { AppPaths } from "./app-path-injection-token";
+
+const appPathsStateInjectable = getInjectable({
+ id: "app-paths-state",
+
+ instantiate: () => {
+ let state: AppPaths;
+
+ return {
+ get: () =>{
+ if (!state) {
+ throw new Error("Tried to get app paths before state is setupped.");
+ }
+
+ return state;
+ },
+
+ set: (newState: AppPaths) => {
+ if (state) {
+ throw new Error("Tried to overwrite existing state of app paths.");
+ }
+
+ state = newState;
+ },
+ };
+ },
+});
+
+export default appPathsStateInjectable;
diff --git a/src/common/app-paths/app-paths.injectable.ts b/src/common/app-paths/app-paths.injectable.ts
new file mode 100644
index 0000000000..803f9e1380
--- /dev/null
+++ b/src/common/app-paths/app-paths.injectable.ts
@@ -0,0 +1,15 @@
+/**
+ * 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 { appPathsInjectionToken } from "./app-path-injection-token";
+import appPathsStateInjectable from "./app-paths-state.injectable";
+
+const appPathsInjectable = getInjectable({
+ id: "app-paths",
+ instantiate: (di) => di.inject(appPathsStateInjectable).get(),
+ injectionToken: appPathsInjectionToken,
+});
+
+export default appPathsInjectable;
diff --git a/src/common/app-paths/app-paths.test.ts b/src/common/app-paths/app-paths.test.ts
index b436426e2e..5793295e0e 100644
--- a/src/common/app-paths/app-paths.test.ts
+++ b/src/common/app-paths/app-paths.test.ts
@@ -2,27 +2,27 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import type { DiContainer } from "@ogre-tools/injectable";
import type { AppPaths } from "./app-path-injection-token";
import { appPathsInjectionToken } from "./app-path-injection-token";
import getElectronAppPathInjectable from "../../main/app-paths/get-electron-app-path/get-electron-app-path.injectable";
-import { getDisForUnitTesting } from "../../test-utils/get-dis-for-unit-testing";
import type { PathName } from "./app-path-names";
import setElectronAppPathInjectable from "../../main/app-paths/set-electron-app-path/set-electron-app-path.injectable";
import appNameInjectable from "../../main/app-paths/app-name/app-name.injectable";
import directoryForIntegrationTestingInjectable from "../../main/app-paths/directory-for-integration-testing/directory-for-integration-testing.injectable";
+import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
+import type { DiContainer } from "@ogre-tools/injectable";
describe("app-paths", () => {
- let mainDi: DiContainer;
+ let applicationBuilder: ApplicationBuilder;
let rendererDi: DiContainer;
- let runSetups: () => Promise;
+ let mainDi: DiContainer;
beforeEach(() => {
- const dis = getDisForUnitTesting({ doGeneralOverrides: true });
+ applicationBuilder = getApplicationBuilder();
- mainDi = dis.mainDi;
- rendererDi = dis.rendererDi;
- runSetups = dis.runSetups;
+ rendererDi = applicationBuilder.dis.rendererDi;
+ mainDi = applicationBuilder.dis.mainDi;
const defaultAppPathsStub: AppPaths = {
appData: "some-app-data",
@@ -40,30 +40,32 @@ describe("app-paths", () => {
recent: "some-recent",
temp: "some-temp",
videos: "some-videos",
- userData: "some-irrelevant",
+ userData: "some-irrelevant-user-data",
};
- mainDi.override(
- getElectronAppPathInjectable,
- () =>
- (key: PathName): string | null =>
- defaultAppPathsStub[key],
- );
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(
+ getElectronAppPathInjectable,
+ () =>
+ (key: PathName): string | null =>
+ defaultAppPathsStub[key],
+ );
- mainDi.override(
- setElectronAppPathInjectable,
- () =>
- (key: PathName, path: string): void => {
- defaultAppPathsStub[key] = path;
- },
- );
+ mainDi.override(
+ setElectronAppPathInjectable,
+ () =>
+ (key: PathName, path: string): void => {
+ defaultAppPathsStub[key] = path;
+ },
+ );
- mainDi.override(appNameInjectable, () => "some-app-name");
+ mainDi.override(appNameInjectable, () => "some-app-name");
+ });
});
describe("normally", () => {
beforeEach(async () => {
- await runSetups();
+ await applicationBuilder.render();
});
it("given in renderer, when injecting app paths, returns application specific app paths", () => {
@@ -115,12 +117,14 @@ describe("app-paths", () => {
describe("when running integration tests", () => {
beforeEach(async () => {
- mainDi.override(
- directoryForIntegrationTestingInjectable,
- () => "some-integration-testing-app-data",
- );
+ applicationBuilder.beforeApplicationStart(({ mainDi }) => {
+ mainDi.override(
+ directoryForIntegrationTestingInjectable,
+ () => "some-integration-testing-app-data",
+ );
+ });
- await runSetups();
+ await applicationBuilder.render();
});
it("given in renderer, when injecting path for app data, has integration specific app data path", () => {
diff --git a/src/common/app-paths/directory-for-bundled-binaries/directory-for-bundled-binaries.injectable.ts b/src/common/app-paths/directory-for-bundled-binaries/directory-for-bundled-binaries.injectable.ts
deleted file mode 100644
index 9c25407d4d..0000000000
--- a/src/common/app-paths/directory-for-bundled-binaries/directory-for-bundled-binaries.injectable.ts
+++ /dev/null
@@ -1,13 +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 { baseBinariesDir } from "../../vars";
-
-const directoryForBundledBinariesInjectable = getInjectable({
- id: "directory-for-bundled-binaries",
- instantiate: () => baseBinariesDir.get(),
-});
-
-export default directoryForBundledBinariesInjectable;
diff --git a/src/common/application-update/application-update-status-channel.injectable.ts b/src/common/application-update/application-update-status-channel.injectable.ts
new file mode 100644
index 0000000000..1365fd19af
--- /dev/null
+++ b/src/common/application-update/application-update-status-channel.injectable.ts
@@ -0,0 +1,29 @@
+/**
+ * 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 type { MessageChannel } from "../utils/channel/message-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+export type ApplicationUpdateStatusEventId =
+ | "checking-for-updates"
+ | "no-updates-available"
+ | "download-for-update-started"
+ | "download-for-update-failed";
+
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+export type ApplicationUpdateStatusChannelMessage = { eventId: ApplicationUpdateStatusEventId; version?: string };
+export type ApplicationUpdateStatusChannel = MessageChannel;
+
+const applicationUpdateStatusChannelInjectable = getInjectable({
+ id: "application-update-status-channel",
+
+ instantiate: (): ApplicationUpdateStatusChannel => ({
+ id: "application-update-status-channel",
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default applicationUpdateStatusChannelInjectable;
diff --git a/src/common/application-update/discovered-update-version/discovered-update-version.injectable.ts b/src/common/application-update/discovered-update-version/discovered-update-version.injectable.ts
new file mode 100644
index 0000000000..60557de211
--- /dev/null
+++ b/src/common/application-update/discovered-update-version/discovered-update-version.injectable.ts
@@ -0,0 +1,28 @@
+/**
+ * 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 createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
+import type { UpdateChannel } from "../update-channels";
+import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
+
+const discoveredUpdateVersionInjectable = getInjectable({
+ id: "discovered-update-version",
+
+ instantiate: (di) => {
+ const createSyncBox = di.inject(createSyncBoxInjectable);
+
+ return createSyncBox<
+ | { version: string; updateChannel: UpdateChannel }
+ | null
+ >(
+ "discovered-update-version",
+ null,
+ );
+ },
+
+ injectionToken: syncBoxInjectionToken,
+});
+
+export default discoveredUpdateVersionInjectable;
diff --git a/src/common/application-update/progress-of-update-download/progress-of-update-download.injectable.ts b/src/common/application-update/progress-of-update-download/progress-of-update-download.injectable.ts
new file mode 100644
index 0000000000..26ecd1d618
--- /dev/null
+++ b/src/common/application-update/progress-of-update-download/progress-of-update-download.injectable.ts
@@ -0,0 +1,25 @@
+/**
+ * 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 createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
+import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
+
+export interface ProgressOfDownload {
+ percentage: number;
+}
+
+const progressOfUpdateDownloadInjectable = getInjectable({
+ id: "progress-of-update-download-state",
+
+ instantiate: (di) => {
+ const createSyncBox = di.inject(createSyncBoxInjectable);
+
+ return createSyncBox("progress-of-update-download", { percentage: 0 });
+ },
+
+ injectionToken: syncBoxInjectionToken,
+});
+
+export default progressOfUpdateDownloadInjectable;
diff --git a/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts b/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts
new file mode 100644
index 0000000000..3d9101b672
--- /dev/null
+++ b/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts
@@ -0,0 +1,27 @@
+/**
+ * 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 { SemVer } from "semver";
+import appVersionInjectable from "../../get-configuration-file-model/app-version/app-version.injectable";
+import type { UpdateChannelId } from "../update-channels";
+import { updateChannels } from "../update-channels";
+
+const defaultUpdateChannelInjectable = getInjectable({
+ id: "default-update-channel",
+
+ instantiate: (di) => {
+ const appVersion = di.inject(appVersionInjectable);
+
+ const currentReleaseChannel = new SemVer(appVersion).prerelease[0]?.toString() as UpdateChannelId;
+
+ if (currentReleaseChannel && updateChannels[currentReleaseChannel]) {
+ return updateChannels[currentReleaseChannel];
+ }
+
+ return updateChannels.latest;
+ },
+});
+
+export default defaultUpdateChannelInjectable;
diff --git a/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts b/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts
new file mode 100644
index 0000000000..ceb47aee5e
--- /dev/null
+++ b/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts
@@ -0,0 +1,39 @@
+/**
+ * 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 type { IComputedValue } from "mobx";
+import { action, computed, observable } from "mobx";
+import type { UpdateChannel, UpdateChannelId } from "../update-channels";
+import { updateChannels } from "../update-channels";
+import defaultUpdateChannelInjectable from "./default-update-channel.injectable";
+
+export interface SelectedUpdateChannel {
+ value: IComputedValue;
+ setValue: (channelId?: UpdateChannelId) => void;
+}
+
+const selectedUpdateChannelInjectable = getInjectable({
+ id: "selected-update-channel",
+
+ instantiate: (di): SelectedUpdateChannel => {
+ const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable);
+ const state = observable.box(defaultUpdateChannel);
+
+ return {
+ value: computed(() => state.get()),
+
+ setValue: action((channelId) => {
+ const targetUpdateChannel =
+ channelId && updateChannels[channelId]
+ ? updateChannels[channelId]
+ : defaultUpdateChannel;
+
+ state.set(targetUpdateChannel);
+ }),
+ };
+ },
+});
+
+export default selectedUpdateChannelInjectable;
diff --git a/src/common/application-update/update-channels.ts b/src/common/application-update/update-channels.ts
new file mode 100644
index 0000000000..c5f7b4b8c1
--- /dev/null
+++ b/src/common/application-update/update-channels.ts
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+export type UpdateChannelId = "alpha" | "beta" | "latest";
+
+const latestChannel: UpdateChannel = {
+ id: "latest",
+ label: "Stable",
+ moreStableUpdateChannel: null,
+};
+
+const betaChannel: UpdateChannel = {
+ id: "beta",
+ label: "Beta",
+ moreStableUpdateChannel: latestChannel,
+};
+
+const alphaChannel: UpdateChannel = {
+ id: "alpha",
+ label: "Alpha",
+ moreStableUpdateChannel: betaChannel,
+};
+
+export const updateChannels: Record = {
+ latest: latestChannel,
+ beta: betaChannel,
+ alpha: alphaChannel,
+};
+
+export interface UpdateChannel {
+ readonly id: UpdateChannelId;
+ readonly label: string;
+ readonly moreStableUpdateChannel: UpdateChannel | null;
+}
diff --git a/src/common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable.ts b/src/common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable.ts
new file mode 100644
index 0000000000..e1701d7952
--- /dev/null
+++ b/src/common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable.ts
@@ -0,0 +1,21 @@
+/**
+ * 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 createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
+import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
+
+const updateIsBeingDownloadedInjectable = getInjectable({
+ id: "update-is-being-downloaded",
+
+ instantiate: (di) => {
+ const createSyncBox = di.inject(createSyncBoxInjectable);
+
+ return createSyncBox("update-is-being-downloaded", false);
+ },
+
+ injectionToken: syncBoxInjectionToken,
+});
+
+export default updateIsBeingDownloadedInjectable;
diff --git a/src/common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable.ts b/src/common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable.ts
new file mode 100644
index 0000000000..21f1c14bec
--- /dev/null
+++ b/src/common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable.ts
@@ -0,0 +1,21 @@
+/**
+ * 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 createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
+import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
+
+const updatesAreBeingDiscoveredInjectable = getInjectable({
+ id: "updates-are-being-discovered",
+
+ instantiate: (di) => {
+ const createSyncBox = di.inject(createSyncBoxInjectable);
+
+ return createSyncBox("updates-are-being-discovered", false);
+ },
+
+ injectionToken: syncBoxInjectionToken,
+});
+
+export default updatesAreBeingDiscoveredInjectable;
diff --git a/src/common/ask-boolean/ask-boolean-answer-channel.injectable.ts b/src/common/ask-boolean/ask-boolean-answer-channel.injectable.ts
new file mode 100644
index 0000000000..9901c04e30
--- /dev/null
+++ b/src/common/ask-boolean/ask-boolean-answer-channel.injectable.ts
@@ -0,0 +1,21 @@
+/**
+ * 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 type { MessageChannel } from "../utils/channel/message-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+export type AskBooleanAnswerChannel = MessageChannel<{ id: string; value: boolean }>;
+
+const askBooleanAnswerChannelInjectable = getInjectable({
+ id: "ask-boolean-answer-channel",
+
+ instantiate: (): AskBooleanAnswerChannel => ({
+ id: "ask-boolean-answer",
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default askBooleanAnswerChannelInjectable;
diff --git a/src/common/ask-boolean/ask-boolean-question-channel.injectable.ts b/src/common/ask-boolean/ask-boolean-question-channel.injectable.ts
new file mode 100644
index 0000000000..664337158f
--- /dev/null
+++ b/src/common/ask-boolean/ask-boolean-question-channel.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 type { MessageChannel } from "../utils/channel/message-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+export type AskBooleanQuestionParameters = { id: string; title: string; question: string };
+export type AskBooleanQuestionChannel = MessageChannel;
+
+const askBooleanQuestionChannelInjectable = getInjectable({
+ id: "ask-boolean-question-channel",
+
+ instantiate: (): AskBooleanQuestionChannel => ({
+ id: "ask-boolean-question",
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default askBooleanQuestionChannelInjectable;
diff --git a/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts b/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts
index bbddddcca7..d681713a80 100644
--- a/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts
+++ b/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts
@@ -2,20 +2,30 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { kubernetesClusterCategory } from "../kubernetes-cluster";
+
+import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
+import kubernetesClusterCategoryInjectable from "../../catalog/categories/kubernetes-cluster.injectable";
+import type { KubernetesClusterCategory } from "../kubernetes-cluster";
+
describe("kubernetesClusterCategory", () => {
+ let kubernetesClusterCategory: KubernetesClusterCategory;
+
+ beforeEach(() => {
+ const di = getDiForUnitTesting();
+
+ kubernetesClusterCategory = di.inject(kubernetesClusterCategoryInjectable);
+ });
+
describe("filteredItems", () => {
const item1 = {
icon: "Icon",
title: "Title",
- // eslint-disable-next-line @typescript-eslint/no-empty-function
onClick: () => {},
};
const item2 = {
icon: "Icon 2",
title: "Title 2",
- // eslint-disable-next-line @typescript-eslint/no-empty-function
onClick: () => {},
};
diff --git a/src/common/catalog-entities/general.ts b/src/common/catalog-entities/general.ts
index 9c33499ec8..2d3b404ee0 100644
--- a/src/common/catalog-entities/general.ts
+++ b/src/common/catalog-entities/general.ts
@@ -5,8 +5,7 @@
import { navigate } from "../../renderer/navigation";
import type { CatalogEntityMetadata, CatalogEntitySpec, CatalogEntityStatus } from "../catalog";
-import { CatalogCategory, CatalogEntity } from "../catalog";
-import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
+import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
interface GeneralEntitySpec extends CatalogEntitySpec {
path: string;
@@ -23,18 +22,6 @@ export class GeneralEntity extends CatalogEntity(this)
- ?.emit("contextMenuOpen", this, context);
}
}
-class KubernetesClusterCategory extends CatalogCategory {
+export class KubernetesClusterCategory extends CatalogCategory {
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
public readonly kind = "CatalogCategory";
public metadata = {
@@ -145,17 +144,10 @@ class KubernetesClusterCategory extends CatalogCategory {
public spec: CatalogCategorySpec = {
group: "entity.k8slens.dev",
versions: [
- {
- name: "v1alpha1",
- entityClass: KubernetesCluster,
- },
+ categoryVersion("v1alpha1", KubernetesCluster as CatalogEntityConstructor),
],
names: {
kind: "KubernetesCluster",
},
};
}
-
-export const kubernetesClusterCategory = new KubernetesClusterCategory();
-
-catalogCategoryRegistry.add(kubernetesClusterCategory);
diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts
index 15331cc0fc..35dc86be57 100644
--- a/src/common/catalog-entities/web-link.ts
+++ b/src/common/catalog-entities/web-link.ts
@@ -4,8 +4,7 @@
*/
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
-import { CatalogCategory, CatalogEntity } from "../catalog";
-import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
+import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
import { productName } from "../vars";
import { WeblinkStore } from "../weblink-store";
@@ -30,11 +29,7 @@ export class WebLink extends CatalogEntity(this)
- ?.emit("contextMenuOpen", this, context);
}
}
@@ -62,15 +53,10 @@ export class WebLinkCategory extends CatalogCategory {
public spec = {
group: "entity.k8slens.dev",
versions: [
- {
- name: "v1alpha1",
- entityClass: WebLink,
- },
+ categoryVersion("v1alpha1", WebLink),
],
names: {
kind: "WebLink",
},
};
}
-
-catalogCategoryRegistry.add(new WebLinkCategory());
diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts
index 7eb3e0fac8..d456f38f06 100644
--- a/src/common/catalog/catalog-category-registry.ts
+++ b/src/common/catalog/catalog-category-registry.ts
@@ -3,96 +3,10 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { action, computed, observable, makeObservable } from "mobx";
-import { once } from "lodash";
-import { iter, getOrInsertMap, strictSet } from "../utils";
-import type { Disposer } from "../utils";
-import type { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
+import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
+import catalogCategoryRegistryInjectable from "./category-registry.injectable";
-export type CategoryFilter = (category: CatalogCategory) => any;
-
-export class CatalogCategoryRegistry {
- protected categories = observable.set();
- protected groupKinds = new Map>();
- protected filters = observable.set([], {
- deep: false,
- });
-
- constructor() {
- makeObservable(this);
- }
-
- @action add(category: CatalogCategory): Disposer {
- const byGroup = getOrInsertMap(this.groupKinds, category.spec.group);
-
- this.categories.add(category);
- strictSet(byGroup, category.spec.names.kind, category);
-
- return () => {
- this.categories.delete(category);
- byGroup.delete(category.spec.names.kind);
- };
- }
-
- @computed get items() {
- return Array.from(this.categories);
- }
-
- @computed get filteredItems() {
- return Array.from(
- iter.reduce(
- this.filters,
- iter.filter,
- this.items.values(),
- ),
- );
- }
-
-
- getForGroupKind(group: string, kind: string): T | undefined {
- return this.groupKinds.get(group)?.get(kind) as T;
- }
-
- getEntityForData(data: CatalogEntityData & CatalogEntityKindData) {
- const category = this.getCategoryForEntity(data);
-
- if (!category) {
- return null;
- }
-
- const splitApiVersion = data.apiVersion.split("/");
- const version = splitApiVersion[1];
-
- const specVersion = category.spec.versions.find((v) => v.name === version);
-
- if (!specVersion) {
- return null;
- }
-
- return new specVersion.entityClass(data);
- }
-
- getCategoryForEntity(data: CatalogEntityData & CatalogEntityKindData): T | undefined {
- const splitApiVersion = data.apiVersion.split("/");
- const group = splitApiVersion[0];
-
- return this.getForGroupKind(group, data.kind);
- }
-
- getByName(name: string) {
- return this.items.find(category => category.metadata?.name == name);
- }
-
- /**
- * Add a new filter to the set of category filters
- * @param fn The function that should return a truthy value if that category should be displayed
- * @returns A function to remove that filter
- */
- addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
- this.filters.add(fn);
-
- return once(() => void this.filters.delete(fn));
- }
-}
-
-export const catalogCategoryRegistry = new CatalogCategoryRegistry();
+/**
+ * @deprecated use `di.inject(catalogCategoryRegistryInjectable)` instead
+ */
+export const catalogCategoryRegistry = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable);
diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts
index c8b905ffab..7effe60f2f 100644
--- a/src/common/catalog/catalog-entity.ts
+++ b/src/common/catalog/catalog-entity.ts
@@ -11,19 +11,19 @@ import type { Disposer } from "../utils";
import { iter } from "../utils";
import type { CategoryColumnRegistration } from "../../renderer/components/+catalog/custom-category-columns";
-type ExtractEntityMetadataType = Entity extends CatalogEntity ? Metadata : never;
-type ExtractEntityStatusType = Entity extends CatalogEntity ? Status : never;
-type ExtractEntitySpecType = Entity extends CatalogEntity ? Spec : never;
+export type CatalogEntityDataFor = Entity extends CatalogEntity
+ ? CatalogEntityData
+ : never;
+
+export type CatalogEntityInstanceFrom = Constructor extends CatalogEntityConstructor
+ ? Entity
+ : never;
export type CatalogEntityConstructor = (
- (new (data: CatalogEntityData<
- ExtractEntityMetadataType,
- ExtractEntityStatusType,
- ExtractEntitySpecType
- >) => Entity)
+ new (data: CatalogEntityDataFor) => Entity
);
-export interface CatalogCategoryVersion {
+export interface CatalogCategoryVersion {
/**
* The specific version that the associated constructor is for. This MUST be
* a DNS label and SHOULD be of the form `vN`, `vNalphaY`, or `vNbetaY` where
@@ -35,19 +35,19 @@ export interface CatalogCategoryVersion {
* - `v1alpha2`
* - `v3beta2`
*/
- name: string;
+ readonly name: string;
/**
* The constructor for the entities.
*/
- entityClass: CatalogEntityConstructor;
+ readonly entityClass: CatalogEntityConstructor;
}
export interface CatalogCategorySpec {
/**
* The grouping for for the category. This MUST be a DNS label.
*/
- group: string;
+ readonly group: string;
/**
* The specific versions of the constructors.
@@ -56,18 +56,18 @@ export interface CatalogCategorySpec {
* For example, if `group = "entity.k8slens.dev"` and there is an entry in `.versions` with
* `name = "v1alpha1"` then the resulting `.apiVersion` MUST be `entity.k8slens.dev/v1alpha1`
*/
- versions: CatalogCategoryVersion[];
+ readonly versions: CatalogCategoryVersion[];
/**
* This is the concerning the category
*/
- names: {
+ readonly names: {
/**
* The kind of entity that this category is for. This value MUST be a DNS
* label and MUST be equal to the `kind` fields that are produced by the
* `.versions.[] | .entityClass` fields.
*/
- kind: string;
+ readonly kind: string;
};
/**
@@ -81,7 +81,7 @@ export interface CatalogCategorySpec {
*
* These columns will not be used in the "Browse" view.
*/
- displayColumns?: CategoryColumnRegistration[];
+ readonly displayColumns?: CategoryColumnRegistration[];
}
/**
@@ -109,6 +109,30 @@ export interface CatalogCategoryEvents {
contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
}
+export interface CatalogCategoryMetadata {
+ /**
+ * The name of your category. The category can be searched for by this
+ * value. This will also be used for the catalog menu.
+ */
+ readonly name: string;
+ /**
+ * Either an `` or the name of an icon from {@link IconProps}
+ */
+ readonly icon: string;
+}
+
+export function categoryVersion<
+ T extends CatalogEntity,
+ Metadata extends CatalogEntityMetadata,
+ Status extends CatalogEntityStatus,
+ Spec extends CatalogEntitySpec,
+>(name: string, entityClass: new (data: CatalogEntityData) => T): CatalogCategoryVersion {
+ return {
+ name,
+ entityClass: entityClass as CatalogEntityConstructor,
+ };
+}
+
export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter) {
/**
* The version of category that you are wanting to declare.
@@ -131,28 +155,17 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
/**
* The data about the category itself
*/
- abstract readonly metadata: {
- /**
- * The name of your category. The category can be searched for by this
- * value. This will also be used for the catalog menu.
- */
- name: string;
-
- /**
- * Either an `` or the name of an icon from {@link IconProps}
- */
- icon: string;
- };
+ abstract readonly metadata: CatalogCategoryMetadata;
/**
* The most important part of a category, as it is where entity versions are declared.
*/
- abstract spec: CatalogCategorySpec;
+ abstract readonly spec: CatalogCategorySpec;
/**
* @internal
*/
- protected filters = observable.set([], {
+ protected readonly filters = observable.set([], {
deep: false,
});
@@ -217,14 +230,16 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
}
}
-export interface CatalogEntityMetadata {
+export type EntityMetadataObject = { [Key in string]?: EntityMetadataValue };
+export type EntityMetadataValue = string | number | boolean | EntityMetadataObject | undefined;
+
+export interface CatalogEntityMetadata extends EntityMetadataObject {
uid: string;
name: string;
shortName?: string;
description?: string;
source?: string;
labels: Record;
- [key: string]: string | object;
}
export interface CatalogEntityStatus {
@@ -392,7 +407,7 @@ export abstract class CatalogEntity<
return this.status.enabled ?? true;
}
- public abstract onRun?(context: CatalogEntityActionContext): void | Promise;
- public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise;
- public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise;
+ public onRun?(context: CatalogEntityActionContext): void | Promise;
+ public onContextMenuOpen?(context: CatalogEntityContextMenuContext): void | Promise;
+ public onSettingsOpen?(context: CatalogEntitySettingsContext): void | Promise;
}
diff --git a/src/common/catalog/categories/general.injectable.ts b/src/common/catalog/categories/general.injectable.ts
new file mode 100644
index 0000000000..d2e3ba7a69
--- /dev/null
+++ b/src/common/catalog/categories/general.injectable.ts
@@ -0,0 +1,15 @@
+/**
+ * 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 { GeneralCategory } from "../../catalog-entities";
+import { builtInCategoryInjectionToken } from "../category-registry.injectable";
+
+const generalCategoryInjectable = getInjectable({
+ id: "general-category",
+ instantiate: () => new GeneralCategory(),
+ injectionToken: builtInCategoryInjectionToken,
+});
+
+export default generalCategoryInjectable;
diff --git a/src/common/catalog/categories/kubernetes-cluster.injectable.ts b/src/common/catalog/categories/kubernetes-cluster.injectable.ts
new file mode 100644
index 0000000000..6dc3f9be8d
--- /dev/null
+++ b/src/common/catalog/categories/kubernetes-cluster.injectable.ts
@@ -0,0 +1,15 @@
+/**
+ * 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 { KubernetesClusterCategory } from "../../catalog-entities/kubernetes-cluster";
+import { builtInCategoryInjectionToken } from "../category-registry.injectable";
+
+const kubernetesClusterCategoryInjectable = getInjectable({
+ id: "kubernetes-cluster-category",
+ instantiate: () => new KubernetesClusterCategory(),
+ injectionToken: builtInCategoryInjectionToken,
+});
+
+export default kubernetesClusterCategoryInjectable;
diff --git a/src/common/catalog/categories/weblink.injectable.ts b/src/common/catalog/categories/weblink.injectable.ts
new file mode 100644
index 0000000000..339758efbf
--- /dev/null
+++ b/src/common/catalog/categories/weblink.injectable.ts
@@ -0,0 +1,15 @@
+/**
+ * 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 { WebLinkCategory } from "../../catalog-entities";
+import { builtInCategoryInjectionToken } from "../category-registry.injectable";
+
+const weblinkCategoryInjectable = getInjectable({
+ id: "weblink-category",
+ instantiate: () => new WebLinkCategory(),
+ injectionToken: builtInCategoryInjectionToken,
+});
+
+export default weblinkCategoryInjectable;
diff --git a/src/common/catalog/category-registry.injectable.ts b/src/common/catalog/category-registry.injectable.ts
new file mode 100644
index 0000000000..a73ed973f6
--- /dev/null
+++ b/src/common/catalog/category-registry.injectable.ts
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
+import type { CatalogCategory } from "./catalog-entity";
+import { CatalogCategoryRegistry } from "./category-registry";
+
+export const builtInCategoryInjectionToken = getInjectionToken({
+ id: "built-in-category-token",
+});
+
+const catalogCategoryRegistryInjectable = getInjectable({
+ id: "catalog-category-registry",
+ instantiate: (di) => {
+ const registry = new CatalogCategoryRegistry();
+ const categories = di.injectMany(builtInCategoryInjectionToken);
+
+ for (const category of categories) {
+ registry.add(category);
+ }
+
+ return registry;
+ },
+});
+
+export default catalogCategoryRegistryInjectable;
diff --git a/src/common/catalog/category-registry.ts b/src/common/catalog/category-registry.ts
new file mode 100644
index 0000000000..75c33d8a10
--- /dev/null
+++ b/src/common/catalog/category-registry.ts
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import { action, computed, observable, makeObservable } from "mobx";
+import { once } from "lodash";
+import { iter, getOrInsertMap, strictSet } from "../utils";
+import type { Disposer } from "../utils";
+import type { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
+
+export type CategoryFilter = (category: CatalogCategory) => any;
+
+export class CatalogCategoryRegistry {
+ protected readonly categories = observable.set();
+ protected readonly groupKinds = new Map>();
+ protected readonly filters = observable.set([], {
+ deep: false,
+ });
+
+ constructor() {
+ makeObservable(this);
+ }
+
+ @action add(category: CatalogCategory): Disposer {
+ const byGroup = getOrInsertMap(this.groupKinds, category.spec.group);
+
+ this.categories.add(category);
+ strictSet(byGroup, category.spec.names.kind, category);
+
+ return () => {
+ this.categories.delete(category);
+ byGroup.delete(category.spec.names.kind);
+ };
+ }
+
+ @computed get items() {
+ return Array.from(this.categories);
+ }
+
+ @computed get filteredItems() {
+ return Array.from(
+ iter.reduce(
+ this.filters,
+ iter.filter,
+ this.items.values(),
+ ),
+ );
+ }
+
+
+ getForGroupKind(group: string, kind: string): T | undefined {
+ return this.groupKinds.get(group)?.get(kind) as T;
+ }
+
+ getEntityForData(data: CatalogEntityData & CatalogEntityKindData) {
+ const category = this.getCategoryForEntity(data);
+
+ if (!category) {
+ return null;
+ }
+
+ const splitApiVersion = data.apiVersion.split("/");
+ const version = splitApiVersion[1];
+
+ const specVersion = category.spec.versions.find((v) => v.name === version);
+
+ if (!specVersion) {
+ return null;
+ }
+
+ return new specVersion.entityClass(data);
+ }
+
+ hasCategoryForEntity({ kind, apiVersion }: CatalogEntityData & CatalogEntityKindData): boolean {
+ const splitApiVersion = apiVersion.split("/");
+ const group = splitApiVersion[0];
+
+ return this.groupKinds.get(group)?.has(kind) ?? false;
+ }
+
+ getCategoryForEntity(data: CatalogEntityData & CatalogEntityKindData): T | undefined {
+ const splitApiVersion = data.apiVersion.split("/");
+ const group = splitApiVersion[0];
+
+ return this.getForGroupKind(group, data.kind);
+ }
+
+ getByName(name: string) {
+ return this.items.find(category => category.metadata?.name == name);
+ }
+
+ /**
+ * Add a new filter to the set of category filters
+ * @param fn The function that should return a truthy value if that category should be displayed
+ * @returns A function to remove that filter
+ */
+ addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
+ this.filters.add(fn);
+
+ return once(() => void this.filters.delete(fn));
+ }
+}
diff --git a/src/common/catalog/has-category-for-entity.injectable.ts b/src/common/catalog/has-category-for-entity.injectable.ts
new file mode 100644
index 0000000000..cff7d720c1
--- /dev/null
+++ b/src/common/catalog/has-category-for-entity.injectable.ts
@@ -0,0 +1,21 @@
+/**
+ * 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 type { CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
+import catalogCategoryRegistryInjectable from "./category-registry.injectable";
+
+export type HasCategoryForEntity = (data: CatalogEntityData & CatalogEntityKindData) => boolean;
+
+const hasCategoryForEntityInjectable = getInjectable({
+ id: "has-category-for-entity",
+
+ instantiate: (di): HasCategoryForEntity => {
+ const registry = di.inject(catalogCategoryRegistryInjectable);
+
+ return (data) => registry.hasCategoryForEntity(data);
+ },
+});
+
+export default hasCategoryForEntityInjectable;
diff --git a/src/common/catalog/index.ts b/src/common/catalog/index.ts
index 2e897fff01..a5c5ec4276 100644
--- a/src/common/catalog/index.ts
+++ b/src/common/catalog/index.ts
@@ -4,4 +4,5 @@
*/
export * from "./catalog-category-registry";
+export * from "./category-registry";
export * from "./catalog-entity";
diff --git a/src/common/catalog/visit-entity-context-menu.injectable.ts b/src/common/catalog/visit-entity-context-menu.injectable.ts
new file mode 100644
index 0000000000..eb1a2abeba
--- /dev/null
+++ b/src/common/catalog/visit-entity-context-menu.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 type { CatalogEntity, CatalogEntityContextMenuContext } from "./catalog-entity";
+import catalogCategoryRegistryInjectable from "./category-registry.injectable";
+
+export type VisitEntityContextMenu = (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
+
+const visitEntityContextMenuInjectable = getInjectable({
+ id: "visit-entity-context-menu",
+ instantiate: (di): VisitEntityContextMenu => {
+ const categoryRegistry = di.inject(catalogCategoryRegistryInjectable);
+
+ return (entity, context) => {
+ entity.onContextMenuOpen?.(context);
+ categoryRegistry.getCategoryForEntity(entity)?.emit("contextMenuOpen", entity, context);
+ };
+ },
+});
+
+export default visitEntityContextMenuInjectable;
diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets-store.injectable.ts b/src/common/cluster-frames.injectable.ts
similarity index 53%
rename from src/renderer/components/+workloads-daemonsets/daemonsets-store.injectable.ts
rename to src/common/cluster-frames.injectable.ts
index 044750d493..23897012a0 100644
--- a/src/renderer/components/+workloads-daemonsets/daemonsets-store.injectable.ts
+++ b/src/common/cluster-frames.injectable.ts
@@ -3,13 +3,12 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
-import { daemonSetStore } from "./daemonsets.store";
+import { clusterFrameMap } from "./cluster-frames";
-const daemonsetsStoreInjectable = getInjectable({
- id: "daemonsets-store",
- instantiate: () => daemonSetStore,
+const clusterFramesInjectable = getInjectable({
+ id: "cluster-frames",
+ instantiate: () => clusterFrameMap,
causesSideEffects: true,
});
-export default daemonsetsStoreInjectable;
-
+export default clusterFramesInjectable;
diff --git a/src/common/cluster-store/allowed-resources.injectable.ts b/src/common/cluster-store/allowed-resources.injectable.ts
index 2277befbd6..27ce2d510f 100644
--- a/src/common/cluster-store/allowed-resources.injectable.ts
+++ b/src/common/cluster-store/allowed-resources.injectable.ts
@@ -12,7 +12,7 @@ const allowedResourcesInjectable = getInjectable({
instantiate: (di) => {
const cluster = di.inject(hostedClusterInjectable);
- return computed(() => new Set(cluster.allowedResources), {
+ return computed(() => new Set(cluster?.allowedResources), {
// This needs to be here so that during refresh changes are only propogated when necessary
equals: (cur, prev) => comparer.structural(cur, prev),
});
diff --git a/src/common/cluster-store/cluster-store.injectable.ts b/src/common/cluster-store/cluster-store.injectable.ts
index a47978376a..58b540495a 100644
--- a/src/common/cluster-store/cluster-store.injectable.ts
+++ b/src/common/cluster-store/cluster-store.injectable.ts
@@ -9,10 +9,13 @@ import { createClusterInjectionToken } from "../cluster/create-cluster-injection
const clusterStoreInjectable = getInjectable({
id: "cluster-store",
- instantiate: (di) =>
- ClusterStore.createInstance({
+ instantiate: (di) => {
+ ClusterStore.resetInstance();
+
+ return ClusterStore.createInstance({
createCluster: di.inject(createClusterInjectionToken),
- }),
+ });
+ },
causesSideEffects: true,
});
diff --git a/src/common/cluster-store/cluster-store.ts b/src/common/cluster-store/cluster-store.ts
index 901f340bda..55ebf6aad1 100644
--- a/src/common/cluster-store/cluster-store.ts
+++ b/src/common/cluster-store/cluster-store.ts
@@ -103,8 +103,12 @@ export class ClusterStore extends BaseStore {
return this.clusters.size > 0;
}
- getById(id: ClusterId): Cluster | null {
- return this.clusters.get(id) ?? null;
+ getById(id: ClusterId | undefined): Cluster | undefined {
+ if (id) {
+ return this.clusters.get(id);
+ }
+
+ return undefined;
}
addCluster(clusterOrModel: ClusterModel | Cluster): Cluster {
diff --git a/src/common/cluster-store/hosted-cluster-id.injectable.ts b/src/common/cluster-store/hosted-cluster-id.injectable.ts
new file mode 100644
index 0000000000..5a5c99c580
--- /dev/null
+++ b/src/common/cluster-store/hosted-cluster-id.injectable.ts
@@ -0,0 +1,14 @@
+/**
+ * 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 { getClusterIdFromHost } from "../utils";
+
+const hostedClusterIdInjectable = getInjectable({
+ id: "hosted-cluster-id",
+ instantiate: () => getClusterIdFromHost(location.host),
+ causesSideEffects: true,
+});
+
+export default hostedClusterIdInjectable;
diff --git a/src/common/cluster-store/hosted-cluster.injectable.ts b/src/common/cluster-store/hosted-cluster.injectable.ts
index 1bcafc9238..fa49cbca48 100644
--- a/src/common/cluster-store/hosted-cluster.injectable.ts
+++ b/src/common/cluster-store/hosted-cluster.injectable.ts
@@ -3,16 +3,17 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
-import { getHostedClusterId } from "../utils";
+import hostedClusterIdInjectable from "./hosted-cluster-id.injectable";
import clusterStoreInjectable from "./cluster-store.injectable";
const hostedClusterInjectable = getInjectable({
id: "hosted-cluster",
instantiate: (di) => {
- const hostedClusterId = getHostedClusterId();
+ const hostedClusterId = di.inject(hostedClusterIdInjectable);
+ const store = di.inject(clusterStoreInjectable);
- return di.inject(clusterStoreInjectable).getById(hostedClusterId);
+ return store.getById(hostedClusterId);
},
});
diff --git a/src/common/cluster/cluster.ts b/src/common/cluster/cluster.ts
index fbe7880f3c..1652e18ef1 100644
--- a/src/common/cluster/cluster.ts
+++ b/src/common/cluster/cluster.ts
@@ -3,10 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { ipcMain } from "electron";
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
import { broadcastMessage } from "../ipc";
-import type { ContextHandler } from "../../main/context-handler/context-handler";
+import type { ClusterContextHandler } from "../../main/context-handler/context-handler";
import type { KubeConfig } from "@kubernetes/client-node";
import { HttpError } from "@kubernetes/client-node";
import type { Kubectl } from "../../main/kubectl/kubectl";
@@ -14,25 +13,29 @@ import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig
import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers";
import type { KubeApiResource, KubeResource } from "../rbac";
import { apiResourceRecord, apiResources } from "../rbac";
-import logger from "../../main/logger";
-import { VersionDetector } from "../../main/cluster-detectors/version-detector";
-import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
+import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
+import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
import plimit from "p-limit";
import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate } from "../cluster-types";
import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus } from "../cluster-types";
-import { disposer, toJS } from "../utils";
+import { disposer, isDefined, isRequestError, toJS } from "../utils";
import type { Response } from "request";
import { clusterListNamespaceForbiddenChannel } from "../ipc/cluster";
import type { CanI } from "./authorization-review.injectable";
import type { ListNamespaces } from "./list-namespaces.injectable";
+import assert from "assert";
+import type { Logger } from "../logger";
export interface ClusterDependencies {
readonly directoryForKubeConfigs: string;
+ readonly logger: Logger;
+ readonly detectorRegistry: DetectorRegistry;
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
- createContextHandler: (cluster: Cluster) => ContextHandler;
+ createContextHandler: (cluster: Cluster) => ClusterContextHandler;
createKubectl: (clusterVersion: string) => Kubectl;
createAuthorizationReview: (config: KubeConfig) => CanI;
createListNamespaces: (config: KubeConfig) => ListNamespaces;
+ createVersionDetector: (cluster: Cluster) => VersionDetector;
}
/**
@@ -43,17 +46,31 @@ export interface ClusterDependencies {
export class Cluster implements ClusterModel, ClusterState {
/** Unique id for a cluster */
public readonly id: ClusterId;
- private kubeCtl: Kubectl;
+ private kubeCtl: Kubectl | undefined;
/**
* Context handler
*
* @internal
*/
- public contextHandler: ContextHandler;
- protected proxyKubeconfigManager: KubeconfigManager;
- protected eventsDisposer = disposer();
+ protected readonly _contextHandler: ClusterContextHandler | undefined;
+ protected readonly _proxyKubeconfigManager: KubeconfigManager | undefined;
+ protected readonly eventsDisposer = disposer();
protected activated = false;
- private resourceAccessStatuses: Map = new Map();
+ private readonly resourceAccessStatuses = new Map();
+
+ public get contextHandler() {
+ // TODO: remove these once main/renderer are seperate classes
+ assert(this._contextHandler, "contextHandler is only defined in the main environment");
+
+ return this._contextHandler;
+ }
+
+ protected get proxyKubeconfigManager() {
+ // TODO: remove these once main/renderer are seperate classes
+ assert(this._proxyKubeconfigManager, "proxyKubeconfigManager is only defined in the main environment");
+
+ return this._proxyKubeconfigManager;
+ }
get whenReady() {
return when(() => this.ready);
@@ -64,21 +81,21 @@ export class Cluster implements ClusterModel, ClusterState {
*
* @observable
*/
- @observable contextName: string;
+ @observable contextName!: string;
/**
* Path to kubeconfig
*
* @observable
*/
- @observable kubeConfigPath: string;
+ @observable kubeConfigPath!: string;
/**
* @deprecated
*/
- @observable workspace: string;
+ @observable workspace?: string;
/**
* @deprecated
*/
- @observable workspaces: string[];
+ @observable workspaces?: string[];
/**
* Kubernetes API server URL
*
@@ -215,7 +232,7 @@ export class Cluster implements ClusterModel, ClusterState {
* @computed
* @internal
*/
- @computed get defaultNamespace(): string {
+ @computed get defaultNamespace(): string | undefined {
return this.preferences.defaultNamespace;
}
@@ -231,19 +248,24 @@ export class Cluster implements ClusterModel, ClusterState {
throw validationError;
}
- this.apiUrl = config.getCluster(config.getContextObject(this.contextName).cluster).server;
+ const context = config.getContextObject(this.contextName);
- if (ipcMain) {
- // for the time being, until renderer gets its own cluster type
- this.contextHandler = this.dependencies.createContextHandler(this);
- this.proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this);
+ assert(context);
- logger.debug(`[CLUSTER]: Cluster init success`, {
- id: this.id,
- context: this.contextName,
- apiUrl: this.apiUrl,
- });
- }
+ const cluster = config.getCluster(context.cluster);
+
+ assert(cluster);
+
+ this.apiUrl = cluster.server;
+
+ // for the time being, until renderer gets its own cluster type
+ this._contextHandler = this.dependencies.createContextHandler(this);
+ this._proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this);
+ this.dependencies.logger.debug(`[CLUSTER]: Cluster init success`, {
+ id: this.id,
+ context: this.contextName,
+ apiUrl: this.apiUrl,
+ });
}
/**
@@ -255,6 +277,7 @@ export class Cluster implements ClusterModel, ClusterState {
// Note: do not assign ID as that should never be updated
this.kubeConfigPath = model.kubeConfigPath;
+ this.contextName = model.contextName;
if (model.workspace) {
this.workspace = model.workspace;
@@ -264,10 +287,6 @@ export class Cluster implements ClusterModel, ClusterState {
this.workspaces = model.workspaces;
}
- if (model.contextName) {
- this.contextName = model.contextName;
- }
-
if (model.preferences) {
this.preferences = model.preferences;
}
@@ -289,7 +308,7 @@ export class Cluster implements ClusterModel, ClusterState {
* @internal
*/
protected bindEvents() {
- logger.info(`[CLUSTER]: bind events`, this.getMeta());
+ this.dependencies.logger.info(`[CLUSTER]: bind events`, this.getMeta());
const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s
const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes
@@ -310,13 +329,13 @@ export class Cluster implements ClusterModel, ClusterState {
* @internal
*/
protected async recreateProxyKubeconfig() {
- logger.info("[CLUSTER]: Recreating proxy kubeconfig");
+ this.dependencies.logger.info("[CLUSTER]: Recreating proxy kubeconfig");
try {
await this.proxyKubeconfigManager.clear();
await this.getProxyKubeconfig();
} catch (error) {
- logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error);
+ this.dependencies.logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error);
}
}
@@ -330,7 +349,7 @@ export class Cluster implements ClusterModel, ClusterState {
return this.pushState();
}
- logger.info(`[CLUSTER]: activate`, this.getMeta());
+ this.dependencies.logger.info(`[CLUSTER]: activate`, this.getMeta());
if (!this.eventsDisposer.length) {
this.bindEvents();
@@ -348,7 +367,7 @@ export class Cluster implements ClusterModel, ClusterState {
await this.refreshAccessibility();
// download kubectl in background, so it's not blocking dashboard
this.ensureKubectl()
- .catch(error => logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error));
+ .catch(error => this.dependencies.logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error));
this.broadcastConnectUpdate("Connected, waiting for view to load ...");
}
@@ -372,9 +391,8 @@ export class Cluster implements ClusterModel, ClusterState {
*/
@action
async reconnect() {
- logger.info(`[CLUSTER]: reconnect`, this.getMeta());
- this.contextHandler?.stopServer();
- await this.contextHandler?.ensureServer();
+ this.dependencies.logger.info(`[CLUSTER]: reconnect`, this.getMeta());
+ await this.contextHandler?.restartServer();
this.disconnected = false;
}
@@ -383,10 +401,10 @@ export class Cluster implements ClusterModel, ClusterState {
*/
@action disconnect(): void {
if (this.disconnected) {
- return void logger.debug("[CLUSTER]: already disconnected", { id: this.id });
+ return void this.dependencies.logger.debug("[CLUSTER]: already disconnected", { id: this.id });
}
- logger.info(`[CLUSTER]: disconnecting`, { id: this.id });
+ this.dependencies.logger.info(`[CLUSTER]: disconnecting`, { id: this.id });
this.eventsDisposer();
this.contextHandler?.stopServer();
this.disconnected = true;
@@ -397,7 +415,7 @@ export class Cluster implements ClusterModel, ClusterState {
this.allowedNamespaces = [];
this.resourceAccessStatuses.clear();
this.pushState();
- logger.info(`[CLUSTER]: disconnected`, { id: this.id });
+ this.dependencies.logger.info(`[CLUSTER]: disconnected`, { id: this.id });
}
/**
@@ -406,7 +424,7 @@ export class Cluster implements ClusterModel, ClusterState {
*/
@action
async refresh(opts: ClusterRefreshOptions = {}) {
- logger.info(`[CLUSTER]: refresh`, this.getMeta());
+ this.dependencies.logger.info(`[CLUSTER]: refresh`, this.getMeta());
await this.refreshConnectionStatus();
if (this.accessible) {
@@ -424,8 +442,8 @@ export class Cluster implements ClusterModel, ClusterState {
*/
@action
async refreshMetadata() {
- logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
- const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
+ this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
+ const metadata = await this.dependencies.detectorRegistry.detectForCluster(this);
const existingMetadata = this.metadata;
this.metadata = Object.assign(existingMetadata, metadata);
@@ -488,41 +506,49 @@ export class Cluster implements ClusterModel, ClusterState {
protected async getConnectionStatus(): Promise {
try {
- const versionDetector = new VersionDetector(this);
+ const versionDetector = this.dependencies.createVersionDetector(this);
const versionData = await versionDetector.detect();
this.metadata.version = versionData.value;
return ClusterStatus.AccessGranted;
} catch (error) {
- logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`);
+ this.dependencies.logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`);
- if (error.statusCode) {
- if (error.statusCode >= 400 && error.statusCode < 500) {
- this.broadcastConnectUpdate("Invalid credentials", true);
+ if (isRequestError(error)) {
+ if (error.statusCode) {
+ if (error.statusCode >= 400 && error.statusCode < 500) {
+ this.broadcastConnectUpdate("Invalid credentials", true);
- return ClusterStatus.AccessDenied;
- }
+ return ClusterStatus.AccessDenied;
+ }
- this.broadcastConnectUpdate(error.error || error.message, true);
+ const message = String(error.error || error.message) || String(error);
- return ClusterStatus.Offline;
- }
-
- if (error.failed === true) {
- if (error.timedOut === true) {
- this.broadcastConnectUpdate("Connection timed out", true);
+ this.broadcastConnectUpdate(message, true);
return ClusterStatus.Offline;
}
- this.broadcastConnectUpdate("Failed to fetch credentials", true);
+ if (error.failed === true) {
+ if (error.timedOut === true) {
+ this.broadcastConnectUpdate("Connection timed out", true);
- return ClusterStatus.AccessDenied;
+ return ClusterStatus.Offline;
+ }
+
+ this.broadcastConnectUpdate("Failed to fetch credentials", true);
+
+ return ClusterStatus.AccessDenied;
+ }
+
+ const message = String(error.error || error.message) || String(error);
+
+ this.broadcastConnectUpdate(message, true);
+ } else {
+ this.broadcastConnectUpdate("Unknown error has occurred", true);
}
- this.broadcastConnectUpdate(error.message, true);
-
return ClusterStatus.Offline;
}
}
@@ -571,7 +597,7 @@ export class Cluster implements ClusterModel, ClusterState {
* @param state cluster state
*/
pushState(state = this.getState()) {
- logger.silly(`[CLUSTER]: push-state`, state);
+ this.dependencies.logger.silly(`[CLUSTER]: push-state`, state);
broadcastMessage("cluster:state", this.id, state);
}
@@ -594,7 +620,7 @@ export class Cluster implements ClusterModel, ClusterState {
broadcastConnectUpdate(message: string, isError = false): void {
const update: KubeAuthUpdate = { message, isError };
- logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() });
+ this.dependencies.logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() });
broadcastMessage(`cluster:${this.id}:connection-update`, update);
}
@@ -609,12 +635,12 @@ export class Cluster implements ClusterModel, ClusterState {
return await listNamespaces();
} catch (error) {
const ctx = proxyConfig.getContextObject(this.contextName);
- const namespaceList = [ctx.namespace].filter(Boolean);
+ const namespaceList = [ctx?.namespace].filter(isDefined);
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
const { response } = error as HttpError & { response: Response };
- logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
+ this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
broadcastMessage(clusterListNamespaceForbiddenChannel, this.id);
}
diff --git a/src/common/cluster/create-cluster-injection-token.ts b/src/common/cluster/create-cluster-injection-token.ts
index 0508e7b325..f1e8ef9757 100644
--- a/src/common/cluster/create-cluster-injection-token.ts
+++ b/src/common/cluster/create-cluster-injection-token.ts
@@ -6,5 +6,8 @@ import { getInjectionToken } from "@ogre-tools/injectable";
import type { ClusterModel } from "../cluster-types";
import type { Cluster } from "./cluster";
-export const createClusterInjectionToken =
- getInjectionToken<(model: ClusterModel) => Cluster>({ id: "create-cluster-token" });
+export type CreateCluster = (model: ClusterModel) => Cluster;
+
+export const createClusterInjectionToken = getInjectionToken({
+ id: "create-cluster-token",
+});
diff --git a/src/common/cluster/list-namespaces.injectable.ts b/src/common/cluster/list-namespaces.injectable.ts
index 200326c705..468ff3ac2e 100644
--- a/src/common/cluster/list-namespaces.injectable.ts
+++ b/src/common/cluster/list-namespaces.injectable.ts
@@ -5,6 +5,7 @@
import type { KubeConfig } from "@kubernetes/client-node";
import { CoreV1Api } from "@kubernetes/client-node";
import { getInjectable } from "@ogre-tools/injectable";
+import { isDefined } from "../utils";
export type ListNamespaces = () => Promise;
@@ -14,7 +15,9 @@ export function listNamespaces(config: KubeConfig): ListNamespaces {
return async () => {
const { body: { items }} = await coreApi.listNamespace();
- return items.map(ns => ns.metadata.name);
+ return items
+ .map(ns => ns.metadata?.name)
+ .filter(isDefined);
};
}
diff --git a/src/common/front-end-routing/app-navigation-channel.injectable.ts b/src/common/front-end-routing/app-navigation-channel.injectable.ts
new file mode 100644
index 0000000000..869fbfdecd
--- /dev/null
+++ b/src/common/front-end-routing/app-navigation-channel.injectable.ts
@@ -0,0 +1,22 @@
+/**
+ * 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 { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
+import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+export type AppNavigationChannel = MessageChannel;
+
+const appNavigationChannelInjectable = getInjectable({
+ id: "app-navigation-channel",
+
+ instantiate: (): AppNavigationChannel => ({
+ id: IpcRendererNavigationEvents.NAVIGATE_IN_APP,
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default appNavigationChannelInjectable;
diff --git a/src/common/front-end-routing/cluster-frame-navigation-channel.injectable.ts b/src/common/front-end-routing/cluster-frame-navigation-channel.injectable.ts
new file mode 100644
index 0000000000..596bd6d351
--- /dev/null
+++ b/src/common/front-end-routing/cluster-frame-navigation-channel.injectable.ts
@@ -0,0 +1,22 @@
+/**
+ * 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 { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
+import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
+import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
+
+export type ClusterFrameNavigationChannel = MessageChannel;
+
+const clusterFrameNavigationChannelInjectable = getInjectable({
+ id: "cluster-frame-navigation-channel",
+
+ instantiate: (): ClusterFrameNavigationChannel => ({
+ id: IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER,
+ }),
+
+ injectionToken: messageChannelInjectionToken,
+});
+
+export default clusterFrameNavigationChannelInjectable;
diff --git a/src/common/front-end-routing/navigation-ipc-channel.ts b/src/common/front-end-routing/navigation-ipc-channel.ts
deleted file mode 100644
index 6094664f81..0000000000
--- a/src/common/front-end-routing/navigation-ipc-channel.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Copyright (c) OpenLens Authors. All rights reserved.
- * Licensed under MIT License. See LICENSE in root directory for more information.
- */
-import { createChannel } from "../ipc-channel/create-channel/create-channel";
-import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
-
-export const appNavigationIpcChannel = createChannel(IpcRendererNavigationEvents.NAVIGATE_IN_APP);
-export const clusterFrameNavigationIpcChannel = createChannel(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER);
diff --git a/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts b/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts
index 7cf871f9b9..369fb6eb8c 100644
--- a/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts
+++ b/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts
@@ -11,15 +11,12 @@ import type { ClusterStore } from "../cluster-store/cluster-store";
import { pipeline } from "@ogre-tools/fp";
describe("verify-that-all-routes-have-component", () => {
- it("verify that routes have route component", async () => {
+ it("verify that routes have route component", () => {
const rendererDi = getDiForUnitTesting({ doGeneralOverrides: true });
- rendererDi.override(
- clusterStoreInjectable,
- () => ({ getById: (): null => null } as unknown as ClusterStore),
- );
-
- await rendererDi.runSetups();
+ rendererDi.override(clusterStoreInjectable, () => ({
+ getById: () => null,
+ } as unknown as ClusterStore));
const routes = rendererDi.injectMany(routeInjectionToken);
const routeComponents = rendererDi.injectMany(
diff --git a/src/common/fs/ensure-dir.injectable.ts b/src/common/fs/ensure-dir.injectable.ts
new file mode 100644
index 0000000000..88410ceee2
--- /dev/null
+++ b/src/common/fs/ensure-dir.injectable.ts
@@ -0,0 +1,18 @@
+/**
+ * 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 fsInjectable from "./fs.injectable";
+
+const ensureDirInjectable = getInjectable({
+ id: "ensure-dir",
+
+ // TODO: Remove usages of ensureDir from business logic.
+ // TODO: Read, Write, Watch etc. operations should do this internally.
+ instantiate: (di) => di.inject(fsInjectable).ensureDir,
+
+ causesSideEffects: true,
+});
+
+export default ensureDirInjectable;
diff --git a/src/common/get-configuration-file-model/app-version/app-version.injectable.ts b/src/common/get-configuration-file-model/app-version/app-version.injectable.ts
index 0fe3142332..5fdfd30eba 100644
--- a/src/common/get-configuration-file-model/app-version/app-version.injectable.ts
+++ b/src/common/get-configuration-file-model/app-version/app-version.injectable.ts
@@ -3,12 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
-import packageInfo from "../../../../package.json";
+import packageJsonInjectable from "../../vars/package-json.injectable";
const appVersionInjectable = getInjectable({
id: "app-version",
- instantiate: () => packageInfo.version,
- causesSideEffects: true,
+ instantiate: (di) => di.inject(packageJsonInjectable).version,
});
export default appVersionInjectable;
diff --git a/src/common/hotbars/add-hotbar.injectable.ts b/src/common/hotbars/add-hotbar.injectable.ts
new file mode 100644
index 0000000000..25ee0f588a
--- /dev/null
+++ b/src/common/hotbars/add-hotbar.injectable.ts
@@ -0,0 +1,20 @@
+/**
+ * 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 hotbarStoreInjectable from "./store.injectable";
+import type { CreateHotbarData, CreateHotbarOptions } from "./types";
+
+export type AddHotbar = (data: CreateHotbarData, opts?: CreateHotbarOptions) => void;
+
+const addHotbarInjectable = getInjectable({
+ id: "add-hotbar",
+ instantiate: (di): AddHotbar => {
+ const store = di.inject(hotbarStoreInjectable);
+
+ return (data, opts) => store.add(data, opts);
+ },
+});
+
+export default addHotbarInjectable;
diff --git a/src/common/hotbar-store.injectable.ts b/src/common/hotbars/store.injectable.ts
similarity index 65%
rename from src/common/hotbar-store.injectable.ts
rename to src/common/hotbars/store.injectable.ts
index e8a883cf0a..ace13b8be4 100644
--- a/src/common/hotbar-store.injectable.ts
+++ b/src/common/hotbars/store.injectable.ts
@@ -3,8 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
-import catalogCatalogEntityInjectable from "./catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
-import { HotbarStore } from "./hotbar-store";
+import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
+import { HotbarStore } from "./store";
+import loggerInjectable from "../logger.injectable";
const hotbarStoreInjectable = getInjectable({
id: "hotbar-store",
@@ -14,6 +15,7 @@ const hotbarStoreInjectable = getInjectable({
return HotbarStore.createInstance({
catalogCatalogEntity: di.inject(catalogCatalogEntityInjectable),
+ logger: di.inject(loggerInjectable),
});
},
diff --git a/src/common/hotbar-store.ts b/src/common/hotbars/store.ts
similarity index 81%
rename from src/common/hotbar-store.ts
rename to src/common/hotbars/store.ts
index abbae0e1b0..a75182b23b 100644
--- a/src/common/hotbar-store.ts
+++ b/src/common/hotbars/store.ts
@@ -4,22 +4,17 @@
*/
import { action, comparer, observable, makeObservable, computed } from "mobx";
-import { BaseStore } from "./base-store";
-import migrations from "../migrations/hotbar-store";
-import { toJS } from "./utils";
-import type { CatalogEntity } from "./catalog";
-import logger from "../main/logger";
-import { broadcastMessage } from "./ipc";
-import type {
- Hotbar,
- CreateHotbarData,
- CreateHotbarOptions } from "./hotbar-types";
-import {
- defaultHotbarCells,
- getEmptyHotbar,
-} from "./hotbar-types";
-import { hotbarTooManyItemsChannel } from "./ipc/hotbar";
-import type { GeneralEntity } from "./catalog-entities";
+import { BaseStore } from "../base-store";
+import migrations from "../../migrations/hotbar-store";
+import { toJS } from "../utils";
+import type { CatalogEntity } from "../catalog";
+import { broadcastMessage } from "../ipc";
+import type { Hotbar, CreateHotbarData, CreateHotbarOptions } from "./types";
+import { defaultHotbarCells, getEmptyHotbar } from "./types";
+import { hotbarTooManyItemsChannel } from "../ipc/hotbar";
+import type { GeneralEntity } from "../catalog-entities";
+import type { Logger } from "../logger";
+import assert from "assert";
export interface HotbarStoreModel {
hotbars: Hotbar[];
@@ -27,15 +22,16 @@ export interface HotbarStoreModel {
}
interface Dependencies {
- catalogCatalogEntity: GeneralEntity;
+ readonly catalogCatalogEntity: GeneralEntity;
+ readonly logger: Logger;
}
export class HotbarStore extends BaseStore {
readonly displayName = "HotbarStore";
@observable hotbars: Hotbar[] = [];
- @observable private _activeHotbarId: string;
+ @observable private _activeHotbarId!: string;
- constructor(private dependencies: Dependencies) {
+ constructor(private readonly dependencies: Dependencies) {
super({
configName: "lens-hotbar-store",
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
@@ -44,8 +40,8 @@ export class HotbarStore extends BaseStore {
},
migrations,
});
+
makeObservable(this);
- this.load();
}
@computed get activeHotbarId() {
@@ -62,7 +58,7 @@ export class HotbarStore extends BaseStore {
this._activeHotbarId = this.hotbars[hotbar].id;
}
} else if (typeof hotbar === "string") {
- if (this.getById(hotbar)) {
+ if (this.findById(hotbar)) {
this._activeHotbarId = hotbar;
}
} else {
@@ -120,34 +116,35 @@ export class HotbarStore extends BaseStore {
return toJS(model);
}
- getActive() {
- return this.getById(this.activeHotbarId);
+ getActive(): Hotbar {
+ const hotbar = this.findById(this.activeHotbarId);
+
+ assert(hotbar, "There MUST always be an active hotbar");
+
+ return hotbar;
}
- getByName(name: string) {
+ findByName(name: string) {
return this.hotbars.find((hotbar) => hotbar.name === name);
}
- getById(id: string) {
+ findById(id: string) {
return this.hotbars.find((hotbar) => hotbar.id === id);
}
- add = action(
- (
- data: CreateHotbarData,
- { setActive = false }: CreateHotbarOptions = {},
- ) => {
- const hotbar = getEmptyHotbar(data.name, data.id);
+ @action
+ add(data: CreateHotbarData, { setActive = false }: CreateHotbarOptions = {}) {
+ const hotbar = getEmptyHotbar(data.name, data.id);
- this.hotbars.push(hotbar);
+ this.hotbars.push(hotbar);
- if (setActive) {
- this._activeHotbarId = hotbar.id;
- }
- },
- );
+ if (setActive) {
+ this._activeHotbarId = hotbar.id;
+ }
+ }
- setHotbarName = action((id: string, name: string) => {
+ @action
+ setHotbarName(id: string, name: string): void {
const index = this.hotbars.findIndex((hotbar) => hotbar.id === id);
if (index < 0) {
@@ -158,19 +155,18 @@ export class HotbarStore extends BaseStore {
}
this.hotbars[index].name = name;
- });
+ }
- remove = action((hotbar: Hotbar) => {
- if (this.hotbars.length <= 1) {
- throw new Error("Cannot remove the last hotbar");
- }
+ @action
+ remove(hotbar: Hotbar) {
+ assert(this.hotbars.length >= 2, "Cannot remove the last hotbar");
this.hotbars = this.hotbars.filter((h) => h !== hotbar);
if (this.activeHotbarId === hotbar.id) {
this.setActiveHotbar(0);
}
- });
+ }
@action
addToHotbar(item: CatalogEntity, cellIndex?: number) {
@@ -209,7 +205,7 @@ export class HotbarStore extends BaseStore {
} else if (0 <= cellIndex && cellIndex < hotbar.items.length) {
hotbar.items[cellIndex] = newItem;
} else {
- logger.error(
+ this.dependencies.logger.error(
`[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range`,
{ entityId: uid, hotbarId: hotbar.id, cellIndex },
);
@@ -246,8 +242,9 @@ export class HotbarStore extends BaseStore {
findClosestEmptyIndex(from: number, direction = 1) {
let index = from;
+ const hotbar = this.getActive();
- while (this.getActive().items[index] != null) {
+ while (hotbar.items[index] != null) {
index += direction;
}
@@ -314,11 +311,9 @@ export class HotbarStore extends BaseStore {
return false;
}
- return (
- this.getActive().items.findIndex(
- (item) => item?.entity.uid === entity.getId(),
- ) >= 0
- );
+ const indexInActiveHotbar = this.getActive().items.findIndex(item => item?.entity.uid === entity.getId());
+
+ return indexInActiveHotbar >= 0;
}
getDisplayLabel(hotbar: Hotbar): string {
diff --git a/src/common/hotbar-types.ts b/src/common/hotbars/types.ts
similarity index 90%
rename from src/common/hotbar-types.ts
rename to src/common/hotbars/types.ts
index 34ccfaa74e..6370fe136d 100644
--- a/src/common/hotbar-types.ts
+++ b/src/common/hotbars/types.ts
@@ -4,13 +4,13 @@
*/
import * as uuid from "uuid";
-import type { Tuple } from "./utils";
-import { tuple } from "./utils";
+import type { Tuple } from "../utils";
+import { tuple } from "../utils";
export interface HotbarItem {
entity: {
uid: string;
- name?: string;
+ name: string;
source?: string;
};
params?: {
diff --git a/src/common/ipc-channel/create-channel/create-channel.ts b/src/common/ipc-channel/create-channel/create-channel.ts
deleted file mode 100644
index 2a18e3c145..0000000000
--- a/src/common/ipc-channel/create-channel/create-channel.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * Copyright (c) OpenLens Authors. All rights reserved.
- * Licensed under MIT License. See LICENSE in root directory for more information.
- */
-import type { Channel } from "../channel";
-
-export const createChannel = (name: string): Channel => ({
- name,
- _template: null,
-});
diff --git a/src/common/ipc/__tests__/type-enforced-ipc.test.ts b/src/common/ipc/__tests__/type-enforced-ipc.test.ts
index d2820ec231..bd456257cb 100644
--- a/src/common/ipc/__tests__/type-enforced-ipc.test.ts
+++ b/src/common/ipc/__tests__/type-enforced-ipc.test.ts
@@ -53,7 +53,7 @@ describe("type enforced ipc tests", () => {
const source = new EventEmitter();
const listener = () => called += 1;
const results = [true, false, true];
- const verifier = (args: unknown[]): args is [] => results.pop();
+ const verifier = (args: unknown[]): args is [] => results.pop() ?? false;
const channel = "foobar";
onCorrect({ source, listener, verifier, channel });
diff --git a/src/common/ipc/broadcast-message.injectable.ts b/src/common/ipc/broadcast-message.injectable.ts
new file mode 100644
index 0000000000..9df36ac27a
--- /dev/null
+++ b/src/common/ipc/broadcast-message.injectable.ts
@@ -0,0 +1,14 @@
+/**
+ * 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 { broadcastMessage } from "./ipc";
+
+const broadcastMessageInjectable = getInjectable({
+ id: "broadcast-message",
+ instantiate: () => broadcastMessage,
+ causesSideEffects: true,
+});
+
+export default broadcastMessageInjectable;
diff --git a/src/common/ipc/index.ts b/src/common/ipc/index.ts
index 60ae46438e..bb60ce4f6c 100644
--- a/src/common/ipc/index.ts
+++ b/src/common/ipc/index.ts
@@ -5,5 +5,4 @@
export * from "./ipc";
export * from "./invalid-kubeconfig";
-export * from "./update-available";
export * from "./type-enforced-ipc";
diff --git a/src/common/ipc/update-available.ts b/src/common/ipc/update-available.ts
deleted file mode 100644
index ed5b18b13d..0000000000
--- a/src/common/ipc/update-available.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright (c) OpenLens Authors. All rights reserved.
- * Licensed under MIT License. See LICENSE in root directory for more information.
- */
-
-import type { UpdateInfo } from "electron-updater";
-
-export const UpdateAvailableChannel = "update-available";
-export const AutoUpdateChecking = "auto-update:checking";
-export const AutoUpdateNoUpdateAvailable = "auto-update:no-update";
-export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]";
-
-export type UpdateAvailableFromMain = [backChannel: string, updateInfo: UpdateInfo];
-
-export function areArgsUpdateAvailableFromMain(args: unknown[]): args is UpdateAvailableFromMain {
- if (args.length !== 2) {
- return false;
- }
-
- if (typeof args[0] !== "string") {
- return false;
- }
-
- if (typeof args[1] !== "object" || args[1] === null) {
- // TODO: improve this checking
- return false;
- }
-
- return true;
-}
-
-export type BackchannelArg = {
- doUpdate: false;
-} | {
- doUpdate: true;
- now: boolean;
-};
-
-export type UpdateAvailableToBackchannel = [updateDecision: BackchannelArg];
-
-export function areArgsUpdateAvailableToBackchannel(args: unknown[]): args is UpdateAvailableToBackchannel {
- if (args.length !== 1) {
- return false;
- }
-
- if (typeof args[0] !== "object" || args[0] === null) {
- // TODO: improve this checking
- return false;
- }
-
- return true;
-}
diff --git a/src/common/item.store.ts b/src/common/item.store.ts
index 68ef6813b9..805137e95c 100644
--- a/src/common/item.store.ts
+++ b/src/common/item.store.ts
@@ -13,8 +13,6 @@ export interface ItemObject {
}
export abstract class ItemStore- {
- abstract loadAll(...args: any[]): Promise
;
-
protected defaultSorting = (item: Item) => item.getName();
@observable failedLoading = false;
@@ -44,8 +42,7 @@ export abstract class ItemStore- {
return this.items.length;
}
- getByName(name: string, ...args: any[]): Item;
- getByName(name: string): Item {
+ getByName(name: string): Item | undefined {
return this.items.find(item => item.getName() === name);
}
@@ -115,7 +112,6 @@ export abstract class ItemStore
- {
}
}
- protected async loadItem(...args: any[]): Promise
- ;
@action
protected async loadItem(request: () => Promise
- , sortItems = true) {
const item = await Promise.resolve(request()).catch(() => null);
@@ -133,9 +129,9 @@ export abstract class ItemStore
- {
if (sortItems) items = this.sortItems(items);
this.items.replace(items);
}
-
- return item;
}
+
+ return item;
}
@action
diff --git a/src/common/k8s-api/__tests__/api-manager.test.ts b/src/common/k8s-api/__tests__/api-manager.test.ts
index 25d613ee1c..3e411b6584 100644
--- a/src/common/k8s-api/__tests__/api-manager.test.ts
+++ b/src/common/k8s-api/__tests__/api-manager.test.ts
@@ -3,19 +3,32 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { ingressStore } from "../../../renderer/components/+network-ingresses/ingress.store";
-import { apiManager } from "../api-manager";
+import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
+import type { ApiManager } from "../api-manager";
+import apiManagerInjectable from "../api-manager/manager.injectable";
import { KubeApi } from "../kube-api";
import { KubeObject } from "../kube-object";
+import { KubeObjectStore } from "../kube-object.store";
class TestApi extends KubeApi
{
-
protected async checkPreferredVersion() {
return;
}
}
+class TestStore extends KubeObjectStore {
+
+}
+
describe("ApiManager", () => {
+ let apiManager: ApiManager;
+
+ beforeEach(() => {
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ apiManager = di.inject(apiManagerInjectable);
+ });
+
describe("registerApi", () => {
it("re-register store if apiBase changed", async () => {
const apiBase = "apis/v1/foo";
@@ -23,25 +36,27 @@ describe("ApiManager", () => {
const kubeApi = new TestApi({
objectConstructor: KubeObject,
apiBase,
+ kind: "foo",
fallbackApiBases: [fallbackApiBase],
checkPreferredVersion: true,
});
+ const kubeStore = new TestStore(kubeApi);
apiManager.registerApi(apiBase, kubeApi);
// Define to use test api for ingress store
- Object.defineProperty(ingressStore, "api", { value: kubeApi });
- apiManager.registerStore(ingressStore, [kubeApi]);
+ Object.defineProperty(kubeStore, "api", { value: kubeApi });
+ apiManager.registerStore(kubeStore, [kubeApi]);
// Test that store is returned with original apiBase
- expect(apiManager.getStore(kubeApi)).toBe(ingressStore);
+ expect(apiManager.getStore(kubeApi)).toBe(kubeStore);
// Change apiBase similar as checkPreferredVersion does
Object.defineProperty(kubeApi, "apiBase", { value: fallbackApiBase });
apiManager.registerApi(fallbackApiBase, kubeApi);
// Test that store is returned with new apiBase
- expect(apiManager.getStore(kubeApi)).toBe(ingressStore);
+ expect(apiManager.getStore(kubeApi)).toBe(kubeStore);
});
});
});
diff --git a/src/common/k8s-api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts
index 5d9e51afe1..e1538dfbe6 100644
--- a/src/common/k8s-api/__tests__/crd.test.ts
+++ b/src/common/k8s-api/__tests__/crd.test.ts
@@ -16,8 +16,15 @@ describe("Crds", () => {
name: "foo",
resourceVersion: "12345",
uid: "12345",
+ selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/foo",
},
spec: {
+ group: "foo.bar",
+ names: {
+ kind: "Foo",
+ plural: "foos",
+ },
+ scope: "Namespaced",
versions: [
{
name: "123",
@@ -44,8 +51,15 @@ describe("Crds", () => {
name: "foo",
resourceVersion: "12345",
uid: "12345",
+ selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/foo",
},
spec: {
+ group: "foo.bar",
+ names: {
+ kind: "Foo",
+ plural: "foos",
+ },
+ scope: "Namespaced",
versions: [
{
name: "123",
@@ -72,8 +86,15 @@ describe("Crds", () => {
name: "foo",
resourceVersion: "12345",
uid: "12345",
+ selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/foo",
},
spec: {
+ group: "foo.bar",
+ names: {
+ kind: "Foo",
+ plural: "foos",
+ },
+ scope: "Namespaced",
versions: [
{
name: "123",
@@ -100,8 +121,15 @@ describe("Crds", () => {
name: "foo",
resourceVersion: "12345",
uid: "12345",
+ selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/foo",
},
spec: {
+ group: "foo.bar",
+ names: {
+ kind: "Foo",
+ plural: "foos",
+ },
+ scope: "Namespaced",
version: "abc",
versions: [
{
@@ -129,6 +157,7 @@ describe("Crds", () => {
name: "foo",
resourceVersion: "12345",
uid: "12345",
+ selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/foo",
},
spec: {
version: "abc",
diff --git a/src/common/k8s-api/__tests__/deployment.api.test.ts b/src/common/k8s-api/__tests__/deployment.api.test.ts
index 827e2c33bd..60ada4e4d1 100644
--- a/src/common/k8s-api/__tests__/deployment.api.test.ts
+++ b/src/common/k8s-api/__tests__/deployment.api.test.ts
@@ -3,31 +3,39 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { Deployment, DeploymentApi } from "../endpoints/deployment.api";
+import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
+import storesAndApisCanBeCreatedInjectable from "../../../renderer/stores-apis-can-be-created.injectable";
+import apiKubeInjectable from "../../../renderer/k8s/api-kube.injectable";
+import type { DeploymentApi } from "../endpoints/deployment.api";
+import deploymentApiInjectable from "../endpoints/deployment.api.injectable";
import type { KubeJsonApi } from "../kube-json-api";
-class DeploymentApiTest extends DeploymentApi {
- public setRequest(request: any) {
- this.request = request;
- }
-}
-
describe("DeploymentApi", () => {
+ let deploymentApi: DeploymentApi;
+ let kubeJsonApi: jest.Mocked;
+
+ beforeEach(() => {
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ di.override(storesAndApisCanBeCreatedInjectable, () => true);
+ kubeJsonApi = {
+ getResponse: jest.fn(),
+ get: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ patch: jest.fn(),
+ del: jest.fn(),
+ } as never;
+ di.override(apiKubeInjectable, () => kubeJsonApi);
+
+ deploymentApi = di.inject(deploymentApiInjectable);
+ });
+
describe("scale", () => {
- const requestMock = {
- patch: () => ({}),
- } as unknown as KubeJsonApi;
-
- const sub = new DeploymentApiTest({ objectConstructor: Deployment });
-
- sub.setRequest(requestMock);
-
it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => {
- const patchSpy = jest.spyOn(requestMock, "patch");
+ deploymentApi.scale({ namespace: "default", name: "deployment-1" }, 5);
- sub.scale({ namespace: "default", name: "deployment-1" }, 5);
-
- expect(patchSpy).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/deployments/deployment-1/scale", {
+ expect(kubeJsonApi.patch).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/deployments/deployment-1/scale", {
data: {
spec: {
replicas: 5,
diff --git a/src/common/k8s-api/__tests__/endpoint.api.test.ts b/src/common/k8s-api/__tests__/endpoint.api.test.ts
index 58105b0387..666c5df63a 100644
--- a/src/common/k8s-api/__tests__/endpoint.api.test.ts
+++ b/src/common/k8s-api/__tests__/endpoint.api.test.ts
@@ -3,42 +3,26 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { EndpointSubset } from "../endpoints";
+import { formatEndpointSubset } from "../endpoints";
describe("endpoint tests", () => {
describe("EndpointSubset", () => {
- it.each([
- 4,
- false,
- null,
- {},
- [],
- "ahe",
- /a/,
- ])("should always initialize fields when given %j", (data: any) => {
- const sub = new EndpointSubset(data);
-
- expect(sub.addresses).toStrictEqual([]);
- expect(sub.notReadyAddresses).toStrictEqual([]);
- expect(sub.ports).toStrictEqual([]);
- });
-
- it("toString should be addresses X ports", () => {
- const sub = new EndpointSubset({
+ it("formatEndpointSubset should be addresses X ports", () => {
+ const formatted = formatEndpointSubset({
addresses: [{
ip: "1.1.1.1",
}, {
ip: "1.1.1.2",
- }] as any,
+ }],
notReadyAddresses: [],
ports: [{
- port: "81",
+ port: 81,
}, {
- port: "82",
- }] as any,
+ port: 82,
+ }],
});
- expect(sub.toString()).toBe("1.1.1.1:81, 1.1.1.1:82, 1.1.1.2:81, 1.1.1.2:82");
+ expect(formatted).toBe("1.1.1.1:81, 1.1.1.1:82, 1.1.1.2:81, 1.1.1.2:82");
});
});
});
diff --git a/src/common/k8s-api/__tests__/helm-charts.api.test.ts b/src/common/k8s-api/__tests__/helm-charts.api.test.ts
index 283c5168f5..e7a4cb9439 100644
--- a/src/common/k8s-api/__tests__/helm-charts.api.test.ts
+++ b/src/common/k8s-api/__tests__/helm-charts.api.test.ts
@@ -9,33 +9,33 @@ import { HelmChart } from "../endpoints/helm-charts.api";
describe("HelmChart tests", () => {
describe("HelmChart.create() tests", () => {
it("should throw on non-object input", () => {
- expect(() => HelmChart.create("" as any)).toThrowError('"value" must be of type object');
- expect(() => HelmChart.create(1 as any)).toThrowError('"value" must be of type object');
- expect(() => HelmChart.create(false as any)).toThrowError('"value" must be of type object');
- expect(() => HelmChart.create([] as any)).toThrowError('"value" must be of type object');
- expect(() => HelmChart.create(Symbol() as any)).toThrowError('"value" must be of type object');
+ expect(() => HelmChart.create("" as never)).toThrowError('"value" must be of type object');
+ expect(() => HelmChart.create(1 as never)).toThrowError('"value" must be of type object');
+ expect(() => HelmChart.create(false as never)).toThrowError('"value" must be of type object');
+ expect(() => HelmChart.create([] as never)).toThrowError('"value" must be of type object');
+ expect(() => HelmChart.create(Symbol() as never)).toThrowError('"value" must be of type object');
});
it("should throw on missing fields", () => {
- expect(() => HelmChart.create({} as any)).toThrowError('"apiVersion" is required');
+ expect(() => HelmChart.create({} as never)).toThrowError('"apiVersion" is required');
expect(() => HelmChart.create({
apiVersion: "!",
- } as any)).toThrowError('"name" is required');
+ } as never)).toThrowError('"name" is required');
expect(() => HelmChart.create({
apiVersion: "!",
name: "!",
- } as any)).toThrowError('"version" is required');
+ } as never)).toThrowError('"version" is required');
expect(() => HelmChart.create({
apiVersion: "!",
name: "!",
version: "!",
- } as any)).toThrowError('"repo" is required');
+ } as never)).toThrowError('"repo" is required');
expect(() => HelmChart.create({
apiVersion: "!",
name: "!",
version: "!",
repo: "!",
- } as any)).toThrowError('"created" is required');
+ } as never)).toThrowError('"created" is required');
});
it("should throw on fields being wrong type", () => {
@@ -46,7 +46,7 @@ describe("HelmChart tests", () => {
repo: "!",
created: "!",
digest: "!",
- } as any)).toThrowError('"apiVersion" must be a string');
+ } as never)).toThrowError('"apiVersion" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: 1,
@@ -54,7 +54,7 @@ describe("HelmChart tests", () => {
repo: "!",
created: "!",
digest: "!",
- } as any)).toThrowError('"name" must be a string');
+ } as never)).toThrowError('"name" must be a string');
expect(() => HelmChart.create({
apiVersion: "!",
name: "!",
@@ -62,7 +62,7 @@ describe("HelmChart tests", () => {
repo: "!",
created: "!",
digest: 1,
- } as any)).toThrowError('"digest" must be a string');
+ } as never)).toThrowError('"digest" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "",
@@ -70,7 +70,7 @@ describe("HelmChart tests", () => {
repo: "!",
created: "!",
digest: "!",
- } as any)).toThrowError('"version" must be a string');
+ } as never)).toThrowError('"version" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -78,7 +78,7 @@ describe("HelmChart tests", () => {
repo: 1,
created: "!",
digest: "!",
- } as any)).toThrowError('"repo" must be a string');
+ } as never)).toThrowError('"repo" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -86,7 +86,7 @@ describe("HelmChart tests", () => {
repo: "1",
created: 1,
digest: "a",
- } as any)).toThrowError('"created" must be a string');
+ } as never)).toThrowError('"created" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -94,7 +94,7 @@ describe("HelmChart tests", () => {
repo: "1",
created: "!",
digest: 1,
- } as any)).toThrowError('"digest" must be a string');
+ } as never)).toThrowError('"digest" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -103,7 +103,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
kubeVersion: 1,
- } as any)).toThrowError('"kubeVersion" must be a string');
+ } as never)).toThrowError('"kubeVersion" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -112,7 +112,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
description: 1,
- } as any)).toThrowError('"description" must be a string');
+ } as never)).toThrowError('"description" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -121,7 +121,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
home: 1,
- } as any)).toThrowError('"home" must be a string');
+ } as never)).toThrowError('"home" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -130,7 +130,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
engine: 1,
- } as any)).toThrowError('"engine" must be a string');
+ } as never)).toThrowError('"engine" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -139,7 +139,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
icon: 1,
- } as any)).toThrowError('"icon" must be a string');
+ } as never)).toThrowError('"icon" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -148,7 +148,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
appVersion: 1,
- } as any)).toThrowError('"appVersion" must be a string');
+ } as never)).toThrowError('"appVersion" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -157,7 +157,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
tillerVersion: 1,
- } as any)).toThrowError('"tillerVersion" must be a string');
+ } as never)).toThrowError('"tillerVersion" must be a string');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -166,7 +166,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
deprecated: 1,
- } as any)).toThrowError('"deprecated" must be a boolean');
+ } as never)).toThrowError('"deprecated" must be a boolean');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -175,7 +175,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
keywords: 1,
- } as any)).toThrowError('"keywords" must be an array');
+ } as never)).toThrowError('"keywords" must be an array');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -184,7 +184,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
sources: 1,
- } as any)).toThrowError('"sources" must be an array');
+ } as never)).toThrowError('"sources" must be an array');
expect(() => HelmChart.create({
apiVersion: "1",
name: "1",
@@ -193,7 +193,7 @@ describe("HelmChart tests", () => {
digest: "1",
created: "!",
maintainers: 1,
- } as any)).toThrowError('"maintainers" must be an array');
+ } as never)).toThrowError('"maintainers" must be an array');
});
it("should filter non-string keywords", () => {
@@ -204,10 +204,10 @@ describe("HelmChart tests", () => {
repo: "1",
digest: "1",
created: "!",
- keywords: [1, "a", false, {}, "b"] as any,
+ keywords: [1, "a", false, {}, "b"] as never,
});
- expect(chart.keywords).toStrictEqual(["a", "b"]);
+ expect(chart?.keywords).toStrictEqual(["a", "b"]);
});
it("should filter non-string sources", () => {
@@ -218,10 +218,10 @@ describe("HelmChart tests", () => {
repo: "1",
digest: "1",
created: "!",
- sources: [1, "a", false, {}, "b"] as any,
+ sources: [1, "a", false, {}, "b"] as never,
});
- expect(chart.sources).toStrictEqual(["a", "b"]);
+ expect(chart?.sources).toStrictEqual(["a", "b"]);
});
it("should filter invalid maintainers", () => {
@@ -236,10 +236,10 @@ describe("HelmChart tests", () => {
name: "a",
email: "b",
url: "c",
- }] as any,
+ }] as never,
});
- expect(chart.maintainers).toStrictEqual([{
+ expect(chart?.maintainers).toStrictEqual([{
name: "a",
email: "b",
url: "c",
@@ -261,9 +261,9 @@ describe("HelmChart tests", () => {
name: "a",
email: "b",
url: "c",
- }] as any,
+ }] as never,
"asdjhajksdhadjks": 1,
- } as any);
+ } as never);
expect(warnFn).toHaveBeenCalledWith("HelmChart data has unexpected fields", {
original: anyObject(),
diff --git a/src/common/k8s-api/__tests__/ingress.api.ts b/src/common/k8s-api/__tests__/ingress.api.ts
index 3b84c37038..d5e4d323ad 100644
--- a/src/common/k8s-api/__tests__/ingress.api.ts
+++ b/src/common/k8s-api/__tests__/ingress.api.ts
@@ -14,6 +14,8 @@ describe("computeRuleDeclarations", () => {
name: "foo",
resourceVersion: "1",
uid: "bar",
+ namespace: "default",
+ selfLink: "/apis/networking.k8s.io/v1/ingresses/default/foo",
},
});
@@ -21,6 +23,7 @@ describe("computeRuleDeclarations", () => {
host: "foo.bar",
http: {
paths: [{
+ pathType: "Exact",
backend: {
service: {
name: "my-service",
@@ -44,6 +47,8 @@ describe("computeRuleDeclarations", () => {
name: "foo",
resourceVersion: "1",
uid: "bar",
+ namespace: "default",
+ selfLink: "/apis/networking.k8s.io/v1/ingresses/default/foo",
},
});
@@ -55,6 +60,7 @@ describe("computeRuleDeclarations", () => {
host: "foo.bar",
http: {
paths: [{
+ pathType: "Exact",
backend: {
service: {
name: "my-service",
@@ -78,6 +84,8 @@ describe("computeRuleDeclarations", () => {
name: "foo",
resourceVersion: "1",
uid: "bar",
+ namespace: "default",
+ selfLink: "/apis/networking.k8s.io/v1/ingresses/default/foo",
},
});
@@ -91,6 +99,7 @@ describe("computeRuleDeclarations", () => {
host: "foo.bar",
http: {
paths: [{
+ pathType: "Exact",
backend: {
service: {
name: "my-service",
diff --git a/src/common/k8s-api/__tests__/kube-api-parse.test.ts b/src/common/k8s-api/__tests__/kube-api-parse.test.ts
index 8801837256..547f78adef 100644
--- a/src/common/k8s-api/__tests__/kube-api-parse.test.ts
+++ b/src/common/k8s-api/__tests__/kube-api-parse.test.ts
@@ -19,7 +19,7 @@ import { parseKubeApi } from "../kube-api-parse";
/**
* [, ]
*/
-type KubeApiParseTestData = [string, Required];
+type KubeApiParseTestData = [string, IKubeApiParsed];
const tests: KubeApiParseTestData[] = [
["/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com", {
@@ -126,6 +126,6 @@ describe("parseApi unit tests", () => {
});
it.each(throwtests)("testing %j should throw", (url) => {
- expect(() => parseKubeApi(url)).toThrowError("invalid apiPath");
+ expect(() => parseKubeApi(url as never)).toThrowError("invalid apiPath");
});
});
diff --git a/src/common/k8s-api/__tests__/kube-api.test.ts b/src/common/k8s-api/__tests__/kube-api.test.ts
index b5b4094bf7..9efa23bdaf 100644
--- a/src/common/k8s-api/__tests__/kube-api.test.ts
+++ b/src/common/k8s-api/__tests__/kube-api.test.ts
@@ -3,34 +3,34 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import type { Request } from "node-fetch";
import { forRemoteCluster, KubeApi } from "../kube-api";
import { KubeJsonApi } from "../kube-json-api";
import { KubeObject } from "../kube-object";
import AbortController from "abort-controller";
import { delay } from "../../utils/delay";
import { PassThrough } from "stream";
-import type { ApiManager } from "../api-manager";
-import { apiManager } from "../api-manager";
-import { Ingress, Pod } from "../endpoints";
+import { ApiManager } from "../api-manager";
+import type { FetchMock } from "jest-fetch-mock/types";
+import { DeploymentApi, Ingress, IngressApi, Pod, PodApi } from "../endpoints";
+import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
+import apiManagerInjectable from "../api-manager/manager.injectable";
+import autoRegistrationInjectable from "../api-manager/auto-registration.injectable";
jest.mock("../api-manager");
-const mockApiManager = apiManager as jest.Mocked;
-
-class TestKubeObject extends KubeObject {
- static kind = "Pod";
- static namespaced = true;
- static apiBase = "/api/v1/pods";
-}
-
-class TestKubeApi extends KubeApi {
- public async checkPreferredVersion() {
- return super.checkPreferredVersion();
- }
-}
+const mockFetch = fetch as FetchMock;
describe("forRemoteCluster", () => {
+ let apiManager: jest.Mocked;
+
+ beforeEach(() => {
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ apiManager = new ApiManager() as jest.Mocked;
+
+ di.override(apiManagerInjectable, () => apiManager);
+ });
+
it("builds api client for KubeObject", async () => {
const api = forRemoteCluster({
cluster: {
@@ -39,7 +39,7 @@ describe("forRemoteCluster", () => {
user: {
token: "daa",
},
- }, TestKubeObject);
+ }, Pod);
expect(api).toBeInstanceOf(KubeApi);
});
@@ -52,9 +52,9 @@ describe("forRemoteCluster", () => {
user: {
token: "daa",
},
- }, TestKubeObject, TestKubeApi);
+ }, Pod, PodApi);
- expect(api).toBeInstanceOf(TestKubeApi);
+ expect(api).toBeInstanceOf(PodApi);
});
it("calls right api endpoint", async () => {
@@ -65,9 +65,9 @@ describe("forRemoteCluster", () => {
user: {
token: "daa",
},
- }, TestKubeObject);
+ }, Pod);
- (fetch as any).mockResponse(async (request: any) => {
+ mockFetch.mockResponse(async (request: any) => {
expect(request.url).toEqual("https://127.0.0.1:6443/api/v1/pods");
return {
@@ -83,22 +83,29 @@ describe("forRemoteCluster", () => {
describe("KubeApi", () => {
let request: KubeJsonApi;
+ let apiManager: jest.Mocked;
beforeEach(() => {
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
request = new KubeJsonApi({
serverAddress: `http://127.0.0.1:9999`,
apiBase: "/api-kube",
});
+ apiManager = new ApiManager() as jest.Mocked;
+
+ di.override(apiManagerInjectable, () => apiManager);
+ di.inject(autoRegistrationInjectable);
});
it("uses url from apiBase if apiBase contains the resource", async () => {
- (fetch as any).mockResponse(async (request: any) => {
+ mockFetch.mockResponse(async (request: any) => {
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
return {
body: JSON.stringify({
resources: [{
name: "ingresses",
- }] as any[],
+ }],
}),
};
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
@@ -107,13 +114,13 @@ describe("KubeApi", () => {
body: JSON.stringify({
resources: [{
name: "ingresses",
- }] as any[],
+ }],
}),
};
} else {
return {
body: JSON.stringify({
- resources: [] as any[],
+ resources: [],
}),
};
}
@@ -121,9 +128,9 @@ describe("KubeApi", () => {
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
- const kubeApi = new KubeApi({
+ const kubeApi = new IngressApi({
request,
- objectConstructor: KubeObject,
+ objectConstructor: Ingress,
apiBase,
fallbackApiBases: [fallbackApiBase],
checkPreferredVersion: true,
@@ -138,11 +145,11 @@ describe("KubeApi", () => {
});
it("uses url from fallbackApiBases if apiBase lacks the resource", async () => {
- (fetch as any).mockResponse(async (request: any) => {
+ mockFetch.mockResponse(async (request: any) => {
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
return {
body: JSON.stringify({
- resources: [] as any[],
+ resources: [],
}),
};
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
@@ -150,13 +157,13 @@ describe("KubeApi", () => {
body: JSON.stringify({
resources: [{
name: "ingresses",
- }] as any[],
+ }],
}),
};
} else {
return {
body: JSON.stringify({
- resources: [] as any[],
+ resources: [],
}),
};
}
@@ -164,9 +171,10 @@ describe("KubeApi", () => {
const apiBase = "apis/networking.k8s.io/v1/ingresses";
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
- const kubeApi = new KubeApi({
+ const kubeApi = new IngressApi({
request,
objectConstructor: Object.assign(KubeObject, { apiBase }),
+ kind: "Ingress",
fallbackApiBases: [fallbackApiBase],
checkPreferredVersion: true,
});
@@ -183,107 +191,100 @@ describe("KubeApi", () => {
it("registers with apiManager if checkPreferredVersion changes apiVersionPreferred", async () => {
expect.hasAssertions();
- const api = new TestKubeApi({
+ const api = new IngressApi({
objectConstructor: Ingress,
checkPreferredVersion: true,
fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"],
request: {
get: jest.fn()
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/apis/networking.k8s.io/v1");
-
- throw new Error("no");
- })
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/apis/extensions/v1beta1");
-
- return {
- resources: [
- {
- name: "ingresses",
- },
- ],
- };
- })
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/apis/extensions");
-
- return {
- preferredVersion: {
- version: "v1beta1",
- },
- };
+ .mockImplementation((path: string) => {
+ switch (path) {
+ case "/apis/networking.k8s.io/v1":
+ throw new Error("no");
+ case "/apis/extensions/v1beta1":
+ return {
+ resources: [
+ {
+ name: "ingresses",
+ },
+ ],
+ };
+ case "/apis/extensions":
+ return {
+ preferredVersion: {
+ version: "v1beta1",
+ },
+ };
+ default:
+ throw new Error("unknown path");
+ }
}),
- } as any,
+ } as Partial as KubeJsonApi,
});
- await api.checkPreferredVersion();
+ await (api as any).checkPreferredVersion();
expect(api.apiVersionPreferred).toBe("v1beta1");
- expect(mockApiManager.registerApi).toBeCalledWith("/apis/extensions/v1beta1/ingresses", expect.anything());
+ expect(apiManager.registerApi).toBeCalledWith(api);
});
it("registers with apiManager if checkPreferredVersion changes apiVersionPreferred with non-grouped apis", async () => {
expect.hasAssertions();
- const api = new TestKubeApi({
+ const api = new PodApi({
objectConstructor: Pod,
checkPreferredVersion: true,
fallbackApiBases: ["/api/v1beta1/pods"],
request: {
get: jest.fn()
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/api/v1");
-
- throw new Error("no");
- })
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/api/v1beta1");
-
- return {
- resources: [
- {
- name: "pods",
- },
- ],
- };
- })
- .mockImplementationOnce((path: string) => {
- expect(path).toBe("/api");
-
- return {
- preferredVersion: {
- version: "v1beta1",
- },
- };
+ .mockImplementation((path: string) => {
+ switch (path) {
+ case "/api/v1":
+ throw new Error("no");
+ case "/api/v1beta1":
+ return {
+ resources: [
+ {
+ name: "pods",
+ },
+ ],
+ };
+ case "/api":
+ return {
+ preferredVersion: {
+ version: "v1beta1",
+ },
+ };
+ default:
+ throw new Error("unknown path");
+ }
}),
- } as any,
+ } as Partial as KubeJsonApi,
});
- await api.checkPreferredVersion();
+ await (api as any).checkPreferredVersion();
expect(api.apiVersionPreferred).toBe("v1beta1");
- expect(mockApiManager.registerApi).toBeCalledWith("/api/v1beta1/pods", expect.anything());
+ expect(apiManager.registerApi).toBeCalledWith(api);
});
});
describe("patch", () => {
- let api: TestKubeApi;
+ let api: DeploymentApi;
beforeEach(() => {
- api = new TestKubeApi({
+ api = new DeploymentApi({
request,
- objectConstructor: TestKubeObject,
});
});
it("sends strategic patch by default", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("PATCH");
expect(request.headers.get("content-type")).toMatch("strategic-merge-patch");
- expect(request.body.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
+ expect(request.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
return {};
});
@@ -296,10 +297,10 @@ describe("KubeApi", () => {
it("allows to use merge patch", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("PATCH");
expect(request.headers.get("content-type")).toMatch("merge-patch");
- expect(request.body.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
+ expect(request.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
return {};
});
@@ -312,10 +313,10 @@ describe("KubeApi", () => {
it("allows to use json patch", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("PATCH");
expect(request.headers.get("content-type")).toMatch("json-patch");
- expect(request.body.toString()).toEqual(JSON.stringify([{ op: "replace", path: "/spec/replicas", value: 2 }]));
+ expect(request.body?.toString()).toEqual(JSON.stringify([{ op: "replace", path: "/spec/replicas", value: 2 }]));
return {};
});
@@ -328,10 +329,10 @@ describe("KubeApi", () => {
it("allows deep partial patch", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("PATCH");
expect(request.headers.get("content-type")).toMatch("merge-patch");
- expect(request.body.toString()).toEqual(JSON.stringify({ metadata: { annotations: { provisioned: "true" }}}));
+ expect(request.body?.toString()).toEqual(JSON.stringify({ metadata: { annotations: { provisioned: "true" }}}));
return {};
});
@@ -345,18 +346,18 @@ describe("KubeApi", () => {
});
describe("delete", () => {
- let api: TestKubeApi;
+ let api: PodApi;
beforeEach(() => {
- api = new TestKubeApi({
+ api = new PodApi({
request,
- objectConstructor: TestKubeObject,
+ objectConstructor: Pod,
});
});
it("sends correct request with empty namespace", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("DELETE");
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/pods/foo?propagationPolicy=Background");
@@ -368,7 +369,7 @@ describe("KubeApi", () => {
it("sends correct request without namespace", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("DELETE");
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background");
@@ -380,7 +381,7 @@ describe("KubeApi", () => {
it("sends correct request with namespace", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("DELETE");
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods/foo?propagationPolicy=Background");
@@ -392,7 +393,7 @@ describe("KubeApi", () => {
it("allows to change propagationPolicy", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("DELETE");
expect(request.url).toMatch("propagationPolicy=Orphan");
@@ -404,13 +405,13 @@ describe("KubeApi", () => {
});
describe("watch", () => {
- let api: TestKubeApi;
+ let api: PodApi;
let stream: PassThrough;
beforeEach(() => {
- api = new TestKubeApi({
+ api = new PodApi({
request,
- objectConstructor: TestKubeObject,
+ objectConstructor: Pod,
});
stream = new PassThrough();
});
@@ -423,9 +424,10 @@ describe("KubeApi", () => {
it("sends a valid watch request", () => {
const spy = jest.spyOn(request, "getResponse");
- (fetch as any).mockResponse(async () => {
+ mockFetch.mockResponse(async () => {
return {
- body: stream,
+ // needed for https://github.com/jefflau/jest-fetch-mock/issues/218
+ body: stream as unknown as string,
};
});
@@ -436,9 +438,10 @@ describe("KubeApi", () => {
it("sends timeout as a query parameter", async () => {
const spy = jest.spyOn(request, "getResponse");
- (fetch as any).mockResponse(async () => {
+ mockFetch.mockResponse(async () => {
return {
- body: stream,
+ // needed for https://github.com/jefflau/jest-fetch-mock/issues/218
+ body: stream as unknown as string,
};
});
@@ -449,13 +452,14 @@ describe("KubeApi", () => {
it("aborts watch using abortController", async (done) => {
const spy = jest.spyOn(request, "getResponse");
- (fetch as any).mockResponse(async (request: Request) => {
- (request as any).signal.addEventListener("abort", () => {
+ mockFetch.mockResponse(async request => {
+ request.signal.addEventListener("abort", () => {
done();
});
return {
- body: stream,
+ // needed for https://github.com/jefflau/jest-fetch-mock/issues/218
+ body: stream as unknown as string,
};
});
@@ -478,9 +482,9 @@ describe("KubeApi", () => {
it("if request ended", (done) => {
const spy = jest.spyOn(request, "getResponse");
- jest.spyOn(stream, "on").mockImplementation((eventName: string, callback: Function) => {
+ jest.spyOn(stream, "on").mockImplementation((event: string | symbol, callback: Function) => {
// End the request in 100ms.
- if (eventName === "end") {
+ if (event === "end") {
setTimeout(() => {
callback();
}, 100);
@@ -493,8 +497,8 @@ describe("KubeApi", () => {
jest.spyOn(global, "fetch").mockImplementation(async () => {
return {
ok: true,
- body: stream,
- } as any;
+ body: stream as never,
+ } as Partial as Response;
});
api.watch({
@@ -512,9 +516,10 @@ describe("KubeApi", () => {
it("if request not closed after timeout", (done) => {
const spy = jest.spyOn(request, "getResponse");
- (fetch as any).mockResponse(async () => {
+ mockFetch.mockResponse(async () => {
return {
- body: stream,
+ // needed for https://github.com/jefflau/jest-fetch-mock/issues/218
+ body: stream as unknown as string,
};
});
@@ -536,9 +541,9 @@ describe("KubeApi", () => {
it("retries only once if request ends and timeout is set", (done) => {
const spy = jest.spyOn(request, "getResponse");
- jest.spyOn(stream, "on").mockImplementation((eventName: string, callback: Function) => {
+ jest.spyOn(stream, "on").mockImplementation((event: string | symbol, callback: Function) => {
// End the request in 100ms.
- if (eventName === "end") {
+ if (event === "end") {
setTimeout(() => {
callback();
}, 100);
@@ -551,8 +556,8 @@ describe("KubeApi", () => {
jest.spyOn(global, "fetch").mockImplementation(async () => {
return {
ok: true,
- body: stream,
- } as any;
+ body: stream as never,
+ } as Partial as Response;
});
const timeoutSeconds = 0.5;
@@ -577,21 +582,21 @@ describe("KubeApi", () => {
});
describe("create", () => {
- let api: TestKubeApi;
+ let api: PodApi;
beforeEach(() => {
- api = new TestKubeApi({
+ api = new PodApi({
request,
- objectConstructor: TestKubeObject,
+ objectConstructor: Pod,
});
});
it("should add kind and apiVersion", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("POST");
- expect(JSON.parse(request.body.toString())).toEqual({
+ expect(JSON.parse(String(request.body))).toEqual({
kind: "Pod",
apiVersion: "v1",
metadata: {
@@ -643,9 +648,9 @@ describe("KubeApi", () => {
it("doesn't override metadata.labels", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("POST");
- expect(JSON.parse(request.body.toString())).toEqual({
+ expect(JSON.parse(String(request.body))).toEqual({
kind: "Pod",
apiVersion: "v1",
metadata: {
@@ -674,21 +679,21 @@ describe("KubeApi", () => {
});
describe("update", () => {
- let api: TestKubeApi;
+ let api: PodApi;
beforeEach(() => {
- api = new TestKubeApi({
+ api = new PodApi({
request,
- objectConstructor: TestKubeObject,
+ objectConstructor: Pod,
});
});
it("doesn't override metadata.labels", async () => {
expect.hasAssertions();
- (fetch as any).mockResponse(async (request: Request) => {
+ mockFetch.mockResponse(async request => {
expect(request.method).toEqual("PUT");
- expect(JSON.parse(request.body.toString())).toEqual({
+ expect(JSON.parse(String(request.body))).toEqual({
metadata: {
name: "foobar",
namespace: "default",
diff --git a/src/common/k8s-api/__tests__/kube-object.store.test.ts b/src/common/k8s-api/__tests__/kube-object.store.test.ts
index f0f26ec0d8..91ed80fbde 100644
--- a/src/common/k8s-api/__tests__/kube-object.store.test.ts
+++ b/src/common/k8s-api/__tests__/kube-object.store.test.ts
@@ -3,6 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
+import type { Cluster } from "../../cluster/cluster";
import type { ClusterContext } from "../cluster-context";
import type { KubeApi } from "../kube-api";
import { KubeObject } from "../kube-object";
@@ -14,6 +15,7 @@ class FakeKubeObjectStore extends KubeObjectStore {
allNamespaces: [],
contextNamespaces: [],
hasSelectedAll: false,
+ cluster: {} as Cluster,
} as ClusterContext;
get context() {
@@ -40,6 +42,7 @@ describe("KubeObjectStore", () => {
resourceVersion: "1",
uid: "some-uid",
namespace: "default",
+ selfLink: "/some/self/link",
},
});
const store = new FakeKubeObjectStore(loadItems, {
@@ -73,6 +76,7 @@ describe("KubeObjectStore", () => {
resourceVersion: "1",
uid: "some-uid",
namespace: "default",
+ selfLink: "/some/self/link",
},
});
const objNotInDefaultNamespace = new KubeObject({
@@ -83,6 +87,7 @@ describe("KubeObjectStore", () => {
resourceVersion: "1",
uid: "some-uid",
namespace: "not-default",
+ selfLink: "/some/self/link",
},
});
const store = new FakeKubeObjectStore(loadItems, {
@@ -115,6 +120,7 @@ describe("KubeObjectStore", () => {
name: "some-obj-name",
resourceVersion: "1",
uid: "some-uid",
+ selfLink: "/some/self/link",
},
});
const clusterScopedObject2 = new KubeObject({
@@ -125,6 +131,7 @@ describe("KubeObjectStore", () => {
resourceVersion: "1",
uid: "some-uid",
namespace: "not-default",
+ selfLink: "/some/self/link",
},
});
const store = new FakeKubeObjectStore(loadItems, {
diff --git a/src/common/k8s-api/__tests__/nodes.test.ts b/src/common/k8s-api/__tests__/node.test.ts
similarity index 66%
rename from src/common/k8s-api/__tests__/nodes.test.ts
rename to src/common/k8s-api/__tests__/node.test.ts
index 4b109a8f96..53ffc59d79 100644
--- a/src/common/k8s-api/__tests__/nodes.test.ts
+++ b/src/common/k8s-api/__tests__/node.test.ts
@@ -8,7 +8,61 @@ import { Node } from "../endpoints";
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-describe("Nodes tests", () => {
+describe("Node tests", () => {
+ describe("isMasterNode()", () => {
+ it("given a master node labelled before kubernetes 1.20, should return true", () => {
+ const node = new Node({
+ apiVersion: "foo",
+ kind: "Node",
+ metadata: {
+ name: "bar",
+ resourceVersion: "1",
+ uid: "bat",
+ labels: {
+ "node-role.kubernetes.io/master": "NoSchedule",
+ },
+ selfLink: "/api/v1/nodes/bar",
+ },
+ });
+
+ expect(node.isMasterNode()).toBe(true);
+ });
+
+ it("given a master node labelled after kubernetes 1.20, should return true", () => {
+ const node = new Node({
+ apiVersion: "foo",
+ kind: "Node",
+ metadata: {
+ name: "bar",
+ resourceVersion: "1",
+ uid: "bat",
+ labels: {
+ "node-role.kubernetes.io/control-plane": "NoSchedule",
+ },
+ selfLink: "/api/v1/nodes/bar",
+ },
+ });
+
+ expect(node.isMasterNode()).toBe(true);
+ });
+
+ it("given a non master node, should return false", () => {
+ const node = new Node({
+ apiVersion: "foo",
+ kind: "Node",
+ metadata: {
+ name: "bar",
+ resourceVersion: "1",
+ uid: "bat",
+ labels: {},
+ selfLink: "/api/v1/nodes/bar",
+ },
+ });
+
+ expect(node.isMasterNode()).toBe(false);
+ });
+ });
+
describe("getRoleLabels()", () => {
it("should return empty string if labels is not present", () => {
const node = new Node({
@@ -18,6 +72,7 @@ describe("Nodes tests", () => {
name: "bar",
resourceVersion: "1",
uid: "bat",
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -33,6 +88,7 @@ describe("Nodes tests", () => {
resourceVersion: "1",
uid: "bat",
labels: {},
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -51,6 +107,7 @@ describe("Nodes tests", () => {
"node-role.kubernetes.io/foobar": "bat",
"hellonode-role.kubernetes.io/foobar1": "bat",
},
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -69,6 +126,7 @@ describe("Nodes tests", () => {
"node-role.kubernetes.io/foobar": "bat",
"hellonode-role.kubernetes.io//////foobar1": "bat",
},
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -86,6 +144,7 @@ describe("Nodes tests", () => {
labels: {
"kubernetes.io/role": "master",
},
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -103,6 +162,7 @@ describe("Nodes tests", () => {
labels: {
"node.kubernetes.io/role": "master",
},
+ selfLink: "/api/v1/nodes/bar",
},
});
@@ -122,6 +182,7 @@ describe("Nodes tests", () => {
"kubernetes.io/role": "master",
"node.kubernetes.io/role": "master-v2-max",
},
+ selfLink: "/api/v1/nodes/bar",
},
});
diff --git a/src/common/k8s-api/__tests__/pods.api.test.ts b/src/common/k8s-api/__tests__/pods.api.test.ts
index 16b57b1b48..9b01dff73b 100644
--- a/src/common/k8s-api/__tests__/pods.api.test.ts
+++ b/src/common/k8s-api/__tests__/pods.api.test.ts
@@ -14,6 +14,8 @@ describe("Pod tests", () => {
name: "foobar",
resourceVersion: "foobar",
uid: "foobar",
+ namespace: "default",
+ selfLink: "/api/v1/pods/default/foobar",
},
});
diff --git a/src/common/k8s-api/__tests__/pods.test.ts b/src/common/k8s-api/__tests__/pods.test.ts
index a7faee1e45..826c2b4617 100644
--- a/src/common/k8s-api/__tests__/pods.test.ts
+++ b/src/common/k8s-api/__tests__/pods.test.ts
@@ -3,6 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
+import assert from "assert";
+import type { PodContainer, PodContainerStatus } from "../endpoints";
import { Pod } from "../endpoints";
interface GetDummyPodOptions {
@@ -12,16 +14,18 @@ interface GetDummyPodOptions {
initDead?: number;
}
-function getDummyPodDefaultOptions(): Required {
- return {
- running: 0,
- dead: 0,
- initDead: 0,
- initRunning: 0,
- };
-}
+function getDummyPod(rawOpts: GetDummyPodOptions = {}): Pod {
+ const {
+ running = 0,
+ dead = 0,
+ initDead = 0,
+ initRunning = 0,
+ } = rawOpts;
-function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Pod {
+ const containers: PodContainer[] = [];
+ const initContainers: PodContainer[] = [];
+ const containerStatuses: PodContainerStatus[] = [];
+ const initContainerStatuses: PodContainerStatus[] = [];
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
@@ -29,36 +33,35 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po
uid: "1",
name: "test",
resourceVersion: "v1",
- selfLink: "http",
+ namespace: "default",
+ selfLink: "/api/v1/pods/default/test",
+ },
+ spec: {
+ containers,
+ initContainers,
+ serviceAccount: "dummy",
+ serviceAccountName: "dummy",
+ },
+ status: {
+ phase: "Running",
+ conditions: [],
+ hostIP: "10.0.0.1",
+ podIP: "10.0.0.1",
+ startTime: "now",
+ containerStatuses,
+ initContainerStatuses,
},
});
- pod.spec = {
- containers: [],
- initContainers: [],
- serviceAccount: "dummy",
- serviceAccountName: "dummy",
- };
+ for (let i = 0; i < running; i += 1) {
+ const name = `container_running_${i}`;
- pod.status = {
- phase: "Running",
- conditions: [],
- hostIP: "10.0.0.1",
- podIP: "10.0.0.1",
- startTime: "now",
- containerStatuses: [],
- initContainerStatuses: [],
- };
-
- for (let i = 0; i < opts.running; i += 1) {
- const name = `container_r_${i}`;
-
- pod.spec.containers.push({
+ containers.push({
image: "dummy",
imagePullPolicy: "dummy",
name,
});
- pod.status.containerStatuses.push({
+ containerStatuses.push({
image: "dummy",
imageID: "dummy",
name,
@@ -72,15 +75,15 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po
});
}
- for (let i = 0; i < opts.dead; i += 1) {
- const name = `container_d_${i}`;
+ for (let i = 0; i < dead; i += 1) {
+ const name = `container_dead_${i}`;
- pod.spec.containers.push({
+ containers.push({
image: "dummy",
imagePullPolicy: "dummy",
name,
});
- pod.status.containerStatuses.push({
+ containerStatuses.push({
image: "dummy",
imageID: "dummy",
name,
@@ -97,15 +100,15 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po
});
}
- for (let i = 0; i < opts.initRunning; i += 1) {
- const name = `container_ir_${i}`;
+ for (let i = 0; i < initRunning; i += 1) {
+ const name = `container_init-running_${i}`;
- pod.spec.initContainers.push({
+ initContainers.push({
image: "dummy",
imagePullPolicy: "dummy",
name,
});
- pod.status.initContainerStatuses.push({
+ initContainerStatuses.push({
image: "dummy",
imageID: "dummy",
name,
@@ -119,15 +122,15 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po
});
}
- for (let i = 0; i < opts.initDead; i += 1) {
- const name = `container_id_${i}`;
+ for (let i = 0; i < initDead; i += 1) {
+ const name = `container_init-dead_${i}`;
- pod.spec.initContainers.push({
+ initContainers.push({
image: "dummy",
imagePullPolicy: "dummy",
name,
});
- pod.status.initContainerStatuses.push({
+ initContainerStatuses.push({
image: "dummy",
imageID: "dummy",
name,
@@ -173,8 +176,8 @@ describe("Pods", () => {
it("getRunningContainers should return only running and init running", () => {
const res = [
- ...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
- ...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
+ ...Array.from(new Array(running), (val, index) => getNamedContainer(`container_running_${index}`)),
+ ...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_init-running_${index}`)),
];
expect(pod.getRunningContainers()).toStrictEqual(res);
@@ -182,10 +185,10 @@ describe("Pods", () => {
it("getAllContainers should return all containers", () => {
const res = [
- ...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
- ...Array.from(new Array(dead), (val, index) => getNamedContainer(`container_d_${index}`)),
- ...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
- ...Array.from(new Array(initDead), (val, index) => getNamedContainer(`container_id_${index}`)),
+ ...Array.from(new Array(running), (val, index) => getNamedContainer(`container_running_${index}`)),
+ ...Array.from(new Array(dead), (val, index) => getNamedContainer(`container_dead_${index}`)),
+ ...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_init-running_${index}`)),
+ ...Array.from(new Array(initDead), (val, index) => getNamedContainer(`container_init-dead_${index}`)),
];
expect(pod.getAllContainers()).toStrictEqual(res);
@@ -253,7 +256,7 @@ describe("Pods", () => {
it("should return true if a condition isn't ready", () => {
const pod = getDummyPod({ running: 1 });
- pod.status.conditions.push({
+ pod.status?.conditions.push({
type: "Ready",
status: "foobar",
lastProbeTime: 1,
@@ -266,7 +269,7 @@ describe("Pods", () => {
it("should return false if a condition is non-ready", () => {
const pod = getDummyPod({ running: 1 });
- pod.status.conditions.push({
+ pod.status?.conditions.push({
type: "dummy",
status: "foobar",
lastProbeTime: 1,
@@ -278,8 +281,11 @@ describe("Pods", () => {
it("should return true if a current container is in a crash loop back off", () => {
const pod = getDummyPod({ running: 1 });
+ const firstStatus = pod.status?.containerStatuses?.[0];
- pod.status.containerStatuses[0].state = {
+ assert(firstStatus);
+
+ firstStatus.state = {
waiting: {
reason: "CrashLookBackOff",
message: "too much foobar",
@@ -292,6 +298,8 @@ describe("Pods", () => {
it("should return true if a current phase isn't running", () => {
const pod = getDummyPod({ running: 1 });
+ assert(pod.status);
+
pod.status.phase = "not running";
expect(pod.hasIssues()).toStrictEqual(true);
@@ -300,6 +308,8 @@ describe("Pods", () => {
it("should return false if a current phase is running", () => {
const pod = getDummyPod({ running: 1 });
+ assert(pod.status);
+
pod.status.phase = "Running";
expect(pod.hasIssues()).toStrictEqual(false);
diff --git a/src/common/k8s-api/__tests__/stateful-set.api.test.ts b/src/common/k8s-api/__tests__/stateful-set.api.test.ts
index 624a852c9d..b7557c8010 100644
--- a/src/common/k8s-api/__tests__/stateful-set.api.test.ts
+++ b/src/common/k8s-api/__tests__/stateful-set.api.test.ts
@@ -3,31 +3,39 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { StatefulSet, StatefulSetApi } from "../endpoints/stateful-set.api";
+import storesAndApisCanBeCreatedInjectable from "../../../renderer/stores-apis-can-be-created.injectable";
+import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
+import apiKubeInjectable from "../../../renderer/k8s/api-kube.injectable";
+import type { StatefulSetApi } from "../endpoints";
+import statefulSetApiInjectable from "../endpoints/stateful-set.api.injectable";
import type { KubeJsonApi } from "../kube-json-api";
-class StatefulSetApiTest extends StatefulSetApi {
- public setRequest(request: any) {
- this.request = request;
- }
-}
-
describe("StatefulSetApi", () => {
+ let statefulSetApi: StatefulSetApi;
+ let kubeJsonApi: jest.Mocked;
+
+ beforeEach(() => {
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ di.override(storesAndApisCanBeCreatedInjectable, () => true);
+ kubeJsonApi = {
+ getResponse: jest.fn(),
+ get: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ patch: jest.fn(),
+ del: jest.fn(),
+ } as never;
+ di.override(apiKubeInjectable, () => kubeJsonApi);
+
+ statefulSetApi = di.inject(statefulSetApiInjectable);
+ });
+
describe("scale", () => {
- const requestMock = {
- patch: () => ({}),
- } as unknown as KubeJsonApi;
-
- const sub = new StatefulSetApiTest({ objectConstructor: StatefulSet });
-
- sub.setRequest(requestMock);
-
it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => {
- const patchSpy = jest.spyOn(requestMock, "patch");
+ statefulSetApi.scale({ namespace: "default", name: "statefulset-1" }, 5);
- sub.scale({ namespace: "default", name: "statefulset-1" }, 5);
-
- expect(patchSpy).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale", {
+ expect(kubeJsonApi.patch).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale", {
data: {
spec: {
replicas: 5,
diff --git a/src/common/k8s-api/api-kube.ts b/src/common/k8s-api/api-kube.ts
index 5ff8478694..4154ec2f00 100644
--- a/src/common/k8s-api/api-kube.ts
+++ b/src/common/k8s-api/api-kube.ts
@@ -3,18 +3,12 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { isClusterPageContext } from "../utils";
-import { KubeJsonApi } from "./kube-json-api";
-import { apiKubePrefix, isDevelopment } from "../vars";
+import { getInjectionToken } from "@ogre-tools/injectable";
+import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
+import type { KubeJsonApi } from "./kube-json-api";
-export const apiKube = isClusterPageContext()
- ? new KubeJsonApi({
- serverAddress: `http://127.0.0.1:${window.location.port}`,
- apiBase: apiKubePrefix,
- debug: isDevelopment,
- }, {
- headers: {
- "Host": window.location.host,
- },
- })
- : undefined;
+export const apiKubeInjectionToken = getInjectionToken({
+ id: "api-kube-injection-token",
+});
+
+export const apiKube = asLegacyGlobalForExtensionApi(apiKubeInjectionToken);
diff --git a/src/common/k8s-api/api-manager.ts b/src/common/k8s-api/api-manager.ts
deleted file mode 100644
index b2d5021337..0000000000
--- a/src/common/k8s-api/api-manager.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * Copyright (c) OpenLens Authors. All rights reserved.
- * Licensed under MIT License. See LICENSE in root directory for more information.
- */
-
-import type { KubeObjectStore } from "./kube-object.store";
-
-import { action, observable, makeObservable } from "mobx";
-import { autoBind, iter } from "../utils";
-import type { KubeApi } from "./kube-api";
-import type { KubeObject } from "./kube-object";
-import type { IKubeObjectRef } from "./kube-api-parse";
-import { parseKubeApi, createKubeApiURL } from "./kube-api-parse";
-
-export class ApiManager {
- private apis = observable.map>();
- private stores = observable.map>();
-
- constructor() {
- makeObservable(this);
- autoBind(this);
- }
-
- getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) {
- if (typeof pathOrCallback === "string") {
- return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase);
- }
-
- return iter.find(this.apis.values(), pathOrCallback ?? (() => true));
- }
-
- getApiByKind(kind: string, apiVersion: string) {
- return iter.find(this.apis.values(), api => api.kind === kind && api.apiVersionWithGroup === apiVersion);
- }
-
- registerApi(apiBase: string, api: KubeApi) {
- if (!api.apiBase) return;
-
- if (!this.apis.has(apiBase)) {
- this.stores.forEach((store) => {
- if (store.api === api) {
- this.stores.set(apiBase, store);
- }
- });
-
- this.apis.set(apiBase, api);
- }
- }
-
- protected resolveApi(api?: string | KubeApi): KubeApi | undefined {
- if (!api) {
- return undefined;
- }
-
- if (typeof api === "string") {
- return this.getApi(api) as KubeApi;
- }
-
- return api;
- }
-
- unregisterApi(api: string | KubeApi) {
- if (typeof api === "string") this.apis.delete(api);
- else {
- const apis = Array.from(this.apis.entries());
- const entry = apis.find(entry => entry[1] === api);
-
- if (entry) this.unregisterApi(entry[0]);
- }
- }
-
- @action
- registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) {
- apis.filter(Boolean).forEach(api => {
- if (api.apiBase) this.stores.set(api.apiBase, store);
- });
- }
-
- getStore>(api: string | KubeApi): S | undefined {
- return this.stores.get(this.resolveApi(api)?.apiBase) as S;
- }
-
- lookupApiLink(ref: IKubeObjectRef, parentObject?: KubeObject): string {
- const {
- kind, apiVersion, name,
- namespace = parentObject?.getNs(),
- } = ref;
-
- if (!kind) return "";
-
- // search in registered apis by 'kind' & 'apiVersion'
- const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);
-
- if (api) {
- return api.getUrl({ namespace, name });
- }
-
- // lookup api by generated resource link
- const apiPrefixes = ["/apis", "/api"];
- const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;
-
- for (const apiPrefix of apiPrefixes) {
- const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });
-
- if (this.getApi(apiLink)) {
- return apiLink;
- }
- }
-
- // resolve by kind only (hpa's might use refs to older versions of resources for example)
- const apiByKind = this.getApi(api => api.kind === kind);
-
- if (apiByKind) {
- return apiByKind.getUrl({ name, namespace });
- }
-
- // otherwise generate link with default prefix
- // resource still might exists in k8s, but api is not registered in the app
- return createKubeApiURL({ apiVersion, name, namespace, resource });
- }
-}
-
-export const apiManager = new ApiManager();
diff --git a/src/common/k8s-api/api-manager/api-manager.ts b/src/common/k8s-api/api-manager/api-manager.ts
new file mode 100644
index 0000000000..080ccb671a
--- /dev/null
+++ b/src/common/k8s-api/api-manager/api-manager.ts
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { KubeObjectStore } from "../kube-object.store";
+
+import { action, observable, makeObservable } from "mobx";
+import { autoBind, isDefined, iter } from "../../utils";
+import type { KubeApi } from "../kube-api";
+import type { KubeJsonApiDataFor, KubeObject, ObjectReference } from "../kube-object";
+import { parseKubeApi, createKubeApiURL } from "../kube-api-parse";
+
+export type RegisterableStore = Store extends KubeObjectStore
+ ? Store
+ : never;
+export type RegisterableApi = Api extends KubeApi
+ ? Api
+ : never;
+export type KubeObjectStoreFrom = Api extends KubeApi
+ ? KubeObjectStore
+ : never;
+
+export class ApiManager {
+ private readonly apis = observable.map();
+ private readonly stores = observable.map();
+
+ constructor() {
+ makeObservable(this);
+ autoBind(this);
+ }
+
+ getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) {
+ if (typeof pathOrCallback === "string") {
+ return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase);
+ }
+
+ return iter.find(this.apis.values(), pathOrCallback ?? (() => true));
+ }
+
+ getApiByKind(kind: string, apiVersion: string) {
+ return iter.find(this.apis.values(), api => api.kind === kind && api.apiVersionWithGroup === apiVersion);
+ }
+
+ registerApi(api: RegisterableApi): void;
+ /**
+ * @deprecated Just register the `api` by itself
+ */
+ registerApi(apiBase: string, api: RegisterableApi): void;
+ registerApi(apiBaseRaw: string | RegisterableApi, apiRaw?: RegisterableApi) {
+ const api = typeof apiBaseRaw === "string"
+ ? apiRaw
+ : apiBaseRaw;
+
+ if (!api?.apiBase) {
+ return;
+ }
+
+ if (!this.apis.has(api.apiBase)) {
+ this.stores.forEach((store) => {
+ if (store.api === api) {
+ this.stores.set(api.apiBase, store);
+ }
+ });
+
+ this.apis.set(api.apiBase, api);
+ }
+ }
+
+ protected resolveApi(api: undefined | string | KubeApi): KubeApi | undefined {
+ if (!api) {
+ return undefined;
+ }
+
+ if (typeof api === "string") {
+ return this.getApi(api);
+ }
+
+ return api;
+ }
+
+ unregisterApi(api: string | KubeApi) {
+ if (typeof api === "string") this.apis.delete(api);
+ else {
+ const apis = Array.from(this.apis.entries());
+ const entry = apis.find(entry => entry[1] === api);
+
+ if (entry) this.unregisterApi(entry[0]);
+ }
+ }
+
+ registerStore(store: RegisterableStore): void;
+ /**
+ * @deprecated KubeObjectStore's should only every be about a single KubeApi type
+ */
+ registerStore(store: KubeObjectStore, KubeJsonApiDataFor>, apis: KubeApi[]): void;
+
+ @action
+ registerStore(store: KubeObjectStore, KubeJsonApiDataFor>, apis: KubeApi[] = [store.api]): void {
+ for (const api of apis.filter(isDefined)) {
+ if (api.apiBase) {
+ this.stores.set(api.apiBase, store as never);
+ }
+ }
+ }
+
+ getStore(api: string | undefined): KubeObjectStore | undefined;
+ getStore(api: RegisterableApi): KubeObjectStoreFrom | undefined;
+ /**
+ * @deprecated use an actual cast instead of hiding it with this unused type param
+ */
+ getStore(api: string | KubeApi): Store | undefined ;
+ getStore(api: string | KubeApi | undefined): KubeObjectStore | undefined {
+ const { apiBase } = this.resolveApi(api) ?? {};
+
+ if (apiBase) {
+ return this.stores.get(apiBase);
+ }
+
+ return undefined;
+ }
+
+ lookupApiLink(ref: ObjectReference, parentObject?: KubeObject): string {
+ const {
+ kind, apiVersion = "v1", name,
+ namespace = parentObject?.getNs(),
+ } = ref;
+
+ if (!kind) return "";
+
+ // search in registered apis by 'kind' & 'apiVersion'
+ const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);
+
+ if (api) {
+ return api.getUrl({ namespace, name });
+ }
+
+ // lookup api by generated resource link
+ const apiPrefixes = ["/apis", "/api"];
+ const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;
+
+ for (const apiPrefix of apiPrefixes) {
+ const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });
+
+ if (this.getApi(apiLink)) {
+ return apiLink;
+ }
+ }
+
+ // resolve by kind only (hpa's might use refs to older versions of resources for example)
+ const apiByKind = this.getApi(api => api.kind === kind);
+
+ if (apiByKind) {
+ return apiByKind.getUrl({ name, namespace });
+ }
+
+ // otherwise generate link with default prefix
+ // resource still might exists in k8s, but api is not registered in the app
+ return createKubeApiURL({ apiVersion, name, namespace, resource });
+ }
+}
diff --git a/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts b/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts
new file mode 100644
index 0000000000..d9a68a988c
--- /dev/null
+++ b/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts
@@ -0,0 +1,27 @@
+/**
+ * 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 EventEmitter from "events";
+import type TypedEventEmitter from "typed-emitter";
+import type { CustomResourceDefinition } from "../endpoints";
+import type { KubeApi } from "../kube-api";
+
+export interface LegacyAutoRegistration {
+ customResourceDefinition: (crd: CustomResourceDefinition) => void;
+ kubeApi: (api: KubeApi) => void;
+}
+
+/**
+ * This is used to remove dependency cycles from auto registering of instances
+ *
+ * - Custom Resource Definitions get their own registered store (will need in the future)
+ * - All KubeApi's get auto registered (this should be changed in the future)
+ */
+const autoRegistrationEmitterInjectable = getInjectable({
+ id: "auto-registration-emitter",
+ instantiate: (): TypedEventEmitter => new EventEmitter(),
+});
+
+export default autoRegistrationEmitterInjectable;
diff --git a/src/common/k8s-api/api-manager/auto-registration.injectable.ts b/src/common/k8s-api/api-manager/auto-registration.injectable.ts
new file mode 100644
index 0000000000..0cf1a3055d
--- /dev/null
+++ b/src/common/k8s-api/api-manager/auto-registration.injectable.ts
@@ -0,0 +1,74 @@
+/**
+ * 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 type { CustomResourceDefinition } from "../endpoints";
+import { KubeApi } from "../kube-api";
+import { KubeObject } from "../kube-object";
+import autoRegistrationEmitterInjectable from "./auto-registration-emitter.injectable";
+import apiManagerInjectable from "./manager.injectable";
+import { CustomResourceStore } from "./resource.store";
+
+const autoRegistrationInjectable = getInjectable({
+ id: "api-manager-auto-registration",
+ instantiate: (di) => {
+ const autoRegistrationEmitter = di.inject(autoRegistrationEmitterInjectable);
+ const beforeApiManagerInitializationCrds: CustomResourceDefinition[] = [];
+ const beforeApiManagerInitializationApis: KubeApi[] = [];
+ let initialized = false;
+
+ const autoInitCustomResourceStore = (crd: CustomResourceDefinition) => {
+ const objectConstructor = class extends KubeObject {
+ static readonly kind = crd.getResourceKind();
+ static readonly namespaced = crd.isNamespaced();
+ static readonly apiBase = crd.getResourceApiBase();
+ };
+
+ const api = (() => {
+ const rawApi = apiManager.getApi(objectConstructor.apiBase);
+
+ if (rawApi) {
+ return rawApi;
+ }
+
+ const api = new KubeApi({ objectConstructor });
+
+ apiManager.registerApi(api);
+
+ return api;
+ })();
+
+ if (!apiManager.getStore(api)) {
+ apiManager.registerStore(new CustomResourceStore(api));
+ }
+ };
+ const autoInitKubeApi = (api: KubeApi) => {
+ apiManager.registerApi(api);
+ };
+
+ autoRegistrationEmitter
+ .on("customResourceDefinition", (crd) => {
+ if (initialized) {
+ autoInitCustomResourceStore(crd);
+ } else {
+ beforeApiManagerInitializationCrds.push(crd);
+ }
+ })
+ .on("kubeApi", (api) => {
+ if (initialized) {
+ autoInitKubeApi(api);
+ } else {
+ beforeApiManagerInitializationApis.push(api);
+ }
+ });
+
+ const apiManager = di.inject(apiManagerInjectable);
+
+ beforeApiManagerInitializationCrds.forEach(autoInitCustomResourceStore);
+ beforeApiManagerInitializationApis.forEach(autoInitKubeApi);
+ initialized = true;
+ },
+});
+
+export default autoRegistrationInjectable;
diff --git a/src/preload.ts b/src/common/k8s-api/api-manager/index.ts
similarity index 73%
rename from src/preload.ts
rename to src/common/k8s-api/api-manager/index.ts
index 64188789ea..56182e815b 100644
--- a/src/preload.ts
+++ b/src/common/k8s-api/api-manager/index.ts
@@ -3,8 +3,4 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import fetch from "node-fetch";
-
-export {
- fetch,
-};
+export * from "./api-manager";
diff --git a/src/common/k8s-api/api-manager/manager.injectable.ts b/src/common/k8s-api/api-manager/manager.injectable.ts
new file mode 100644
index 0000000000..45188cec7a
--- /dev/null
+++ b/src/common/k8s-api/api-manager/manager.injectable.ts
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import type { KubeObjectStore } from "../kube-object.store";
+import { ApiManager } from "./api-manager";
+
+export const kubeObjectStoreInjectionToken = getInjectionToken>({
+ id: "kube-object-store-token",
+});
+
+const apiManagerInjectable = getInjectable({
+ id: "api-manager",
+ instantiate: (di) => {
+ const apiManager = new ApiManager();
+
+ if (di.inject(storesAndApisCanBeCreatedInjectionToken)) {
+ const stores = di.injectMany(kubeObjectStoreInjectionToken);
+
+ for (const store of stores) {
+ apiManager.registerStore(store);
+ }
+ }
+
+ return apiManager;
+ },
+});
+
+export default apiManagerInjectable;
diff --git a/src/common/k8s-api/api-manager/resource.store.ts b/src/common/k8s-api/api-manager/resource.store.ts
new file mode 100644
index 0000000000..63ccdcf93d
--- /dev/null
+++ b/src/common/k8s-api/api-manager/resource.store.ts
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { KubeApi } from "../kube-api";
+import { KubeObjectStore } from "../kube-object.store";
+import type { KubeObject } from "../kube-object";
+
+export class CustomResourceStore extends KubeObjectStore> {
+ constructor(api: KubeApi) {
+ super(api);
+ }
+}
diff --git a/src/common/k8s-api/cluster-context.ts b/src/common/k8s-api/cluster-context.ts
index b85d8f74c5..098d92642d 100644
--- a/src/common/k8s-api/cluster-context.ts
+++ b/src/common/k8s-api/cluster-context.ts
@@ -6,7 +6,7 @@
import type { Cluster } from "../cluster/cluster";
export interface ClusterContext {
- cluster?: Cluster;
+ cluster: Cluster;
allNamespaces: string[]; // available / allowed namespaces from cluster.ts
contextNamespaces: string[]; // selected by user (see: namespace-select.tsx)
hasSelectedAll: boolean;
diff --git a/src/common/k8s-api/endpoints/cluster-role-binding.api.injectable.ts b/src/common/k8s-api/endpoints/cluster-role-binding.api.injectable.ts
new file mode 100644
index 0000000000..c06f3baaff
--- /dev/null
+++ b/src/common/k8s-api/endpoints/cluster-role-binding.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { ClusterRoleBindingApi } from "./cluster-role-binding.api";
+
+const clusterRoleBindingApiInjectable = getInjectable({
+ id: "cluster-role-binding-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "clusterRoleBindingApi is only accessible in certain environments");
+
+ return new ClusterRoleBindingApi();
+ },
+});
+
+export default clusterRoleBindingApiInjectable;
diff --git a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts
index b6e6a517ae..52449be8a3 100644
--- a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts
+++ b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts
@@ -2,35 +2,39 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
+import type { KubeJsonApiData } from "../kube-json-api";
+import type { KubeObjectMetadata, KubeObjectScope } from "../kube-object";
import { KubeObject } from "../kube-object";
+import type { RoleRef } from "./types/role-ref";
+import type { Subject } from "./types/subject";
-export type ClusterRoleBindingSubjectKind = "Group" | "ServiceAccount" | "User";
-
-export interface ClusterRoleBindingSubject {
- kind: ClusterRoleBindingSubjectKind;
- name: string;
- apiGroup?: string;
- namespace?: string;
+export interface ClusterRoleBindingData extends KubeJsonApiData, void, void> {
+ subjects?: Subject[];
+ roleRef: RoleRef;
}
-export interface ClusterRoleBinding {
- subjects?: ClusterRoleBindingSubject[];
- roleRef: {
- kind: string;
- name: string;
- apiGroup?: string;
- };
-}
-
-export class ClusterRoleBinding extends KubeObject {
+export class ClusterRoleBinding extends KubeObject {
static kind = "ClusterRoleBinding";
static namespaced = false;
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings";
+ subjects?: Subject[];
+ roleRef: RoleRef;
+
+ constructor({
+ subjects,
+ roleRef,
+ ...rest
+ }: ClusterRoleBindingData) {
+ super(rest);
+ this.subjects = subjects;
+ this.roleRef = roleRef;
+ }
+
getSubjects() {
- return this.subjects || [];
+ return this.subjects ?? [];
}
getSubjectNames(): string {
@@ -38,17 +42,11 @@ export class ClusterRoleBinding extends KubeObject {
}
}
-/**
- * Only available within kubernetes cluster pages
- */
-let clusterRoleBindingApi: KubeApi;
-
-if (isClusterPageContext()) {
- clusterRoleBindingApi = new KubeApi({
- objectConstructor: ClusterRoleBinding,
- });
+export class ClusterRoleBindingApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: ClusterRoleBinding,
+ });
+ }
}
-
-export {
- clusterRoleBindingApi,
-};
diff --git a/src/common/k8s-api/endpoints/cluster-role.api.injectable.ts b/src/common/k8s-api/endpoints/cluster-role.api.injectable.ts
new file mode 100644
index 0000000000..19a8f83542
--- /dev/null
+++ b/src/common/k8s-api/endpoints/cluster-role.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { ClusterRoleApi } from "./cluster-role.api";
+
+const clusterRoleApiInjectable = getInjectable({
+ id: "cluster-role-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "clusterRoleApi is only available in certain environments");
+
+ return new ClusterRoleApi();
+ },
+});
+
+export default clusterRoleApiInjectable;
diff --git a/src/common/k8s-api/endpoints/cluster-role.api.ts b/src/common/k8s-api/endpoints/cluster-role.api.ts
index 70a5ef05e8..ff9503f231 100644
--- a/src/common/k8s-api/endpoints/cluster-role.api.ts
+++ b/src/common/k8s-api/endpoints/cluster-role.api.ts
@@ -3,40 +3,43 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
+import type { KubeJsonApiData } from "../kube-json-api";
+import type { KubeObjectMetadata, KubeObjectScope } from "../kube-object";
import { KubeObject } from "../kube-object";
+import type { AggregationRule } from "./types/aggregation-rule";
+import type { PolicyRule } from "./types/policy-rule";
-export interface ClusterRole {
- rules: {
- verbs: string[];
- apiGroups: string[];
- resources: string[];
- resourceNames?: string[];
- }[];
+export interface ClusterRoleData extends KubeJsonApiData, void, void> {
+ rules?: PolicyRule[];
+ aggregationRule?: AggregationRule;
}
-export class ClusterRole extends KubeObject {
+export class ClusterRole extends KubeObject {
static kind = "ClusterRole";
static namespaced = false;
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles";
+ rules?: PolicyRule[];
+ aggregationRule?: AggregationRule;
+
+ constructor({ rules, aggregationRule, ...rest }: ClusterRoleData) {
+ super(rest);
+ this.rules = rules;
+ this.aggregationRule = aggregationRule;
+ }
+
getRules() {
return this.rules || [];
}
}
-/**
- * Only available within kubernetes cluster pages
- */
-let clusterRoleApi: KubeApi;
-
-if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context
- clusterRoleApi = new KubeApi({
- objectConstructor: ClusterRole,
- });
+export class ClusterRoleApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: ClusterRole,
+ });
+ }
}
-
-export {
- clusterRoleApi,
-};
diff --git a/src/common/k8s-api/endpoints/cluster.api.injectable.ts b/src/common/k8s-api/endpoints/cluster.api.injectable.ts
new file mode 100644
index 0000000000..fd82ae93f3
--- /dev/null
+++ b/src/common/k8s-api/endpoints/cluster.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { ClusterApi } from "./cluster.api";
+
+const clusterApiInjectable = getInjectable({
+ id: "cluster-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "clusterApi is only available in certain environments");
+
+ return new ClusterApi();
+ },
+});
+
+export default clusterApiInjectable;
diff --git a/src/common/k8s-api/endpoints/cluster.api.ts b/src/common/k8s-api/endpoints/cluster.api.ts
index 377fb47207..53e12800b0 100644
--- a/src/common/k8s-api/endpoints/cluster.api.ts
+++ b/src/common/k8s-api/endpoints/cluster.api.ts
@@ -3,18 +3,25 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import type { IMetrics, IMetricsReqParams } from "./metrics.api";
+import type { MetricData, IMetricsReqParams } from "./metrics.api";
import { metricsApi } from "./metrics.api";
import { KubeObject } from "../kube-object";
+import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
export class ClusterApi extends KubeApi {
static kind = "Cluster";
static namespaced = true;
+
+ constructor(opts: DerivedKubeApiOptions & IgnoredKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: Cluster,
+ });
+ }
}
-export function getMetricsByNodeNames(nodeNames: string[], params?: IMetricsReqParams): Promise {
+export function getMetricsByNodeNames(nodeNames: string[], params?: IMetricsReqParams): Promise {
const nodes = nodeNames.join("|");
const opts = { category: "cluster", nodes };
@@ -45,20 +52,19 @@ export enum ClusterStatus {
ERROR = "Error",
}
-export interface IClusterMetrics {
- [metric: string]: T;
- memoryUsage: T;
- memoryRequests: T;
- memoryLimits: T;
- memoryCapacity: T;
- cpuUsage: T;
- cpuRequests: T;
- cpuLimits: T;
- cpuCapacity: T;
- podUsage: T;
- podCapacity: T;
- fsSize: T;
- fsUsage: T;
+export interface ClusterMetricData extends Partial> {
+ memoryUsage: MetricData;
+ memoryRequests: MetricData;
+ memoryLimits: MetricData;
+ memoryCapacity: MetricData;
+ cpuUsage: MetricData;
+ cpuRequests: MetricData;
+ cpuLimits: MetricData;
+ cpuCapacity: MetricData;
+ podUsage: MetricData;
+ podCapacity: MetricData;
+ fsSize: MetricData;
+ fsUsage: MetricData;
}
export interface Cluster {
@@ -107,18 +113,3 @@ export class Cluster extends KubeObject {
return ClusterStatus.ACTIVE;
}
}
-
-/**
- * Only available within kubernetes cluster pages
- */
-let clusterApi: ClusterApi;
-
-if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context
- clusterApi = new ClusterApi({
- objectConstructor: Cluster,
- });
-}
-
-export {
- clusterApi,
-};
diff --git a/src/common/k8s-api/endpoints/component-status.api.injectable.ts b/src/common/k8s-api/endpoints/component-status.api.injectable.ts
new file mode 100644
index 0000000000..fbe4b7f176
--- /dev/null
+++ b/src/common/k8s-api/endpoints/component-status.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { ComponentStatusApi } from "./component-status.api";
+
+const componentStatusApiInjectable = getInjectable({
+ id: "component-status-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "componentStatusApi is only available in certain environments");
+
+ return new ComponentStatusApi();
+ },
+});
+
+export default componentStatusApiInjectable;
diff --git a/src/common/k8s-api/endpoints/component-status.api.ts b/src/common/k8s-api/endpoints/component-status.api.ts
index 30f272400a..5335207b71 100644
--- a/src/common/k8s-api/endpoints/component-status.api.ts
+++ b/src/common/k8s-api/endpoints/component-status.api.ts
@@ -4,16 +4,17 @@
*/
import { KubeObject } from "../kube-object";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
-export interface IComponentStatusCondition {
+export interface ComponentStatusCondition {
type: string;
status: string;
message: string;
}
export interface ComponentStatus {
- conditions: IComponentStatusCondition[];
+ conditions: ComponentStatusCondition[];
}
export class ComponentStatus extends KubeObject {
@@ -26,6 +27,11 @@ export class ComponentStatus extends KubeObject {
}
}
-export const componentStatusApi = new KubeApi({
- objectConstructor: ComponentStatus,
-});
+export class ComponentStatusApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: ComponentStatus,
+ });
+ }
+}
diff --git a/src/common/k8s-api/endpoints/config-map.api.injectable.ts b/src/common/k8s-api/endpoints/config-map.api.injectable.ts
new file mode 100644
index 0000000000..715e1ba728
--- /dev/null
+++ b/src/common/k8s-api/endpoints/config-map.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { ConfigMapApi } from "./config-map.api";
+
+const configMapApiInjectable = getInjectable({
+ id: "config-map-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "configMapApi is only available in certain environments");
+
+ return new ConfigMapApi();
+ },
+});
+
+export default configMapApiInjectable;
diff --git a/src/common/k8s-api/endpoints/config-map.api.ts b/src/common/k8s-api/endpoints/config-map.api.ts
new file mode 100644
index 0000000000..5577c690f7
--- /dev/null
+++ b/src/common/k8s-api/endpoints/config-map.api.ts
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { KubeObjectMetadata, KubeObjectScope } from "../kube-object";
+import { KubeObject } from "../kube-object";
+import type { KubeJsonApiData } from "../kube-json-api";
+import type { DerivedKubeApiOptions } from "../kube-api";
+import { KubeApi } from "../kube-api";
+import { autoBind } from "../../utils";
+
+export interface ConfigMapData extends KubeJsonApiData, void, void> {
+ data?: Partial>;
+ binaryData?: Partial>;
+ immutable?: boolean;
+}
+
+export class ConfigMap extends KubeObject {
+ static kind = "ConfigMap";
+ static namespaced = true;
+ static apiBase = "/api/v1/configmaps";
+
+ data: Partial>;
+ binaryData: Partial>;
+ immutable?: boolean;
+
+ constructor({ data, binaryData, immutable, ...rest }: ConfigMapData) {
+ super(rest);
+ autoBind(this);
+
+ this.data = data ?? {};
+ this.binaryData = binaryData ?? {};
+ this.immutable = immutable;
+ }
+
+ getKeys(): string[] {
+ return Object.keys(this.data);
+ }
+}
+
+export class ConfigMapApi extends KubeApi {
+ constructor(opts?: DerivedKubeApiOptions) {
+ super({
+ objectConstructor: ConfigMap,
+ ...opts ?? {},
+ });
+ }
+}
diff --git a/src/common/k8s-api/endpoints/configmap.api.ts b/src/common/k8s-api/endpoints/configmap.api.ts
deleted file mode 100644
index 82bbc47bf7..0000000000
--- a/src/common/k8s-api/endpoints/configmap.api.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) OpenLens Authors. All rights reserved.
- * Licensed under MIT License. See LICENSE in root directory for more information.
- */
-
-import { KubeObject } from "../kube-object";
-import type { KubeJsonApiData } from "../kube-json-api";
-import { KubeApi } from "../kube-api";
-import { autoBind } from "../../utils";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
-
-export interface ConfigMap {
- data: {
- [param: string]: string;
- };
-}
-
-export class ConfigMap extends KubeObject {
- static kind = "ConfigMap";
- static namespaced = true;
- static apiBase = "/api/v1/configmaps";
-
- constructor(data: KubeJsonApiData) {
- super(data);
- autoBind(this);
-
- this.data ??= {};
- }
-
- getKeys(): string[] {
- return Object.keys(this.data);
- }
-}
-
-/**
- * Only available within kubernetes cluster pages
- */
-let configMapApi: KubeApi;
-
-if (isClusterPageContext()) {
- configMapApi = new KubeApi({
- objectConstructor: ConfigMap,
- });
-}
-
-export {
- configMapApi,
-};
diff --git a/src/common/k8s-api/endpoints/cron-job.api.injectable.ts b/src/common/k8s-api/endpoints/cron-job.api.injectable.ts
new file mode 100644
index 0000000000..9390d5d4c8
--- /dev/null
+++ b/src/common/k8s-api/endpoints/cron-job.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { CronJobApi } from "./cron-job.api";
+
+const cronJobApiInjectable = getInjectable({
+ id: "cron-job-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "cronJobApi is only available in certain environments");
+
+ return new CronJobApi();
+ },
+});
+
+export default cronJobApiInjectable;
diff --git a/src/common/k8s-api/endpoints/cron-job.api.ts b/src/common/k8s-api/endpoints/cron-job.api.ts
index cf50780b0f..5c3dda4d7d 100644
--- a/src/common/k8s-api/endpoints/cron-job.api.ts
+++ b/src/common/k8s-api/endpoints/cron-job.api.ts
@@ -4,15 +4,21 @@
*/
import moment from "moment";
+import type { KubeObjectScope, ObjectReference } from "../kube-object";
import { KubeObject } from "../kube-object";
-import type { IPodContainer } from "./pods.api";
import { formatDuration } from "../../utils/formatDuration";
-import { autoBind } from "../../utils";
+import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
-import type { KubeJsonApiData } from "../kube-json-api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
+import type { JobTemplateSpec } from "./types/job-template-spec";
export class CronJobApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions & IgnoredKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: CronJob,
+ });
+ }
+
suspend(params: { namespace: string; name: string }) {
return this.request.patch(this.getUrl(params), {
data: {
@@ -44,61 +50,33 @@ export class CronJobApi extends KubeApi {
}
}
-export interface CronJob {
- spec: {
- schedule: string;
- concurrencyPolicy: string;
- suspend: boolean;
- jobTemplate: {
- metadata: {
- creationTimestamp?: string;
- labels?: {
- [key: string]: string;
- };
- annotations?: {
- [key: string]: string;
- };
- };
- spec: {
- template: {
- metadata: {
- creationTimestamp?: string;
- };
- spec: {
- containers: IPodContainer[];
- restartPolicy: string;
- terminationGracePeriodSeconds: number;
- dnsPolicy: string;
- hostPID: boolean;
- schedulerName: string;
- };
- };
- };
- };
- successfulJobsHistoryLimit: number;
- failedJobsHistoryLimit: number;
- };
- status: {
- lastScheduleTime?: string;
- };
+export interface CronJobSpec {
+ concurrencyPolicy?: string;
+ failedJobsHistoryLimit?: number;
+ jobTemplate?: JobTemplateSpec;
+ schedule: string;
+ startingDeadlineSeconds?: number;
+ successfulJobsHistoryLimit?: number;
+ suspend?: boolean;
}
-export class CronJob extends KubeObject {
- static kind = "CronJob";
- static namespaced = true;
- static apiBase = "/apis/batch/v1beta1/cronjobs";
+export interface CronJobStatus {
+ lastScheduleTime?: string;
+ lastSuccessfulTime?: string;
+ active?: ObjectReference[];
+}
- constructor(data: KubeJsonApiData) {
- super(data);
- autoBind(this);
- }
+export class CronJob extends KubeObject {
+ static readonly kind = "CronJob";
+ static readonly namespaced = true;
+ static readonly apiBase = "/apis/batch/v1beta1/cronjobs";
getSuspendFlag() {
- return this.spec.suspend.toString();
+ return (this.spec.suspend ?? false).toString();
}
getLastScheduleTime() {
- if (!this.status.lastScheduleTime) return "-";
+ if (!this.status?.lastScheduleTime) return "-";
const diff = moment().diff(this.status.lastScheduleTime);
return formatDuration(diff, true);
@@ -124,18 +102,3 @@ export class CronJob extends KubeObject {
return this.spec.suspend;
}
}
-
-/**
- * Only available within kubernetes cluster pages
- */
-let cronJobApi: CronJobApi;
-
-if (isClusterPageContext()) {
- cronJobApi = new CronJobApi({
- objectConstructor: CronJob,
- });
-}
-
-export {
- cronJobApi,
-};
diff --git a/src/common/k8s-api/endpoints/custom-resource-definition.api.injectable.ts b/src/common/k8s-api/endpoints/custom-resource-definition.api.injectable.ts
new file mode 100644
index 0000000000..abe728850c
--- /dev/null
+++ b/src/common/k8s-api/endpoints/custom-resource-definition.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { CustomResourceDefinitionApi } from "./custom-resource-definition.api";
+
+const customResourceDefinitionApiInjectable = getInjectable({
+ id: "custom-resource-definition-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "customResourceDefinitionApi is only available in certain environments");
+
+ return new CustomResourceDefinitionApi();
+ },
+});
+
+export default customResourceDefinitionApiInjectable;
diff --git a/src/common/k8s-api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/custom-resource-definition.api.ts
similarity index 62%
rename from src/common/k8s-api/endpoints/crd.api.ts
rename to src/common/k8s-api/endpoints/custom-resource-definition.api.ts
index f668c819f3..90485a5ab8 100644
--- a/src/common/k8s-api/endpoints/crd.api.ts
+++ b/src/common/k8s-api/endpoints/custom-resource-definition.api.ts
@@ -3,19 +3,21 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import { KubeCreationError, KubeObject } from "../kube-object";
-import { KubeApi } from "../kube-api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
-import type { KubeJsonApiData } from "../kube-json-api";
import { getLegacyGlobalDiForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import customResourcesRouteInjectable from "../../front-end-routing/routes/cluster/custom-resources/custom-resources/custom-resources-route.injectable";
import { buildURL } from "../../utils/buildUrl";
+import type { BaseKubeObjectCondition, KubeObjectScope } from "../kube-object";
+import { KubeObject } from "../kube-object";
+import type { DerivedKubeApiOptions } from "../kube-api";
+import { KubeApi } from "../kube-api";
+import type { JSONSchemaProps } from "./types/json-schema-props";
interface AdditionalPrinterColumnsCommon {
name: string;
type: "integer" | "number" | "string" | "boolean" | "date";
- priority: number;
- description: string;
+ priority?: number;
+ format?: "int32" | "int64" | "float" | "double" | "byte" | "binary" | "date" | "date-time" | "password";
+ description?: string;
}
export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & {
@@ -26,80 +28,90 @@ type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
JSONPath: string;
};
-export interface CRDVersion {
+export interface CustomResourceValidation {
+ openAPIV3Schema?: JSONSchemaProps;
+}
+
+export interface CustomResourceDefinitionVersion {
name: string;
served: boolean;
storage: boolean;
- schema?: object; // required in v1 but not present in v1beta
+ schema?: CustomResourceValidation; // required in v1 but not present in v1beta
additionalPrinterColumns?: AdditionalPrinterColumnsV1[];
}
+export interface CustomResourceDefinitionNames {
+ categories?: string[];
+ kind: string;
+ listKind?: string;
+ plural: string;
+ shortNames?: string[];
+ singular?: string;
+}
+
+export interface CustomResourceConversion {
+ strategy?: string;
+ webhook?: WebhookConversion;
+}
+
+export interface WebhookConversion {
+ clientConfig?: WebhookClientConfig[];
+ conversionReviewVersions: string[];
+}
+
+export interface WebhookClientConfig {
+ caBundle?: string;
+ url?: string;
+ service?: ServiceReference;
+}
+
+export interface ServiceReference {
+ name: string;
+ namespace: string;
+ path?: string;
+ port?: number;
+}
+
export interface CustomResourceDefinitionSpec {
group: string;
/**
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
*/
version?: string;
- names: {
- plural: string;
- singular: string;
- kind: string;
- listKind: string;
- };
+ names: CustomResourceDefinitionNames;
scope: "Namespaced" | "Cluster";
/**
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
*/
validation?: object;
- versions?: CRDVersion[];
- conversion: {
- strategy?: string;
- webhook?: any;
- };
+ versions?: CustomResourceDefinitionVersion[];
+ conversion?: CustomResourceConversion;
/**
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
*/
additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[];
+ preserveUnknownFields?: boolean;
}
-export interface CustomResourceDefinition {
- spec: CustomResourceDefinitionSpec;
- status: {
- conditions: {
- lastTransitionTime: string;
- message: string;
- reason: string;
- status: string;
- type?: string;
- }[];
- acceptedNames: {
- plural: string;
- singular: string;
- kind: string;
- shortNames: string[];
- listKind: string;
- };
- storedVersions: string[];
- };
+export interface CustomResourceDefinitionConditionAcceptedNames {
+ plural: string;
+ singular: string;
+ kind: string;
+ shortNames: string[];
+ listKind: string;
}
-export interface CRDApiData extends KubeJsonApiData {
- spec: object; // TODO: make better
+export interface CustomResourceDefinitionStatus {
+ conditions?: BaseKubeObjectCondition[];
+ acceptedNames: CustomResourceDefinitionConditionAcceptedNames;
+ storedVersions: string[];
}
-export class CustomResourceDefinition extends KubeObject {
+export class CustomResourceDefinition extends KubeObject {
static kind = "CustomResourceDefinition";
static namespaced = false;
static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions";
- constructor(data: CRDApiData) {
- super(data);
-
- if (!data.spec || typeof data.spec !== "object") {
- throw new KubeCreationError("Cannot create a CustomResourceDefinition from an object without spec", data);
- }
- }
-
getResourceUrl() {
const di = getLegacyGlobalDiForExtensionApi();
@@ -141,12 +153,12 @@ export class CustomResourceDefinition extends KubeObject {
return this.spec.scope;
}
- getPreferedVersion(): CRDVersion {
+ getPreferedVersion(): CustomResourceDefinitionVersion {
const { apiVersion } = this;
switch (apiVersion) {
case "apiextensions.k8s.io/v1":
- for (const version of this.spec.versions) {
+ for (const version of this.spec.versions ?? []) {
if (version.storage) {
return version;
}
@@ -158,7 +170,8 @@ export class CustomResourceDefinition extends KubeObject {
const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath }));
return {
- name: this.spec.version,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ name: this.spec.version!,
served: true,
storage: true,
schema: this.spec.validation,
@@ -179,7 +192,7 @@ export class CustomResourceDefinition extends KubeObject {
}
getStoredVersions() {
- return this.status.storedVersions.join(", ");
+ return this.status?.storedVersions.join(", ") ?? "";
}
getNames() {
@@ -216,18 +229,12 @@ export class CustomResourceDefinition extends KubeObject {
}
}
-/**
- * Only available within kubernetes cluster pages
- */
-let crdApi: KubeApi;
-
-if (isClusterPageContext()) {
- crdApi = new KubeApi({
- objectConstructor: CustomResourceDefinition,
- checkPreferredVersion: true,
- });
+export class CustomResourceDefinitionApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ objectConstructor: CustomResourceDefinition,
+ checkPreferredVersion: true,
+ ...opts,
+ });
+ }
}
-
-export {
- crdApi,
-};
diff --git a/src/common/k8s-api/endpoints/daemon-set.api.injectable.ts b/src/common/k8s-api/endpoints/daemon-set.api.injectable.ts
new file mode 100644
index 0000000000..346742c996
--- /dev/null
+++ b/src/common/k8s-api/endpoints/daemon-set.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { DaemonSetApi } from "./daemon-set.api";
+
+const daemonSetApiInjectable = getInjectable({
+ id: "daemon-set-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "daemonSetApi is only available in certain environements");
+
+ return new DaemonSetApi();
+ },
+});
+
+export default daemonSetApiInjectable;
diff --git a/src/common/k8s-api/endpoints/daemon-set.api.ts b/src/common/k8s-api/endpoints/daemon-set.api.ts
index ad12b44931..449e021495 100644
--- a/src/common/k8s-api/endpoints/daemon-set.api.ts
+++ b/src/common/k8s-api/endpoints/daemon-set.api.ts
@@ -3,88 +3,91 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-import get from "lodash/get";
-import type { IAffinity } from "../workload-kube-object";
-import { WorkloadKubeObject } from "../workload-kube-object";
-import { autoBind } from "../../utils";
+import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
import { metricsApi } from "./metrics.api";
-import type { KubeJsonApiData } from "../kube-json-api";
-import type { IPodContainer, IPodMetrics } from "./pods.api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
-import type { LabelSelector } from "../kube-object";
+import type { PodMetricData } from "./pod.api";
+import type { KubeObjectScope, KubeObjectStatus, LabelSelector } from "../kube-object";
+import { KubeObject } from "../kube-object";
+import type { PodTemplateSpec } from "./types/pod-template-spec";
-export class DaemonSet extends WorkloadKubeObject {
+export interface RollingUpdateDaemonSet {
+ maxUnavailable?: number | string;
+ maxSurge?: number | string;
+}
+
+export interface DaemonSetUpdateStrategy {
+ type: string;
+ rollingUpdate: RollingUpdateDaemonSet;
+}
+
+export interface DaemonSetSpec {
+ selector: LabelSelector;
+ template: PodTemplateSpec;
+ updateStrategy: DaemonSetUpdateStrategy;
+ minReadySeconds?: number;
+ revisionHistoryLimit?: number;
+}
+
+export interface DaemonSetStatus extends KubeObjectStatus {
+ collisionCount?: number;
+ currentNumberScheduled: number;
+ desiredNumberScheduled: number;
+ numberAvailable?: number;
+ numberMisscheduled: number;
+ numberReady: number;
+ numberUnavailable?: number;
+ observedGeneration?: number;
+ updatedNumberScheduled?: number;
+}
+
+export class DaemonSet extends KubeObject {
static kind = "DaemonSet";
static namespaced = true;
static apiBase = "/apis/apps/v1/daemonsets";
- constructor(data: KubeJsonApiData) {
- super(data);
- autoBind(this);
+ getSelectors(): string[] {
+ return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
}
- declare spec: {
- selector: LabelSelector;
- template: {
- metadata: {
- creationTimestamp?: string;
- labels: {
- name: string;
- };
- };
- spec: {
- containers: IPodContainer[];
- initContainers?: IPodContainer[];
- restartPolicy: string;
- terminationGracePeriodSeconds: number;
- dnsPolicy: string;
- hostPID: boolean;
- affinity?: IAffinity;
- nodeSelector?: {
- [selector: string]: string;
- };
- securityContext: {};
- schedulerName: string;
- tolerations: {
- key: string;
- operator: string;
- effect: string;
- tolerationSeconds: number;
- }[];
- };
- };
- updateStrategy: {
- type: string;
- rollingUpdate: {
- maxUnavailable: number;
- };
- };
- revisionHistoryLimit: number;
- };
- declare status: {
- currentNumberScheduled: number;
- numberMisscheduled: number;
- desiredNumberScheduled: number;
- numberReady: number;
- observedGeneration: number;
- updatedNumberScheduled: number;
- numberAvailable: number;
- numberUnavailable: number;
- };
+ getNodeSelectors(): string[] {
+ return KubeObject.stringifyLabels(this.spec.template.spec?.nodeSelector);
+ }
+
+ getTemplateLabels(): string[] {
+ return KubeObject.stringifyLabels(this.spec.template.metadata?.labels);
+ }
+
+ getTolerations() {
+ return this.spec.template.spec?.tolerations ?? [];
+ }
+
+ getAffinity() {
+ return this.spec.template.spec?.affinity;
+ }
+
+ getAffinityNumber() {
+ return Object.keys(this.getAffinity() ?? {}).length;
+ }
getImages() {
- const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []);
- const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []);
+ const containers = this.spec.template?.spec?.containers ?? [];
+ const initContainers = this.spec.template?.spec?.initContainers ?? [];
return [...containers, ...initContainers].map(container => container.image);
}
}
export class DaemonSetApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions & IgnoredKubeApiOptions = {}) {
+ super({
+ ...opts,
+ objectConstructor: DaemonSet,
+ });
+ }
}
-export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: string, selector = ""): Promise {
+export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: string, selector = ""): Promise {
const podSelector = daemonsets.map(daemonset => `${daemonset.getName()}-[[:alnum:]]{5}`).join("|");
const opts = { category: "pods", pods: podSelector, namespace, selector };
@@ -100,18 +103,3 @@ export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: stri
namespace,
});
}
-
-/**
- * Only available within kubernetes cluster pages
- */
-let daemonSetApi: DaemonSetApi;
-
-if (isClusterPageContext()) {
- daemonSetApi = new DaemonSetApi({
- objectConstructor: DaemonSet,
- });
-}
-
-export {
- daemonSetApi,
-};
diff --git a/src/common/k8s-api/endpoints/deployment.api.injectable.ts b/src/common/k8s-api/endpoints/deployment.api.injectable.ts
new file mode 100644
index 0000000000..5b94d949aa
--- /dev/null
+++ b/src/common/k8s-api/endpoints/deployment.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { DeploymentApi } from "./deployment.api";
+
+const deploymentApiInjectable = getInjectable({
+ id: "deployment-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "deploymentApi is only available in certain environments");
+
+ return new DeploymentApi();
+ },
+});
+
+export default deploymentApiInjectable;
diff --git a/src/common/k8s-api/endpoints/deployment.api.ts b/src/common/k8s-api/endpoints/deployment.api.ts
index 324310fa74..c877669ba4 100644
--- a/src/common/k8s-api/endpoints/deployment.api.ts
+++ b/src/common/k8s-api/endpoints/deployment.api.ts
@@ -5,25 +5,34 @@
import moment from "moment";
-import type { IAffinity } from "../workload-kube-object";
-import { WorkloadKubeObject } from "../workload-kube-object";
-import { autoBind } from "../../utils";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
import { metricsApi } from "./metrics.api";
-import type { IPodMetrics } from "./pods.api";
-import type { KubeJsonApiData } from "../kube-json-api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
-import type { LabelSelector } from "../kube-object";
+import type { PodMetricData, PodSpec } from "./pod.api";
+import type { KubeObjectScope, KubeObjectStatus, LabelSelector } from "../kube-object";
+import { KubeObject } from "../kube-object";
+import { hasTypedProperty, isNumber, isObject } from "../../utils";
export class DeploymentApi extends KubeApi {
+ constructor(opts?: DerivedKubeApiOptions) {
+ super({
+ objectConstructor: Deployment,
+ ...opts ?? {},
+ });
+ }
+
protected getScaleApiUrl(params: { namespace: string; name: string }) {
return `${this.getUrl(params)}/scale`;
}
- getReplicas(params: { namespace: string; name: string }): Promise {
- return this.request
- .get(this.getScaleApiUrl(params))
- .then(({ status }: any) => status?.replicas);
+ async getReplicas(params: { namespace: string; name: string }): Promise {
+ const { status } = await this.request.get(this.getScaleApiUrl(params));
+
+ if (isObject(status) && hasTypedProperty(status, "replicas", isNumber)) {
+ return status.replicas;
+ }
+
+ return 0;
}
scale(params: { namespace: string; name: string }, replicas: number) {
@@ -61,7 +70,7 @@ export class DeploymentApi extends KubeApi {
}
}
-export function getMetricsForDeployments(deployments: Deployment[], namespace: string, selector = ""): Promise {
+export function getMetricsForDeployments(deployments: Deployment[], namespace: string, selector = ""): Promise {
const podSelector = deployments.map(deployment => `${deployment.getName()}-[[:alnum:]]{9,}-[[:alnum:]]{5}`).join("|");
const opts = { category: "pods", pods: podSelector, namespace, selector };
@@ -78,136 +87,66 @@ export function getMetricsForDeployments(deployments: Deployment[], namespace: s
});
}
-interface IContainerProbe {
- httpGet?: {
- path?: string;
- port: number;
- scheme: string;
- host?: string;
+export interface DeploymentSpec {
+ replicas: number;
+ selector: LabelSelector;
+ template: {
+ metadata: {
+ creationTimestamp?: string;
+ labels: Partial>;
+ annotations?: Partial>;
+ };
+ spec: PodSpec;
};
- exec?: {
- command: string[];
+ strategy: {
+ type: string;
+ rollingUpdate: {
+ maxUnavailable: number;
+ maxSurge: number;
+ };
};
- tcpSocket?: {
- port: number;
- };
- initialDelaySeconds?: number;
- timeoutSeconds?: number;
- periodSeconds?: number;
- successThreshold?: number;
- failureThreshold?: number;
}
-export class Deployment extends WorkloadKubeObject {
+export interface DeploymentStatus extends KubeObjectStatus {
+ observedGeneration: number;
+ replicas: number;
+ updatedReplicas: number;
+ readyReplicas: number;
+ availableReplicas?: number;
+ unavailableReplicas?: number;
+}
+
+export class Deployment extends KubeObject {
static kind = "Deployment";
static namespaced = true;
static apiBase = "/apis/apps/v1/deployments";
- constructor(data: KubeJsonApiData) {
- super(data);
- autoBind(this);
+ getSelectors(): string[] {
+ return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
}
- declare spec: {
- replicas: number;
- selector: LabelSelector;
- template: {
- metadata: {
- creationTimestamp?: string;
- labels: { [app: string]: string };
- annotations?: { [app: string]: string };
- };
- spec: {
- containers: {
- name: string;
- image: string;
- args?: string[];
- ports?: {
- name: string;
- containerPort: number;
- protocol: string;
- }[];
- env?: {
- name: string;
- value: string;
- }[];
- resources: {
- limits?: {
- cpu: string;
- memory: string;
- };
- requests: {
- cpu: string;
- memory: string;
- };
- };
- volumeMounts?: {
- name: string;
- mountPath: string;
- }[];
- livenessProbe?: IContainerProbe;
- readinessProbe?: IContainerProbe;
- startupProbe?: IContainerProbe;
- terminationMessagePath: string;
- terminationMessagePolicy: string;
- imagePullPolicy: string;
- }[];
- restartPolicy: string;
- terminationGracePeriodSeconds: number;
- dnsPolicy: string;
- affinity?: IAffinity;
- nodeSelector?: {
- [selector: string]: string;
- };
- serviceAccountName: string;
- serviceAccount: string;
- securityContext: {};
- schedulerName: string;
- tolerations?: {
- key: string;
- operator: string;
- effect: string;
- tolerationSeconds: number;
- }[];
- volumes?: {
- name: string;
- configMap: {
- name: string;
- defaultMode: number;
- optional: boolean;
- };
- }[];
- };
- };
- strategy: {
- type: string;
- rollingUpdate: {
- maxUnavailable: number;
- maxSurge: number;
- };
- };
- };
- declare status: {
- observedGeneration: number;
- replicas: number;
- updatedReplicas: number;
- readyReplicas: number;
- availableReplicas?: number;
- unavailableReplicas?: number;
- conditions: {
- type: string;
- status: string;
- lastUpdateTime: string;
- lastTransitionTime: string;
- reason: string;
- message: string;
- }[];
- };
+ getNodeSelectors(): string[] {
+ return KubeObject.stringifyLabels(this.spec.template.spec.nodeSelector);
+ }
+
+ getTemplateLabels(): string[] {
+ return KubeObject.stringifyLabels(this.spec.template.metadata.labels);
+ }
+
+ getTolerations() {
+ return this.spec.template.spec.tolerations ?? [];
+ }
+
+ getAffinity() {
+ return this.spec.template.spec.affinity;
+ }
+
+ getAffinityNumber() {
+ return Object.keys(this.getAffinity() ?? {}).length;
+ }
getConditions(activeOnly = false) {
- const { conditions } = this.status;
-
- if (!conditions) return [];
+ const { conditions = [] } = this.status ?? {};
if (activeOnly) {
return conditions.filter(c => c.status === "True");
@@ -217,22 +156,12 @@ export class Deployment extends WorkloadKubeObject {
}
getConditionsText(activeOnly = true) {
- return this.getConditions(activeOnly).map(({ type }) => type).join(" ");
+ return this.getConditions(activeOnly)
+ .map(({ type }) => type)
+ .join(" ");
}
getReplicas() {
return this.spec.replicas || 0;
}
}
-
-let deploymentApi: DeploymentApi;
-
-if (isClusterPageContext()) {
- deploymentApi = new DeploymentApi({
- objectConstructor: Deployment,
- });
-}
-
-export {
- deploymentApi,
-};
diff --git a/src/common/k8s-api/endpoints/endpoint.api.injectable.ts b/src/common/k8s-api/endpoints/endpoint.api.injectable.ts
new file mode 100644
index 0000000000..44a6595b6c
--- /dev/null
+++ b/src/common/k8s-api/endpoints/endpoint.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { EndpointsApi } from "./endpoint.api";
+
+const endpointsApiInjectable = getInjectable({
+ id: "endpoints-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "endpointsApi is only available in certain environments");
+
+ return new EndpointsApi();
+ },
+});
+
+export default endpointsApiInjectable;
diff --git a/src/common/k8s-api/endpoints/endpoint.api.ts b/src/common/k8s-api/endpoints/endpoint.api.ts
index 9e025eb158..38af0044a5 100644
--- a/src/common/k8s-api/endpoints/endpoint.api.ts
+++ b/src/common/k8s-api/endpoints/endpoint.api.ts
@@ -4,144 +4,114 @@
*/
import { autoBind } from "../../utils";
+import type { KubeObjectMetadata, KubeObjectScope, ObjectReference } from "../kube-object";
import { KubeObject } from "../kube-object";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
import type { KubeJsonApiData } from "../kube-json-api";
-import { get } from "lodash";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
-export interface IEndpointPort {
+export function formatEndpointSubset(subset: EndpointSubset): string {
+ const { addresses, ports } = subset;
+
+ if (!addresses || !ports) {
+ return "";
+ }
+
+ return addresses
+ .map(address => (
+ ports
+ .map(port => `${address.ip}:${port.port}`)
+ .join(", ")
+ ))
+ .join(", ");
+
+}
+
+export interface ForZone {
+ name: string;
+}
+
+export interface EndpointHints {
+ forZones?: ForZone[];
+}
+
+export interface EndpointConditions {
+ ready?: boolean;
+ serving?: boolean;
+ terminating?: boolean;
+}
+
+export interface EndpointData {
+ addresses: string[];
+ conditions?: EndpointConditions;
+ hints?: EndpointHints;
+ hostname?: string;
+ nodeName?: string;
+ targetRef?: ObjectReference;
+ zone?: string;
+}
+
+export interface EndpointPort {
+ appProtocol?: string;
name?: string;
- protocol: string;
+ protocol?: string;
port: number;
}
-export interface IEndpointAddress {
- hostname: string;
+export interface EndpointAddress {
+ hostname?: string;
ip: string;
- nodeName: string;
+ nodeName?: string;
+ targetRef?: ObjectReference;
}
-export interface IEndpointSubset {
- addresses: IEndpointAddress[];
- notReadyAddresses: IEndpointAddress[];
- ports: IEndpointPort[];
+export interface EndpointSubset {
+ addresses?: EndpointAddress[];
+ notReadyAddresses?: EndpointAddress[];
+ ports?: EndpointPort[];
}
-interface ITargetRef {
- kind: string;
- namespace: string;
- name: string;
- uid: string;
- resourceVersion: string;
- apiVersion: string;
+export interface EndpointsData extends KubeJsonApiData, void, void> {
+ subsets?: EndpointSubset[];
}
-export class EndpointAddress implements IEndpointAddress {
- hostname: string;
- ip: string;
- nodeName: string;
- targetRef?: {
- kind: string;
- namespace: string;
- name: string;
- uid: string;
- resourceVersion: string;
- };
-
- static create(data: IEndpointAddress): EndpointAddress {
- return new EndpointAddress(data);
- }
-
- constructor(data: IEndpointAddress) {
- Object.assign(this, data);
- }
-
- getId() {
- return this.ip;
- }
-
- getName() {
- return this.hostname;
- }
-
- getTargetRef(): ITargetRef {
- if (this.targetRef) {
- return Object.assign(this.targetRef, { apiVersion: "v1" });
- } else {
- return null;
- }
- }
-}
-
-export class EndpointSubset implements IEndpointSubset {
- addresses: IEndpointAddress[];
- notReadyAddresses: IEndpointAddress[];
- ports: IEndpointPort[];
-
- constructor(data: IEndpointSubset) {
- this.addresses = get(data, "addresses", []);
- this.notReadyAddresses = get(data, "notReadyAddresses", []);
- this.ports = get(data, "ports", []);
- }
-
- getAddresses(): EndpointAddress[] {
- return this.addresses.map(EndpointAddress.create);
- }
-
- getNotReadyAddresses(): EndpointAddress[] {
- return this.notReadyAddresses.map(EndpointAddress.create);
- }
-
- toString(): string {
- return this.addresses
- .map(address => (
- this.ports
- .map(port => `${address.ip}:${port.port}`)
- .join(", ")
- ))
- .join(", ");
- }
-}
-
-export interface Endpoint {
- subsets: IEndpointSubset[];
-}
-
-export class Endpoint extends KubeObject {
+export class Endpoints extends KubeObject {
static kind = "Endpoints";
static namespaced = true;
static apiBase = "/api/v1/endpoints";
- constructor(data: KubeJsonApiData) {
- super(data);
+ subsets?: EndpointSubset[];
+
+ constructor({ subsets, ...rest }: EndpointsData) {
+ super(rest);
autoBind(this);
+ this.subsets = subsets;
}
- getEndpointSubsets(): EndpointSubset[] {
- const subsets = this.subsets || [];
-
- return subsets.map(s => new EndpointSubset(s));
+ getEndpointSubsets(): Required[] {
+ return this.subsets?.map(({
+ addresses = [],
+ notReadyAddresses = [],
+ ports = [],
+ }) => ({
+ addresses,
+ notReadyAddresses,
+ ports,
+ })) ?? [];
}
toString(): string {
- if(this.subsets) {
- return this.getEndpointSubsets().map(es => es.toString()).join(", ");
- } else {
- return "";
- }
+ return this.getEndpointSubsets()
+ .map(formatEndpointSubset)
+ .join(", ") || "";
}
-
}
-let endpointApi: KubeApi;
-
-if (isClusterPageContext()) {
- endpointApi = new KubeApi({
- objectConstructor: Endpoint,
- });
+export class EndpointsApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ objectConstructor: Endpoints,
+ ...opts,
+ });
+ }
}
-
-export {
- endpointApi,
-};
diff --git a/src/common/k8s-api/endpoints/events.api.injectable.ts b/src/common/k8s-api/endpoints/events.api.injectable.ts
new file mode 100644
index 0000000000..c4fbe81224
--- /dev/null
+++ b/src/common/k8s-api/endpoints/events.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { KubeEventApi } from "./events.api";
+
+const kubeEventApiInjectable = getInjectable({
+ id: "kube-event-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "kubeEventApi is only available in certain environments");
+
+ return new KubeEventApi();
+ },
+});
+
+export default kubeEventApiInjectable;
diff --git a/src/common/k8s-api/endpoints/events.api.ts b/src/common/k8s-api/endpoints/events.api.ts
index f2f73ce383..8e6bc843b1 100644
--- a/src/common/k8s-api/endpoints/events.api.ts
+++ b/src/common/k8s-api/endpoints/events.api.ts
@@ -4,34 +4,38 @@
*/
import moment from "moment";
+import type { KubeObjectMetadata, ObjectReference } from "../kube-object";
import { KubeObject } from "../kube-object";
import { formatDuration } from "../../utils/formatDuration";
+import type { DerivedKubeApiOptions } from "../kube-api";
import { KubeApi } from "../kube-api";
-import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
+import type { KubeJsonApiData } from "../kube-json-api";
-export interface KubeEvent {
- involvedObject: {
- kind: string;
- namespace: string;
- name: string;
- uid: string;
- apiVersion: string;
- resourceVersion: string;
- fieldPath: string;
- };
- reason: string;
- message: string;
- source: {
- component: string;
- host: string;
- };
- firstTimestamp: string;
- lastTimestamp: string;
- count: number;
- type: "Normal" | "Warning" | string;
- eventTime: null;
- reportingComponent: string;
- reportingInstance: string;
+export interface EventSeries {
+ count?: number;
+ lastObservedTime?: string;
+}
+
+export interface EventSource {
+ component?: string;
+ host?: string;
+}
+
+export interface KubeEventData extends KubeJsonApiData {
+ action?: string;
+ count?: number;
+ eventTime?: string;
+ firstTimestamp?: string;
+ involvedObject: Required;
+ lastTimestamp?: string;
+ message?: string;
+ reason?: string;
+ related?: ObjectReference;
+ reportingComponent?: string;
+ reportingInstance?: string;
+ series?: EventSeries;
+ source?: EventSource;
+ type?: string;
}
export class KubeEvent extends KubeObject {
@@ -39,14 +43,73 @@ export class KubeEvent extends KubeObject {
static namespaced = true;
static apiBase = "/api/v1/events";
+ action?: string;
+ count?: number;
+ eventTime?: string;
+ firstTimestamp?: string;
+ involvedObject: Required;
+ lastTimestamp?: string;
+ message?: string;
+ reason?: string;
+ related?: ObjectReference;
+ reportingComponent?: string;
+ reportingInstance?: string;
+ series?: EventSeries;
+ source?: EventSource;
+
+ /**
+ * Current supported values are:
+ * - "Normal"
+ * - "Warning"
+ */
+ type?: string;
+
+ constructor({
+ action,
+ count,
+ eventTime,
+ firstTimestamp,
+ involvedObject,
+ lastTimestamp,
+ message,
+ reason,
+ related,
+ reportingComponent,
+ reportingInstance,
+ series,
+ source,
+ type,
+ ...rest
+ }: KubeEventData) {
+ super(rest);
+ this.action = action;
+ this.count = count;
+ this.eventTime = eventTime;
+ this.firstTimestamp = firstTimestamp;
+ this.involvedObject = involvedObject;
+ this.lastTimestamp = lastTimestamp;
+ this.message = message;
+ this.reason = reason;
+ this.related = related;
+ this.reportingComponent = reportingComponent;
+ this.reportingInstance = reportingInstance;
+ this.series = series;
+ this.source = source;
+ this.type = type;
+ }
+
isWarning() {
return this.type === "Warning";
}
getSource() {
- const { component, host } = this.source;
+ if (!this.source?.component) {
+ return "";
+ }
- return `${component} ${host || ""}`;
+ const { component, host = "" } = this.source;
+
+ return `${component} ${host}`;
}
/**
@@ -68,14 +131,11 @@ export class KubeEvent extends KubeObject {
}
}
-let eventApi: KubeApi;
-
-if (isClusterPageContext()) {
- eventApi = new KubeApi({
- objectConstructor: KubeEvent,
- });
+export class KubeEventApi extends KubeApi {
+ constructor(opts: DerivedKubeApiOptions = {}) {
+ super({
+ objectConstructor: KubeEvent,
+ ...opts,
+ });
+ }
}
-
-export {
- eventApi,
-};
diff --git a/src/common/k8s-api/endpoints/helm-charts.api.ts b/src/common/k8s-api/endpoints/helm-charts.api.ts
index 163f90ef36..2690e95afb 100644
--- a/src/common/k8s-api/endpoints/helm-charts.api.ts
+++ b/src/common/k8s-api/endpoints/helm-charts.api.ts
@@ -7,7 +7,7 @@ import { compile } from "path-to-regexp";
import { apiBase } from "../index";
import { stringify } from "querystring";
import type { RequestInit } from "node-fetch";
-import { autoBind, bifurcateArray } from "../../utils";
+import { autoBind, bifurcateArray, isDefined } from "../../utils";
import Joi from "joi";
export type RepoHelmChartList = Record;
@@ -30,9 +30,9 @@ export async function listCharts(): Promise {
return Object
.values(data)
- .reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), [])
+ .reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), new Array())
.map(([chart]) => HelmChart.create(chart, { onError: "log" }))
- .filter(Boolean);
+ .filter(isDefined);
}
export interface GetChartDetailsOptions {
@@ -51,7 +51,7 @@ export async function getChartDetails(repo: string, name: string, { version, req
const path = endpoint({ repo, name });
const { readme, ...data } = await apiBase.get(`${path}?${stringify({ version })}`, undefined, reqInit);
- const versions = data.versions.map(version => HelmChart.create(version, { onError: "log" })).filter(Boolean);
+ const versions = data.versions.map(version => HelmChart.create(version, { onError: "log" })).filter(isDefined);
return {
readme,
@@ -242,7 +242,7 @@ export interface RawHelmChartDependency {
export type HelmChartDependency = Required>
& Pick;
-export interface HelmChart {
+export interface HelmChartData {
apiVersion: string;
name: string;
version: string;
@@ -266,8 +266,30 @@ export interface HelmChart {
tillerVersion?: string;
}
-export class HelmChart {
- private constructor(value: HelmChart) {
+export class HelmChart implements HelmChartData {
+ apiVersion: string;
+ name: string;
+ version: string;
+ repo: string;
+ created: string;
+ description: string;
+ keywords: string[];
+ sources: string[];
+ urls: string[];
+ annotations: Record;
+ dependencies: HelmChartDependency[];
+ maintainers: HelmChartMaintainer[];
+ deprecated: boolean;
+ kubeVersion?: string;
+ digest?: string;
+ home?: string;
+ engine?: string;
+ icon?: string;
+ appVersion?: string;
+ type?: string;
+ tillerVersion?: string;
+
+ private constructor(value: HelmChart | HelmChartData) {
this.apiVersion = value.apiVersion;
this.name = value.name;
this.version = value.version;
@@ -294,25 +316,25 @@ export class HelmChart {
}
static create(data: RawHelmChart, { onError = "throw" }: HelmChartCreateOpts = {}): HelmChart | undefined {
- const { value, error } = helmChartValidator.validate(data, {
+ const result = helmChartValidator.validate(data, {
abortEarly: false,
});
- if (!error) {
- return new HelmChart(value);
+ if (!result.error) {
+ return new HelmChart(result.value);
}
- const [actualErrors, unknownDetails] = bifurcateArray(error.details, ({ type }) => type === "object.unknown");
+ const [actualErrors, unknownDetails] = bifurcateArray(result.error.details, ({ type }) => type === "object.unknown");
if (unknownDetails.length > 0) {
console.warn("HelmChart data has unexpected fields", { original: data, unknownFields: unknownDetails.flatMap(d => d.path) });
}
if (actualErrors.length === 0) {
- return new HelmChart(value);
+ return new HelmChart(result.value as unknown as HelmChartData);
}
- const validationError = new Joi.ValidationError(actualErrors.map(er => er.message).join(". "), actualErrors, error._original);
+ const validationError = new Joi.ValidationError(actualErrors.map(er => er.message).join(". "), actualErrors, result.error._original);
if (onError === "throw") {
throw validationError;
@@ -347,7 +369,7 @@ export class HelmChart {
return this.icon;
}
- getHome(): string {
+ getHome(): string | undefined {
return this.home;
}
diff --git a/src/common/k8s-api/endpoints/helm-releases.api.ts b/src/common/k8s-api/endpoints/helm-releases.api.ts
index 141f884c60..b3922276bd 100644
--- a/src/common/k8s-api/endpoints/helm-releases.api.ts
+++ b/src/common/k8s-api/endpoints/helm-releases.api.ts
@@ -9,12 +9,12 @@ import capitalize from "lodash/capitalize";
import { apiBase } from "../index";
import { helmChartStore } from "../../../renderer/components/+helm-charts/helm-chart.store";
import type { ItemObject } from "../../item.store";
-import { KubeObject } from "../kube-object";
import type { JsonApiData } from "../json-api";
import { buildURLPositional } from "../../utils/buildUrl";
import type { KubeJsonApiData } from "../kube-json-api";
-interface IReleasePayload {
+export interface HelmReleaseDetails {
+ resources: KubeJsonApiData[];
name: string;
namespace: string;
version: string;
@@ -30,15 +30,7 @@ interface IReleasePayload {
};
}
-interface IReleaseRawDetails extends IReleasePayload {
- resources: KubeJsonApiData[];
-}
-
-export interface IReleaseDetails extends IReleasePayload {
- resources: KubeObject[];
-}
-
-export interface IReleaseCreatePayload {
+export interface HelmReleaseCreatePayload {
name?: string;
repo: string;
chart: string;
@@ -47,19 +39,19 @@ export interface IReleaseCreatePayload {
values: string;
}
-export interface IReleaseUpdatePayload {
+export interface HelmReleaseUpdatePayload {
repo: string;
chart: string;
version: string;
values: string;
}
-export interface IReleaseUpdateDetails {
+export interface HelmReleaseUpdateDetails {
log: string;
- release: IReleaseDetails;
+ release: HelmReleaseDetails;
}
-export interface IReleaseRevision {
+export interface HelmReleaseRevision {
revision: number;
updated: string;
status: string;
@@ -85,18 +77,13 @@ export async function listReleases(namespace?: string): Promise {
return releases.map(toHelmRelease);
}
-export async function getRelease(name: string, namespace: string): Promise {
+export async function getRelease(name: string, namespace: string): Promise {
const path = endpoint({ name, namespace });
- const { resources: rawResources, ...details } = await apiBase.get(path);
- const resources = rawResources.map(KubeObject.create);
- return {
- ...details,
- resources,
- };
+ return apiBase.get(path);
}
-export async function createRelease(payload: IReleaseCreatePayload): Promise {
+export async function createRelease(payload: HelmReleaseCreatePayload): Promise {
const { repo, chart: rawChart, values: rawValues, ...data } = payload;
const chart = `${repo}/${rawChart}`;
const values = yaml.load(rawValues);
@@ -110,7 +97,7 @@ export async function createRelease(payload: IReleaseCreatePayload): Promise {
+export async function updateRelease(name: string, namespace: string, payload: HelmReleaseUpdatePayload): Promise {
const { repo, chart: rawChart, values: rawValues, ...data } = payload;
const chart = `${repo}/${rawChart}`;
const values = yaml.load(rawValues);
@@ -137,7 +124,7 @@ export async function getReleaseValues(name: string, namespace: string, all?: bo
return apiBase.get(path);
}
-export async function getReleaseHistory(name: string, namespace: string): Promise {
+export async function getReleaseHistory(name: string, namespace: string): Promise {
const route = "history";
const path = endpoint({ name, namespace, route });
diff --git a/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable.ts b/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable.ts
new file mode 100644
index 0000000000..70b6458456
--- /dev/null
+++ b/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 assert from "assert";
+import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
+import { HorizontalPodAutoscalerApi } from "./horizontal-pod-autoscaler.api";
+
+const horizontalPodAutoscalerApiInjectable = getInjectable({
+ id: "horizontal-pod-autoscaler-api",
+ instantiate: (di) => {
+ assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "horizontalPodAutoscalerApi is only available in certain environments");
+
+ return new HorizontalPodAutoscalerApi();
+ },
+});
+
+export default horizontalPodAutoscalerApiInjectable;
diff --git a/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.ts b/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.ts
new file mode 100644
index 0000000000..06d5669220
--- /dev/null
+++ b/src/common/k8s-api/endpoints/horizontal-pod-autoscaler.api.ts
@@ -0,0 +1,261 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { BaseKubeObjectCondition, KubeObjectScope, LabelSelector } from "../kube-object";
+import { KubeObject } from "../kube-object";
+import type { DerivedKubeApiOptions } from "../kube-api";
+import { KubeApi } from "../kube-api";
+import type { OptionVarient } from "../../utils";
+
+export enum HpaMetricType {
+ Resource = "Resource",
+ Pods = "Pods",
+ Object = "Object",
+ External = "External",
+ ContainerResource = "ContainerResource",
+}
+
+export interface HorizontalPodAutoscalerMetricTarget {
+ kind: string;
+ name: string;
+ apiVersion: string;
+}
+
+export interface ContainerResourceMetricSource {
+ container: string;
+ name: string;
+ targetAverageUtilization?: number;
+ targetAverageValue?: string;
+}
+
+export interface ExternalMetricSource {
+ metricName: string;
+ metricSelector?: LabelSelector;
+ targetAverageValue?: string;
+ targetValue?: string;
+}
+
+export interface ObjectMetricSource {
+ averageValue?: string;
+ metricName: string;
+ selector?: LabelSelector;
+ target: CrossVersionObjectReference;
+ targetValue: string;
+}
+
+export interface PodsMetricSource {
+ metricName: string;
+ selector?: LabelSelector;
+ targetAverageValue: string;
+}
+
+export interface ResourceMetricSource {
+ name: string;
+ targetAverageUtilization?: number;
+ targetAverageValue?: string;
+}
+
+export interface BaseHorizontalPodAutoscalerMetricSpec {
+ resource: ResourceMetricSource;
+ object: ObjectMetricSource;
+ external: ExternalMetricSource;
+ pods: PodsMetricSource;
+ containerResource: ContainerResourceMetricSource;
+}
+
+export type HorizontalPodAutoscalerMetricSpec =
+ | OptionVarient
+ | OptionVarient
+ | OptionVarient
+ | OptionVarient
+ | OptionVarient