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

Merge remote-tracking branch 'origin/master' into issue-3498

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-02-24 11:12:34 -05:00
commit cee32b1838
158 changed files with 39517 additions and 37226 deletions

View File

@ -24,9 +24,9 @@ jobs:
- name: Generate Extensions API Reference using typedocs
run: |
yarn install
yarn run build:docs
npm install
npm run build:docs
- name: Verify that the markdown is valid
run: |
yarn run mkdocs:verify
npm run mkdocs:verify

View File

@ -21,9 +21,9 @@ jobs:
- name: Install deps
run: |
yarn install
npm install
sudo apt-get install -y ripgrep
cd packages/bump-version-for-cron && yarn build
cd packages/bump-version-for-cron && npm run build
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Bump version
@ -85,14 +85,14 @@ jobs:
- name: Build package
shell: bash
run: |
yarn install --frozen-lockfile
yarn run build
npm ci
npm run build
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release to GitHub NPM registry
run: |
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
yarn lerna \
npx lerna \
publish from-package \
--no-push \
--no-git-tag-version \

View File

@ -20,7 +20,7 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Install deps
run: yarn install
run: npm install
- name: Lint
run: yarn run lint
run: npm run lint

View File

@ -34,12 +34,12 @@ jobs:
- name: Generate Extensions API Reference using typedocs
run: |
yarn install
yarn run build:docs
npm install
npm run build:docs
- name: Verify that the markdown is valid
run: |
yarn run mkdocs:verify
npm run mkdocs:verify
build:
name: Deploy docs
@ -77,8 +77,8 @@ jobs:
- name: Generate Extensions API Reference using typedocs
run: |
yarn install --frozen-lockfile
yarn build:docs
npm ci
npm run build:docs
- name: mkdocs deploy master
if: contains(github.ref, 'refs/heads/master')

View File

@ -37,8 +37,8 @@ jobs:
- name: Generate Extensions API Reference using typedocs
run: |
yarn install
yarn typedocs-extensions-api
npm install
npm run typedocs-extensions-api
- name: Checkout master branch from lens
uses: actions/checkout@v3

View File

@ -32,8 +32,8 @@ jobs:
- name: Generate NPM packages
run: |
yarn install --frozen-lockfile
yarn run build
npm ci
npm run build
- name: Publish NPM packages
run: |
@ -41,7 +41,7 @@ jobs:
VERSION=$(cat lerna.json | jq '.version' --raw-output)
echo ${VERSION}
DIST_TAG=$(node packages/semver/dist/index.js --prerelease 0 ${VERSION})
yarn lerna \
npx lerna \
publish from-package \
--no-push \
--no-git-tag-version \

View File

@ -32,18 +32,20 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Get yarn cache directory path
id: yarn-cache-dir-path
- name: Get npm cache directory path
if: ${{ runner.os != 'Windows' }}
id: npm-cache-dir-path
shell: bash
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
if: ${{ runner.os != 'Windows' }}
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
path: ${{ steps.npm-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-yarn-
${{ runner.os }}-npm-
- uses: nick-fields/retry@v2
name: Install dependencies
@ -51,9 +53,9 @@ jobs:
timeout_minutes: 20
max_attempts: 3
retry_on: error
command: yarn install --frozen-lockfile
command: npm ci
- run: yarn run test:unit
- run: npm run test:unit
name: Run tests
if: ${{ matrix.type == 'unit' }}
@ -64,15 +66,15 @@ jobs:
minikube-version: latest
if: ${{ runner.os == 'Linux' && matrix.type == 'smoke' }}
- run: xvfb-run --auto-servernum --server-args='-screen 0, 1600x900x24' yarn run test:integration
- run: xvfb-run --auto-servernum --server-args='-screen 0, 1600x900x24' npm run test:integration
name: Run Linux integration tests
if: ${{ runner.os == 'Linux' && matrix.type == 'smoke' }}
- run: yarn run test:integration
- run: npm run test:integration
name: Run macOS integration tests
shell: bash
if: ${{ runner.os == 'macOS' && matrix.type == 'smoke' }}
- run: yarn run test:integration
- run: npm run test:integration
name: Run Windows integration tests
if: ${{ runner.os == 'Windows' && matrix.type == 'smoke' }}

3
.gitignore vendored
View File

@ -6,3 +6,6 @@ lens.log
docs/extensions/api
site/
lerna-debug.log
coverage
dist
node_modules

4
.npmrc
View File

@ -1 +1,3 @@
engine-strict=true
disturl "https://electronjs.org/headers"
target "19.0.4"
runtime "electron"

View File

@ -1,3 +0,0 @@
--install.check-files true
--install.network-timeout 100000
--publish.access public

View File

@ -5,15 +5,15 @@ All releases will be made by creating a PR which bumps the version field in the
## Prerequisites
- `yarn`
- Running `yarn` (to install all dependencies)
- `npm`
- Running `npm install`
- `gh` (Github's CLI) with a version at least 2.15.0
## Steps
1. If you are making a minor or major release (or prereleases for one) make sure you are on the `master` branch.
1. If you are making a patch release (or a prerelease for one) make sure you are on the `release/v<MAJOR>.<MINOR>` branch.
1. Run `yarn create-release-pr <release-type>`. If you are making a subsequent prerelease release, provide the `--check-commits` flag.
1. Run `npm run create-release-pr <release-type>`. If you are making a subsequent prerelease release, provide the `--check-commits` flag.
1. If you are checking the commits, type `y<ENTER>` to pick a commit, and `n<ENTER>` to skip it. You will want to skip the commits that were part of previous prerelease releases.
1. Once the PR is created, approved, and then merged the `Release Open Lens` workflow will create a tag and release for you.
1. If you are making a major or minor release, create a `release/v<MAJOR>.<MINOR>` branch and push it to `origin` so that future patch releases can be made from it.

4
jest.config.js Normal file
View File

@ -0,0 +1,4 @@
const { monorepoRootConfig } = require("@k8slens/jest");
module.exports = monorepoRootConfig(__dirname);

View File

@ -1,11 +1,8 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": false,
"packages": [
"packages/*"
],
"useWorkspaces": true,
"version": "6.4.0-beta.13",
"npmClient": "yarn",
"npmClient": "npm",
"npmClientArgs": [
"--network-timeout=100000"
]

34548
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,13 @@
{
"name": "lens-monorepo",
"private": true,
"workspaces": [
"packages/**/*"
],
"scripts": {
"all:install": "npm install",
"adr:create": "echo \"What is the title?\"; read title; adr new \"$title\"",
"adr:change-status": "echo \"Decision number?:\"; read decision; adr status $decision",
"adr:update-readme": "adr update",
@ -16,16 +22,16 @@
"mkdocs:serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest",
"mkdocs:verify": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict",
"test:unit": "lerna run --stream test:unit",
"test:unit:watch": "jest --watch",
"test:integration": "lerna run --stream test:integration",
"bump-version": "lerna version --no-git-tag-version --no-push",
"precreate-release-pr": "cd packages/release-tool && yarn run build",
"create-release-pr": "node packages/release-tool/dist/index.js",
"postinstall": "lerna bootstrap --ignore open-lens && lerna bootstrap --scope open-lens --include-dependencies"
"precreate-release-pr": "cd packages/release-tool && npm run build",
"create-release-pr": "node packages/release-tool/dist/index.js"
},
"devDependencies": {
"adr": "^1.4.3",
"cross-env": "^7.0.3",
"lerna": "^6.5.0",
"lerna": "^6.5.1",
"rimraf": "^4.1.2"
}
}

View File

@ -1,2 +0,0 @@
dist/
node_modules/

View File

@ -48,7 +48,7 @@ try {
});
}
await exec(`yarn run bump-version --yes ${newVersion}`);
await exec(`npm run bump-version ${newVersion} -- --yes`);
} catch (error) {
console.error(error);
process.exit(1);

View File

@ -1,890 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@mole-inc/bin-wrapper@^8.0.1":
version "8.0.1"
resolved "https://registry.yarnpkg.com/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz#d7fd0ceb1cfa8a855293a3ed9d7d135f4d442f0e"
integrity sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==
dependencies:
bin-check "^4.1.0"
bin-version-check "^5.0.0"
content-disposition "^0.5.4"
ext-name "^5.0.0"
file-type "^17.1.6"
filenamify "^5.0.2"
got "^11.8.5"
os-filter-obj "^2.0.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@sindresorhus/is@^4.0.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==
"@swc/cli@^0.1.61":
version "0.1.61"
resolved "https://registry.yarnpkg.com/@swc/cli/-/cli-0.1.61.tgz#202c70644b30e7b5f9c2590045f7fda72920b998"
integrity sha512-HeYMJ+8gKfJzM9xgcZqTpAHJYAJVGSljBSmWRUx2B6UiGraLsLjEcqxITwi6/t6Af+QboBMiQX5Wwll89oPK7g==
dependencies:
"@mole-inc/bin-wrapper" "^8.0.1"
commander "^7.1.0"
fast-glob "^3.2.5"
semver "^7.3.8"
slash "3.0.0"
source-map "^0.7.3"
"@swc/core-darwin-arm64@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.35.tgz#55ff0cc069769ce8bf6562ca0e724fe9c43deb8c"
integrity sha512-zQUFkHx4gZpu0uo2IspvPnKsz8bsdXd5bC33xwjtoAI1cpLerDyqo4v2zIahEp+FdKZjyVsLHtfJiQiA1Qka3A==
"@swc/core-darwin-x64@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.35.tgz#270543a2aad6ddbc2d8e8d9a0b025bc08cef9a48"
integrity sha512-oOSkSGWtALovaw22lNevKD434OQTPf8X+dVPvPMrJXJpJ34dWDlFWpLntoc+arvKLNZ7LQmTuk8rR1hkrAY7cw==
"@swc/core-linux-arm-gnueabihf@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.35.tgz#d2c81406202202962c09451ec58e37efacb15c38"
integrity sha512-Yie8k00O6O8BCATS/xeKStquV4OYSskUGRDXBQVDw1FrE23PHaSeHCgg4q6iNZjJzXCOJbaTCKnYoIDn9DMf7A==
"@swc/core-linux-arm64-gnu@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.35.tgz#f4670584fbe71525d919fa06db3ad778cee242e6"
integrity sha512-Zlv3WHa/4x2p51HSvjUWXHfSe1Gl2prqImUZJc8NZOlj75BFzVuR0auhQ+LbwvIQ3gaA1LODX9lyS9wXL3yjxA==
"@swc/core-linux-arm64-musl@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.35.tgz#fd116255cca2d8e098637e95f38ae08f95a47db6"
integrity sha512-u6tCYsrSyZ8U+4jLMA/O82veBfLy2aUpn51WxQaeH7wqZGy9TGSJXoO8vWxARQ6b72vjsnKDJHP4MD8hFwcctg==
"@swc/core-linux-x64-gnu@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.35.tgz#7a0fb187f1e9baa38d05273a7576c4eaf80a96b8"
integrity sha512-Dtxf2IbeH7XlNhP1Qt2/MvUPkpEbn7hhGfpSRs4ot8D3Vf5QEX4S/QtC1OsFWuciiYgHAT1Ybjt4xZic9DSkmA==
"@swc/core-linux-x64-musl@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.35.tgz#ad2632b9ae0ea2bfd1461f121b324063c3d6755e"
integrity sha512-4XavNJ60GprjpTiESCu5daJUnmErixPAqDitJSMu4TV32LNIE8G00S9pDLXinDTW1rgcGtQdq1NLkNRmwwovtg==
"@swc/core-win32-arm64-msvc@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.35.tgz#5761d0f6efd9affa5571104f1a1951b8b530ec45"
integrity sha512-dNGfKCUSX2M4qVyaS80Lyos0FkXyHRCvrdQ2Y4Hrg3FVokiuw3yY6fLohpUfQ5ws3n2A39dh7jGDeh34+l0sGA==
"@swc/core-win32-ia32-msvc@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.35.tgz#53ebcf1a6abb0e5152c17da3871d695dfdc07338"
integrity sha512-ChuPSrDR+JBf7S7dEKPicnG8A3bM0uWPsW2vG+V2wH4iNfNxKVemESHosmYVeEZXqMpomNMvLyeHep1rjRsc0Q==
"@swc/core-win32-x64-msvc@1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.35.tgz#186170a7f33d1a08ce00800baf293e6d114659a9"
integrity sha512-/RvphT4WfuGfIK84Ha0dovdPrKB1bW/mc+dtdmhv2E3EGkNc5FoueNwYmXWRimxnU7X0X7IkcRhyKB4G5DeAmg==
"@swc/core@^1.3.35":
version "1.3.35"
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.35.tgz#a96fa52651e56dc00af7b0b83750be33e151bfa8"
integrity sha512-KmiBin0XSVzJhzX19zTiCqmLslZ40Cl7zqskJcTDeIrRhfgKdiAsxzYUanJgMJIRjYtl9Kcg1V/Ip2o2wL8v3w==
optionalDependencies:
"@swc/core-darwin-arm64" "1.3.35"
"@swc/core-darwin-x64" "1.3.35"
"@swc/core-linux-arm-gnueabihf" "1.3.35"
"@swc/core-linux-arm64-gnu" "1.3.35"
"@swc/core-linux-arm64-musl" "1.3.35"
"@swc/core-linux-x64-gnu" "1.3.35"
"@swc/core-linux-x64-musl" "1.3.35"
"@swc/core-win32-arm64-msvc" "1.3.35"
"@swc/core-win32-ia32-msvc" "1.3.35"
"@swc/core-win32-x64-msvc" "1.3.35"
"@szmarczak/http-timer@^4.0.5":
version "4.0.6"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
dependencies:
defer-to-connect "^2.0.0"
"@tokenizer/token@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
"@types/cacheable-request@^6.0.1":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
dependencies:
"@types/http-cache-semantics" "*"
"@types/keyv" "^3.1.4"
"@types/node" "*"
"@types/responselike" "^1.0.0"
"@types/http-cache-semantics@*":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
"@types/keyv@^3.1.4":
version "3.1.4"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
dependencies:
"@types/node" "*"
"@types/node@*":
version "18.13.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850"
integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==
"@types/node@^16.18.11":
version "16.18.12"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.12.tgz#e3bfea80e31523fde4292a6118f19ffa24fd6f65"
integrity sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==
"@types/responselike@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
dependencies:
"@types/node" "*"
"@types/semver@^7.3.13":
version "7.3.13"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
arch@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
arg@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
bin-check@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49"
integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==
dependencies:
execa "^0.7.0"
executable "^4.1.0"
bin-version-check@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/bin-version-check/-/bin-version-check-5.0.0.tgz#958de30174d3fcedadbfc52f89f37bca62594877"
integrity sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==
dependencies:
bin-version "^6.0.0"
semver "^7.3.5"
semver-truncate "^2.0.0"
bin-version@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/bin-version/-/bin-version-6.0.0.tgz#08ecbe5fc87898b441425e145f9e105064d00315"
integrity sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==
dependencies:
execa "^5.0.0"
find-versions "^5.0.0"
braces@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
cacheable-lookup@^5.0.3:
version "5.0.4"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
cacheable-request@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^4.0.0"
lowercase-keys "^2.0.0"
normalize-url "^6.0.1"
responselike "^2.0.0"
clone-response@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
dependencies:
mimic-response "^1.0.0"
commander@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
content-disposition@^0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
dependencies:
safe-buffer "5.2.1"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==
dependencies:
lru-cache "^4.0.1"
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
dependencies:
mimic-response "^3.1.0"
defer-to-connect@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
integrity sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==
dependencies:
cross-spawn "^5.0.1"
get-stream "^3.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^5.0.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
human-signals "^2.1.0"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.1"
onetime "^5.1.2"
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
executable@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c"
integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==
dependencies:
pify "^2.2.0"
ext-list@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
dependencies:
mime-db "^1.28.0"
ext-name@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6"
integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==
dependencies:
ext-list "^2.0.0"
sort-keys-length "^1.0.0"
fast-glob@^3.2.5:
version "3.2.12"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fastq@^1.6.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
dependencies:
reusify "^1.0.4"
file-type@^17.1.6:
version "17.1.6"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-17.1.6.tgz#18669e0577a4849ef6e73a41f8bdf1ab5ae21023"
integrity sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==
dependencies:
readable-web-to-node-stream "^3.0.2"
strtok3 "^7.0.0-alpha.9"
token-types "^5.0.0-alpha.2"
filename-reserved-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz#3d5dd6d4e2d73a3fed2ebc4cd0b3448869a081f7"
integrity sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==
filenamify@^5.0.2:
version "5.1.1"
resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-5.1.1.tgz#a1ccc5ae678a5e34f578afcb9b72898264d166d2"
integrity sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==
dependencies:
filename-reserved-regex "^3.0.0"
strip-outer "^2.0.0"
trim-repeated "^2.0.0"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
find-versions@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-5.1.0.tgz#973f6739ce20f5e439a27eba8542a4b236c8e685"
integrity sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==
dependencies:
semver-regex "^4.0.5"
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
got@^11.8.5:
version "11.8.6"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
dependencies:
"@sindresorhus/is" "^4.0.0"
"@szmarczak/http-timer" "^4.0.5"
"@types/cacheable-request" "^6.0.1"
"@types/responselike" "^1.0.0"
cacheable-lookup "^5.0.3"
cacheable-request "^7.0.2"
decompress-response "^6.0.0"
http2-wrapper "^1.0.0-beta.5.2"
lowercase-keys "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
http-cache-semantics@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
http2-wrapper@^1.0.0-beta.5.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
dependencies:
quick-lru "^5.1.1"
resolve-alpn "^1.0.0"
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
keyv@^4.0.0:
version "4.5.2"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56"
integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==
dependencies:
json-buffer "3.0.1"
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
dependencies:
pseudomap "^1.0.2"
yallist "^2.1.2"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
mime-db@^1.28.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
mimic-response@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
normalize-url@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
dependencies:
path-key "^2.0.0"
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
onetime@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
os-filter-obj@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/os-filter-obj/-/os-filter-obj-2.0.0.tgz#1c0b62d5f3a2442749a2d139e6dddee6e81d8d16"
integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==
dependencies:
arch "^2.1.0"
p-cancelable@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
path-key@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
peek-readable@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
readable-stream@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-web-to-node-stream@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb"
integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==
dependencies:
readable-stream "^3.6.0"
resolve-alpn@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
responselike@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
dependencies:
lowercase-keys "^2.0.0"
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.1.2.tgz#20dfbc98083bdfaa28b01183162885ef213dbf7c"
integrity sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
safe-buffer@5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
semver-regex@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-4.0.5.tgz#fbfa36c7ba70461311f5debcb3928821eb4f9180"
integrity sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==
semver-truncate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/semver-truncate/-/semver-truncate-2.0.0.tgz#cce4c0af36dbd97e898b821be870d17fbfb67f56"
integrity sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==
dependencies:
semver "^6.0.0"
semver@^6.0.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.5, semver@^7.3.8:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
dependencies:
lru-cache "^6.0.0"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
signal-exit@^3.0.0, signal-exit@^3.0.3:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
slash@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
sort-keys-length@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
integrity sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==
dependencies:
sort-keys "^1.0.0"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
integrity sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==
dependencies:
is-plain-obj "^1.0.0"
source-map@^0.7.3:
version "0.7.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
strip-outer@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-2.0.0.tgz#c45c724ed9b1ff6be5f660503791404f4714084b"
integrity sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==
strtok3@^7.0.0-alpha.9:
version "7.0.0"
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5"
integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==
dependencies:
"@tokenizer/token" "^0.3.0"
peek-readable "^5.0.0"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
token-types@^5.0.0-alpha.2:
version "5.0.1"
resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4"
integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==
dependencies:
"@tokenizer/token" "^0.3.0"
ieee754 "^1.2.1"
trim-repeated@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-2.0.0.tgz#5d60556d6d40d9461b7c7e06c3ac20b6b1d50090"
integrity sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==
dependencies:
escape-string-regexp "^5.0.0"
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

View File

@ -1,5 +1,3 @@
static/build/
build/webpack/
binaries/
dist/
node_modules/

View File

@ -1,3 +0,0 @@
disturl "https://electronjs.org/headers"
target "19.0.4"
runtime "electron"

View File

@ -1,27 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
const { notarize } = require("electron-notarize");
exports.default = async function notarizing(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== "darwin") {
return;
}
if (!process.env.APPLEID || !process.env.APPLEIDPASS) {
return;
}
const appName = context.packager.appInfo.productFilename;
return await notarize({
appBundleId: process.env.APPBUNDLEID || "io.kontena.lens-app",
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
ascProvider:process.env.ASCPROVIDER,
});
};

View File

@ -50,14 +50,14 @@
"license": "MIT",
"author": "OpenLens Authors <info@k8slens.dev>",
"scripts": {
"build": "cross-env NODE_ENV=production yarn run webpack --config webpack/library-bundle.ts --progress",
"build": "cross-env NODE_ENV=production webpack --config webpack/library-bundle.ts --progress",
"clean": "rimraf dist static/build",
"prepare:dev": "cross-env NODE_ENV=development yarn run webpack --config webpack/library-bundle.ts --progress",
"dev": "cross-env NODE_ENV=development yarn run webpack --config webpack/library-bundle.ts --watch",
"prepare:dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --progress",
"dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --watch",
"test:unit": "jest --testPathIgnorePatterns integration",
"test:watch": "func() { jest ${1} --watch --testPathIgnorePatterns integration; }; func",
"lint": "PROD=true yarn run eslint --ext js,ts,tsx --max-warnings=0 .",
"lint:fix": "yarn run lint --fix"
"lint": "PROD=true eslint --ext js,ts,tsx --max-warnings=0 .",
"lint:fix": "npm run lint --fix"
},
"config": {
"k8sProxyVersion": "0.3.0",
@ -126,7 +126,7 @@
"dependencies": {
"@astronautlabs/jsonpath": "^1.1.0",
"@hapi/call": "^9.0.1",
"@hapi/subtext": "^7.0.4",
"@hapi/subtext": "^7.1.0",
"@k8slens/node-fetch": "^6.4.0-beta.13",
"@kubernetes/client-node": "^0.18.1",
"@material-ui/styles": "^4.11.5",
@ -158,12 +158,12 @@
"hpagent": "^1.2.0",
"http-proxy": "^1.18.1",
"immer": "^9.0.19",
"joi": "^17.7.0",
"joi": "^17.7.1",
"js-yaml": "^4.1.0",
"lodash": "^4.17.15",
"marked": "^4.2.12",
"md5-file": "^5.0.0",
"mobx": "^6.7.0",
"mobx": "^6.8.0",
"mobx-observable-history": "^2.0.3",
"mobx-react": "^7.6.0",
"mobx-utils": "^6.0.4",
@ -192,7 +192,7 @@
"win-ca": "^3.5.0",
"winston": "^3.8.2",
"winston-transport-browserconsole": "^1.0.5",
"ws": "^8.12.0",
"ws": "^8.12.1",
"xterm-link-provider": "^1.3.1"
},
"devDependencies": {
@ -242,7 +242,7 @@
"@types/react-window": "^1.8.5",
"@types/readable-stream": "^2.3.13",
"@types/semver": "^7.3.13",
"@types/tar": "^6.1.3",
"@types/tar": "^6.1.4",
"@types/tcp-port-used": "^1.0.1",
"@types/tempy": "^0.3.0",
"@types/triple-beam": "^1.3.2",
@ -268,8 +268,7 @@
"dompurify": "^2.4.4",
"electron": "^19.1.9",
"electron-builder": "^23.6.0",
"electron-notarize": "^0.3.0",
"esbuild": "^0.17.7",
"esbuild": "^0.17.8",
"esbuild-loader": "^2.21.0",
"eslint": "^8.33.0",
"eslint-import-resolver-typescript": "^3.5.3",
@ -310,7 +309,7 @@
"react-table": "^7.8.0",
"react-window": "^1.8.8",
"rimraf": "^4.1.2",
"sass": "^1.58.0",
"sass": "^1.58.2",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.2.4",
@ -318,7 +317,7 @@
"ts-node": "^10.9.1",
"type-fest": "^2.14.0",
"typed-emitter": "^1.4.0",
"typedoc": "0.23.24",
"typedoc": "0.23.25",
"typedoc-plugin-markdown": "^3.13.6",
"typescript": "^4.9.5",
"typescript-plugin-css-modules": "^3.4.0",
@ -330,6 +329,7 @@
"xterm-addon-fit": "^0.5.0"
},
"peerDependencies": {
"@k8slens/application": "^6.4.0-beta.13",
"@types/byline": "^4.2.33",
"@types/chart.js": "^2.9.36",
"@types/color": "^3.0.3",
@ -340,7 +340,7 @@
"@types/react-router-dom": "^5.3.3",
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5",
"@types/tar": "^6.1.3",
"@types/tar": "^6.1.4",
"@types/tcp-port-used": "^1.0.1",
"@types/url-parse": "^1.4.8",
"@types/uuid": "^8.3.4",

View File

@ -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 replicationControllersRouteInjectable from "./replicationcontrollers-route.injectable";
import { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
const navigateToReplicationControllersInjectable = getInjectable({
id: "navigate-to-replicationcontrollers",
instantiate: (di) => {
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
const route = di.inject(replicationControllersRouteInjectable);
return () => navigateToRoute(route);
},
});
export default navigateToReplicationControllersInjectable;

View File

@ -0,0 +1,24 @@
/**
* 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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const replicationControllersRouteInjectable = getInjectable({
id: "replicationcontrollers-route",
instantiate: (di) => ({
path: "/replicationcontrollers",
clusterFrame: true,
isEnabled: di.inject(shouldShowResourceInjectionToken, {
apiName: "replicationcontrollers",
group: "", // core
}),
}),
injectionToken: frontEndRouteInjectionToken,
});
export default replicationControllersRouteInjectable;

View File

@ -2,13 +2,13 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "../../../vars/application-information-token";
const welcomeRouteConfigInjectable = getInjectable({
id: "welcome-route-config",
instantiate: (di) => di.inject(applicationInformationToken).config.welcomeRoute,
instantiate: (di) => di.inject(applicationInformationToken).welcomeRoute,
});
export default welcomeRouteConfigInjectable;

View File

@ -19,6 +19,9 @@ import { KubeObject } from "../kube-object";
import { KubeObjectStore } from "../kube-object.store";
import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
// eslint-disable-next-line no-restricted-imports
import { KubeApi as ExternalKubeApi } from "../../../extensions/common-api/k8s-api";
class TestApi extends KubeApi<KubeObject> {
protected async checkPreferredVersion() {
return;
@ -54,7 +57,7 @@ describe("ApiManager", () => {
});
describe("registerApi", () => {
it("re-register store if apiBase changed", async () => {
it("re-register store if apiBase changed", () => {
const apiBase = "apis/v1/foo";
const fallbackApiBase = "/apis/extensions/v1beta1/foo";
const kubeApi = new TestApi({
@ -72,21 +75,48 @@ describe("ApiManager", () => {
logger: di.inject(loggerInjectable),
}, kubeApi);
apiManager.registerApi(apiBase, kubeApi);
apiManager.registerApi(kubeApi);
// Define to use test api for ingress store
Object.defineProperty(kubeStore, "api", { value: kubeApi });
apiManager.registerStore(kubeStore, [kubeApi]);
apiManager.registerStore(kubeStore);
// Test that store is returned with original apiBase
expect(apiManager.getStore(kubeApi)).toBe(kubeStore);
// Change apiBase similar as checkPreferredVersion does
Object.defineProperty(kubeApi, "apiBase", { value: fallbackApiBase });
apiManager.registerApi(fallbackApiBase, kubeApi);
apiManager.registerApi(kubeApi);
// Test that store is returned with new apiBase
expect(apiManager.getStore(kubeApi)).toBe(kubeStore);
});
});
describe("technical tests for autorun", () => {
it("given two extensions register apis with the same apibase, settle into using the second", () => {
const apiBase = "/apis/aquasecurity.github.io/v1alpha1/vulnerabilityreports";
const firstApi = Object.assign(new ExternalKubeApi({
objectConstructor: KubeObject,
apiBase,
kind: "VulnerabilityReport",
}), {
myField: 1,
});
const secondApi = Object.assign(new ExternalKubeApi({
objectConstructor: KubeObject,
apiBase,
kind: "VulnerabilityReport",
}), {
myField: 2,
});
void firstApi;
void secondApi;
expect(apiManager.getApi(apiBase)).toMatchObject({
myField: 2,
});
});
});
});

View File

@ -41,19 +41,22 @@ export class ApiManager {
const apis = chain(this.dependencies.apis.get().values())
.concat(this.externalApis.values());
const removedApis = new Set(this.apis.values());
const newState = new Map(this.apis);
for (const api of apis) {
removedApis.delete(api);
this.apis.set(api.apiBase, api);
newState.set(api.apiBase, api);
}
for (const api of removedApis) {
for (const [apiBase, storedApi] of this.apis) {
for (const [apiBase, storedApi] of newState) {
if (storedApi === api) {
this.apis.delete(apiBase);
newState.delete(apiBase);
}
}
}
this.apis.replace(newState);
});
}

View File

@ -33,6 +33,7 @@ export * from "./pod-metrics.api";
export * from "./pod-security-policy.api";
export * from "./priority-class.api";
export * from "./replica-set.api";
export * from "./replication-controller.api";
export * from "./resource-quota.api";
export * from "./role.api";
export * from "./role-binding.api";

View File

@ -37,18 +37,17 @@ export interface RequestMetricsParams {
namespace?: string;
}
export interface RequestMetrics {
(query: string, params?: RequestMetricsParams): Promise<MetricData>;
(query: string[], params?: RequestMetricsParams): Promise<MetricData[]>;
<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
}
export type RequestMetrics = ReturnType<typeof requestMetricsInjectable["instantiate"]>;
const requestMetricsInjectable = getInjectable({
id: "request-metrics",
instantiate: (di) => {
const apiBase = di.inject(apiBaseInjectable);
return (async (query: object, params: RequestMetricsParams = {}) => {
function requestMetrics(query: string, params?: RequestMetricsParams): Promise<MetricData>;
function requestMetrics(query: string[], params?: RequestMetricsParams): Promise<MetricData[]>;
function requestMetrics<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
async function requestMetrics(query: string | string[] | Partial<Record<string, Partial<Record<string, string>>>>, params: RequestMetricsParams = {}): Promise<MetricData | MetricData[] | Partial<Record<string, MetricData>>> {
const { range = 3600, step = 60, namespace } = params;
let { start, end } = params;
@ -66,7 +65,9 @@ const requestMetricsInjectable = getInjectable({
"kubernetes_namespace": namespace,
},
});
}) as RequestMetrics;
}
return requestMetrics;
},
});

View File

@ -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 { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
import loggerInjectable from "../../logger.injectable";
import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
import { ReplicationControllerApi } from "./replication-controller.api";
const replicationControllerApiInjectable = getInjectable({
id: "replication-controller-api",
instantiate: (di) => {
return new ReplicationControllerApi({
logger: di.inject(loggerInjectable),
maybeKubeApi: di.inject(maybeKubeApiInjectable),
});
},
injectionToken: kubeApiInjectionToken,
});
export default replicationControllerApiInjectable;

View File

@ -0,0 +1,149 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
import { KubeApi } from "../kube-api";
import type {
BaseKubeObjectCondition, KubeObjectMetadata,
KubeObjectStatus,
NamespaceScopedMetadata,
} from "../kube-object";
import { KubeObject } from "../kube-object";
import type { PodTemplateSpec } from "./types";
export class ReplicationControllerApi extends KubeApi<ReplicationController> {
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
super(deps, {
...opts ?? {},
objectConstructor: ReplicationController,
});
}
protected getScaleApiUrl(params: { namespace: string; name: string }) {
return `${this.formatUrlForNotListing(params)}/scale`;
}
getScale(params: { namespace: string; name: string }): Promise<Scale> {
return this.request.get(this.getScaleApiUrl(params));
}
scale(params: { namespace: string; name: string }, replicas: number): Promise<Scale> {
return this.request.patch(this.getScaleApiUrl(params), {
data: {
metadata: params,
spec: {
replicas,
},
},
}, {
headers: {
"content-type": "application/strategic-merge-patch+json",
},
});
}
}
export interface Scale {
apiVersion: "autoscaling/v1";
kind: "Scale";
metadata: KubeObjectMetadata;
spec: {
replicas: number;
};
status: {
replicas: number;
selector: string;
};
}
export interface ReplicationControllerSpec {
/**
* Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available.
* Defaults to 0 (pod will be considered available as soon as it is ready)
*/
minReadySeconds?: number;
/**
* Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified.
* Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
*/
replicas?: number;
/**
* Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template.
* Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template.
* More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
*/
selector?: Record<string, string>;
/**
* Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef.
* More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template
*/
template: PodTemplateSpec;
}
export interface ReplicationControllerStatus extends KubeObjectStatus {
/**
* The number of available replicas (ready for at least minReadySeconds) for this replication controller.
*/
availableReplicas: number;
/**
* The number of pods that have labels matching the labels of the pod template of the replication controller.
*/
fullyLabeledReplicas: number;
/**
* ObservedGeneration reflects the generation of the most recently observed replication controller.
*/
observedGeneration: number;
/**
* The number of ready replicas for this replication controller.
*/
readyReplicas: number;
/**
* Replicas is the most recently observed number of replicas.
* More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
*/
replicas: number;
}
export class ReplicationController extends KubeObject<
NamespaceScopedMetadata,
ReplicationControllerStatus,
ReplicationControllerSpec
> {
static kind = "ReplicationController";
static namespaced = true;
static apiBase = "/api/v1/replicationcontrollers";
getMinReadySeconds(): number {
return this.spec?.minReadySeconds ?? 0;
}
getGeneration() {
return this.status?.observedGeneration;
}
getSelectorLabels(): string[] {
return KubeObject.stringifyLabels(this.spec.selector);
}
getReplicas(): number | undefined {
return this.status?.replicas;
}
getDesiredReplicas(): number {
return this.spec?.replicas ?? 0;
}
getAvailableReplicas(): number | undefined {
return this.status?.availableReplicas;
}
getLabeledReplicas(): number | undefined {
return this.status?.fullyLabeledReplicas;
}
getConditions(): BaseKubeObjectCondition[] {
return this.status?.conditions ?? [];
}
}

View File

@ -4,6 +4,4 @@
*/
// @experimental
export { applicationInformationToken } from "./vars/application-information-token";
export type { ApplicationInformation } from "./vars/application-information-token";
export { bundledExtensionInjectionToken } from "../extensions/extension-discovery/bundled-extension-token";

View File

@ -6,7 +6,7 @@
export type KubeResource =
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "replicationcontrollers" | "jobs" | "cronjobs" |
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "verticalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
"priorityclasses" | "runtimeclasses" |
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts";
@ -171,6 +171,11 @@ export const apiResourceRecord: Record<KubeResource, KubeApiResourceData> = {
group: "apps",
namespaced: true,
},
replicationcontrollers: {
kind: "ReplicationController",
group: "", // core
namespaced: true,
},
roles: {
kind: "Role",
group: "rbac.authorization.k8s.io",

View File

@ -6,7 +6,7 @@
import { getGlobalOverride } from "../test-utils/get-global-override";
import randomBytesInjectable from "./random-bytes.injectable";
export default getGlobalOverride(randomBytesInjectable, () => async (size) => {
export default getGlobalOverride(randomBytesInjectable, () => (size) => {
const res = Buffer.alloc(size);
for (let i = 0; i < size; i += 1) {

View File

@ -4,13 +4,12 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { randomBytes } from "crypto";
import { promisify } from "util";
export type RandomBytes = (size: number) => Promise<Buffer>;
export type RandomBytes = (size: number) => Buffer;
const randomBytesInjectable = getInjectable({
id: "random-bytes",
instantiate: (): RandomBytes => promisify(randomBytes),
instantiate: (): RandomBytes => randomBytes,
causesSideEffects: true,
});

View File

@ -2,8 +2,8 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const applicationCopyrightInjectable = getInjectable({
id: "application-copyright",

View File

@ -2,8 +2,8 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const applicationDescriptionInjectable = getInjectable({
id: "application-description",

View File

@ -0,0 +1,30 @@
/**
* 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 { applicationInformationToken } from "@k8slens/application";
export const applicationInformationFakeInjectable = getInjectable({
id: "application-information-fake",
instantiate: () => ({
name: "some-product-name",
productName: "some-product-name",
version: "6.0.0",
updatingIsEnabled: false,
k8sProxyVersion: "0.2.1",
bundledKubectlVersion: "1.23.3",
bundledHelmVersion: "3.7.2",
sentryDsn: "",
contentSecurityPolicy:
"script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
welcomeRoute: "/welcome",
copyright: "some-copyright-information",
description: "some-descriptive-text",
}),
injectionToken: applicationInformationToken,
});

View File

@ -1,20 +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 packageJson from "../../../package.json";
import { applicationInformationToken } from "../../common/vars/application-information-token";
const applicationInformationInjectable = getInjectable({
id: "application-information",
injectionToken: applicationInformationToken,
instantiate: () => {
const { version, config, productName, build, copyright, description, name } = packageJson;
return { version, config, productName, build, copyright, description, name };
},
causesSideEffects: true,
});
export default applicationInformationInjectable;

View File

@ -1,15 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type packageJson from "../../../package.json";
export type ApplicationInformation = Pick<typeof packageJson, "version" | "config" | "productName" | "copyright" | "description" | "name"> & {
build: Partial<typeof packageJson["build"]> & { publish?: unknown[] };
};
export const applicationInformationToken = getInjectionToken<ApplicationInformation>({
id: "application-information-token",
});

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../test-utils/get-global-override";
import applicationInformationInjectable from "./application-information-injectable";
export default getGlobalOverride(applicationInformationInjectable, () => ({
name: "some-product-name",
productName: "some-product-name",
version: "6.0.0",
build: {} as any,
config: {
k8sProxyVersion: "0.2.1",
bundledKubectlVersion: "1.23.3",
bundledHelmVersion: "3.7.2",
sentryDsn: "",
contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
welcomeRoute: "/welcome",
},
copyright: "some-copyright-information",
description: "some-descriptive-text",
}));

View File

@ -2,12 +2,12 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const bundledKubectlVersionInjectable = getInjectable({
id: "bundled-kubectl-version",
instantiate: (di) => di.inject(applicationInformationToken).config.bundledKubectlVersion,
instantiate: (di) => di.inject(applicationInformationToken).bundledKubectlVersion,
});
export default bundledKubectlVersionInjectable;

View File

@ -2,12 +2,12 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const contentSecurityPolicyInjectable = getInjectable({
id: "content-security-policy",
instantiate: (di) => di.inject(applicationInformationToken).config.contentSecurityPolicy,
instantiate: (di) => di.inject(applicationInformationToken).contentSecurityPolicy,
});
export default contentSecurityPolicyInjectable;

View File

@ -2,8 +2,8 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const productNameInjectable = getInjectable({
id: "product-name",

View File

@ -2,12 +2,12 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "./application-information-token";
const sentryDataSourceNameInjectable = getInjectable({
id: "sentry-data-source-name",
instantiate: (di) => di.inject(applicationInformationToken).config.sentryDsn,
instantiate: (di) => di.inject(applicationInformationToken).sentryDsn,
});
export default sentryDataSourceNameInjectable;

View File

@ -47,17 +47,29 @@ const getKubeApiDeps = (): KubeApiDependencies => {
};
};
export interface ExternalKubeApiOptions {
/**
* If `true` then on creation of the `KubeApi`instance a call to `apiManager.registerApi` will be
* made. This is `true` by default to maintain backwards compatability.
*
* Setting this to `false` might make `KubeObject`'s details drawer stop working.
*
* @default true
*/
autoRegister?: boolean;
}
// NOTE: this is done to preserve `instanceOf` behaviour
function KubeApiCstr<
Object extends KubeObject = KubeObject,
Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>,
>(opts: KubeApiOptions<Object, Data>) {
>({ autoRegister = true, ...opts }: KubeApiOptions<Object, Data> & ExternalKubeApiOptions) {
const api = new InternalKubeApi(getKubeApiDeps(), opts);
const di = getLegacyGlobalDiForExtensionApi();
const storesAndApisCanBeCreated = di.inject(storesAndApisCanBeCreatedInjectionToken);
if (storesAndApisCanBeCreated) {
if (storesAndApisCanBeCreated && autoRegister) {
apiManager.registerApi(api);
}
@ -72,7 +84,7 @@ export type KubeApi<
export const KubeApi = KubeApiCstr as unknown as new<
Object extends KubeObject = KubeObject,
Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>,
>(opts: KubeApiOptions<Object, Data>) => InternalKubeApi<Object, Data>;
>(opts: KubeApiOptions<Object, Data> & ExternalKubeApiOptions) => InternalKubeApi<Object, Data>;
/**
* @deprecated Switch to using `Common.createResourceStack` instead

View File

@ -3,17 +3,18 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ObservableMap } from "mobx";
import { getInjectable } from "@ogre-tools/injectable";
import { getOrInsertWithAsync } from "../../../common/utils";
import { getOrInsert } from "../../../common/utils";
import randomBytesInjectable from "../../../common/utils/random-bytes.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable";
import getHashInjectable from "./get-hash.injectable";
import getPathToLegacyPackageJsonInjectable from "./get-path-to-legacy-package-json.injectable";
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
export type EnsureHashedDirectoryForExtension = (extensionName: string, registeredExtensions: ObservableMap<string, string>) => Promise<string>;
export type EnsureHashedDirectoryForExtension = (extensionName: string) => Promise<string>;
const ensureHashedDirectoryForExtensionInjectable = getInjectable({
id: "ensure-hashed-directory-for-extension",
@ -24,14 +25,27 @@ const ensureHashedDirectoryForExtensionInjectable = getInjectable({
const directoryForExtensionData = di.inject(directoryForExtensionDataInjectable);
const ensureDirectory = di.inject(ensureDirInjectable);
const getHash = di.inject(getHashInjectable);
const getPathToLegacyPackageJson = di.inject(getPathToLegacyPackageJsonInjectable);
const registeredExtensions = di.inject(registeredExtensionsInjectable);
return async (extensionName, registeredExtensions) => {
const dirPath = await getOrInsertWithAsync(registeredExtensions, extensionName, async () => {
const salt = (await randomBytes(32)).toString("hex");
return async (extensionName) => {
let dirPath: string;
const legacyDirPath = getPathToLegacyPackageJson(extensionName);
const hashedDirectoryForLegacyDirPath = registeredExtensions.get(legacyDirPath);
if (hashedDirectoryForLegacyDirPath) {
registeredExtensions.set(extensionName, hashedDirectoryForLegacyDirPath);
registeredExtensions.delete(legacyDirPath);
dirPath = hashedDirectoryForLegacyDirPath;
} else {
const salt = randomBytes(32).toString("hex");
const hashedName = getHash(`${extensionName}/${salt}`);
return joinPaths(directoryForExtensionData, hashedName);
});
const hashedExtensionDirectory = joinPaths(directoryForExtensionData, hashedName);
dirPath = getOrInsert(registeredExtensions, extensionName, hashedExtensionDirectory);
}
await ensureDirectory(dirPath);

View File

@ -0,0 +1,96 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ObservableMap } from "mobx";
import { runInAction } from "mobx";
import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting";
import type { EnsureHashedDirectoryForExtension } from "./ensure-hashed-directory-for-extension.injectable";
import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable";
import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable";
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
describe("ensure-hashed-directory-for-extension", () => {
let ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
let ensureDirMock: jest.Mock;
let registeredExtensions: ObservableMap<string, string>;
beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
ensureDirMock = jest.fn();
di.override(ensureDirInjectable, () => ensureDirMock);
di.override(directoryForExtensionDataInjectable, () => "some-directory-for-extension-data");
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
ensureHashedDirectoryForExtension = di.inject(
ensureHashedDirectoryForExtensionInjectable,
);
registeredExtensions = di.inject(registeredExtensionsInjectable);
});
it("given registered extension exists, returns existing directory", async () => {
runInAction(() => {
registeredExtensions.set("some-extension-name", "some-directory");
});
const actual = await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(actual).toBe("some-directory");
});
it("given registered extension does not exist, returns random directory", async () => {
const actual = await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(actual).toBe("some-directory-for-extension-data/a37a1cfefc0391af3733f23cb6b29443f596a2b8ffe6d116c35df7bc3cd99ef6");
});
describe("given extension directory was saved based on extension's package.json path", () => {
beforeEach(() => {
runInAction(() => {
registeredExtensions.set("/some-directory-for-user-data/node_modules/some-extension-name/package.json", "some-directory");
});
ensureDirMock.mockClear();
});
it("returns existing directory", async () => {
const actual = await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(actual).toBe("some-directory");
});
it("ensure dir is called with some directory", async () => {
await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(ensureDirMock).toHaveBeenCalledWith("some-directory");
});
it("is migrated to use the extension name as key", async () => {
await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(registeredExtensions.get("some-extension-name")).toEqual("some-directory");
});
it("old key is removed", async () => {
await ensureHashedDirectoryForExtension(
"some-extension-name",
);
expect(registeredExtensions.has("/some-directory-for-user-data/node_modules/some-extension-name/package.json")).toEqual(false);
});
});
});

View File

@ -0,0 +1,10 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { MigrationDeclaration } from "../../../common/base-store/migrations.injectable";
export const fileSystemProvisionerStoreInjectionToken = getInjectionToken<MigrationDeclaration>({
id: "file-system-provisioner-store-injection-token",
});

View File

@ -15,6 +15,7 @@ import { enlistMessageChannelListenerInjectionToken } from "../../../common/util
import fileSystemProvisionerStoreMigrationVersionInjectable from "./migration-version.injectable";
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable";
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
const fileSystemProvisionerStoreInjectable = getInjectable({
id: "file-system-provisioner-store",
@ -32,6 +33,7 @@ const fileSystemProvisionerStoreInjectable = getInjectable({
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
sendMessageToChannel: di.inject(sendMessageToChannelInjectionToken),
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
registeredExtensions: di.inject(registeredExtensionsInjectable),
}),
});

View File

@ -3,7 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { action, makeObservable, observable } from "mobx";
import type { ObservableMap } from "mobx";
import { action, makeObservable } from "mobx";
import type { BaseStoreDependencies } from "../../../common/base-store/base-store";
import { BaseStore } from "../../../common/base-store/base-store";
import type { LensExtensionId } from "../../lens-extension";
@ -16,11 +17,10 @@ interface FSProvisionModel {
interface Dependencies extends BaseStoreDependencies {
ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
registeredExtensions: ObservableMap<LensExtensionId, string>;
}
export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
readonly registeredExtensions = observable.map<LensExtensionId, string>();
constructor(protected readonly dependencies: Dependencies) {
super(dependencies, {
configName: "lens-filesystem-provisioner-store",
@ -37,17 +37,17 @@ export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
* @returns path to the folder that the extension can safely write files to.
*/
async requestDirectory(extensionName: string): Promise<string> {
return this.dependencies.ensureHashedDirectoryForExtension(extensionName, this.registeredExtensions);
return this.dependencies.ensureHashedDirectoryForExtension(extensionName);
}
@action
protected fromStore({ extensions }: FSProvisionModel = { extensions: {}}): void {
this.registeredExtensions.merge(extensions);
this.dependencies.registeredExtensions.merge(extensions);
}
toJSON(): FSProvisionModel {
return toJS({
extensions: Object.fromEntries(this.registeredExtensions),
extensions: Object.fromEntries(this.dependencies.registeredExtensions),
});
}
}

View File

@ -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 directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
export type GetPathToLegacyPackageJson = (extensionName: string) => string;
const getPathToLegacyPackageJson = getInjectable({
id: "get-path-to-legacy-package-json",
instantiate: (di): GetPathToLegacyPackageJson => {
const directoryForUserData = di.inject(directoryForUserDataInjectable);
const joinPaths = di.inject(joinPathsInjectable);
return (extensionName: string) => joinPaths(directoryForUserData, "node_modules", extensionName, "package.json");
},
});
export default getPathToLegacyPackageJson;

View File

@ -0,0 +1,12 @@
/**
* 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 { observable } from "mobx";
import type { LensExtensionId } from "../../lens-extension";
export const registeredExtensionsInjectable = getInjectable({
id: "registered-extensions",
instantiate: () => observable.map<LensExtensionId, string>(),
});

View File

@ -27,12 +27,12 @@ export abstract class IpcMain extends IpcRegistrar {
listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
const cleanup = once(() => {
this.extension[lensExtensionDependencies].logger.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
return ipcMain.removeListener(prefixedChannel, listener);
});
this.extension[lensExtensionDependencies].logger.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
ipcMain.addListener(prefixedChannel, listener);
this.extension[Disposers].push(cleanup);
@ -47,10 +47,10 @@ export abstract class IpcMain extends IpcRegistrar {
handle(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
this.extension[lensExtensionDependencies].logger.info(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
ipcMainHandle(prefixedChannel, handler);
this.extension[Disposers].push(() => {
this.extension[lensExtensionDependencies].logger.info(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
return ipcMain.removeHandler(prefixedChannel);
});

View File

@ -28,12 +28,12 @@ export abstract class IpcRenderer extends IpcRegistrar {
listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
const cleanup = once(() => {
console.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
console.debug(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
return ipcRenderer.removeListener(prefixedChannel, listener);
});
console.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
console.debug(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
ipcRenderer.addListener(prefixedChannel, listener);
this.extension[Disposers].push(cleanup);

View File

@ -38,6 +38,8 @@ import kubeEventApiInjectable from "../../common/k8s-api/endpoints/events.api.in
import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-binding.api.injectable";
import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable";
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
import requestMetricsInjectable from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
const di = getLegacyGlobalDiForExtensionApi();
@ -93,6 +95,17 @@ export const crdApi = asLegacyGlobalForExtensionApi(customResourceDefinitionApiI
export * from "../common-api/k8s-api";
export const requestMetrics = asLegacyGlobalFunctionForExtensionApi(requestMetricsInjectable);
export type {
RequestMetrics,
RequestMetricsParams,
} from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
export type {
MetricData,
MetricResult,
} from "../../common/k8s-api/endpoints/metrics.api";
export {
KubeObjectStatusLevel,
type KubeObjectStatus,

View File

@ -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 { bundledExtensionInjectionToken } from "../../../../../../common/library";
import buildSemanticVersionInjectable from "../../../../../../common/vars/build-semantic-version.injectable";
const aboutBundledExtensionsInjectable = getInjectable({
id: "about-bundled-extensions",
instantiate: (di) => {
const buildSemanticVersion = di.inject(buildSemanticVersionInjectable);
const bundledExtensions = di.injectMany(bundledExtensionInjectionToken);
if (buildSemanticVersion.get().prerelease[0] === "latest") {
return [];
}
return bundledExtensions.map(ext => `${ext.manifest.name}: ${ext.manifest.version}`);
},
});
export default aboutBundledExtensionsInjectable;

View File

@ -10,6 +10,7 @@ import productNameInjectable from "../../../../../../common/vars/product-name.in
import buildVersionInjectable from "../../../../../../main/vars/build-version/build-version.injectable";
import extensionApiVersionInjectable from "../../../../../../common/vars/extension-api-version.injectable";
import applicationCopyrightInjectable from "../../../../../../common/vars/application-copyright.injectable";
import aboutBundledExtensionsInjectable from "./about-bundled-extensions.injectable";
const showAboutInjectable = getInjectable({
id: "show-about",
@ -22,6 +23,7 @@ const showAboutInjectable = getInjectable({
const appName = di.inject(appNameInjectable);
const productName = di.inject(productNameInjectable);
const applicationCopyright = di.inject(applicationCopyrightInjectable);
const aboutBundledExtensions = di.inject(aboutBundledExtensionsInjectable);
return () => {
const appInfo = [
@ -30,6 +32,7 @@ const showAboutInjectable = getInjectable({
`Electron: ${process.versions.electron}`,
`Chrome: ${process.versions.chrome}`,
`Node: ${process.versions.node}`,
...aboutBundledExtensions,
applicationCopyright,
];

View File

@ -2,12 +2,12 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "../../../../../common/vars/application-information-token";
const publishIsConfiguredInjectable = getInjectable({
id: "publish-is-configured",
instantiate: (di) => Boolean(di.inject(applicationInformationToken).build.publish?.length),
instantiate: (di) => Boolean(di.inject(applicationInformationToken).updatingIsEnabled),
});
export default publishIsConfiguredInjectable;

View File

@ -4323,3 +4323,497 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
</div>
</div>
`;
exports[`cluster - sidebar and tab navigation for extensions given extension with cluster pages and cluster page menus with explicit 'orderNumber' given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered renders 1`] = `
<div>
<div
class="Animate slide-right Drawer KubeObjectDetails flex column right enter leave"
style="--size: 725px; --enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="drawer-wrapper flex column"
>
<div
class="drawer-title flex align-center"
>
<div
class="drawer-title-text flex gaps align-center"
>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
<div>
Close
</div>
</div>
<div
class="drawer-content flex column box grow"
/>
</div>
<div
class="ResizingAnchor horizontal leading"
/>
</div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
>
<div
class="sidebar"
>
<div
class="flex flex-col"
data-testid="cluster-sidebar"
>
<div
class="SidebarCluster"
>
<div
class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
>
??
</div>
<div
class="loadingClusterName"
/>
</div>
<div
class="sidebarNav sidebar-active-status"
>
<div
class="SidebarItem"
data-is-active-test="true"
data-testid="sidebar-item-some-extension-name-some-parent-id"
>
<a
aria-current="page"
class="navItem active"
data-testid="sidebar-item-link-for-some-extension-name-some-parent-id"
href="/"
>
<div>
Some icon
</div>
<span>
Parent
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-workloads"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-workloads"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span>
Workloads
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-config"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-config"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="list"
>
list
</span>
</i>
<span>
Config
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-network"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-network"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="device_hub"
>
device_hub
</span>
</i>
<span>
Network
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-storage"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-storage"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="storage"
>
storage
</span>
</i>
<span>
Storage
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-helm"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-helm"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span>
Helm
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-user-management"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-user-management"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="security"
>
security
</span>
</i>
<span>
Access Control
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-custom-resources"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-custom-resources"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="extension"
>
extension
</span>
</i>
<span>
Custom Resources
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
</div>
</div>
<div
class="ResizingAnchor horizontal trailing"
/>
</div>
<div
class="contents"
>
<div
class="TabLayout"
data-testid="tab-layout"
>
<div
class="Tabs center scrollable"
>
<div
class="Tab flex gaps align-center active"
data-is-active-test="true"
data-testid="tab-link-for-some-extension-name-some-child-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Child 1
</div>
</div>
<div
class="Tab flex gaps align-center"
data-is-active-test="false"
data-testid="tab-link-for-some-extension-name-some-other-child-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Child 2
</div>
</div>
</div>
<main
class=""
>
<div
data-testid="some-child-page"
>
Some child page
</div>
</main>
</div>
</div>
<div
class="footer"
>
<div
class="Dock"
tabindex="-1"
>
<div
class="ResizingAnchor vertical leading"
/>
<div
class="tabs-container flex align-center"
>
<div
class="dockTabs"
role="tablist"
>
<div
class="Tabs tabs"
>
<div
class="Tab flex gaps align-center DockTab TerminalTab active"
data-testid="dock-tab-for-terminal"
id="tab-terminal"
role="tab"
tabindex="0"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="terminal"
>
terminal
</span>
</i>
<div
class="label"
>
<div
class="flex align-center"
>
<span
class="title"
>
Terminal
</span>
<div
class="close"
>
<i
class="Icon material interactive focusable small"
data-testid="dock-tab-close-for-terminal"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
<div
data-testid="tooltip-content-for-dock-tab-close-for-terminal"
>
Close ⌘+W
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="toolbar flex gaps align-center box grow"
>
<div
class="dock-menu box grow"
>
<i
class="Icon new-dock-tab material interactive focusable"
id="menu-actions-for-dock"
tabindex="0"
>
<span
class="icon"
data-icon-name="add"
>
add
</span>
</i>
<div>
New tab
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="fullscreen"
>
fullscreen
</span>
</i>
<div>
Fit to window
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="keyboard_arrow_up"
>
keyboard_arrow_up
</span>
</i>
<div>
Open
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -79,7 +79,11 @@ exports[`disable kube object detail items when cluster is not relevant given ext
<span
class="value"
>
some-namespace
<a
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
>
some-namespace
</a>
</span>
</div>
<div
@ -710,7 +714,11 @@ exports[`disable kube object detail items when cluster is not relevant given ext
<span
class="value"
>
some-namespace
<a
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
>
some-namespace
</a>
</span>
</div>
<div>
@ -1336,7 +1344,11 @@ exports[`disable kube object detail items when cluster is not relevant given not
<span
class="value"
>
some-namespace
<a
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
>
some-namespace
</a>
</span>
</div>
<div>

View File

@ -79,7 +79,11 @@ exports[`reactively hide kube object detail item renders 1`] = `
<span
class="value"
>
some-namespace
<a
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
>
some-namespace
</a>
</span>
</div>
<div>
@ -705,7 +709,11 @@ exports[`reactively hide kube object detail item when the item is shown renders
<span
class="value"
>
some-namespace
<a
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
>
some-namespace
</a>
</span>
</div>
<div

View File

@ -21,6 +21,7 @@ import { runInAction, computed, observable } from "mobx";
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import { flushPromises } from "../../common/test-utils/flush-promises";
import type { ClusterPageMenuRegistration } from "../../extensions/common-api/types";
describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder;
@ -141,15 +142,12 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const route = windowDi
.inject(routesInjectable)
.get()
.find(
matches({
path: "/extension/some-extension-name/some-child-page-id",
}),
);
.find(matches({
path: "/extension/some-extension-name/some-child-page-id",
}));
assert(route);
navigateToRoute(route);
});
it("renders", () => {
@ -455,4 +453,131 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
});
});
});
describe("given extension with cluster pages and cluster page menus with explicit 'orderNumber'", () => {
let someObservable: IObservableValue<boolean>;
beforeEach(() => {
someObservable = observable.box(false);
const testExtension = {
id: "some-extension-id",
name: "some-extension-name",
rendererOptions: {
clusterPages: [
{
components: {
Page: () => {
throw new Error("should never come here");
},
},
},
{
id: "some-child-page-id",
components: {
Page: () => <div data-testid="some-child-page">Some child page</div>,
},
},
{
id: "some-other-child-page-id",
components: {
Page: () => (
<div data-testid="some-other-child-page">Some other child page</div>
),
},
},
],
clusterPageMenus: [
{
id: "some-parent-id",
title: "Parent",
components: {
Icon: () => <div>Some icon</div>,
},
orderNumber: -Infinity,
},
{
id: "some-child-id",
target: { pageId: "some-child-page-id" },
parentId: "some-parent-id",
title: "Child 1",
components: {
Icon: null as never,
},
},
{
id: "some-other-child-id",
target: { pageId: "some-other-child-page-id" },
parentId: "some-parent-id",
title: "Child 2",
components: {
Icon: null as never,
},
},
{
id: "some-menu-with-controlled-visibility",
title: "Some menu with controlled visibility",
visible: computed(() => someObservable.get()),
components: {
Icon: () => <div>Some icon</div>,
},
},
] as ClusterPageMenuRegistration[],
},
};
applicationBuilder.extensions.enable(testExtension);
});
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
beforeEach(async () => {
rendered = await applicationBuilder.render();
const windowDi = applicationBuilder.applicationWindow.only.di;
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const route = windowDi
.inject(routesInjectable)
.get()
.find(matches({
path: "/extension/some-extension-name/some-child-page-id",
}));
assert(route);
navigateToRoute(route);
});
it("renders", () => {
expect(rendered.container).toMatchSnapshot();
});
it("renderes parent as first item in sidebar", () => {
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
assert(parent);
expect(parent.previousSibling).toBeNull();
});
it("parent is highlighted", () => {
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
expect(parent?.dataset.isActiveTest).toBe("true");
});
it("parent sidebar item is not expanded", () => {
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
expect(child).toBeNull();
});
it("child page is shown", () => {
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
});
});
});
});

View File

@ -2939,7 +2939,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -3016,7 +3016,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -3142,7 +3142,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
class="Select__menu-portal css-1no2yl0-MenuPortal"
>
<div
class="theme-outlined install-chart-version-select-for-some-first-tab-id-options Select__menu css-1nmdiq5-menu"
class="theme-dark install-chart-version-select-for-some-first-tab-id-options Select__menu css-1nmdiq5-menu"
id="react-select-install-chart-version-select-for-some-first-tab-id-listbox"
>
<div
@ -3958,7 +3958,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -4033,7 +4033,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -4951,7 +4951,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -5026,7 +5026,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -5939,7 +5939,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -6014,7 +6014,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -6927,7 +6927,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -7002,7 +7002,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -7937,7 +7937,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -8012,7 +8012,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -8140,7 +8140,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
class="Select__menu-portal css-1no2yl0-MenuPortal"
>
<div
class="NamespaceSelectMenu theme-outlined install-chart-namespace-select-for-some-first-tab-id-options Select__menu css-1nmdiq5-menu"
class="NamespaceSelectMenu theme-dark install-chart-namespace-select-for-some-first-tab-id-options Select__menu css-1nmdiq5-menu"
id="react-select-install-chart-namespace-select-for-some-first-tab-id-listbox"
>
<div
@ -8956,7 +8956,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -9031,7 +9031,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -9944,7 +9944,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -10019,7 +10019,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -13453,7 +13453,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -13528,7 +13528,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -15566,7 +15566,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -15643,7 +15643,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -16608,7 +16608,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -16683,7 +16683,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -17596,7 +17596,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -17671,7 +17671,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -18584,7 +18584,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -18659,7 +18659,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"

View File

@ -1125,7 +1125,7 @@ exports[`installing helm chart from previously opened tab given tab for installi
Version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -1200,7 +1200,7 @@ exports[`installing helm chart from previously opened tab given tab for installi
Namespace
</span>
<div
class="Select theme-outlined NamespaceSelect css-b62m3t-container"
class="Select theme-dark NamespaceSelect css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"

View File

@ -4064,7 +4064,7 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
Upgrade version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
@ -5074,7 +5074,7 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
Upgrade version
</span>
<div
class="Select theme-outlined chart-version css-b62m3t-container"
class="Select theme-dark chart-version css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"

View File

@ -225,15 +225,96 @@ describe("showing details for helm release", () => {
it("closes details for first release", () => {
expect(
rendered.queryByTestId("helm-release-details-for-some-namespace/some-name"),
rendered.queryByTestId(
"helm-release-details-for-some-namespace/some-name",
),
).not.toBeInTheDocument();
});
it("opens details for second release", () => {
expect(
rendered.getByTestId("helm-release-details-for-some-other-namespace/some-other-name"),
rendered.getByTestId(
"helm-release-details-for-some-other-namespace/some-other-name",
),
).toBeInTheDocument();
});
it("shows spinner", () => {
expect(
rendered.getByTestId("helm-release-detail-content-spinner"),
).toBeInTheDocument();
});
describe("when details for second release resolve", () => {
beforeEach(async () => {
await requestDetailedHelmReleaseMock.resolve({
callWasSuccessful: true,
response: {
release: {
appVersion: "some-app-version",
chart: "some-chart-1.0.0",
status: "some-status",
updated: "some-updated",
revision: "some-revision",
name: "some-other-name",
namespace: "some-other-namespace",
},
details: {
name: "some-other-name",
namespace: "some-other-namespace",
version: "some-version",
config: "some-config",
manifest: "some-manifest",
info: {
deleted: "some-deleted",
description: "some-description",
first_deployed: "some-first-deployed",
last_deployed: "some-last-deployed",
notes: "some-notes",
status: "some-status",
},
resources: [
{
kind: "some-kind",
apiVersion: "some-api-version",
metadata: {
uid: "some-uid",
name: "some-resource",
namespace: "some-namespace",
creationTimestamp: "2015-10-22T07:28:00Z",
},
},
],
},
},
});
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("calls for release configuration", () => {
expect(
requestHelmReleaseConfigurationMock,
).toHaveBeenCalledWith("some-other-name", "some-other-namespace", true);
});
describe("when configuration resolves", () => {
beforeEach(async () => {
await requestHelmReleaseConfigurationMock.resolve(
"some-other-configuration",
);
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
});
});
});
describe("when details is closed", () => {
@ -411,7 +492,7 @@ describe("showing details for helm release", () => {
describe("when changing the configuration", () => {
beforeEach(() => {
const configuration = rendered.getByTestId(
"monaco-editor-for-helm-release-configuration",
"monaco-editor-for-helm-release-configuration-some-namespace/some-name",
);
fireEvent.change(configuration, {
@ -425,7 +506,7 @@ describe("showing details for helm release", () => {
it("has the configuration", () => {
const input = rendered.getByTestId(
"monaco-editor-for-helm-release-configuration",
"monaco-editor-for-helm-release-configuration-some-namespace/some-name",
);
expect(input).toHaveValue("some-new-configuration");
@ -467,7 +548,7 @@ describe("showing details for helm release", () => {
it("overrides the user inputted configuration with new configuration", () => {
const input = rendered.getByTestId(
"monaco-editor-for-helm-release-configuration",
"monaco-editor-for-helm-release-configuration-some-namespace/some-name",
);
expect(input).toHaveValue("some-other-configuration");

View File

@ -6,12 +6,12 @@
// Fix embedded kubeconfig paths under snap config
import { getInjectable } from "@ogre-tools/injectable";
import { applicationInformationToken } from "../../../common/vars/application-information-token";
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
import loggerInjectable from "../../../common/logger.injectable";
import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable";
import type { ClusterModel } from "../../../common/cluster-types";
import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable";
import { applicationInformationToken } from "@k8slens/application";
const clusterStoreSnapMigrationInjectable = getInjectable({
id: "cluster-store-snap-migration",

View File

@ -3,15 +3,5 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { createContainer } from "@ogre-tools/injectable";
import { runInAction } from "mobx";
import applicationInformationInjectable from "../common/vars/application-information-injectable";
export const getDi = () => {
const di = createContainer("main");
runInAction(() => {
di.register(applicationInformationInjectable);
});
return di;
};
export const getDi = () => createContainer("main");

View File

@ -29,9 +29,9 @@ import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
import initializeClusterManagerInjectable from "./cluster/initialize-manager.injectable";
import type { GlobalOverride } from "../common/test-utils/get-global-override";
import applicationInformationInjectable from "../common/vars/application-information-injectable";
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
import { applicationInformationFakeInjectable } from "../common/vars/application-information-fake-injectable";
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
const {
@ -57,9 +57,10 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
.filter(isInjectable)
) as Injectable<any, any, any>[];
registerMobX(di);
runInAction(() => {
registerMobX(di);
di.register(applicationInformationInjectable);
di.register(applicationInformationFakeInjectable);
chunk(100)(injectables).forEach(chunkInjectables => {
di.register(...chunkInjectables);

View File

@ -13,9 +13,9 @@ import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-b
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
import lensResourcesDirInjectable from "../../../../common/vars/lens-resources-dir.injectable";
import isLinuxInjectable from "../../../../common/vars/is-linux.injectable";
import { applicationInformationToken } from "../../../../common/vars/application-information-token";
import pathExistsSyncInjectable from "../../../../common/fs/path-exists-sync.injectable";
import lensProxyCertificateInjectable from "../../../../common/certificate/lens-proxy-certificate.injectable";
import { applicationInformationToken } from "@k8slens/application";
export type ElectronWindowTitleBarStyle = "hiddenInset" | "hidden" | "default" | "customButtonsOnHover";
@ -27,10 +27,11 @@ export interface UrlSource {
}
export type ContentSource = RequireExactlyOne<FileSource & UrlSource>;
// see https://www.electronjs.org/docs/latest/api/session#sessetcertificateverifyprocproc
enum ChromiumNetError {
SUCCESS = 0,
FAILURE = 1,
RESULT_FROM_CHROMIUM,
FAILURE = -2,
RESULT_FROM_CHROMIUM = -3,
}
export interface ElectronWindowConfiguration {

View File

@ -7,8 +7,8 @@ import { docsUrl, slackUrl } from "../../../common/vars";
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
import { getInjectable } from "@ogre-tools/injectable";
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
import { applicationInformationToken } from "../../../common/vars/application-information-token";
import { lensDocumentationWeblinkId, lensSlackWeblinkId } from "../links";
import { applicationInformationToken } from "@k8slens/application";
const currentVersionWeblinkStoreMigrationInjectable = getInjectable({
id: "current-version-weblink-store-migration",

View File

@ -29,17 +29,9 @@ export async function bootstrap(di: DiContainer) {
assert(rootElem, "#app MUST exist");
const extensionLoader = di.inject(extensionLoaderInjectable);
extensionLoader.init();
const extensionDiscovery = di.inject(extensionDiscoveryInjectable);
extensionDiscovery.init();
const extensionInstallationStateStore = di.inject(extensionInstallationStateStoreInjectable);
extensionInstallationStateStore.bindIpcListeners();
await di.inject(extensionLoaderInjectable).init();
await di.inject(extensionDiscoveryInjectable).init();
di.inject(extensionInstallationStateStoreInjectable).bindIpcListeners();
let App;
let initializeApp;

View File

@ -127,7 +127,7 @@
}
.catalogAvatar {
font-size: 1.2ch;
font-size: 1.2ch !important;
}
.views {

View File

@ -85,6 +85,7 @@ const NonInjectedReleaseDetailsContent = observer(({ model }: Dependencies & Rel
</DrawerItem>
<ReleaseValues
releaseId={model.id}
configuration={model.configuration}
onlyUserSuppliedValuesAreShown={
model.onlyUserSuppliedValuesAreShown
@ -150,11 +151,12 @@ const ResourceGroup = ({
);
interface ReleaseValuesProps {
releaseId: string;
configuration: ConfigurationInput;
onlyUserSuppliedValuesAreShown: OnlyUserSuppliedValuesAreShownToggle;
}
const ReleaseValues = observer(({ configuration, onlyUserSuppliedValuesAreShown }: ReleaseValuesProps) => {
const ReleaseValues = observer(({ releaseId, configuration, onlyUserSuppliedValuesAreShown }: ReleaseValuesProps) => {
const configurationIsLoading = configuration.isLoading.get();
return (
@ -171,7 +173,7 @@ const ReleaseValues = observer(({ configuration, onlyUserSuppliedValuesAreShown
/>
<MonacoEditor
id="helm-release-configuration"
id={`helm-release-configuration-${releaseId}`}
style={{ minHeight: 300 }}
value={configuration.nonSavedValue.get()}
onChange={configuration.onChange}

View File

@ -9,7 +9,7 @@ import React from "react";
import upperFirst from "lodash/upperFirst";
import kebabCase from "lodash/kebabCase";
import { disposeOnUnmount, observer } from "mobx-react";
import { DrawerItem, DrawerItemLabels } from "../drawer";
import { DrawerItem } from "../drawer";
import { Badge } from "../badge";
import type { KubeObjectDetailsProps } from "../kube-object-details";
import { formatNodeTaint, Node } from "../../../common/k8s-api/endpoints";
@ -23,7 +23,8 @@ import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.inj
import type { PodStore } from "../+workloads-pods/store";
import podStoreInjectable from "../+workloads-pods/store.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import loadPodsFromAllNamespacesInjectable from "../+workloads-pods/load-pods-from-all-namespaces.injectable";
import loadPodsFromAllNamespacesInjectable
from "../+workloads-pods/load-pods-from-all-namespaces.injectable";
export interface NodeDetailsProps extends KubeObjectDetailsProps<Node> {
}
@ -97,14 +98,6 @@ class NonInjectedNodeDetails extends React.Component<NodeDetailsProps & Dependen
</DrawerItem>
</>
)}
<DrawerItemLabels
name="Labels"
labels={node.getLabels()}
/>
<DrawerItemLabels
name="Annotations"
labels={node.getAnnotations()}
/>
{taints.length > 0 && (
<DrawerItem name="Taints" labelsOnly>
{taints.map(taint => <Badge key={taint.key} label={formatNodeTaint(taint)} />)}

View File

@ -78,7 +78,7 @@ class NonInjectedDeploymentReplicaSets extends React.Component<DeploymentReplica
sortSyncWithUrl={false}
className="box grow"
>
<TableHead flat>
<TableHead flat sticky={false}>
<TableCell className="name" sortBy={sortBy.name}>Name</TableCell>
<TableCell className="warning"/>
<TableCell className="namespace" sortBy={sortBy.namespace}>Namespace</TableCell>

View File

@ -190,7 +190,7 @@ class NonInjectedPodDetailsList extends React.Component<PodDetailsListProps & De
)}
className="box grow"
>
<TableHead flat>
<TableHead flat sticky={virtual}>
<TableCell className="name" sortBy={sortBy.name}>Name</TableCell>
<TableCell className="warning"/>
<TableCell className="node" sortBy={sortBy.node}>Node</TableCell>

View File

@ -0,0 +1,7 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export * from "./replicationcontrollers";
export * from "./replicationcontroller-details";

View File

@ -0,0 +1,24 @@
/**
* 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 { ReplicationControllers } from "./replicationcontrollers";
import {
routeSpecificComponentInjectionToken,
} from "../../routes/route-specific-component-injection-token";
import replicationControllersRouteInjectable
from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable";
const replicationControllersRouteComponentInjectable = getInjectable({
id: "replicationcontroller-route-component",
instantiate: (di) => ({
route: di.inject(replicationControllersRouteInjectable),
Component: ReplicationControllers,
}),
injectionToken: routeSpecificComponentInjectionToken,
});
export default replicationControllersRouteComponentInjectable;

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
.ReplicationControllerDetails {
.replicas {
display: flex;
gap: calc(var(--margin) * 2);
align-items: center;
> * {
flex-shrink: 0;
}
}
}

View File

@ -0,0 +1,122 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "./replicationcontroller-details.module.scss";
import React from "react";
import { action, makeObservable, observable } from "mobx";
import { observer } from "mobx-react";
import { withInjectables } from "@ogre-tools/injectable-react";
import { DrawerItem, DrawerTitle } from "../drawer";
import { Badge } from "../badge";
import type { KubeObjectDetailsProps } from "../kube-object-details";
import type {
ReplicationController,
ReplicationControllerApi,
} from "../../../common/k8s-api/endpoints";
import replicationControllerApiInjectable
from "../../../common/k8s-api/endpoints/replication-controller.api.injectable";
import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
import type { ShowNotification } from "../notifications";
import { Slider } from "../slider";
export interface ReplicationControllerDetailsProps extends KubeObjectDetailsProps<ReplicationController> {
}
interface Dependencies {
api: ReplicationControllerApi;
showNotificationError: ShowNotification;
}
@observer
class NonInjectedReplicationControllerDetails<Props extends ReplicationControllerDetailsProps & Dependencies> extends React.Component<Props> {
@observable sliderReplicasValue = this.props.object.getDesiredReplicas();
@observable sliderReplicasDisabled = false;
constructor(props: Props) {
super(props);
makeObservable(this);
}
@action
async scale(replicas: number) {
const { object: resource, api, showNotificationError } = this.props;
try {
await api.scale({
name: resource.getName(),
namespace: resource.getNs(),
}, replicas);
} catch (error) {
this.sliderReplicasValue = resource.getDesiredReplicas(); // rollback to last valid value
showNotificationError(error as Error);
}
}
@action
async onScaleSliderChangeCommitted(evt: React.FormEvent<any>, replicas: number) {
this.sliderReplicasDisabled = true;
await this.scale(replicas);
this.sliderReplicasDisabled = false;
}
render() {
const { object: resource } = this.props;
return (
<div className={styles.ReplicationControllerDetails}>
<DrawerTitle>
Spec
</DrawerTitle>
<DrawerItem name="Replicas">
<div className={styles.replicas}>
<div>{resource.getDesiredReplicas()}</div>
<div>Scale</div>
<Slider
min={0}
max={100}
valueLabelDisplay="auto"
disabled={this.sliderReplicasDisabled}
value={this.sliderReplicasValue}
onChange={(evt, value) => this.sliderReplicasValue = value}
onChangeCommitted={(event, value) => this.onScaleSliderChangeCommitted(event, value as number)}
/>
</div>
</DrawerItem>
<DrawerItem name="Selectors" labelsOnly>
{
resource.getSelectorLabels().map(label => (<Badge key={label} label={label} />))
}
</DrawerItem>
<DrawerTitle>
Status
</DrawerTitle>
<DrawerItem name="Replicas">
{resource.getReplicas()}
</DrawerItem>
<DrawerItem name="Available Replicas">
{resource.getAvailableReplicas()}
</DrawerItem>
<DrawerItem name="Labeled Replicas">
{resource.getLabeledReplicas()}
</DrawerItem>
<DrawerItem name="Controller Generation">
{resource.getGeneration()}
</DrawerItem>
<DrawerItem name="Minimum Pod Readiness">
{`${resource.getMinReadySeconds()} seconds`}
</DrawerItem>
</div>
);
}
}
export const ReplicationControllerDetails = withInjectables<Dependencies, ReplicationControllerDetailsProps>(NonInjectedReplicationControllerDetails, {
getProps: (di, props) => ({
...props,
api: di.inject(replicationControllerApiInjectable),
showNotificationError: di.inject(showErrorNotificationInjectable),
}),
});

View File

@ -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 { computed } from "mobx";
import { workloadsSidebarItemId } from "../+workloads/workloads-sidebar-items.injectable";
import { sidebarItemsInjectionToken } from "../layout/sidebar-items.injectable";
import routeIsActiveInjectable from "../../routes/route-is-active.injectable";
import replicationControllersRouteInjectable
from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable";
import navigateToReplicationControllersInjectable
from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable";
const replicationControllerSidebarItemsInjectable = getInjectable({
id: "replicationctrl-sidebar-items",
instantiate: (di) => {
const route = di.inject(replicationControllersRouteInjectable);
const navigateToPage = di.inject(navigateToReplicationControllersInjectable);
const routeIsActive = di.inject(routeIsActiveInjectable, route);
return computed(() => [
{
id: "replication-controllers",
parentId: workloadsSidebarItemId,
title: "Replication Controllers",
onClick: navigateToPage,
isActive: routeIsActive,
isVisible: route.isEnabled,
orderNumber: 61,
},
]);
},
injectionToken: sidebarItemsInjectionToken,
});
export default replicationControllerSidebarItemsInjectable;

View File

@ -0,0 +1,26 @@
/**
* 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 { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/kube-object-store-token";
import { ReplicationControllerStore } from "./replicationcontroller-store";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import replicationControllerApiInjectable
from "../../../common/k8s-api/endpoints/replication-controller.api.injectable";
const replicationControllerStoreInjectable = getInjectable({
id: "replication-controller-store",
instantiate: (di) => {
const api = di.inject(replicationControllerApiInjectable);
return new ReplicationControllerStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
logger: di.inject(loggerInjectable),
}, api);
},
injectionToken: kubeObjectStoreInjectionToken,
});
export default replicationControllerStoreInjectable;

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type {
ReplicationController,
ReplicationControllerApi,
} from "../../../common/k8s-api/endpoints";
import type {
KubeObjectStoreDependencies,
KubeObjectStoreOptions,
} from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
export interface ReplicationControllerStoreDependencies extends KubeObjectStoreDependencies {
}
export class ReplicationControllerStore extends KubeObjectStore<ReplicationController, ReplicationControllerApi> {
constructor(protected readonly dependencies: ReplicationControllerStoreDependencies, api: ReplicationControllerApi, opts?: KubeObjectStoreOptions) {
super(dependencies, api, opts);
}
}

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
.ReplicationControllers {
}

View File

@ -0,0 +1,86 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "./replicationcontrollers.module.scss";
import React from "react";
import { observer } from "mobx-react";
import { KubeObjectListLayout } from "../kube-object-list-layout";
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
import type { ReplicationControllerStore } from "./replicationcontroller-store";
import { withInjectables } from "@ogre-tools/injectable-react";
import replicationControllerStoreInjectable from "./replicationcontroller-store.injectable";
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
import { Badge } from "../badge";
enum columnId {
name = "name",
namespace = "namespace",
replicas = "replicas",
replicasDesired = "replicasDesired",
selector = "selector",
}
interface Dependencies {
store: ReplicationControllerStore;
}
const NonInjectedReplicationControllers = observer((props: Dependencies) => {
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
isConfigurable
tableId="workload_replicationcontrollers"
className={styles.ReplicationControllers}
store={props.store}
sortingCallbacks={{
[columnId.name]: item => item.getName(),
[columnId.namespace]: item => item.getNs(),
[columnId.selector]: item => item.getSelectorLabels(),
[columnId.replicas]: item => item.getReplicas(),
[columnId.replicasDesired]: item => item.getDesiredReplicas(),
}}
searchFilters={[
item => item.getSearchFields(),
item => item.getSelectorLabels(),
]}
renderHeaderTitle="Replication Controllers"
renderTableHeader={[
{ title: "Name", className: "name", sortBy: columnId.name, id: columnId.name },
{
title: "Namespace",
className: "namespace",
sortBy: columnId.namespace,
id: columnId.namespace,
},
{ title: "Replicas", sortBy: columnId.replicas, id: columnId.replicas },
{
title: "Desired Replicas",
sortBy: columnId.replicasDesired,
id: columnId.replicasDesired,
},
{
title: "Selector",
sortBy: columnId.selector,
id: columnId.selector,
},
]}
renderTableContents={item => [
item.getName(),
<NamespaceSelectBadge key="namespace" namespace={item.getNs()} />,
item.getReplicas(),
item.getDesiredReplicas(),
item.getSelectorLabels().map(label => (<Badge key={label} label={label} />)),
]}
/>
</SiblingsInTabLayout>
);
});
export const ReplicationControllers = withInjectables<Dependencies>(NonInjectedReplicationControllers, {
getProps: (di, props) => ({
...props,
store: di.inject(replicationControllerStoreInjectable),
}),
});

View File

@ -142,7 +142,6 @@ class NonInjectedCreateResource extends React.Component<CreateResourceProps & De
options={this.props.createResourceTemplates.get()}
formatGroupLabel={group => group.label}
menuPlacement="top"
themeName="outlined"
onChange={(option) => {
if (option) {
this.props.createResourceTabStore.setData(this.tabId, option.value);

View File

@ -93,14 +93,12 @@ const NonInjectedInstallChart = observer(
options={version.options.get()}
onChange={(changed) => version.onChange(changed?.value)}
menuPlacement="top"
themeName="outlined"
id={`install-chart-version-select-for-${tabId}`}
/>
<span>Namespace</span>
<NamespaceSelect
showIcons={false}
menuPlacement="top"
themeName="outlined"
value={namespace.value.get()}
onChange={namespace.onChange}
id={`install-chart-namespace-select-for-${tabId}`}

View File

@ -7,10 +7,6 @@
--overlay-bg: #8cc474b8;
--overlay-active-bg: orange;
// fix for `this.logsElement.scrollTop = this.logsElement.scrollHeight`
// `overflow: overlay` don't allow scroll to the last line
overflow: auto;
position: relative;
color: var(--logsForeground);
background: var(--logsBackground);
@ -21,6 +17,7 @@
.list {
overflow-x: scroll!important;
overflow-y: auto!important;
.LogRow {
padding: 2px 16px;

View File

@ -28,7 +28,7 @@ export interface InstantiateArgs {
const logsViewModelInjectable = getInjectable({
id: "logs-view-model",
instantiate: (di, { tabId }: InstantiateArgs) => new LogTabViewModel(tabId, {
instantiate: (di, tabId) => new LogTabViewModel(tabId, {
getLogs: di.inject(getLogsInjectable),
getLogsWithoutTimestamps: di.inject(getLogsWithoutTimestampsInjectable),
getTimestampSplitLogs: di.inject(getTimestampSplitLogsInjectable),
@ -45,7 +45,10 @@ const logsViewModelInjectable = getInjectable({
downloadAllLogs: di.inject(downloadAllLogsInjectable),
searchStore: di.inject(searchStoreInjectable),
}),
lifecycle: lifecycleEnum.transient,
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, tabId: TabId) => `log-tab-view-model-${tabId}}`,
}),
});
export default logsViewModelInjectable;

View File

@ -101,9 +101,7 @@ const NonInjectedLogsDockTab = observer(({
export const LogsDockTab = withInjectables<Dependencies, LogsDockTabProps>(NonInjectedLogsDockTab, {
getProps: (di, props) => ({
...props,
model: di.inject(logsViewModelInjectable, {
tabId: props.tab.id,
}),
model: di.inject(logsViewModelInjectable, props.tab.id),
subscribeStores: di.inject(subscribeStoresInjectable),
podStore: di.inject(podStoreInjectable),
}),

View File

@ -81,7 +81,6 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
id="char-version-input"
className="chart-version"
menuPlacement="top"
themeName="outlined"
value={model.version.value.get()}
options={model.versionOptions.get()}
onChange={model.version.set}

View File

@ -0,0 +1,35 @@
/**
* 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 { kubeObjectDetailItemInjectionToken } from "../kube-object-detail-item-injection-token";
import { computed } from "mobx";
import {
kubeObjectMatchesToKindAndApiVersion,
} from "../kube-object-matches-to-kind-and-api-version";
import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
import { ReplicationControllerDetails } from "../../../+workloads-replicationcontrollers";
const replicationControllerDetailItemInjectable = getInjectable({
id: "replication-controller-detail-item",
instantiate(di) {
const kubeObject = di.inject(currentKubeObjectInDetailsInjectable);
return {
Component: ReplicationControllerDetails,
enabled: computed(() => isReplicationController(kubeObject.value.get()?.object)),
orderNumber: 10,
};
},
injectionToken: kubeObjectDetailItemInjectionToken,
});
export const isReplicationController = kubeObjectMatchesToKindAndApiVersion(
"ReplicationController",
["v1"],
);
export default replicationControllerDetailItemInjectable;

View File

@ -19,6 +19,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import type { NamespaceApi } from "../../../common/k8s-api/endpoints";
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
export interface KubeObjectMetaProps {
object: KubeObject;
@ -28,20 +30,24 @@ export interface KubeObjectMetaProps {
interface Dependencies {
getDetailsUrl: GetDetailsUrl;
apiManager: ApiManager;
namespaceApi: NamespaceApi;
logger: Logger;
}
const NonInjectedKubeObjectMeta = observer(({
apiManager,
getDetailsUrl,
object,
hideFields = [
"uid",
"resourceVersion",
"selfLink",
],
logger,
}: Dependencies & KubeObjectMetaProps) => {
const NonInjectedKubeObjectMeta = observer((
{
apiManager,
getDetailsUrl,
object,
hideFields = [
"uid",
"resourceVersion",
"selfLink",
],
logger,
namespaceApi,
}
: Dependencies & KubeObjectMetaProps) => {
if (!object) {
return null;
}
@ -59,6 +65,10 @@ const NonInjectedKubeObjectMeta = observer(({
getFinalizers, getId, getName, metadata: { creationTimestamp },
} = object;
const ownerRefs = object.getOwnerRefs();
const namespace = getNs();
const namespaceDetailsUrl = namespace ? getDetailsUrl(
namespaceApi.formatUrlForNotListing({ name: namespace }),
) : "";
return (
<>
@ -71,8 +81,8 @@ const NonInjectedKubeObjectMeta = observer(({
{getName()}
<KubeObjectStatusIcon key="icon" object={object} />
</DrawerItem>
<DrawerItem name="Namespace" hidden={isHidden("namespace") || !getNs()}>
{getNs()}
<DrawerItem name="Namespace" hidden={isHidden("namespace") || !namespace}>
<Link to={namespaceDetailsUrl}>{namespace}</Link>
</DrawerItem>
<DrawerItem name="UID" hidden={isHidden("uid")}>
{getId()}
@ -122,5 +132,6 @@ export const KubeObjectMeta = withInjectables<Dependencies, KubeObjectMetaProps>
getDetailsUrl: di.inject(getDetailsUrlInjectable),
apiManager: di.inject(apiManagerInjectable),
logger: di.inject(loggerInjectable),
namespaceApi: di.inject(namespaceApiInjectable),
}),
});

View File

@ -15,6 +15,7 @@ export interface ClusterPageMenuRegistration {
title: React.ReactNode;
components: ClusterPageMenuComponents;
visible?: IComputedValue<boolean>;
orderNumber?: number;
}
export interface ClusterPageMenuComponents {

View File

@ -57,7 +57,7 @@ const extensionSidebarItemRegistratorInjectable = getInjectable({
const res: SidebarItemRegistration = {
id: `${extension.sanitizedExtensionId}-${registration.id}`,
orderNumber: 9999,
orderNumber: registration.orderNumber ?? 9999,
parentId: registration.parentId
? `${extension.sanitizedExtensionId}-${registration.parentId}`

View File

@ -43,10 +43,6 @@ html {
}
}
&__value-container {
margin-bottom: 1px;
}
&__single-value {
color: var(--textColorSecondary);
overflow: visible;
@ -93,6 +89,8 @@ html {
&__option {
white-space: nowrap;
cursor: pointer;
border-radius: 3px;
padding: 6px 8px;
&:active {
background: var(--primary);
@ -179,21 +177,6 @@ html {
}
}
&.theme-outlined {
.Select__control {
box-shadow: 0 0 0 1px var(--colorVague);
color: var(--primary);
.Select__value-container {
padding: 0 $padding * 0.5;
}
.Select__dropdown-indicator {
padding: 3px;
}
}
}
&.theme-lens {
:hover {
&.Select__control {

View File

@ -38,7 +38,6 @@
}
&.flat {
background-color: transparent;
font-weight: 600;
}
}

Some files were not shown because too many files have changed in this diff Show More